LangSmith 如何监听 RAG + Agent 项目:普通 Python、LangChain、LangGraph 三种写法对比

适合读者:正在做 RAG、Agent、多轮工具调用,想知道 LangSmith 到底怎么接入、怎么监听、在 LangChain / LangGraph 里应该怎么用的开发者。

⚠️ LangSmith 非开源,申请有免费额度
⚠️ 企业级生产环境慎用! 避免数据泄露
开源推荐用 langfuse

摘要

LangSmith 不是业务框架,它不负责帮你写 RAG、Agent、工具调用,也不负责替你检索知识库。

它的定位更像是大模型应用的 Trace / Debug / Evaluation / Monitoring 平台。简单说,它负责把一次 AI 请求从输入到输出的完整过程记录下来,让你能看到:

  • 用户输入是什么
  • 最终 Prompt 长什么样
  • 模型返回了什么
  • 哪一步耗时最长
  • 有没有报错
  • token / 成本统计
  • RAG 检索到了哪些内容
  • Agent 调用了哪些工具

在普通 Python 项目里,你通常需要用 @traceablewrap_openai 显式埋点。

在 LangChain / LangGraph 项目里,只要配置好环境变量,LangSmith 可以通过 LangChain / LangGraph 内部的 callback tracing 机制自动监听链路。


目录

文章目录

1. 先说结论

三种项目形态下,LangSmith 的使用方式不一样。

项目类型 业务编排方式 LangSmith 接入方式 适合场景
普通 RAG + Agent 项目 自己写 Python 函数、OpenAI SDK、工具函数 @traceable + wrap_openai 没用 LangChain / LangGraph,但想看清调用链
LangChain 项目 RunnableAgentToolChatOpenAI 环境变量自动追踪,必要时加 run_name/tags/metadata 快速搭建 RAG / Agent,想少写监控代码
LangGraph 项目 StateGraph、节点、边、条件跳转、ToolNode 环境变量自动追踪图节点和工具调用 复杂 Agent、多步骤流程、多分支状态机

最核心的环境变量是:

export LANGSMITH_TRACING=true
export LANGSMITH_API_KEY="你的 LangSmith API Key"
export LANGSMITH_PROJECT="你的项目名"

这三行配置好以后,LangChain / LangGraph 项目里的模型调用、工具调用、Runnable、Graph 节点就会自动被 LangSmith 记录。


2. LangSmith 到底监听了什么?

LangSmith 监听的不是某个端口,也不是偷偷扫描你的代码。

它监听的是一次 AI 应用运行过程中的 Run / Trace 事件

一次请求可以理解成一个 Trace:

用户问题
  -> 输入校验
  -> RAG 检索
  -> Prompt 拼装
  -> 模型调用
  -> Agent 工具调用
  -> 模型总结
  -> 最终回答

LangSmith 会把上面每一步记录成节点,每个节点都有自己的:

  • input
  • output
  • start time
  • end time
  • duration
  • error
  • metadata
  • tags
  • token usage

所以当线上用户说“这个 AI 又乱答了”,你不用只看日志猜问题,而是可以打开 LangSmith 看完整链路。


3. 普通 RAG + Agent 项目中如何用 LangSmith

如果你的项目没有用 LangChain,也没有用 LangGraph,只是普通 Python 代码,例如:

  • 自己写检索函数
  • 自己拼 Prompt
  • 自己调用 OpenAI / DeepSeek / 通义等模型
  • 自己写工具函数

这种情况下,LangSmith 不知道你的业务函数谁是谁,所以你需要显式告诉它:哪些函数需要被记录。

3.1 安装依赖

pip install -U langsmith openai

3.2 配置环境变量

export LANGSMITH_TRACING=true
export LANGSMITH_API_KEY="你的 LangSmith API Key"
export LANGSMITH_PROJECT="plain-rag-agent-demo"
export OPENAI_API_KEY="你的模型 Key"

3.3 普通 Python 项目示例

from openai import OpenAI
from langsmith import traceable
from langsmith.wrappers import wrap_openai


client = wrap_openai(OpenAI())


@traceable(name="RAG 检索")
def retrieve_docs(question: str) -> list[str]:
    """根据用户问题检索知识库文档,并让 LangSmith 记录检索输入和输出。"""
    if "退款" in question:
        return ["会员订单支持 7 天内无理由退款,超过 7 天需要人工审核。"]
    return ["没有检索到明确匹配的知识片段。"]


@traceable(name="Prompt 拼装")
def build_prompt(question: str, docs: list[str]) -> list[dict[str, str]]:
    """把用户问题和检索结果拼成最终发送给模型的 messages。"""
    context = "\n".join(docs)
    return [
        {
            "role": "system",
            "content": "你是一个严谨的中文业务助手,只能基于给定上下文回答。",
        },
        {
            "role": "user",
            "content": f"用户问题:{question}\n\n检索上下文:\n{context}",
        },
    ]


@traceable(name="RAG 主流程")
def answer_question(question: str) -> str:
    """执行完整 RAG 流程,并让 LangSmith 串联检索、Prompt 和模型调用。"""
    docs = retrieve_docs(question)
    messages = build_prompt(question, docs)

    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=messages,
        temperature=0,
    )
    return response.choices[0].message.content


if __name__ == "__main__":
    print(answer_question("会员订单可以退款吗?"))

3.4 这时 LangSmith 能看到什么?

你关心的问题 LangSmith 里看哪里
用户输入是什么 RAG 主流程 的 input
RAG 检索到了什么 RAG 检索 的 output
Prompt 最终长什么样 Prompt 拼装 的 output
模型返回了什么 OpenAI 调用节点的 output
token / 成本统计 OpenAI 调用节点
哪一步耗时最长 Trace 树中每个节点的 duration
有没有报错 出错节点会显示 error

3.5 普通项目的特点

优点:

  • 不依赖 LangChain / LangGraph
  • 改造成本低
  • 适合已有老项目逐步接入

缺点:

  • 需要自己决定哪些函数加 @traceable
  • 工具调用、检索、Agent 循环结构需要自己标注清楚
  • 链路复杂后,埋点容易散

4. LangChain 项目中如何用 LangSmith

LangChain 本身已经有统一的 Runnable、Agent、Tool、Model 抽象。

所以在 LangChain 项目里,LangSmith 不一定需要你手动写 @traceable

只要开启:

export LANGSMITH_TRACING=true

LangChain 执行过程中的 Runnable、Agent、Tool、模型调用就会被自动记录。

4.1 安装依赖

pip install -U langchain langchain-openai langsmith

4.2 配置环境变量

export LANGSMITH_TRACING=true
export LANGSMITH_API_KEY="你的 LangSmith API Key"
export LANGSMITH_PROJECT="langchain-rag-agent-demo"
export OPENAI_API_KEY="你的模型 Key"

4.3 LangChain 业务示例

import re

from langchain.agents import create_agent
from langchain.tools import tool
from langchain_core.runnables import RunnableLambda
from langchain_openai import ChatOpenAI


KNOWLEDGE_BASE = [
    {
        "doc_id": "doc-001",
        "title": "退款政策",
        "content": "会员订单支持 7 天内无理由退款,超过 7 天需要人工审核。",
    },
    {
        "doc_id": "doc-002",
        "title": "六月销售数据",
        "content": "2026 年 6 月 A 产品销售额 1200 元,B 产品销售额 800 元。",
    },
]


def validate_user_input(user_input: str) -> dict:
    """校验用户输入,并转换成 LangChain Agent 接收的 messages 格式。"""
    question = user_input.strip()
    if not question:
        raise ValueError("用户问题不能为空")
    return {"messages": [{"role": "user", "content": question}]}


@tool
def retrieve_docs(question: str) -> list[dict]:
    """根据用户问题检索知识库文档,LangSmith 会记录这个工具的输入和输出。"""
    return [
        doc
        for doc in KNOWLEDGE_BASE
        if any(word in question for word in ["退款", "销售", "销售额"])
    ]


@tool
def calculate_sum(text: str) -> dict:
    """从文本中提取金额并计算合计,LangSmith 会记录 Agent 的工具调用。"""
    numbers = [float(value) for value in re.findall(r"(\d+(?:\.\d+)?)\s*元", text)]
    return {"numbers": numbers, "total": sum(numbers)}


def extract_final_answer(agent_result: dict) -> str:
    """从 Agent 返回结果中提取最后一条模型回答。"""
    return agent_result["messages"][-1].content


model = ChatOpenAI(model="gpt-4o-mini", temperature=0)

agent = create_agent(
    model=model,
    tools=[retrieve_docs, calculate_sum],
    system_prompt=(
        "你是一个严谨的中文业务助手。"
        "回答业务问题时,必须先调用 retrieve_docs 检索知识库;"
        "如果问题涉及合计、总共、总销售额,再调用 calculate_sum 做计算。"
    ),
)

business_chain = (
    RunnableLambda(validate_user_input).with_config({"run_name": "输入校验"})
    | agent.with_config({"run_name": "LangChain Agent 业务链路"})
    | RunnableLambda(extract_final_answer).with_config({"run_name": "提取最终回答"})
).with_config({"run_name": "LangSmith 监听的 LangChain 业务请求"})


if __name__ == "__main__":
    answer = business_chain.invoke(
        "2026 年 6 月 A 产品和 B 产品总销售额是多少?",
        config={
            "tags": ["langsmith", "langchain", "rag", "agent"],
            "metadata": {
                "request_id": "req-001",
                "user_id": "user-123",
            },
        },
    )
    print(answer)

4.4 这段代码里 LangSmith 在哪里?

代码里没有直接写:

from langsmith import Client

也没有手动写:

client.create_run(...)

LangSmith 的监听来自环境变量:

export LANGSMITH_TRACING=true
export LANGSMITH_API_KEY="你的 LangSmith API Key"

然后 LangChain 在执行:

business_chain.invoke(...)

时,会通过内部 callback tracing 机制把这些事件发给 LangSmith:

  • Runnable 开始
  • Runnable 结束
  • LLM 开始
  • LLM 结束
  • Tool 开始
  • Tool 结束
  • Chain 报错

4.5 with_config({"run_name": "输入校验"}) 是什么?

这句:

RunnableLambda(validate_user_input).with_config({"run_name": "输入校验"})

不是开启 LangSmith 的关键。

它的作用是给这个节点起一个更好识别的名字。

没有它,LangSmith 仍然能记录,但页面上可能显示默认名称,不方便定位。

类似地:

config={
    "tags": ["langsmith", "langchain", "rag", "agent"],
    "metadata": {
        "request_id": "req-001",
        "user_id": "user-123",
    },
}

也不是必须的。

它的作用是让你在 LangSmith 后台更方便筛选和排查,例如按 request_id 找某一次请求。

4.6 如果不用 LangSmith,可以怎么写?

如果不用 LangSmith,但还想用 LangChain 链式语法,可以去掉 with_config

business_chain = (
    RunnableLambda(validate_user_input)
    | agent
    | RunnableLambda(extract_final_answer)
)

注意不能直接写:

business_chain = (
    validate_user_input
    | agent
    | extract_final_answer
)

因为普通 Python 函数不能直接用 | 连接。需要先用 RunnableLambda 包装成 LangChain Runnable。

4.7 LangChain 项目中 LangSmith 能看到什么?

你关心的问题 LangSmith 里看哪里
用户输入是什么 根 Trace 的 input
Prompt 最终长什么样 ChatOpenAI 模型调用节点里的 messages
模型返回了什么 模型调用节点 output
哪一步耗时最长 每个 Runnable / Tool / LLM 节点的 duration
有没有报错 报错节点会标红
token / 成本统计 ChatOpenAI 调用节点
RAG 检索到了哪些内容 retrieve_docs 工具节点 output
Agent 调用了哪些工具 Agent 节点下面的 tool calls

5. LangGraph 项目中如何用 LangSmith

LangGraph 更适合复杂 Agent。

如果 LangChain Agent 更像一个封装好的 Agent 执行器,那么 LangGraph 更像是你自己画一个状态机:

START
  -> validate_input
  -> llm_call
  -> tools
  -> llm_call
  -> END

每一个节点、每一条边、每一次条件判断,都可以被清晰地组织起来。

LangSmith 监听 LangGraph 时,会把图节点、模型调用、工具调用都记录下来。

5.1 安装依赖

pip install -U langgraph langchain langchain-openai langsmith

5.2 配置环境变量

export LANGSMITH_TRACING=true
export LANGSMITH_API_KEY="你的 LangSmith API Key"
export LANGSMITH_PROJECT="langgraph-rag-agent-demo"
export OPENAI_API_KEY="你的模型 Key"

5.3 LangGraph 业务示例

import re
from typing import Annotated, Any, Literal

from langchain.tools import tool
from langchain_core.messages import BaseMessage, HumanMessage, SystemMessage
from langchain_openai import ChatOpenAI
from langgraph.graph import END, START, StateGraph, add_messages
from langgraph.prebuilt import ToolNode
from typing_extensions import TypedDict


class AgentState(TypedDict):
    """定义 LangGraph 状态,messages 会在节点之间持续累加。"""

    messages: Annotated[list[BaseMessage], add_messages]


KNOWLEDGE_BASE = [
    {
        "doc_id": "doc-001",
        "title": "退款政策",
        "content": "会员订单支持 7 天内无理由退款,超过 7 天需要人工审核。",
    },
    {
        "doc_id": "doc-002",
        "title": "六月销售数据",
        "content": "2026 年 6 月 A 产品销售额 1200 元,B 产品销售额 800 元。",
    },
]


@tool
def retrieve_docs(question: str) -> list[dict[str, Any]]:
    """根据用户问题检索 RAG 文档,LangSmith 会记录工具输入和输出。"""
    return [
        doc
        for doc in KNOWLEDGE_BASE
        if any(word in question for word in ["退款", "销售", "销售额"])
    ]


@tool
def calculate_sum(text: str) -> dict[str, Any]:
    """从文本中提取金额并计算合计,用于演示 Agent 工具调用。"""
    numbers = [float(value) for value in re.findall(r"(\d+(?:\.\d+)?)\s*元", text)]
    return {"numbers": numbers, "total": sum(numbers)}


TOOLS = [retrieve_docs, calculate_sum]

model = ChatOpenAI(model="gpt-4o-mini", temperature=0)
model_with_tools = model.bind_tools(TOOLS)

SYSTEM_PROMPT = (
    "你是一个严谨的中文业务助手。"
    "回答业务问题时,必须先调用 retrieve_docs 检索知识库;"
    "如果问题涉及合计、总共、总销售额,再调用 calculate_sum 做计算。"
)


def validate_input(state: AgentState) -> dict:
    """校验用户输入;异常会被 LangSmith 标记为错误节点。"""
    if not state["messages"]:
        raise ValueError("messages 不能为空")

    first_message = state["messages"][0]
    if not str(first_message.content).strip():
        raise ValueError("用户问题不能为空")

    return {}


def call_llm(state: AgentState) -> dict:
    """调用绑定工具后的模型,由模型决定是否继续请求工具调用。"""
    messages = [
        SystemMessage(content=SYSTEM_PROMPT),
        *state["messages"],
    ]
    response = model_with_tools.invoke(messages)
    return {"messages": [response]}


def should_continue(state: AgentState) -> Literal["tools", "__end__"]:
    """根据最后一条模型消息是否包含 tool_calls 决定下一步。"""
    last_message = state["messages"][-1]
    if getattr(last_message, "tool_calls", None):
        return "tools"
    return END


graph_builder = StateGraph(AgentState)
graph_builder.add_node("validate_input", validate_input)
graph_builder.add_node("llm_call", call_llm)
graph_builder.add_node("tools", ToolNode(TOOLS))

graph_builder.add_edge(START, "validate_input")
graph_builder.add_edge("validate_input", "llm_call")
graph_builder.add_conditional_edges("llm_call", should_continue, ["tools", END])
graph_builder.add_edge("tools", "llm_call")

graph = graph_builder.compile()


if __name__ == "__main__":
    result = graph.invoke(
        {
            "messages": [
                HumanMessage(content="2026 年 6 月 A 产品和 B 产品总销售额是多少?")
            ]
        },
        config={
            "run_name": "LangGraph RAG Agent 业务请求",
            "tags": ["langsmith", "langgraph", "rag", "agent"],
            "metadata": {
                "request_id": "req-001",
                "user_id": "user-123",
            },
        },
    )

    print(result["messages"][-1].content)

5.4 LangSmith 是如何监听 LangGraph 的?

关键还是环境变量:

export LANGSMITH_TRACING=true

执行:

graph.invoke(...)

时,LangGraph 会执行这些节点:

validate_input
llm_call
tools
llm_call

每个节点运行时都会通过 LangChain / LangGraph 的 tracing callback 产生事件。

LangSmith 接收到这些事件后,就能在后台展示一棵 Trace 树。

5.5 LangGraph 中 config 不写会怎样?

这段:

config={
    "run_name": "LangGraph RAG Agent 业务请求",
    "tags": ["langsmith", "langgraph", "rag", "agent"],
    "metadata": {
        "request_id": "req-001",
        "user_id": "user-123",
    },
}

不写也能运行。

也不会影响 LangSmith 是否监听。

真正影响监听的是:

LANGSMITH_TRACING=true
LANGSMITH_API_KEY=...

config 的作用只是:

  • run_name:给这次运行起一个好认的名字
  • tags:方便在 LangSmith 后台筛选
  • metadata:记录业务上下文,例如 request_id、环境、租户 ID

生产环境建议至少保留 request_id,这样后端日志和 LangSmith Trace 能对上。

5.6 LangGraph 项目中 LangSmith 能看到什么?

你关心的问题 LangSmith 里看哪里
用户输入是什么 graph.invoke 的 input
Prompt 最终长什么样 llm_call 里的模型调用 messages
模型返回了什么 llm_call 模型节点 output
哪一步耗时最长 图节点和子节点的 duration
有没有报错 validate_input / tools / llm_call 出错时会标红
token / 成本统计 模型调用节点
RAG 检索到了哪些内容 tools 节点下的 retrieve_docs output
Agent 调用了哪些工具 ToolNode 下的 tool calls

6. 三种写法怎么选?

6.1 已有普通 Python 项目

如果你已经写好了业务代码,只是想加观测,优先用:

from langsmith import traceable
from langsmith.wrappers import wrap_openai

适合:

  • 现有代码不想大改
  • 只想追踪几个关键函数
  • 项目暂时不需要 LangChain / LangGraph

6.2 新项目,流程不复杂

如果你只是做一个常规 RAG + Agent:

用户输入 -> 检索 -> Prompt -> 模型 -> 工具 -> 回答

可以优先用 LangChain。

它的好处是:

  • 上手快
  • 集成模型和工具方便
  • LangSmith 自动追踪
  • 代码比纯手写 Agent 简洁

6.3 复杂 Agent、多分支、多状态

如果你的流程像这样:

用户输入
  -> 意图识别
  -> 路由到不同 Agent
  -> 检索
  -> 工具调用
  -> 人工确认
  -> 再次调用模型
  -> 总结输出

建议用 LangGraph。

LangGraph 更适合:

  • 多步骤工作流
  • 多 Agent 协作
  • 条件分支
  • 循环调用
  • 人工介入
  • 状态持久化

LangSmith 在这种场景下特别有价值,因为你可以看到复杂图结构里到底卡在哪一步。


7. 实战建议

7.1 不要一上来就追求复杂评测

第一次接 LangSmith,建议先做 Trace。

先确认你能看到:

  • 输入
  • 检索结果
  • Prompt
  • 模型输出
  • 工具调用
  • token
  • 报错

这些都看清楚以后,再做 Dataset、Evaluation、Prompt 对比。

7.2 生产环境一定要加 request_id

建议每次请求都带上:

config={
    "metadata": {
        "request_id": request_id,
        "env": "prod",
    }
}

这样用户反馈问题时,你可以:

用户报错 -> 后端日志查 request_id -> LangSmith 查 trace -> 定位问题节点

7.3 不要直接记录敏感信息

LangSmith 会记录输入、输出、Prompt、metadata。

所以不要直接放:

  • 手机号
  • 身份证
  • 邮箱
  • 明文 token
  • 内部密钥
  • 完整用户隐私文本

生产环境要做脱敏或最小化记录。

7.4 run_name 要有业务含义

不要全叫:

chain
node
run
function

建议叫:

输入校验
知识库检索
订单工具调用
模型生成回答
客服 Agent 主流程

这样在 LangSmith UI 里排查问题会快很多。

7.5 LangSmith 不替代日志

LangSmith 很适合看大模型调用链,但它不应该完全替代后端日志。

建议:

  • 后端日志记录系统级错误、请求 ID、接口耗时
  • LangSmith 记录 LLM / RAG / Agent 的内部链路
  • 两边用 request_id 打通

8. 常见误区

8.1 误区一:代码里没 import langsmith,就说明没用 LangSmith

不一定。

LangChain / LangGraph 项目里,LangSmith 经常是通过环境变量自动启用的。

只要有:

LANGSMITH_TRACING=true

并且安装了 langsmith,LangChain / LangGraph 的运行过程就可以自动上报。

8.2 误区二:run_name 是开启监听的开关

不是。

run_name 只是展示名。

开启监听靠:

LANGSMITH_TRACING=true
LANGSMITH_API_KEY=...

8.3 误区三:LangSmith 会自动知道你的普通 Python 函数

普通 Python 函数不会天然被 LangSmith 知道。

如果不用 LangChain / LangGraph,建议加:

@traceable

8.4 误区四:用了 LangSmith 就不用关心 Prompt 版本

LangSmith 能帮你记录 Prompt,但 Prompt 怎么设计、怎么版本管理、怎么评测,仍然需要你自己建立流程。

建议把坏案例沉淀为 Dataset,然后用 Evaluation 对比不同 Prompt 和模型。


9. 总结

一句话总结:

LangSmith 负责看清楚 AI 应用发生了什么;LangChain / LangGraph 负责组织 AI 应用怎么跑。

普通项目、LangChain、LangGraph 的区别是:

普通 Python 项目:
  业务自己写,LangSmith 需要显式埋点。

LangChain 项目:
  业务用 Runnable / Agent / Tool 写,LangSmith 可以自动监听。

LangGraph 项目:
  业务用图节点和状态机写,LangSmith 可以自动监听每个节点、模型和工具调用。

如果只是开始接入,我建议顺序是:

先接 Trace
  -> 看清输入、Prompt、输出、工具、检索
  -> 收集 bad case
  -> 做 Dataset
  -> 做 Evaluation
  -> 最后做线上监控和质量回归

这样 LangSmith 才不是一个“好看的后台”,而是真正变成 RAG / Agent 项目的调试和质量保障工具。


参考资料

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐