news 2026/11/5 19:11:42

用 LangSmith 打通 Agent 链路追踪:从 Trace 到回归测试的实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用 LangSmith 打通 Agent 链路追踪:从 Trace 到回归测试的实战指南

上个月帮朋友排查他们内部客服机器人的 Bug,问题特别典型:用户提交退款申请,机器人明明查询到订单状态是“已退款”,最后却回复“退款正在处理中,请耐心等待”。从结果看这就是一次标准幻觉,但最让人头疼的从来不是幻觉本身,而是你完全不知道它从哪一步开始跑偏——是查询工具没被调用?是工具返回内容被截断?还是模型在最后归纳时犯了傻?在没有追踪系统的情况下,这类问题只能靠猜,往 prompt 里多加几句“注意不要瞎说”,然后祈祷。

后来我把这套系统接入了 LangSmith。LangSmith 是 LangChain 团队推出的 LLM 应用可观测平台,核心就是解决 Agent 链路“过程黑盒”的问题。你只需要做最小化的配置,之后每一个 Agent 任务从开始到结束的完整路径,包括每次 LLM 调用、每个工具请求与响应、每一步决策,都会被记录成一条可浏览、可检索、可回放的 Trace。这篇文章我就以一个正在把 Agent 项目往生产推的工程师视角,聊聊怎么用 LangSmith 打通 Agent 链路追踪,以及我在真实项目里踩过的一些坑。

1. 先搞明白一件事:Agent 为什么必须要“可追踪”

1.1 Agent 应用和传统接口调用差在哪

传统后端接口是确定性流水线:请求进来,经过预设逻辑,返回结果。出错时你有异常堆栈、有断点调试、有日志上下文,哪怕链路再长,也能靠调用链工具一层层翻到底。

Agent 应用不一样。它是由模型驱动的决策循环:LLM 先理解用户目标,决定下一步动作,调用工具后拿到结果,再重新判断,循环往复,直到模型认为任务完成。这导致同一个问题的执行路径每次都可能不同,而且绝大多数“过程”发生在模型的隐层思考里。

我习惯用一个类比:传统系统像工厂里固定好的传送带,哪里卡住一眼就能看到;Agent 则像一个有自主裁量权的临时员工,你必须全程看着他办事,才知道他把活干成了什么样。大家现在都在聊 agent 开发、agent 架构、agent 框架与编排,但很多团队只关心“怎么把 Agent 接进来”,却忽略了真正上线后会遇到的问题:你不知道它每次到底干了什么。

1.2 Agent 链路里最容易翻车的几个环节

做 agent 应用时间长了你会发现,Agent 的幺蛾子往往就出在这几个地方:

环节常见问题在链路里怎么看
意图理解用户真实诉求和任务目标偏移看 LLM 节点输入里是否包含完整上下文
工具选择多个工具时选错、或者干脆不调用工具看是否出现了 ToolCall 记录
工具入参JSON 参数拼错、日期格式传错、字段缺位看工具节点的 arguments 字段
工具结果处理返回过长被截断、格式异常、模型忽略结果看工具节点的 output 和后续 LLM 输入
循环与终止Agent 反复调用工具停不下来,或提前误判完成看 Trace 总步数和每个节点的耗时
副作用安全工具带写入操作时,危险调用难以被发现看全部工具调用记录,做事后审计

很多时候最终回答是错的,但根因在中间某一步。没有哑链路记录,你只能对着最终输出猜,猜来猜去几乎不可能命中。

1.3 LangSmith 在设计上把钱花在哪里

LangSmith 不只是一个日志系统,它把 LLM 应用的可观测性分成了几层:链路追踪(tracing)、调试(debugging)、离线评估(evaluation)、线上监控(monitoring)。链路追踪是所有上层操作的地基。

它的核心价值在于“全自动”。只要用了 LangChain 或 LangGraph,代码里设置好环境变量,框架会自动把整条 Agent 执行链上报,不需要你为每一次 LLM 调用、每一个工具函数手工写埋点。这一点太重要了,因为手工埋点的最大问题不是麻烦,而是你永远会遗漏几个关键位置,而真正出问题的地方恰恰是你没埋的那一步。

当然,LangSmith 现在也提供了手动接入能力,不依赖 LangChain 也能用。对于已经用 LangChain 跑通的团队,接入成本几乎为零,这也是我推荐大家先上手的理由。

2. 开始接入前:先认清 LangSmith 的核心概念

2.1 Project、Run、Trace、Span,它们到底什么关系

我见过不少开发者第一次打开 LangSmith 后台直接懵掉,满屏英文词分不清谁是谁。先把概念理顺,后面效率会高很多。

一个 Project 相当于一个应用的日志“文件夹”,通常我们按项目名或环境来建,比如 agent-demo、prod-support-bot。一个 Project 里包含大量 Run。Run 是某个执行单元的记录,可以嵌套;最顶层的那个 Run 就是 Trace,代表一次完整任务。Tracean 下面每一个具体步骤,比如一次 LLM 调用、一次工具调用,都叫 Span。

这样理解会更顺:Project 是巡检记录本,Trace 是某一次巡检的完整记录,Span 是巡检过程中一个个具体动作。你在 LangSmith 界面看到的树形结构,本质就是 Trace 和 Span 的嵌套关系。

2.2 最小化接入:环境变量与初始化代码

接入 LangSmith 的第一步不是写代码,而是先拿到 API Key。登录 LangSmith 后台,在 Settings 里创建 API Key,格式一般是lsv2_开头。

然后配置环境变量,我推荐在应用启动脚本或环境配置文件里统一设置:

export LANGCHAIN_TRACING_V2=true export LANGCHAIN_API_KEY=lsv2_你的key export LANGCHAIN_PROJECT=agent-tutorial

如果你用的是较新的 SDK,有的版本也支持LANGSMITH_API_KEY,为了兼容起见,两个变量都设上没坏处。

依赖方面,最少需要这些:

pip install langchain langchain-openai langsmith

如果要用社区工具,再补一个langchain-community。配置完环境变量,LangChain 的链式调用、AgentExecutor、LangGraph 状态图会自动产生 Trace,不需要额外传参。第一次跑通时,你会看到后台出现第一条不完整或完整的链路,那一刻的成就感非常直观。

2.3 先想清楚:采样策略与成本

很多人接入 LangSmith 之后立刻开启全量上报,跑了几天发现账单不太舒服。LangSmith 的定价和数据量挂钩,虽然单条 Trace 费用不高,但生产环境请求量大,积少成多就明显了。

我建议从一开始就把采样率定好。开发环境全量追踪没问题,因为量小、调试需要;生产环境使用LANGCHAIN_TRACING_SAMPLING_RATE控制采样比例,比如只追踪 10% 的请求:

export LANGCHAIN_TRACING_SAMPLING_RATE=0.1

另外,线上问题和开发问题要分 Project。同一个 Project 里混合开发流量和生产流量,排查时很容易互相干扰。我见过朋友在生产集群上忘记切 Project,结果一个 Bad Case 翻半天,因为其他环境的 Trace 太多。按环境建 Project,按需求调整采样比例,是我刚开始接入时最后悔没做的事。

3. 第一个可追踪的 Agent:从代码到 Trace

3.1 用 LangChain 跑通一个带工具的 Agent

我们直接写一个最小可运行的 Agent:它带一个天气查询工具,用户问天气时,LLM 判断需要工具,调用它拿数据后组织回答。

import os os.environ["LANGCHAIN_TRACING_V2"] = "true" os.environ["LANGCHAIN_API_KEY"] = "lsv2_你的key" os.environ["LANGCHAIN_PROJECT"] = "agent-tutorial" from langchain_openai import ChatOpenAI from langchain.agents import create_tool_calling_agent, AgentExecutor from langchain_core.tools import tool @tool def get_weather(city: str) -> str: """返回指定城市的实时天气,只接受精确城市名。 例如:北京市、上海市。""" # 生产环境这里换成真实天气 API return f"{city}今天晴,气温18-24℃,体感舒适。" tools = [get_weather] llm = ChatOpenAI(model="gpt-4o-mini", temperature=0) agent = create_tool_calling_agent(llm, tools) executor = AgentExecutor(agent=agent, tools=tools) resp = executor.invoke({"input": "北京今天需要穿羽绒服吗?"}) print(resp["output"])

跑完这段代码,打开 LangSmith 后台的 agent-tutorial 项目,你会看到一条新 Trace。这套流程里,模型先规划是否使用工具,然后生成一个 ToolCall,框架调用 get_weather 并把结果送回给模型,最后模型根据真实天气数据生成回答。整个过程被完整记录。

3.2 打开 LangSmith,逐层读懂节点信息

进入某条 Trace 后,你看到的结构大概长这样:

AgentExecutor 根节点(整次任务) └── ChatOpenAI 调用(模型决策:生成 ToolCall) └── get_weather 工具调用(入参 / 返回结果) └── ChatOpenAI 调用(读取工具结果,生成最终回答)

每个节点都可以点开,看到输入输出、开始结束时间、耗时、Token 用量、模型名等原始信息。排查问题的时候,我最常看的就是工具的原始返回:它是脏数据、是超时、是被截断,一眼就能判断。

比如刚才那个客服机器人案例,我用 LangSmith 一查,发现它压根没有调用查询工具,模型直接凭印象生成了一句话。根因不在 prompt 最后那句“你要诚实”,而在模型决策阶段没有把“先查单再回答”作为强制动作。这种定位,没有链路追踪之前靠猜很难得出。

3.3 换成 LangGraph 后 Trace 和代码一一对应

LangChain 的 AgentExecutor 封装度高,Debug 起来有时候还是隔了一层。最近 agent 框架的主流方向是更显式的编排,LangGraph 逐渐成为标配。节点和边都由你定义,链路追踪的逻辑和代码结构完全对应。

用 LangGraph 重写上面的 Agent:

from typing import TypedDict, Annotated from langgraph.graph import StateGraph, START, END from langgraph.prebuilt import ToolNode from langgraph.graph.message import add_messages from langchain_core.messages import AnyMessage, HumanMessage class AgentState(TypedDict): messages: Annotated[list[AnyMessage], add_messages] llm_with_tools = llm.bind_tools(tools) def call_agent(state: AgentState) -> dict: response = llm_with_tools.invoke(state["messages"]) return {"messages": [response]} builder = StateGraph(AgentState) builder.add_node("agent", call_agent) builder.add_node("tools", ToolNode(tools)) builder.add_edge(START, "agent") builder.add_conditional_edges( "agent", lambda state: "tools" if state["messages"][-1].tool_calls else END, ) builder.add_edge("tools", "agent") graph = builder.compile() graph.invoke({"messages": [HumanMessage(content="上海适合穿什么?")]})

这次 Trace 会清晰地出现两条路径:

agent 节点(第一轮决策) └── tools 节点(执行天气查询) └── agent 节点(第二轮生成回答)

你写的是什么架构,在 LangSmith 里看到的就是什么架构。节点粒度、边逻辑、条件判断全部可见,排查 Agent 行为的体验会好很多。这也是我建议新项目直接上 LangGraph 的原因之一。

3.4 非 LangChain 项目:手动埋点与 wrap_openai

如果你没有用 LangChain,而是直接调用 OpenAI SDK,或者自己封装了一层 HTTP 调用,也不是不能用 LangSmith。官方 SDK 提供了@traceable装饰器和wrap_openai包装器。

以 OpenAI 为例,接入方式非常轻量:

from langsmith.wrappers import wrap_openai from openai import OpenAI client = wrap_openai(OpenAI()) resp = client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": "今天北京天气怎么样?"}], )

调用中的模型名、回调、Token 用量都会被 LangSmith 自动记录。@traceable则适合包裹你自己的业务函数,让每个手动步骤也变成一行 Span。区别就是你需要自己决定哪里埋点,不像 LangChain 那样全自动,但接入成本依然可控。

4. 不只是记录:把 Trace 变成真正有用的证据链

4.1 从“哪里报错”到“为什么出错”

链路追踪最容易踩的误区是把 Trace 当成“新式日志”,只看“有没有报错”。真正要做的,是把 Trace 当作证据链,沿着它找到因果。

我的排查套路固定是三步:

  • 第一,看有没有调用预期中的工具。这一步能区分“模型没规划对”和“工具执行出问题”。
  • 第二,看工具参数和原始返回。参数拼错属于模型生成问题;返回脏数据属于工具侧问题。
  • 第三,看最终回答是否忠实于工具结果。如果工具明确返回“已退款”,模型却说“正在处理中”,那就是生成阶段忠实度不足。

这个套路在 LangSmith 上操作起来很顺手,因为每一步都有独立 Span,你能快速跳转、对比。出问题后,不要直接在结论上争论,把证据链贴出来,比一万句解释都有效。

4.2 用 Playground 快速现场复现

LangSmith 的 Playground 是我很依赖的功能。它可以在网页端直接加载一条 Trace 的配置,重新跑一遍相同或修改后的输入,不需要把代码仓库拉下来。

我经常用它做两类事:一类是复现 Bad Case,把用户原始输入原封不动重发,看看是不是稳定复现;另一类是现场调参,比如把 temperature 从 0 调到 0.3,换一个 prompt 前缀,立刻能看到对比结果。

这里有个很实用的经验:把“怀疑点”写成多条不同的 prompt 变体,在 Playground 里来回切,几分钟就能确定哪个改动真正解决问题。比在本地一遍遍改代码跑测试高效得多。

4.3 人工反馈与迭代闭环

好的链路追踪系统一定支持人工反馈。LangSmith 里可以在 UI 上给 Trace 点赞、点踩,也可以通过 API 记录结构化反馈,便于后续做数据分析。

from langsmith import Client client = Client() client.create_feedback( run_id="带 id 的那条 trace", key="user_score", score=1, comment="回答正确但有点啰嗦", )

线上用户反馈、内部人工标注,都会和对应 Trace 绑定。久而久之,它就变成你评估集的一部分,为后面的回归测试提供素材。

5. 把追踪变成护栏:回归测试与评估

5.1 从历史 Trace 一键生成测试数据集

Agent 项目迭代得越多,越需要一个“考卷”。最缺的反而不是测试用例,而是那些从线上捞回来的真实 Bad Case。LangSmith 支持直接从 Trace 生成数据集,你看到一条代表性的历史记录,点一下 Add to dataset,它就会被固化进指定的 Dataset。

我通常把数据集分成两类:一类是正确行为,防止回归;一类是历史 Bad Case,验证修复有没有生效。这样每次改 prompt、换模型、调整工具逻辑,都有了一个可复现的基准。

5.2 离线评估跑起来

有了 Dataset,下一步就是在 LangSmith 里跑离线评估。用代码触发或者直接在后台创建测试任务,框架会自动把数据集里的每条输入跑一遍,然后用你定义的评估器打分,输出一个可比较的实验结果。

简单示意如下:

from langsmith.evaluation import evaluate def run_agent(inputs: dict) -> dict: answer = executor.invoke({"input": inputs["input"]}) return {"output": answer["output"]} evaluate( run_agent, data="agent-tutorial-dataset", )

你可以加自带评估器,也可以写自定义规则。LangSmith 会把两次实验的得分放在一起对比,让你快速看到这次改动的平均表现和分项表现。这一步做下来,prompt 迭代就不再是拍脑袋,而是有“考试成绩”支撑的工程行为。

5.3 发布前先问自己:新 prompt 会让老问题反弹吗

我吃过最典型的亏是:修好了 A 类 Bad Case,结果 B 类历史问题复发。原因很简单,改 prompt 通常是在“压”模型某一类行为,而模型行为是整体联动的,很容易顾此失彼。

现在我的习惯非常固定:每次要动 prompt 或换模型,先跑一遍整个历史数据集,看分数有没有下降。如果之前的重点场景出现回归,宁可不改或者继续调。没有回归测试这套护栏,Agent 的迭代几乎必然走向“按下葫芦浮起瓢”。

6. 实战排雷:LangSmith 使用中的高频坑与心得

6.1 Trace 不出来?先按这个顺序排查

接入 LangSmith 最常遇到的尴尬是:代码跑完了,后台一条 Trace 都没有。我见过的情况基本集中在这几类:

现象原因处理方式
完全无数据环境变量没设置或 Key 填错检查LANGCHAIN_TRACING_V2和 API Key
数据跑到旧项目LANGCHAIN_PROJECT没更新确认当前进程的环境变量
偶发缺失采样率设置过低把LANGCHAIN_TRACING_SAMPLING_RATE调高或临时去掉
程序结束无输出异步上报没刷新进程退出前调用flush()

另外我要提醒一下:如果你所在网络环境访问 LangSmith API 不稳定,链路会静默丢数据。遇到“偶尔有 Trace、偶尔没有”的情况,先检查网络连通性和超时日志,不要一上来怀疑 SDK。

6.2 成本与性能怎么控

采集本身是异步的,对主流程延迟影响很小,但极端情况下大量 Trace 同时上报,还是可能出现堆积。我这里有几个实用的控制手段:

  • 生产环境默认采样,遇到重大发布或线上事故再临时开全量。
  • 按环境拆分 Project,方便按项目配额管理。
  • 定期清理旧项目或用完的 Dataset,避免后台数据越来越乱。
  • 核心链路全量追踪,非核心链路低频采样,留存最有价值的证据。

成本控制的核心思想是:把追踪作为一种“可调节的观测手段”,而不是无脑全开。

6.3 数据安全、权限与团队协作

Agent 的 Trace 里往往包含用户输入、工具调用参数、检索结果,甚至可能是拼凑出来的隐私信息。如果你的业务对数据合规有要求,上云端的默认区域前必须先确认数据策略。LangSmith 支持私有化部署,适合要求数据不出内网的团队。

团队协作方面,LangSmith 支持成员角色管理和项目权限隔离。建议按团队或模块分 Project,只给需要的人开权限。另外,尽量别在生产环境把 API Key 硬编码在代码里,用密钥管理服务,权限最小化。

6.4 一点个人体会

用 LangSmith 时间越久,我越觉得它的真正价值不是“看链路”,而是逼着我把 Agent 的调用结构想清楚。Agent 开发看上去很自由,但如果没有可观测性兜底,它就是一团看不清的黑箱。链路追踪做起来之后,prompt 迭代、模型选型、工具设计,都会从“玄学”变成“工程”。

最后分享一个小技巧:给自己业务日志里加上 request_id 或 session_id,然后通过元数据写进 LangSmith。线上用户报问题时,你拿着业务侧 ID 一搜就能定位到那条 Trace,时间从半小时缩短到几秒钟。生产排查体验的提升,是立竿见影的。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/23 20:05:16

dB与放大倍数转换全解析:从公式到运放增益设置实战

1. 从一次调试翻车说起:为什么dB和放大倍数总有人算错刚入行那会儿,我在调试一个音频采集前端,电路图上标着增益 40dB,我心想 40 倍嘛,直接把输入信号乘以 40 就完事了。结果实测输出波形削顶削得一塌糊涂,…

作者头像 李华
网站建设 2026/10/30 14:52:37

智能体工程化落地:从Demo到生产系统的关键实践

又到周五,惯例先把 GitHub Trending 扫一遍。这周排名靠前的仓库,跟三个月前完全不是一个画风。以前刷到的多是“XXX Agent Demo”“用LLM实现XX”这类一人演示型项目,现在站在榜单前排的是一批有部署文档、有可观测性设计、有业务案例的工程…

作者头像 李华
网站建设 2026/10/23 6:29:01

M.2 KEY A/B/E/M物理键位详解:识别、兼容与性能真相

1. M.2接口KEY A、B、E、M到底在说什么?别再被“插不进去”搞懵了 你拆开新买的主板,看到那个细长的插槽,旁边印着“M.2”三个字,旁边还有一行小字——KEY E。你手边刚好有一块标着“KEY BM”的固态硬盘,犹豫三秒&…

作者头像 李华
网站建设 2026/10/23 15:10:52

用AI告别周报焦虑:碎片记录+智能组装的实战指南

1. 周报焦虑的根源:你缺的不是工作量,是“翻译器” 周五下午六点,你盯着空白的周报文档,光标一闪一闪,像在嘲笑你。明明这一周开了七个会、回了上百条消息、改了三版方案、处理了两个线上问题,可手指放在键…

作者头像 李华
网站建设 2026/10/23 15:35:46

给插件做插件:DeepSeek Harness 可视化调试工具的设计与实现

1. 从一个“套娃”想法说起:为什么要给插件做插件 第一次跟朋友聊起这个项目,对方的反应基本都是同一句话:“你这不是闲得慌吗?给插件再写个插件?”说实话,我一开始也这么自嘲。但真动手做完之后&#xff0…

作者头像 李华
网站建设 2026/10/23 20:05:30

Tekla OpenAPI开发实战:从环境配置到批量建模自动化

简介:本资源为Tekla Structures开发必备的官方OpenAPI参考文档离线包,面向结构工程BIM开发者、二次开发工程师及高校土木信息化方向学习者,解决中文环境下API学习门槛高、在线文档访问不稳定、关键接口查阅效率低等实际问题。压缩包为RAR格式…

作者头像 李华