☰
LangSmith与Prompt Ops实战:构建LLM应用可观测与评测闭环
2026/10/20 4:48:17 网站建设 项目流程

一个做LLM应用的朋友跟我吐槽,说他的Agent项目在Demo阶段跑得飞快,一上生产就天天被调用方追着问“为什么这个回答和前几天不一样”“为什么这个函数调用又失败了”。我问他用什么做的日志和评测,他说“日志靠print,评测靠肉眼”。我当时就建议他试试LangSmith那一套Prompt Ops的工程化玩法,大概过了一周他跟我说,终于有种“在写正经工程”的感觉了。今天这篇就把我从概念到落地的一套完整思路写出来,适合正在做LLM应用、Agent、RAG项目,并且已经受够了“黑盒式开发循环”的开发者参考。

LangSmith是LLM应用的可观测性与评测平台,核心覆盖跑批评测、链路追踪、在线监控、数据集沉淀和Prompt版本管理。Prompt Ops则是一种把Prompt当成需要持续维护、测试、监控的软件资产来对待的工程理念。两者结合以后,你在本地写Prompt、上生产看效果、出问题回滚、换模型做回归,都能在一个闭环里完成。这篇文会先拆解为什么需要Prompt Ops,再逐个讲LangSmith的核心模块,最后给出一套可以照着抄的落地配置,以及我踩过的坑。

1. 为什么需要Prompt Ops:LLM应用开发的工程化困境

1.1 从Demo到生产:Prompt开发最大的隐藏成本

很多团队做LLM应用的起点,是先在Playground里把Prompt调到“看起来不错”,然后直接复制粘贴进代码。Demo阶段这没问题,因为样本少、场景固定、出错了重跑一遍就行。但一旦进入生产,情况就完全不一样了:真实用户输入千奇百怪,Prompt里哪怕一个标点符号的改动,都可能让十几种边界case的表现同时变化;而你又很难说清楚变化是变好了还是变坏了,因为“好”和“坏”在LLM场景里本身就是模糊的。

这里的隐藏成本在于,Prompt的迭代本质上是离散的、非线性的。传统代码改坏了,编译报错、单测失败,反馈是即时的;Prompt改坏了,可能只是某些回答变啰嗦了,或者某个工具调用参数格式偶尔不对,这种“慢性劣化”最容易在半夜被用户投诉才发现。我之前见过一个团队,线上Prompt被运营同学悄悄加了一段话术引导,结果整个意图识别模块的准确率掉了十几个点,而他们花了两天时间排查才发现是Prompt被人改过。这就是典型的没有Prompt Ops意识导致的线上事故。

1.2 Prompt Ops到底在解决哪些具体问题

Prompt Ops不是一个具体的工具,而是一套围绕Prompt生命周期管理的实践集合。它要解决的核心问题可以拆成四类。

第一是可观测性。你必须要能回答“线上这个请求,模型到底收到了什么、输出了什么、中间调了哪几个工具、各花了多长时间、消耗了多少Token”。没有这些数据,任何问题排查都是猜。

第二是评测体系。你要有一套可以反复运行的评估集,里面包含典型输入、期望行为、判定标准。这样每次改Prompt、换模型、调参数,都可以用同一把尺子量前后的差异,而不是靠感觉拍板。

第三是数据集沉淀。生产环境里的真实用户请求,是最宝贵的测试样本。你需要有机制把这些请求收集下来、脱敏、打标,然后变成回归集的一部分。

第四是版本管理与反馈闭环。Prompt的每一次变更都要可追溯、可回滚;线上效果要能关联到具体的版本;用户反馈(点赞、点踩、纠错)要能回流到评测集里,形成持续改进的循环。

这四个问题,用传统日志系统加手工脚本也能勉强做,但会非常痛苦。因为LLM应用的链路比普通API复杂得多,一次Agent执行可能是“用户输入 -> LLM推理 -> 工具调用 -> 再次推理 -> 生成结果”的多跳结构,普通日志系统难以完整还原链路和关联多轮调用。

1.3 为什么是LangSmith,而不是自己搭一套

自己搭一套LLM应用观测系统,技术上完全可行,但成本远超大多数人预期。你要自己设计Trace的数据结构,解决异步链路串联问题,做Token消耗统计,搭数据集管理界面,写评测Runner,再做可视化看板。把这些做完,一个熟练的工程师至少需要两到三周,而且后期维护还要持续投入。

LangSmith作为专门为LLM应用设计的平台,开箱就具备这些能力。它和LangChain生态天然集成,但并不是绑定关系,你完全可以用纯OpenAI SDK甚至自封装HTTP调用,通过REST API或SDK的埋点方式接入。这种“轻侵入、重覆盖”的设计,使得它既可以服务全新项目,也能嵌入到存量系统里做增量改造。对我个人来说,选择它的关键理由是它把追踪、评测、数据集、监控整合在一个平台里,避免了多个工具之间来回搬运数据的割裂感。

2. LangSmith核心能力拆解:从追踪到评测

2.1 Trace:一次请求的完整生命周期

Trace是LangSmith的基石功能。它的工作方式是在你的应用代码里埋点,把一次完整请求从进入到返回的所有过程串成一条调用链。每次推理、每个工具调用、每次检索,都会变成一个Span,Span之间通过父子关系关联,最终汇聚成一个Trace。

这里有个很容易忽略的点:LangSmith默认的Span单位是Run,一个Run可以是一个LLM调用、一个Chain执行、一个Tool执行,也可以是你在代码里通过create_runner手动划定的一段逻辑。比如一个Agent执行流程中,你可能先做了意图识别,再做了知识库检索,最后拼接Prompt生成回答。如果你不手动埋点,LangSmith就只能看到最外层的结果,中间过程会被折叠成黑盒。所以我在接入时都会额外埋几个关键步骤,让Trace能完整还原“用户说了什么 -> 系统做了什么判断 -> 检索到了什么 -> 模型基于什么生成了什么”的全过程。

LangSmith的Trace详情页会展示每个Span的输入输出、耗时、Token消耗、模型名、Prompt模板版本。排查线上问题时,我一般先看整体耗时,再逐层点开每个Span看延迟,哪一层慢一眼就能定位。它还支持在Trace上直接加评论和打标签,比如“这是错误案例”“这是好案例”,这些标签会同步到数据集模块,成为后续评测样本,非常方便。

2.2 数据集与离线评测:把“感觉”变成“标尺”

数据集模块是LangSmith我最常用的部分。你可以创建数据集,往里添加样本,每个样本包含输入和理想输出,还可以附带额外的元信息(比如该样本属于哪类场景、期望模型遵循什么样的风格)。

离线评测则在数据集上批量跑你的Prompt或Chain,并把结果与理想输出做对比,得出准确率等指标。LangSmith内置了几种Evaluator,如cot_qa用于评估问答正确性、criteria按照自定义标准打分、labeled_criteria参考标注答案做对比评估、embedding_distance用向量距离衡量语义相似度等。我觉得新手最容易上手的是“AI-as-a-Judge”模式,就是让另一个LLM来给当前输出打分,给好明确的评分标准后,它的评估结果在大多数场景下与人工评估的一致性非常高。

我在实际项目里会同时配置两类评估器:一类是客观规则类,比如判断输出是否包含指定关键词、JSON格式是否合法、工具调用参数是否完整;另一类是主观质量类,比如回答是否有逻辑、是否忠实于检索上下文。客观规则保证下限,主观评估保证体验,两者结合才是一套完整的评测标尺。

2.3 在线监控与反馈捕获:生产环境里的第三只眼

离线评测解决的是“改版前”的质量确认,上线之后还需要监控真实流量。LangSmith的监控面板支持配置自定义指标,比如平均延迟、Token消耗、成功率、带某种标签的Trace数量等,超过阈值就触发告警。同时它也允许为Trace打上业务层面的反馈数据,比如用户是否点击了“赞同”、是否正确解决了问题,这些反馈会回流到数据集里,持续丰富评测样本。

不过要注意,在线监控的告警只能帮你发现“出事了”,但没法告诉你“为什么出事了”。所以要配合Trace的明细排查,这又回到了第一小节说的可观测性。我的习惯是监控告警只设置少量最关键的指标,避免告警轰炸导致团队麻木——之前我见过一个团队设置了十几个告警,最后大家基本都忽略了,真正出大事时反倒没人响应。

3. 实战:搭建一个完整的Prompt监控与评测闭环

3.1 环境准备与项目初始化

先搭环境。假设你用的是Python,直接安装官方SDK:

pip install langsmith langchain-openai

然后在代码里配置环境变量:

export LANGCHAIN_TRACING_V2=true export LANGCHAIN_API_KEY=ls_xxxxx export LANGCHAIN_PROJECT=my_llm_app

如果是在生产环境,我建议把LANGCHAIN_TRACING_V2放到部署配置里,通过环境变量注入,不要把密钥写死在代码仓库里。同时说明一下,为了控制成本,你可以在初始化时关掉某些低价值链路的追踪,LangSmith SDK支持给具体调用传langsmith_extra参数或使用tracing_enabled=False做细粒度控制。

如果你不是用LangChain,而是直接调用OpenAI SDK,那么LangSmith也提供了REST API方式埋点,支持POST /trace接口直接上报链路的输入输出。这种方式的接入成本稍微高一点,但对于存量项目改动最小。我自己在某个模块上就是用的纯HTTP接入,效果一样稳定。

3.2 埋点与追踪的接入细节

以LangChain为例,最简单的接入方式是这样,定义Chain之后,运行它时LangSmith会自动采集:

from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser llm = ChatOpenAI(model="gpt-4o", temperature=0.3) prompt = ChatPromptTemplate.from_messages([ ("system", "你是一个专业的{role},请用简洁风格回答用户问题。"), ("human", "{question}") ]) chain = prompt | llm | StrOutputParser() result = chain.invoke({"role": "客服", "question": "我要退货怎么办"})

自动采集已经能拿到主链路数据,但为了让Trace更完整,我会再加中间步骤的埋点。比如这样:

from langsmith.run_helpers import traceable @traceable(name="intent_classify", run_type="chain") def classify_intent(query: str): # 返回意图标签 return intent_label

traceable装饰器会把函数执行纳入当前Trace上下文,并且自动记录输入输出。对于非简单函数,我还习惯手动创建跑分节点来做更精细的埋点,这种方式适合在复杂Agent逻辑里标记“推理”“工具调用”“记忆读取”等不同阶段。

一个关键经验:埋点名称要规范。团队成员写name="retriever"和name="retrieve"各写各的,后期在筛选Trace时会非常痛苦。我们团队的做法是约定统一格式:模块名+动作名,比如rag_search、agent_tool_call,这样在LangSmith筛选器里可以快速检索全链路中某一类型节点。

3.3 从Trace中沉淀评测数据集

生产环境跑了一周后,LangSmith的Projects里会积累大量Trace。这时候你去Logs/Traces列表,按标签或耗时筛选,就能找到“优质回答”和“错误案例”。

LangSmith提供了从Trace直接创建数据集的入口。在Trace详情页右上角有一个“Add to Dataset”按钮,选中后你可以选择“输入输出模式”还是“完整Trace模式”,并填写期望输出和标签。我的用法是每隔几天固定花半小时把当天有价值的Trace打标入库,日积月累就是一套非常有代表性的业务评测集。具体步骤是:

  1. 在Trace列表筛出带有production标签且反馈为负面的记录。
  2. 逐条查看失败原因(可能是格式错误、幻觉、工具调用失败等)。
  3. 从Trace详情页“Add to Dataset”加入数据集,并填写修正后的期望输出。
  4. 每周跑一次全量回归,把新样本加入后立即验证当前Prompt是否在这些新样本上仍然表现良好。

这里有个细节:如果样本是从Trace直接复制的,可能会携带大量轮对话历史或冗余上下文,入库时最好做一次精简。因为评测集真正的价值是覆盖“语义边界”,而不是记录全量对话历史。一个干净的评测样本最好只包含“输入 -> 期望输出”和必要的背景字段。

3.4 评测跑批与回归把关

有了数据集,下一步就是在LangSmith里创建测试(Test)。创建一个Test后,你会选择一个数据集、一个待评估的Chain/Runnable,以及若干Evaluator。点击“Start Test”后,它会批量运行并把结果汇总成评测报告。

我在项目里通常配两组Test:核心回归组和探索组。核心回归组是那些每次发版必须通过的样本,Evaluator以硬性规则为主(格式、关键词、函数调用参数),外加一条AI评分标准;探索组则是新收集的边界样本,Evaluator以AI评分和人工复核为主。这样区分是因为:核心回归组要求快速、稳定、结果可解释;探索组则允许更大方差,重点是发现prompt在不同输入下的行为变化。

评测完成后,LangSmith的Dashboard会呈现每个样本的得分明细。我习惯按分数降序排列,先看低分样本,确认是Prompt本身的问题还是评测标准过于苛刻。另一个实用技巧是:不要只在一个模型上做回归,GPT-4o和本地开源模型并存的话,同一个Test可以切换target模型重复跑,直接横向对比模型差异。这点在做模型选型时帮了我很大的忙。

3.5 配置在线监控与告警

LangSmith监控面板里,可以按照Project维度设置指标看板。我常用的指标如下:

指标类型告警阈值参考
平均响应延迟性能超过P95的2倍或绝对值超过5秒
单次请求Token消耗成本较上周均值上涨20%
带有tool_error标签的Trace占比质量连续3个周期超过2%
无标签Trace占比数据完整性超过30%说明埋点失效

配置告警时,如果用的是LangSmith Cloud,可以直接在Alerts页面选指标、设阈值、填通知渠道。自托管部署则要自己对接Webhook。我个人建议告警渠道接IM机器人,这样可以快速建群拉人排查。

在线监控不只要盯数字,还要定期抽看Trace内容。数字指标只能反映“系统是否健康”,而LLM输出的语义质量需要持续人工抽查。我会在每周巡检时随机抽20条Trace,快速浏览一遍回答质量和工具调用逻辑,发现共性问题就立即挂到评测集里,进入下一轮迭代。

4. 常见问题与排查技巧实录

4.1 Tracing数据丢失,页面上看不到新Trace

这是接入时最常遇到的问题。先检查环境变量是否真的传到了运行进程里,不少部署平台会在启动时覆盖环境变量,你本地配了.env但线上没生效。其次确认LangSmith的SDK版本和LangChain版本兼容,版本不匹配时埋点会静默失败。最后,如果你在代码里显式设置了tracing_enabled=False,或者请求走了离线Mock,都可能导致Trace不落库。

我之前遇到过一个诡异场景:线上偶尔丢Trace,排查后发现是有个并行任务里抛异常导致langsmith_extra的父上下文丢失,新开的线程没有继承Trace ID。解决办法是在多线程入口用run_helpers包一层上下文传播,或者干脆把并行任务改为串行重点路径埋点。

4.2 评测结果不稳定,同样的Prompt两次跑分差很多

LLM本身就是概率模型,同样的输入会产生不同输出,所以评测结果有波动是正常的。但如果你发现波动幅度大到影响判断,就要考虑是评测标准不够明确。比如你用contains关键词这种规则去评测开放性回答,大概率时好时坏;用AI-as-a-Judge时,如果评分标准写得含糊,比如“回答质量高”,不同LLM给出的分数也会飘。

解决办法是把评分标准细化成可观察的行为描述:例如“如果回答中包含明确的操作步骤,加1分”“如果回答承认自己不知道且建议转人工,加1分”。给Judge模型定义一份带示例的评分Ruble,稳定性会显著提升。另外,同一个Test比较不同版本Prompt时,建议把Temperature设为0再做评测,排除采样随机性的干扰。

4.3 Token消耗上涨但功能没变,成本失控

我见过好几回:Prompt模板里塞了一大段历史对话,结果每次请求都要把这堆历史重新编码一次,Token量自然飞涨。LangSmith的Trace详情会展示每个Span的Token使用明细,你只要按Token量排序,一眼就能看到是谁在吃钱。

定位到原因后,要么收缩历史窗口,要么用摘要对话压缩,要么改用带缓存能力的模型接口。这里还要注意一个细节:评测跑批也会消耗Token,而且是一次性跑几十上百条样本,数量大了成本也不低。所以我会把评测集按优先级分层,日常回归只跑核心集,完整集放在发版前跑一次。

4.4 团队协同时的“评测集冲突”

多人共用同一个LangSmith项目时,很容易出现A同学往数据集里加了一批样本,B同学不知情,跑出来的回归结果差异很大,于是在群里争论“为什么这版Prompt变差了”。其实变差的不是Prompt,而是数据集加了新样本。

我们的解决方式是给数据集分“所有者”,样本入库前先沟通,并给每个数据集写README说明用途。同时约定核心回归组只在经过评审后修改,日常探索样本一律进探索集。这套规则虽然简单,但能避免大量无意义的回滚和争论。

5. 从工具到工作流:我的一些心得

5.1 让评测先于Prompt迭代,玩命跑分但不要盲目信分

在实际操作中我发现,一旦你开始用LangSmith,最危险的反而是“过于相信评测分数”。AI-judge评分再合理,它也只是模拟真实用户的部分感知,不是全部。比如某个评测集里大部分样本是“知识问答型”,Judge模型给的分很高,但实际上线后发现用户在“情感支持型”场景下的满意度大幅下滑。原因就是评测集覆盖不均,分数是平均后的假象。

所以我现在的习惯是:把评测集按业务子场景分组,跑分时不仅看总分,还看分场景得分。用LangSmith的Dataset里每条样本的元信息(scene字段)来分组,然后按组看平均分。新增Prompt版本时,如果总分微降但某个关键场景得分大涨,我反而会考虑上线,因为产品指标更依赖那个关键场景。说到底评测分数是辅助决策的信号,不是最终判官,这个定位摆正了,工具才真正为你所用。

5.2 追踪、评测、监控要一起上,别只上追踪

很多人把LangSmith当“高级日志”用,装上之后只看Trace。这当然比没有强,但没发挥出它的真实价值。我建议至少上一个“追踪+离线评测”的组合,因为追踪只能让你知道“发生了什么”,评测才能让你决定“这个变更能不能上”。在线监控可以等数据积累起来后再配,但数据集沉淀一定要从第一天就开始,越早积累,后面的回归判断越有底气。

5.3 给新人的入门路径建议

如果你之前完全没用过这类工具,我的建议是按这个顺序来:先花半小时把Trace跑起来,对照文档理解Run、Span、Project的概念;然后拿一周的真实Trace手工打标,建一个只有20个样本的小数据集;接着在上面跑一次Test,配置最简单的规则评估器,感受评测闭环;最后再逐步增加AI评估标准、告警、团队协作规范。这套路径大概两三天就能走完,但能让你真正理解Prompt Ops在干什么,而不是只在界面上点来点去。

5.4 一个小技巧:把线上错误自动变成数据集样本

最后分享一个我现在一直在用的自动化流程。我会在应用代码里捕获异常或检测到低分反馈时,自动调用LangSmith的数据集API,把当时的输入、输出、错误信息一起写入一个名为auto_capture_errors的数据集。这样每次线上出问题,我连手动操作都省了,第二天直接看这个数据集跑一轮回归,就知道当前Prompt在最新错误样本上的表现。日积月累,这个数据集几乎就是你产品体验的“故障病例库”,非常珍贵。

具体代码很简单:

from langsmith import Client client = Client() def auto_capture(query, output, error_info): client.create_example( dataset_name="auto_capture_errors", inputs={"query": query}, outputs={"output": output, "error": error_info}, metadata={"source": "production", "captured_at": "2025-01-01"} )

接入时唯一要注意的是数据脱敏,线上真实用户文本可能包含敏感信息,入库前先做正则替换或调用脱敏服务,避免隐私数据累积在数据集里。这个小流程坚持用上一个月,你会明显感觉到Prompt迭代的思路清晰很多,再也不用靠记忆和猜测来改Prompt了。

说到底,LangSmith和Prompt Ops带给我的最大改变,不是某个具体功能,而是让我把“试Prompt”这件事从玄学变成了一门可以复盘、可以度量、可以持续改进的工程。手里有Trace、有数据集、有评测报告,改Prompt就像在成熟代码库上做重构一样踏实。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询