☰
LangSmith实战:LLM应用监控从接入到落地的全流程指南
2026/10/21 14:07:26 网站建设 项目流程

做LLM应用开发最让人头疼的,往往不是模型选型,也不是提示词写不好,而是应用上线之后你根本不知道它在线上干了什么。用户说了一句奇怪的话,模型回了一个奇怪的答案,中间到底发生了什么,传统日志里只有输入和输出,完全是一团黑盒。LangSmith就是这个场景下我最常用的工具,它专门用来做LLM应用的追踪、调试、评估和监控。这篇文章我就从实际使用的角度,把LangSmith监控从接入到落地讲透,适合正在做AI应用开发、尤其是基于LangChain做项目的朋友参考。

我第一次接触LangSmith是在一个聊天机器人项目上线第二周,用户反馈说"回答越来越慢了",可服务器指标一切正常。后来才发现是某个工具调用环节反复重试,每次重试都触发一次完整的大模型请求,延迟凭空多出七八秒。这个结论如果只靠传统日志,不知道要排查多久;而有了LangSmith的链路追踪,问题在十分钟内就定位了。所以我一直认为,LLM应用做监控不是可选项,而是工程化的刚需。

1. 为什么LLM应用离不开专门的监控工具

1.1 传统日志审计解决不了的问题

做过后端开发的人都熟悉传统的日志排查思路:打点、收集、聚合、看错误率。但LLM应用跟传统Web服务有个本质区别:它的核心计算单元是模型调用,而这个调用本身存在不确定性。同样的输入,今天和明天的输出可能完全不同,甚至同一个模型版本,温度参数调高一点,结果天差地别。

这种不确定性带来了一系列监控困境。

第一个困境是链路不可见。一次用户请求,可能经历了检索、提示词组装、模型调用、工具执行、结果解析、二次模型调用等多个环节。传统日志只能记录每个环节的输入输出,但环节之间的时序关系、依赖关系、嵌套关系很难串联起来。你看到日志里有三次模型调用,却不知道第一次为什么触发第二次,第二次的上下文从哪来。

第二个困境是评估难。传统后端的成功失败有清晰的判断标准,状态码就是状态码。但LLM应用里的"成功"是什么?模型返回了内容不代表答案正确,回答流畅不代表没有幻觉。你很难用一个布尔值来判定一次模型调用是否"成功",更别提监控它的质量趋势了。

第三个困境是成本可见性差。LLM应用的成本跟调用量、输入token数、输出token数强相关,一段超长的上下文可能让单次调用成本翻几倍。没有专门的监控手段,你根本算不清某个功能一个月烧了多少钱,也不知道哪个用户或哪个场景在消耗大头。

这三个困境,恰恰就是LangSmith这类LLM可观测性工具出现的原因。

1.2 LangSmith的定位与价值

LangSmith是LangChain生态里的可观测性与评估平台,它的核心能力可以概括为四件事:追踪、调试、评估、监控。

追踪,指的是把一次完整的LLM应用请求拆解成一颗树,每个节点都是一个执行步骤,比如一次模型调用、一次检索、一次工具执行。每个步骤的输入、输出、耗时、消耗的token数、使用的模型名全部被记录下来。

调试,指的是你可以直接在网页上查看任意一次请求的完整链路,逐步查看每一步的输入输出,甚至可以直接修改参数重新运行某一步来验证假设。

评估,指的是你可以把一批真实请求沉淀为数据集,然后对新版本模型、提示词做批量回归测试,用分数、对比的方式量化质量变化。

监控,指的是在项目仪表盘上实时看到延迟、错误率、token消耗的趋势,用图表和数据来掌握整个应用的健康度。

用一句话概括:如果说LangChain是帮助你构建LLM应用的工具链,那LangSmith就是给这条工具链配上的仪表盘和黑匣子。

1.3 适用场景与使用成本评估

我个人的经验是,LangSmith几乎适用于所有LLM应用场景。单人开发的原型项目,可以用它来快速调试提示词和链路;小团队协作,可以用它的项目和成员权限来组织工作;上了生产线的应用,可以用它做线上监控和数据回流。

成本方面,LangSmith有免费层和付费层。免费层对于开发调试和中小流量项目基本够用,付费层主要增加的是调用量配额、数据保留时长和高级功能。如果你的数据合规要求非常严格,不允许任何数据出内网,LangSmith也提供了自托管方案,可以部署在私有环境里,数据完全本地化。

2. 基础接入:把第一个Trace跑起来

2.1 环境准备与密钥获取

接入LangSmith的第一步是注册账号并创建一个项目。注册完成后,进入设置页面获取API Key,这个Key就是一串以ls_开头的字符串,相当于你访问LangSmith服务的凭证。

项目概念可以这样理解:一个项目对应一个应用或一个服务。你可以在同一个账号下创建多个项目,分别对应线上环境、测试环境,或者不同的子应用。这样在查看监控数据时,各个项目的指标是隔离的,不会互相干扰。

获取到API Key后,需要在你的应用环境里配置两个关键环境变量:

export LANGCHAIN_TRACING_V2=true export LANGCHAIN_API_KEY=ls_你的密钥 export LANGCHAIN_PROJECT=my-llm-app

第一个变量LANGCHAIN_TRACING_V2是总开关,告诉SDK开启追踪;第二个变量是身份凭证;第三个变量指定数据归属哪个项目。这三个变量配置完成后,你的应用只要是通过LangChain构建的,基本就能自动开始上报追踪数据了,不需要在代码里做任何额外改动。

注意:环境变量中的LANGCHAIN_PROJECT如果没设置,默认会用default项目,多个应用的数据会混在一起,后期排查会非常痛苦。我建议从第一天就养成显式设置项目名的习惯。

2.2 安装SDK并验证链路

如果你的项目不是基于LangChain,或者你想更细粒度地控制追踪行为,就需要直接安装并调用LangSmith的Python SDK。

pip install langsmith

安装完成后,用一段最简单的代码来验证链路是否打通:

from langsmith import Client client = Client() print("项目列表:", client.list_projects())

如果能够正常返回项目列表,说明你的API Key配置正确,SDK和环境是通的。接下来创建一个最基础的追踪:

from langsmith import traceable @traceable(run_type="chain") def generate_answer(question: str) -> str: result = f"这是对问题的模拟回答:{question}" return result @traceable(run_type="llm") def call_model(prompt: str) -> str: return f"模型输出: {prompt}" @traceable(run_type="chain") def main_flow(question: str) -> str: prompt = f"用户问题:{question}" model_result = call_model(prompt) return generate_answer(model_result) main_flow("LangSmith怎么接入") main_flow("今天天气怎么样")

运行这段代码后,登录LangSmith网页端,打开你的项目,就能看到刚刚生成的两条追踪记录。点开任意一条,能看到main_flow下嵌套着call_model和generate_answer两个子步骤,每个子步骤的运行时长都单独记录。

第一次跑通这个链路时,那种"代码运行过程被完整可视化"的感觉,真的很颠覆直觉。你写的每一层函数调用,在网页上都变成了一棵可展开的树,每一步的输入输出、耗时、成本全部清清楚楚。

2.3 不写代码也能接入:与LangChain的自动集成

如果你使用的是LangChain的链式API或LangGraph,LangSmith的接入甚至不需要写任何追踪代码。只要环境变量配置好了,LangChain的Runnable对象、Agent的执行过程、工具调用、检索器的运行细节都会自动上报。

这种自动上报的原理,是LangChain在底层设计时就集成了回调系统。每次Runnable执行时,都会触发一系列回调事件,包括开始、结束、错误、token流式输出等。LangSmith SDK实现了一套回调处理器,把这些事件捕获并组装成Span树。这也就是为什么你在LangSmith上看到的链路结构,跟你代码里的嵌套调用关系几乎完全一致。

如果你用了with_config方法来配置运行参数,还可以做到更精细的控制:

from langchain_core.runnables import RunnableConfig config = RunnableConfig( metadata={"user_id": "12345", "env": "production"}, tags=["customer-service"] ) result = chain.invoke({"question": "退款流程是什么"}, config=config)

这段配置会让本次运行时附带元数据和标签,后续在LangSmith筛选时就能按这些字段过滤查找。

3. 核心概念拆解:Trace、Run与Span

3.1 一次请求的一生

理解LangSmith的数据模型,是玩转监控的关键。它最核心的概念有三个:Trace、Run和Span。

Trace表示一次完整的请求链路,从用户发起请求到最终返回响应,是一次业务闭环。你可以把它想象成你在电商平台下了一个订单,从下单到收货的全程物流信息都被记录下来,这就是一条Trace。

Run是Trace中的一个节点,代表一次具体的执行步骤,比如一次大模型调用、一次向量检索、一次工具调用。Run之间可以嵌套,形成父子关系。回到物流的类比,一条Trace是你整个订单的物流轨迹,而Run则是轨迹上的每一个节点:包裹到达转运中心、包裹派送中、包裹签收。

Span这个概念更多是习惯性的叫法,它和Run在LangSmith中本质上是同一类东西。早期LangSmith叫Run,OpenTelemetry生态里叫Span。如果你的团队有OpenTelemetry背景,完全可以把它当作Span来理解。

这种Trace-Run的树状结构带来一个非常大的好处:你可以只看任意一个子步骤的细节,而不影响对整个请求的理解。比如用户问了一个问题,链路的顶层显示耗时8秒,展开后看到大部分时间花在call_model上,retrieve_documents只用了200毫秒,判断依据一目了然。

3.2 手动追踪的两种姿势

除了装饰器这种自动追踪方式,LangSmith还提供了更底层的RunTree API,适合需要精确控制追踪结构的场景。

from langsmith.run_trees import RunTree parent = RunTree( name="my_chain", run_type="chain", inputs={"question": "什么是LangSmith"} ) child_llm = parent.create_child( name="chat_model_call", run_type="llm", inputs={"prompt": "请回答:什么是LangSmith"} ) child_llm.end(outputs={"response": "LangSmith是一个可观测性平台"}, usage={"total_tokens": 36}) parent.end(outputs={"answer": "完成"}) parent.post()

这里run_type参数很关键,它有四种取值:llm、chain、tool、retriever。你上报的Run类型不同,LangSmith网页端展示的图标、可用的统计维度、可附加的元数据字段都会不同。比如llm类型的Run可以记录usage信息来计算token成本和延迟指标,而tool类型的Run则更适合记录工具的原始输入输出。

手动追踪的好处是灵活,但代价也是明显的,就是需要你手动管理父子关系和生命周期,代码量会多不少。我个人的建议是:能用装饰器就尽量用装饰器,只有当链路结构非常规,或者需要动态决定子步骤数量时,才用RunTree手动构建。

3.3 元数据与标签的工程价值

很多初学者忽略metadata和tags,认为这只是锦上添花。实际上,元数据和标签是监控数据能被真正用起来的关键。

元数据本质上是一组键值对,适合记录结构化信息,比如用户ID、会话ID、实验版本号、部署环境。标签则是一些短字符串,适合做粗粒度的分类标记,比如high-value、needs-review、error-type-timeout。

有了这些字段,LangSmith的筛选器才能发挥作用。比如线上突然有一批请求报错,你想知道这批请求是不是来自同一个渠道,就可以用元数据channel=android来过滤。又比如你在做提示词A/B测试,给两个版本分别打了prompt-v1和prompt-v2的标签,就能在仪表盘里对比两条链路的质量指标。

一个实用的习惯:上线前先在代码里统一好元数据的键名规范,避免出现user_id和UserId这种大小写不一致的字段。混乱的字段命名会让后续查询变成灾难。

3.4 采样与成本控制

全量追踪最直观,但不是所有场景都需要全量。如果你的应用流量很大,每个请求都上报完整的链路数据,不仅会增加网络开销,还会快速消耗配额。这时候就需要采样。

采样最朴素的做法就是按比例随机采样。比如你只想保留10%的请求轨迹,可以在请求入口处做一次随机数判断:

import random import os os.environ["LANGCHAIN_TRACING_V2"] = "true" os.environ["LANGCHAIN_TRACING_SAMPLE_RATE"] = "0.1"

LangSmith SDK支持通过LANGCHAIN_TRACING_SAMPLE_RATE环境变量来设置采样率,值范围从0到1,0意味着完全不上报,1意味着全量上报。这个变量的优先级高于代码内的追踪开关,如果设置了0.5,则只有约一半的请求会被记录。

需要注意的是,采样率设置后,你在LangSmith上看到的延迟、错误率等指标只是样本数据的统计结果,不是全量真实值。在解读数据时要清楚这一点,尤其是做容量规划和成本预估时,要把采样率当成系数折算回去。

当然,采样策略也可以做得更聪明。比如对所有错误请求无条件全量追踪,对成功请求只采样10%。这种条件采样逻辑需要自己在代码里判断处理,但效果远比一刀切的随机采样好,我后面会细说。

4. 监控面板实操:从延迟到成本

4.1 项目仪表盘读法

数据上报之后,真正的工作才开始。打开LangSmith项目页面,你会看到一系列图表和指标,这些不是摆设,而是线上应用健康状况的直接反映。

仪表盘最值得关注的是延迟指标。LangSmith默认会展示P50、P90、P95分位延迟,如果你只盯着平均延迟,就会被少数极慢请求拉高数值误导。P95延迟的意义在于告诉你"95%的请求在多少毫秒内完成",这个值对用户体验的参考价值远高于平均值。

接着说token消耗和成本。在项目概览里能看到输入token数、输出token数和总成本估算。这个成本估算基于模型单价表计算,虽然和账单数字有出入,但作为趋势参考完全够用。我见过不止一个团队,上线了某个功能却不知道它每天烧掉多少费用,直到月底对账单时才傻眼。监控面板上的成本曲线,能帮你尽早发现这种问题。

错误率指标同样重要。LangSmith会把运行异常标记为错误状态,并聚合出错误率曲线。如果错误率突然从0.5%跳升到10%,多半是上游模型API出问题、检索服务挂了,或者你的代码在处理某种特殊输入时出现了异常。这时候可以直接点进错误率最高的时间段,查看对应的Trace失败原因。

4.2 用监控定位一次线上事故

理论讲多了容易抽象,我用一次真实发生的事故来演示完整的排查流程。

某个周末,我的一个对话机器人项目收到用户反馈,说"回答越来越慢了"。服务器CPU、内存、网络指标都正常,传统监控完全无异常。这时我打开LangSmith,先看项目仪表盘的延迟曲线,发现P95延迟从平时的2秒飙升到9秒,持续时间大约四十多分钟。

然后我按时间范围筛选出那个时间段的Trace,按延迟降序排列,点开最慢的一条看链路树。链路显示顶层耗时9.2秒,展开后看到retrieve_documents耗时0.3秒,call_model耗时0.4秒,而tool_execute这一步耗时高达8.2秒。

关键原因找到了,是工具调用环节出了问题。点进tool_execute的详情,看到这个工具在循环调用某个外部API,由于该API内部限流,每次都等待超时,重试机制又反复触发。整个请求在网络等待上浪费了绝大部分时间。

没有链路追踪,这个排查可能要花几个小时;有了LangSmith,从发现问题到定位根因只花了不到十分钟。这个案例很好地说明了一条完整的链路树对排障效率的提升是革命性的。

4.3 评测与数据回流

监控不只是看数字,还可以把线上数据变成改进模型能力的素材。

LangSmith允许你在Trace上打人工评分。打开任意一条Trace,你可以打分并写下评语,标记这个回答是优秀、一般还是不可接受。这些人工反馈会沉淀到项目的数据集,成为后续评估模型的基准。

更进一步,你可以把这些真实Trace整理成数据集,用于回归测试。比如把线上收集的1000条真实用户问题保存为数据集,每次修改提示词或更换模型版本时,都用这批问题批量跑一遍,自动比对新旧版本回答的质量。

这里要说明一下,数据集和监控是两个关联但不同的模块。监控关注的是运行状态和健康度,数据集关注的是质量基准和回归验证。LangSmith把两者打通了,好处是你在监控中看到的糟糕回答,可以一键存入数据集,然后触发一次针对这个问题的修复验证流程。这种从问题发现到解决验证的闭环,才是LLM应用迭代的正确姿势。

5. 生产环境必须知道的坑

5.1 追踪数据丢失的常见原因

接入LangSmith后遇到的第一类问题是明明代码跑完了,网页上却看不到Trace。我排查过几回,整理了最常见的三个原因。

第一个原因是环境变量没生效。很多人把环境变量写在.env文件里,但代码读取的却是系统环境变量,导致SDK根本没拿到配置。验证方法是:在代码启动处打印一下os.environ.get("LANGCHAIN_TRACING_V2"),确认值真的是"true"而不是"True"或"1"。

第二个原因是异步代码没有等待上报完成。LangSmith的异步追踪在底层是异步发送数据的,如果你的主线程结束得太快,上报请求还没来得及发出去进程就退出了,数据就丢了。在FastAPI这类异步框架里特别常见,正确做法是确保请求处理函数的生命周期覆盖追踪上报,或者在进程退出前做个短暂的等待。

第三个原因是采样率设成了0或者误配置。我之前调试过一次,怎么跑都不出数据,最后发现是某个公共配置文件里把LANGCHAIN_TRACING_SAMPLE_RATE设成了0,被自己坑了。

5.2 异步与多线程追踪错乱

这个问题比较隐蔽,但一旦遇到会让数据完全不可信。

Python的异步和多线程环境下,上下文变量是不可跨任务传递的。LangSmith内部用上下文变量来维护当前活跃的Run,如果异步任务或新线程没有正确继承上下文,新的子Run就会被挂到错误的父Run下面,或者干脆变成根Run,导致链路断裂和串线。

典型的症状是:并发量稍微上来后,有些Trace的子步骤跑到别的Trace底下去了,数据组织完全乱套。

解决办法是尽量让追踪装饰器包裹完整的异步函数,而不是在异步函数内部去手动创建子Run。@traceable装饰器本身对异步函数有良好的上下文传播支持,只要结构合理,就不会出问题。另外,如果你用了asyncio.gather并行执行多个子任务,尽量在装饰器层面做并行,让每个并行的子任务都成为一个独立的子Run,而不是在同一个Run内部手动切换。

5.3 敏感数据脱敏与隐私控制

LLM应用处理的数据往往包含用户对话内容,甚至可能有手机号、地址、身份信息。默认情况下,LangSmith会把模型的输入输出传送到云端进行展示,这在很多场景下是有合规风险的。

好消息是,LangSmith提供了多种数据控制手段,你可以在环境变量级别关闭输入输出记录:

export LANGCHAIN_TRACING_REDACT_INPUTS=true export LANGCHAIN_TRACING_REDACT_OUTPUTS=true

设置后,网页端只显示字段的哈希摘要信息,不显示原始内容。如果你只想脱敏部分字段,也可以在traceable装饰器中传入自定义的redact参数,或者在上报前对数据做预处理。

我个人的建议是:对于线上生产环境的数据,如果业务允许,优先做脱敏处理;即使业务需要查看完整对话内容,也应该按角色权限来限制访问。毕竟监控是为了服务开发和排障,不是为了把用户隐私暴露给团队里所有人。

5.4 权限与团队协作

当一个项目有多个人共同维护时,权限管理的重要性就凸显出来了。LangSmith允许你邀请团队成员并分配不同角色,比如只读成员、项目成员、项目管理员等。

很多团队刚上手时不重视这个,所有人都用同一个管理员账号,这样不仅操作记录混乱,而且有人不小心改动了项目设置其他人也不知道。一个比较稳妥的做法是:团队里每个成员都有独立账号,根据职责分配角色;项目的访问权限按环境分开,开发环境大家都能看,生产环境只有少数核心人员有查看和操作权限。

另外,API Key的保管也建议分环境管理。开发环境的Key和生产环境的Key分开生成,定期轮换,这样即使某个Key泄露了,影响范围也可以控制在单个环境内。

5.5 数据保留与成本优化

到了项目中期,你可能会发现LangSmith的调用量配额消耗得很快。除了调整采样率,还有一些实用的优化手段。

第一,合理设置数据保留时间。LangSmith有数据保留策略,超过保留期的数据自动清理。对大多数项目来说,30天到90天的保留期足够了,更长的时间段基本用不上,只会白占配额。

第二,低价值请求不追踪。比如健康检查接口、批量内部任务、测试脚本的请求,这些数据噪声大、价值低。可以在代码层面做一个过滤,对这类请求直接关闭追踪。

第三,对部分链路只记录摘要。不一定每条Trace都要完整记录每一步的输入输出。你可以在子环节的选择上做取舍,比如只保留顶层输入、顶层输出和关键模型调用的详细信息,中间的检索过程只保存统计摘要。

这些细节优化加起来,往往能让同样配额下承载的项目数量翻倍,而且不会明显损失监控价值。

6. 监控数据如何反哺应用优化

6.1 从Trace中发现提示词问题

线上真实的Trace是提示词优化的金矿。你在调试环境精心设计的提示词,可能在真实用户输入下表现完全不同。

有一次我在一个文档问答项目里发现,用户一个问题带了两三个问句,模型只回答了最后一句。从Trace里看到,我的提示词构建逻辑在拼接用户问题时出现了问题,第二个问句被截断了。这种问题在单测和调试环境根本不会暴露,只有在真实流量下才有可能遇到。

所以我的习惯是:每周抽时间把线上Trace翻一遍,重点看那些模型回答比较长、步数比较多、耗时比较高的请求,往往能发现提示词设计和用户真实输入之间的差距。

6.2 用评估数据做版本回归

改提示词或换模型之前,先建好评估集,这是我从踩坑中学到的教训。早期我改提示词比较随意,改完看几个测试用例觉得没问题就上线了,结果线上效果有时反而不如旧版本。

后来我养成了一个习惯:任何一次模型配置变更,都在LangSmith里选一批有代表性的历史Trace作为数据集,先跑一轮批量评估,对比旧版本和新版本在同样问题上的表现。评估维度包括回答完整性、格式规范性、关键信息准确度等,也可以引用大模型作为裁判来自动评分。

这套流程跑下来,我的提示词迭代成功率明显提升,基本不会再出现"改完上线才发现变差了"的尴尬情况。

6.3 把监控指标接入告警

监控的最终形态是告警。不能让研发天天登录网页看仪表盘,要让异常主动来找人。

LangSmith本身提供了一些告警能力,你可以基于错误率、延迟等指标配置通知规则。我建议从三个告警开始配置:错误率突增告警、P95延迟超阈值告警、成本日环比突增告警。这三个指标分别对应可用性、体验和成本,覆盖了LLM应用最重要的三个关注维度。

在配置告警阈值时要参考历史基线。如果你的项目平时错误率就是0.2%,那阈值设成1%就比较合理;如果平时错误率就是2%,就不能照搬别人的1%。一切基于自己项目的统计数据,这样才能减少误报和漏报。

等你的监控数据积累到一定量级,可以反过来用LangSmith的数据集做模型微调数据的筛选——把线上高质量回答作为正样本,把不理想回答标注为负样本,这是一条非常值得投入的数据闭环路径。

个人折腾下来最大的体会是:LangSmith这类工具,越早接入越值钱。不要等项目上线出问题了再回头补监控,那时候你已经错过了调试阶段大量有价值的过程数据。从第一个Hello World级别的连接开始就打开追踪,让监控成为开发习惯的一部分,长期下来积累的数据资产远远超出你的预期。最后分享一个小细节:记得偶尔回看一个月前、两个月前的Trace快照,你会明显看到自己的提示词、链路设计是怎么一步步演进到今天的,这种成长的记录感,也是坚持写监控日志的额外奖励。

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

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

立即咨询