在这里插入图片描述

大模型应用上线前最后一道防线: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-1: PromptTemplate

Run-2: Model 调用

Run-3: Tool Call

Run-4: Output Parser

Input: 用户原始问题

Output: 格式化后的Prompt

Input: 完整Prompt

Output: 模型回答

Token: 输入/输出消耗

Latency: 调用耗时

Tool Name

Tool Args

Tool Return

一个 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 调用链路

先看整体流程,心里有个数:

Tool(查询工具) 大模型(DeepSeek) Agent 用户 Tool(查询工具) 大模型(DeepSeek) Agent 用户 每一步都被 LangSmith 记录 包括:工具选择决策、参数、返回值、耗时 "帮我查订单A1001的物流" System Prompt + 用户问题 + 工具描述 决定调用 search_order_wuliu(order_id="A1001") 执行工具调用 "已付款,等待发货" 工具返回结果 + 原始问题 "您的订单A1001已付款,正在等待发货" 最终回答

关键在哪?模型到工具这一步。模型到底有没有识别出需要调用工具?传的参数对不对?工具返回了什么?模型拿到返回值后怎么组织语言?这些全在 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_nametagsmetadata 这三个字段看着不起眼,实际项目里极其重要。

config={
    "run_name": "agent电商客服助手",   # 追踪记录的显示名称
    "tags": ["chapter10", "agent"],    # 可在 LangSmith 中按标签筛选
    "metadata": {                      # 自定义业务信息
        "course": "LangChain",
        "chapter": 10,
    },
}

线上跑了几百次调用后,你可以直接在 LangSmith 里按 tags 筛选出特定场景的 Trace,或者按 metadata 里的业务字段定位某条记录。不加上这三个字段,后面排查时等于大海捞针。

4.4 Agent 没调工具?排查清单

这是 Agent 项目最常见的坑。Trace 里一眼能看到模型是直接生成了答案还是走了工具调用。如果没调工具,按这个顺序查:

Agent 没调用工具

工具描述是否传给模型?

检查 @tool 装饰器的 docstring

用户问题是否包含必要参数?

如订单号、商品ID等

模型是否直接生成了答案?

加强 System Prompt 强制工具调用

工具调用参数是否正确?

检查参数类型和格式约束

检查工具返回值是否被正确使用

踩过的坑:工具的 docstring 写得太模糊,模型根本不知道什么时候该调。比如 """查询订单""""""根据订单号查询订单状态,包括是否付款、是否发货、快递单号和签收状态""",后者触发率明显高一个档次。工具描述就是模型的说明书,写得越精确,Agent 越靠谱。


五、评估体系:从「手动试」到「批量测」

调试解决单次问题,评估解决整体效果。你不可能每次改了 Prompt 就手动问十个问题,那效率太低。

5.1 评估的核心思路

命中

未命中

测试集 Test Cases

批量调用应用

逐条检查结果

预期关键词命中?

Pass ✅

Fail ❌

统计通过率

定位失败用例

针对性修复

最简单的评估器就是关键词匹配:准备测试集,每条包含问题和预期关键词,跑完后看答案里是否包含关键词。简单粗暴,但够用。

5.2 RAG 评估:四步排查法

RAG 答错了,别急着改 Prompt。按这个顺序查,效率最高:

排查方向

不相关

相关

没传

传了

没理解

原始文档

文档切分

检索结果

上下文拼接

Prompt

模型回答

❌ 答案错误

检索结果相关吗?

问题: 切分不合理 / Embedding质量差

上下文传给模型了吗?

问题: Prompt拼接逻辑有bug

模型理解对了吗?

问题: Prompt指令不清晰

踩过的坑:检索结果明明是对的,但答案还是错了。查了半天发现是 Prompt 模板里把检索内容和系统指令混在了一起,模型把检索到的文档当成指令执行了。所以 Prompt 设计时,检索内容必须和系统指令明确隔离

5.3 Agent 评估:双重校验

Agent 评估比普通 Chain 多一个维度:不光要看答案对不对,还要看工具调得对不对。

情况 答案正确 工具调用正确 判定
✅ 理想状态 Pass
⚠️ 模型在猜 危险!答案对但没走工具
⚠️ 工具白调 模型没用好工具返回值
❌ 双错 Fail

第二种情况最容易被忽视——答案对了但工具没调,说明模型在编。当前问题蒙对了,换个输入就翻车。所以 Agent 评估必须同时校验 expected_keywordexpected_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 整体架构

订单/库存/商品/折扣/多少钱

其他问题

记录

记录

记录

用户输入问题

关键词路由

Agent 模块

RAG 模块

业务工具集

get_order_status
查询订单状态

get_product_inventory
查询商品库存

calculate_discount_price
计算折扣价格

Embedding 向量化

向量数据库
ChromaDB

检索相关文档

DeepSeek 生成回答

返回用户

LangSmith
全程追踪

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 循环简洁太多。

关键词路由简单、可解释,适合项目初期。后续可以升级为意图分类 ChainLangGraph 条件路由,这个在系列后续文章中展开。

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 运行流程

1. 配置 .env

2. 构建索引
python build_index.py

3. 启动应用
python app.py

4. 执行评估
python eval_app.py

5. 查看 LangSmith
追踪 + 评估结果

评估结果长这样:

===== 综合项目评估结果 =====
通过数量: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 + 实际项目实践整理,代码均经过验证。如有问题欢迎评论区交流。

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐