LangSmith全链路追踪与评估体系实战

大模型应用上线前最后一道防线:LangSmith 全链路追踪与评估体系实战
摘要: 大模型应用跑通≠能用。RAG答错找不到根因?Agent该调工具却瞎编?本文以LangChain + DeepSeek实战为例,打通LangSmith从追踪配置、Agent工具调用全链路观测,到RAG/Agent双维度评估的完整闭环。附企业级智能客服综合项目架构与上线Checklist,帮你把黑盒变成白盒。
🔖 标签
LangChain LangSmith AI Agent RAG 大模型 DeepSeek
一、先聊一个真实的痛
你花了几天搭好一套 RAG 知识库问答,Demo 跑得挺溜。上线第二天,业务方甩过来一句:
“用户问退款多久到账,系统回答了一个完全不搭边的政策条款。”
你打开终端,只能看到一行最终输出:
回答:根据《员工手册》第三章第二节,请假需提前审批……
然后呢?用户原始问题是啥、Retriever 检索到哪几段文档、Prompt 拼接后长什么样、模型输入了多少 Token、哪一步最耗时——全黑盒。
Agent 项目更头疼。模型该调工具的时候没调,不该调的时候乱调;调了工具但参数传错了;工具返回了正确数据,模型却自己编了个答案。
这就是大模型应用从 Demo 到上线的鸿沟:调试和评估。
LangSmith 就是来填这条沟的。
二、LangSmith 到底解决了什么
一句话:把一次大模型调用,拆成完整的可观测链路。
传统调试 vs LangSmith 追踪
| 维度 | 传统终端日志 | LangSmith Trace |
|---|---|---|
| 可观测粒度 | 只有最终输出 | 每一步的输入/输出 |
| Prompt 查看 | 手动 print | 自动记录完整 Prompt |
| Token 统计 | 靠手算或估算 | 自动统计输入/输出 Token |
| 耗时分析 | 粗略计时 | 每步精确 Latency |
| Agent 工具调用 | 只看最终回答 | 完整工具调用链路 |
| 多次运行对比 | 基本做不到 | 按项目/标签筛选对比 |
| 错误定位 | 全靠猜 | 精确到具体 Run |
LangSmith Trace 核心概念
一个 Trace 就是树形结构,根节点是完整调用,子节点是每个 Run(PromptTemplate、Model、Tool、Parser 等)。每个 Run 都能点进去看 Input、Output、Token、Latency、Error、Metadata。
三、五分钟接入追踪
配置环境变量
在项目根目录创建 .env:
# DeepSeek 配置
DEEPSEEK_API_KEY=你的DeepSeek_API_Key
DEEPSEEK_BASE_URL=https://api.deepseek.com
# LangSmith 追踪配置
LANGSMITH_TRACING=true
LANGSMITH_API_KEY=你的LangSmith_API_Key
LANGSMITH_PROJECT=langchain-course-demo
| 环境变量 | 作用 | 备注 |
|---|---|---|
LANGSMITH_TRACING |
是否开启追踪 | true 开启,开发期建议常开 |
LANGSMITH_API_KEY |
LangSmith API Key | 官网创建 |
LANGSMITH_PROJECT |
项目名称 | 不同项目用不同名称隔离 |
DEEPSEEK_API_KEY |
DeepSeek API Key | |
DEEPSEEK_BASE_URL |
DeepSeek OpenAI 兼容地址 |
不想追踪时改成 LANGSMITH_TRACING=false 即可,零侵入。
安装依赖
pip install langchain langchain-openai langsmith python-dotenv \
-i https://pypi.tuna.tsinghua.edu.cn/simple
装完之后,任何一次 model.invoke() 都会自动上报到 LangSmith。不需要改一行业务代码。
四、重点深挖:Agent 全链路追踪
这是我觉得 LangSmith 价值最大的地方。普通 Chain 调试相对简单,Agent 才是真正的黑盒——模型自己决定调什么工具、传什么参数、怎么用工具返回值。
4.1 一个典型的 Agent 调用链路
先看整体流程,心里有个数:
关键在哪?模型到工具这一步。模型到底有没有识别出需要调用工具?传的参数对不对?工具返回了什么?模型拿到返回值后怎么组织语言?这些全在 Trace 里。
4.2 上代码
from langchain.agents import create_agent
from langchain_core.messages import HumanMessage
from langchain_core.tools import tool
from utils.model_factory import get_deepSeek_model
@tool
def search_order_wuliu(order_id: str) -> str:
"""根据订单号查询订单状态,包括是否付款、是否发货、快递单号和签收状态。"""
fake_orders = {
"A1001": "已付款,等待发货",
"A1002": "已发货,快递单号 SF123456",
"A1003": "已签收",
}
return fake_orders.get(order_id, "没有查询到该订单")
agent = create_agent(
model=get_deepSeek_model(),
tools=[search_order_wuliu],
system_prompt="你是一个电商客服,善于使用工具查询物流信息"
)
result = agent.invoke(
{"messages": [HumanMessage(content="帮我查询订单A1001的物流信息")]},
config={
"run_name": "agent电商客服助手",
"tags": ["chapter10", "agent"],
"metadata": {
"course": "LangChain",
"chapter": 10,
},
},
)
print(result['messages'][-1].content)
4.3 config 里的三个字段,别忽略
run_name、tags、metadata 这三个字段看着不起眼,实际项目里极其重要。
config={
"run_name": "agent电商客服助手", # 追踪记录的显示名称
"tags": ["chapter10", "agent"], # 可在 LangSmith 中按标签筛选
"metadata": { # 自定义业务信息
"course": "LangChain",
"chapter": 10,
},
}
线上跑了几百次调用后,你可以直接在 LangSmith 里按 tags 筛选出特定场景的 Trace,或者按 metadata 里的业务字段定位某条记录。不加上这三个字段,后面排查时等于大海捞针。
4.4 Agent 没调工具?排查清单
这是 Agent 项目最常见的坑。Trace 里一眼能看到模型是直接生成了答案还是走了工具调用。如果没调工具,按这个顺序查:
踩过的坑:工具的 docstring 写得太模糊,模型根本不知道什么时候该调。比如 """查询订单""" 和 """根据订单号查询订单状态,包括是否付款、是否发货、快递单号和签收状态""",后者触发率明显高一个档次。工具描述就是模型的说明书,写得越精确,Agent 越靠谱。
五、评估体系:从「手动试」到「批量测」
调试解决单次问题,评估解决整体效果。你不可能每次改了 Prompt 就手动问十个问题,那效率太低。
5.1 评估的核心思路
最简单的评估器就是关键词匹配:准备测试集,每条包含问题和预期关键词,跑完后看答案里是否包含关键词。简单粗暴,但够用。
5.2 RAG 评估:四步排查法
RAG 答错了,别急着改 Prompt。按这个顺序查,效率最高:
踩过的坑:检索结果明明是对的,但答案还是错了。查了半天发现是 Prompt 模板里把检索内容和系统指令混在了一起,模型把检索到的文档当成指令执行了。所以 Prompt 设计时,检索内容必须和系统指令明确隔离。
5.3 Agent 评估:双重校验
Agent 评估比普通 Chain 多一个维度:不光要看答案对不对,还要看工具调得对不对。
| 情况 | 答案正确 | 工具调用正确 | 判定 |
|---|---|---|---|
| ✅ 理想状态 | ✅ | ✅ | Pass |
| ⚠️ 模型在猜 | ✅ | ❌ | 危险!答案对但没走工具 |
| ⚠️ 工具白调 | ❌ | ✅ | 模型没用好工具返回值 |
| ❌ 双错 | ❌ | ❌ | Fail |
第二种情况最容易被忽视——答案对了但工具没调,说明模型在编。当前问题蒙对了,换个输入就翻车。所以 Agent 评估必须同时校验 expected_keyword 和 expected_tool:
def get_tools_all(result):
"""从 Agent 返回的 messages 中提取所有被调用的工具名"""
messages = result['messages']
tools = []
for message in messages:
if isinstance(message, ToolMessage):
tools.append(message.name)
return tools
# 评估逻辑:答案包含预期关键词 AND 调用了预期工具
if expected_keyword in answer and expected_tool in tools_name:
passed = True
5.4 进阶:LangSmith 在线评估
前面三种都是本地跑测试集,和 LangSmith 平台无关。LangSmith 本身也提供评估能力——把测试集上传为 Dataset,用自定义 Evaluator 跑批量评估,结果可视化。
from langsmith import Client, evaluate
client = Client()
# 自定义评估器:关键词匹配
def keyword_check_evaluator(run, example):
try:
output_text = run.outputs["output"]
expected_keyword = example.outputs["expected_keyword"]
hit = expected_keyword in output_text
return {
"key": "keyword_match",
"score": 1 if hit else 0,
"comment": f"预期关键词:{expected_keyword},是否命中:{hit}"
}
except Exception as e:
return {
"key": "keyword_match",
"score": None,
"comment": f"评估执行异常: {str(e)}"
}
# 包装目标函数,强制返回字典格式
def target_function(inputs):
result_str = chain.invoke(inputs)
return {"output": result_str} # 保证 run.outputs["output"] 稳定存在
# 创建数据集(首次创建后自动复用)
dataset_name = "llm_course_qa_testset2"
try:
dataset = client.read_dataset(dataset_name=dataset_name)
except Exception:
dataset = client.create_dataset(dataset_name=dataset_name)
client.create_examples(
inputs=[
{"question": "LangChain 中 PromptTemplate 的作用是什么?"},
{"question": "RAG 的核心流程是什么?"},
{"question": "Agent 为什么需要 Tool?"},
],
outputs=[
{"expected_keyword": "提示词"},
{"expected_keyword": "检索"},
{"expected_keyword": "外部"},
],
dataset_id=dataset.id
)
# 启动评估
experiment = evaluate(
target_function,
data=dataset_name,
evaluators=[keyword_check_evaluator],
experiment_prefix="keyword_eval_course_qa",
)
print("评估任务已提交,请前往 LangSmith 网页查看实验结果!")
一个细节:target_function 里必须返回字典 {"output": result_str},不能直接返回字符串。否则 Evaluator 里 run.outputs["output"] 会 KeyError。这个小坑踩过一次就记住了。
本地评估 vs LangSmith 评估的对比:
| 维度 | 本地评估 | LangSmith 评估 |
|---|---|---|
| 测试集管理 | 硬编码在脚本里 | Dataset 管理,可复用 |
| 结果存储 | 终端打印 | 平台持久化,可追溯 |
| 可视化 | 无 | 实验对比图表 |
| 多轮对比 | 手动记录 | 自动记录历史实验 |
| 适合场景 | 快速验证 | 正式评估、回归测试 |
六、综合项目:企业智能客服助手
把前面的追踪和评估整合到一个真实项目里。这个系统要同时处理两类问题:知识库问答(RAG) 和 业务查询(Agent 调工具)。
6.1 整体架构
6.2 关键设计:路由策略
用关键词做简单路由——包含"订单"“库存”“商品”“折扣”"多少钱"等关键词的走 Agent,其余走 RAG:
def is_bussiness_question(question: str):
keywords = ["订单", "库存", "商品", "打折", "折扣", "多少钱"]
return any([keyword in question for keyword in keywords])
any() 的妙用:只要列表里任意一个关键词出现在 question 中就返回 True,全都没有返回 False。比手写 for 循环简洁太多。
关键词路由简单、可解释,适合项目初期。后续可以升级为意图分类 Chain 或 LangGraph 条件路由,这个在系列后续文章中展开。
6.3 项目结构
langchain-final-project/
├── .env # 环境变量
├── requirements.txt # 依赖
├── knowledge_base/ # 知识库文档
├── build_index.py # 构建向量索引
├── model_factory.py # 模型工厂
├── embedding_factory.py # Embedding 工厂
├── rag_service.py # RAG 问答服务
├── business_tools.py # 业务查询工具
├── customer_agent.py # Agent 封装
├── app.py # 终端入口
└── eval_app.py # 评估入口
6.4 运行流程
评估结果长这样:
===== 综合项目评估结果 =====
通过数量:5
通过率:83.33%
失败的用例直接去 LangSmith Trace 里定位——是检索没检索到,还是工具参数传错了,还是 Prompt 指令不清晰,一眼可见。
七、上线前 Checklist
不废话,直接上表。每一项都踩过坑才列进来的。
Prompt 检查
| 检查项 | 说明 |
|---|---|
| 角色是否明确 | System Prompt 要说清"你是谁" |
| 是否限制编造 | 明确指示"资料不足时回答无法确定" |
| 检索内容隔离 | 检索结果不能和系统指令混在一起 |
| 资料不足策略 | 定义模型在检索为空时的兜底行为 |
RAG 检查
| 检查项 | 说明 |
|---|---|
| 文档完整性 | 知识库覆盖业务常见问题 |
| 切分合理性 | Chunk 太大丢精度,太小丢上下文 |
| 索引时效性 | 文档更新后要重建索引 |
| 答案溯源 | 回答要标注来源文档 |
Agent 检查
| 检查项 | 说明 |
|---|---|
| 工具描述清晰 | docstring 精确描述功能和参数 |
| 参数类型约束 | 用 Pydantic Schema 约束入参 |
| 高风险操作确认 | 写操作类工具需要人工确认 |
| 调用日志 | 记录每次工具调用的参数和返回值 |
安全检查
| 检查项 | 说明 |
|---|---|
| API Key 管理 | 放 .env,.env 加入 .gitignore |
| Prompt 注入防护 | 用户输入不能直接拼进 System Prompt |
| 敏感数据脱敏 | LangSmith 会记录完整 Prompt,注意合规 |
| 生产环境追踪策略 | 按需采样或关闭,避免泄露用户数据 |
八、高频问题速查
Q:LangSmith 看不到记录?
检查四件事:LANGSMITH_TRACING 是否为 true、API Key 是否正确、是否看错了 Project、程序是否真的执行了模型调用。网络不通也会静默失败。
Q:生产环境要一直开追踪吗?
开发期建议常开。生产环境视合规要求决定——涉及用户隐私的数据要脱敏或采样,甚至关闭。LangSmith 会记录完整 Prompt 和输入输出,这点不能忽略。
Q:关键词评估靠谱吗?
入门够用,但覆盖不全。答案意思正确但没命中关键词会被误判。后续可以加大模型评分(让另一个 LLM 当裁判)或人工抽检。
九、本系列预告
这篇文章是 LangChain 实战系列 的开篇,聚焦追踪与评估这个「上线前最后一道防线」。后续文章规划:
| 序号 | 主题 | 核心内容 |
|---|---|---|
| 02 | RAG 进阶:从检索到重排 | 多路召回、MMR、重排序模型 |
| 03 | Agent 工程化设计 | 工具注册中心、多 Agent 协作 |
| 04 | LangGraph 状态机编排 | 条件路由、人工审批节点 |
| 05 | 大模型评估体系 | LLM-as-Judge、RAGAS、回归测试 |
| 06 | 生产环境部署 | 流式输出、并发控制、成本优化 |
核心观点:大模型应用从「能跑」到「能上线」,中间隔着一整套调试和评估体系。LangSmith 不只是个可视化工具,它是把黑盒变白盒的基础设施。先把可观测性做起来,后面优化才有方向。
声明:本文基于 LangChain + 实际项目实践整理,代码均经过验证。如有问题欢迎评论区交流。
更多推荐
所有评论(0)