LangSmith 如何监听 RAG + Agent 项目:普通 Python、LangChain、LangGraph 三种写法对比
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 项目里,你通常需要用 @traceable、wrap_openai 显式埋点。
在 LangChain / LangGraph 项目里,只要配置好环境变量,LangSmith 可以通过 LangChain / LangGraph 内部的 callback tracing 机制自动监听链路。
目录
1. 先说结论
三种项目形态下,LangSmith 的使用方式不一样。
| 项目类型 | 业务编排方式 | LangSmith 接入方式 | 适合场景 |
|---|---|---|---|
| 普通 RAG + Agent 项目 | 自己写 Python 函数、OpenAI SDK、工具函数 | @traceable + wrap_openai |
没用 LangChain / LangGraph,但想看清调用链 |
| LangChain 项目 | Runnable、Agent、Tool、ChatOpenAI |
环境变量自动追踪,必要时加 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 项目的调试和质量保障工具。
参考资料
更多推荐



所有评论(0)