欢迎光临
我们一直在努力

LangSmith 实战精讲:LLM 应用 Trace 追踪、评估、监控及 Prompt 管理完整指南

文章目录

  • LangSmith 实战精讲:LLM 应用 Trace 追踪、评估、监控及 Prompt 管理完整指南
      • 概念区分:LangChain / LangGraph / LangSmith
    • 一、为什么 LLM 应用需要专属的可观测性平台
      • 1.1 传统 APM 的能力边界
      • 1.2 LLM 应用的核心调试挑战
      • 1.3 LangSmith 的定位
    • 二、LangSmith 架构与核心组件
      • 2.1 整体架构
      • 2.2 六大核心组件
    • 三、快速接入:从零到看到追踪
      • 3.1 环境变量配置
      • 3.2 验证追踪生效
      • 3.3 非 LangChain 应用的接入
    • 四、Tracing 追踪系统:LLM 应用的"X 光机"
      • 4.1 RunTree:追踪的数据模型
      • 4.2 RunTree 的树形结构
      • 4.3 追踪数据的上报机制
      • 4.4 在 Trace 中添加自定义信息
      • 4.5 OpenTelemetry 集成
        • 适用场景与落地价值
        • 接入方式
        • 适配框架
    • 五、Datasets 数据集:从 Bad Case 到测试体系
      • 5.1 为什么需要数据集
      • 5.2 数据集的结构
      • 5.3 三种创建数据集的方式
      • 5.4 数据集分层规范
    • 六、Evaluation 评估框架:把"感觉"变成"指标"
      • 6.1 评估的核心三要素
      • 6.2 运行评估
      • 6.3 内置评估器详解
        • LLM-as-Judge 的局限与解决方案
      • 6.4 A/B 对比评估
      • 6.5 评估的工程化:CI/CD 集成
    • 七、Prompt Hub:Prompt 的 Git
      • 7.1 为什么 Prompt 需要版本管理
      • 7.2 使用与动态加载
    • 八、Monitoring 生产监控:从开发到运维
      • 8.1 开发 vs 生产:追踪的不同策略
      • 8.2 生产监控核心指标
      • 8.3 采样策略
        • 采样优先级
        • 采样实现
        • 生产踩坑案例
      • 8.4 告警配置
        • LangSmith 后台实操步骤
    • 九、Playground 交互式调试
      • 9.1 Playground 核心能力
      • 9.2 从 Trace 到 Playground 的调试闭环
    • 十、SDK 编程式使用
      • 10.1 实用场景:自动提取 Bad Case
      • 10.2 成本分析报告
        • 价格更新风险与自定义定价适配
    • 十一、与 LangChain / LangGraph 的深度集成
      • 11.1 LangChain 的自动追踪
      • 11.2 LangGraph 的图级追踪
      • 11.3 LangGraph 的中断与恢复追踪
        • 基本用法
        • 生产环境使用场景
        • 生产避坑要点
    • 十二、LangSmith vs 其他可观测方案
      • 12.1 横向对比
      • 12.2 选型建议
    • 十三、最佳实践:从入门到精通
      • 13.1 开发阶段
      • 13.2 生产阶段
      • 13.3 典型使用流程总结
    • 核心总结
    • 时效性声明

LangSmith 实战精讲:LLM 应用 Trace 追踪、评估、监控及 Prompt 管理完整指南

本文系统剖析 LangSmith 的架构原理与工程实践:RunTree 追踪模型、OTel 集成、数据集与评估体系、Prompt Hub 版本管理、生产监控告警、Playground 交互式调试、SDK 编程式调用。从"为什么需要"到"底层怎么实现",拆解 LLM 应用的可观测性基础设施。


概念区分:LangChain / LangGraph / LangSmith

在进入正文之前,先明确三者的定位,避免混淆:

  • LangChain 是 LLM 应用开发框架,提供 Prompt 管理、链式调用、工具集成等基础能力
  • LangGraph 是 Agent 工作流编排框架,基于状态图实现循环、分支、中断恢复等复杂 Agent 逻辑
  • LangSmith 是配套的可观测性平台,为 LangChain / LangGraph 应用提供追踪、评估、监控、调试能力

三者关系:LangChain 和 LangGraph 负责"构建应用",LangSmith 负责"观测和优化应用"。


一、为什么 LLM 应用需要专属的可观测性平台

1.1 传统 APM 的能力边界

传统 APM(Datadog、SkyWalking、Prometheus + Grafana)擅长回答延迟、错误率、QPS 等问题。但 LLM 应用引入了传统 APM 无法覆盖的新需求:

问题类型传统 APMLLM 特有需求
输出质量 HTTP 200 即视为成功 200 也可能答非所问,需质量评估
Token 成本 无概念 每次调用均产生费用,成本差异可达百倍
Prompt 变更影响 无感知 微小变更即可导致效果显著偏移
链路层级 微服务级(A→B→C) 思维链级(Thought→Action→Observation)
评估闭环 需要"测试集→评估器→评分"完整链路

传统 APM 回答"系统有没有崩溃",LangSmith 回答"AI 回答得好不好、花了多少成本、为什么这样回答"。

1.2 LLM 应用的核心调试挑战

基于上述能力边界,LLM 应用在工程实践中面临四大核心挑战:

  • 输出不确定性:LLM 内部状态是数千亿参数的隐式表示,传统断点调试无法触及;相同输入可能产生不同输出,根因可能来自 Prompt 设计、温度参数或模型能力本身
  • 缺乏标准答案:传统软件通过 assertEqual 做单元测试,但 LLM 输出是自然语言,不存在严格的"相等"概念,需要专门的评估框架
  • Token 成本膨胀:Agent 的 ReAct 循环中每轮工具调用的输入输出都进入上下文,10 轮循环后上下文可能膨胀数倍
  • 推理链路不可见:Agent 执行涉及多轮推理和工具调用,若结果有误,缺少全链路追踪则难以定位是检索不准、解析遗漏还是推理偏差

1.3 LangSmith 的定位

LangSmith 覆盖开发、测试、上线、运维的完整闭环:

开发阶段 测试阶段 上线阶段 运维阶段
│ │ │ │
▼ ▼ ▼ ▼
Tracing 追踪 Datasets 数据集 Monitoring 监控 Alerting 告警
调试链路问题 评估效果差异 生产流量追踪 异常自动通知
发现 Bad Case 对比 Prompt 版本 Token 成本统计 延迟/错误告警

LangSmith 之于 LLM 应用,类似于 Datadog 之于微服务、Chrome DevTools 之于前端,是不可或缺的可观测性基础设施。


二、LangSmith 架构与核心组件

2.1 整体架构

LangSmith 采用 SaaS 平台 + 本地 SDK 的双层架构:

┌─────────────────────────────────────────────────────┐
│ 你的 LLM 应用 │
│ │
│ LangChain / LangGraph 原生 OpenAI / 其他框架 │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────────────────────────────┐ │
│ │ LangSmith SDK (langsmith) │ │
│ │ RunTree 追踪 OTel 集成 环境变量 │ │
│ │ 上下文注入 自动埋点 配置管理 │ │
│ └──────────────────────┬──────────────────────┘ │
│ │ │
│ 异步上报 (batch) │
└──────────────────────────┼─────────────────────────────┘
│ HTTPS

┌──────────────────────────┐
│ LangSmith Cloud (SaaS) │
│ │
│ ┌──────┐ ┌──────┐ │
│ │Trace │ │Datasets│ │
│ │Store │ │ Store │ │
│ └──────┘ └──────┘ │
│ ┌──────┐ ┌──────┐ │
│ │Eval │ │Prompt │ │
│ │Engine│ │ Hub │ │
│ └──────┘ └──────┘ │
│ ┌──────┐ ┌──────┐ │
│ │Monitor│ │Playgrnd│ │
│ │ing │ │ │ │
│ └──────┘ └──────┘ │
└──────────────────────────┘

关键设计决策:

  • 异步上报:追踪数据通过异步 batch 发送,不阻塞业务逻辑
  • 零侵入:LangChain 应用只需配置环境变量,零代码改动
  • 框架无关:通过 OTel(OpenTelemetry)标准,支持非 LangChain 应用

2.2 六大核心组件

组件功能对标传统工具
Tracing 全链路追踪,可视化每次调用的层级结构 分布式追踪(Jaeger/Zipkin)
Datasets 测试数据集管理,从 Trace 一键导入 测试用例管理系统
Evaluation 自动评估器,量化 Prompt/模型效果 CI/CD 质量门禁
Prompt Hub Prompt 版本管理与动态加载 Git for Prompts
Monitoring 生产指标监控与告警 APM(Datadog)
Playground 交互式调试与 A/B 对比 Postman for LLM

六者构成闭环协作关系:Tracing 采集数据 → Datasets 沉淀 Bad Case → Evaluation 自动评分 → Prompt Hub 管理版本 → Monitoring 监控生产 → Playground 调试优化。


三、快速接入:从零到看到追踪

3.1 环境变量配置

LangSmith 的设计理念是配置优先,代码零改:

# 【实战代码】最小配置示例
import os

os.environ["LANGSMITH_TRACING"] = "true" # 开启追踪(新版推荐)
os.environ["LANGSMITH_API_KEY"] = "your_langsmith_key" # API 密钥
os.environ["LANGSMITH_PROJECT"] = "my-first-project" # 项目名称

配置完成后,所有 LangChain 的调用都会自动上报,无需修改任何业务代码。API Key 在 smith.langchain.com 的 Settings → API Keys 中创建,格式为 ls__ 开头。

环境变量版本说明:新版 langsmith SDK 推荐使用 LANGSMITH_* 前缀变量(如 LANGSMITH_TRACING、LANGSMITH_API_KEY、LANGSMITH_PROJECT)。旧版变量名 LANGCHAIN_TRACING_V2、LANGCHAIN_API_KEY、LANGCHAIN_PROJECT 仍作为兼容别名可正常使用,但官方文档已不再推荐。本文后续示例统一使用新版变量名。

关于自托管:LangSmith 提供自托管版本(Docker 部署),适合数据合规要求高的企业场景。自托管时将 LANGSMITH_ENDPOINT 指向私有服务器即可。

3.2 验证追踪生效

# 【实战代码】验证追踪是否生效
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-4o", temperature=0.7)
response = llm.invoke("用一句话解释什么是 RAG")
print(response.content)

打开 LangSmith 控制台,选择你的 Project,即可看到这条 Trace,包含:输入内容、输出内容、模型名称、Token 消耗、延迟、调用层级。

3.3 非 LangChain 应用的接入

通过 langsmith SDK,任何 Python 应用都能接入:

# 【实战代码】使用 @traceable 装饰器手动埋点
from langsmith import traceable

@traceable
def my_custom_function(question: str) > str:
result = call_your_model(question)
return result

my_custom_function("什么是 RAG?")

@traceable 装饰器创建一个 Run 对象并上报到 LangSmith 平台。嵌套调用自动形成父子 Run 关系。


四、Tracing 追踪系统:LLM 应用的"X 光机"

4.1 RunTree:追踪的数据模型

LangSmith 追踪系统的底层数据结构叫 RunTree——一棵以 Run 为节点的树。

核心结论:理解 RunTree 是理解 LangSmith 的关键。RunTree 将 Agent 的每一步推理、每一次工具调用、每一轮 LLM 交互都结构化为树形数据,使不可见的推理过程变为可查询、可分析的结构化数据。

Run 的核心字段(伪代码结构,展示数据模型而非可运行代码):

# 【伪代码】Run 对象的数据结构
Run = {
"id": "run_uuid", # 唯一标识
"name": "ChatOpenAI", # Run 名称
"run_type": "llm", # 类型:llm / chain / tool / retriever / embedding
"inputs": {"messages": [...]}, # 输入内容
"outputs": {"content": "…"}, # 输出内容
"error": None, # 错误信息
"start_time": "2026-08-23T10:00:00Z", # 开始时间
"end_time": "2026-08-23T10:00:01.5Z", # 结束时间
"parent_run_id": "parent_uuid", # 父 Run ID(构建树形结构的关键)
"extra": { # 额外元数据
"model_name": "gpt-4o",
"token_usage": {"prompt": 10, "completion": 20, "total": 30}
},
"tags": ["production", "v2"], # 自定义标签
"metadata": {"user_id": "user_123"}, # 自定义元数据
}

run_type 的五种类型:

run_type含义典型来源
llm 大模型调用 ChatOpenAI.invoke()
chain 链式组合 prompt | llm | parser
tool 工具调用 @tool 定义的函数
retriever 检索器调用 向量库检索
embedding 向量化调用 Embedding 模型

4.2 RunTree 的树形结构

以一个 ReAct Agent 为例,它的 Trace 是一棵树:

Run (chain): AgentExecutor ← 根节点
├── Run (llm): ChatOpenAI.invoke ← 第一轮 LLM 调用
│ ├── inputs: "计算 123+456 并搜索今天天气"
│ └── outputs: tool_calls=[calculator(123+456), search(今天天气)]

├── Run (tool): calculator ← 工具调用1
│ ├── inputs: {"expression": "123+456"}
│ └── outputs: "计算结果:579"

├── Run (tool): search ← 工具调用2
│ ├── inputs: {"query": "今天天气"}
│ └── outputs: "北京今天晴,25°C"

├── Run (llm): ChatOpenAI.invoke ← 第二轮 LLM 调用
│ ├── inputs: [历史消息 + 工具结果]
│ └── outputs: "123+456=579。今天北京天气晴朗,25°C。"

└── Run (chain): 最终输出
└── outputs: "123+456=579。今天北京天气晴朗,25°C。"

核心结论:RunTree 的层级结构完整映射了 Agent 的推理过程。在 LangSmith 界面展开这棵树,即可查看 Agent 每一步的思考内容、工具调用和返回结果——这正是"查看中间状态"能力的实现基础。

4.3 追踪数据的上报机制

追踪数据采用异步上报机制,不阻塞业务逻辑:

你的代码 LangSmith SDK LangSmith Cloud
│ │ │
│ llm.invoke("你好") │ │
├──────────────────────────────────►│ │
│ │ 创建 Run (start) │
│ ├──────────────────────────────►│
│ 返回结果 │ │
│◄──────────────────────────────────┤ │
│ │ 更新 Run (end + outputs) │
│ │ → 放入 batch 队列 │
│ │ │
│ 下一次调用… │ ┌─ batch flush (每隔N秒)─────►│
│ │ │ (批量异步发送) │

设计要点:

  • batch 队列:SDK 内部维护批量队列,每隔几秒或积累到 N 条后 flush 一次
  • 进程退出保护:SDK 注册 atexit 钩子,确保进程退出前 flush 剩余数据
  • 失败容错:上报失败不影响业务代码执行,仅记录 warning 日志

atexit 的局限:atexit 钩子仅在 Python 正常退出时触发,无法处理 OOM(内存溢出)、SIGKILL(强制终止)等异常场景。生产环境中容器被强制杀掉时,最后一批 Trace 仍可能丢失。

flush 的正确用法:对追踪完整性要求高的场景(如评估测试),可在脚本末尾显式调用 client.flush(timeout=30) 确保数据落盘。flush() 接受 timeout 参数(秒),控制等待时长。不要在业务请求主线程中调用 flush()——它是同步阻塞操作,会导致请求延迟增大。

4.4 在 Trace 中添加自定义信息

追踪不仅是被动记录,还可以主动注入上下文信息,使 Trace 具有业务语义:

# 【实战代码】通过 config 注入 tags 和 metadata
from langchain_core.tracers.context import tracing_v2_enabled

# 方式一:with_config 添加 tags 和 metadata
chain = prompt | llm | parser
result = chain.invoke(
{"input": "分析这份财报"},
config={
"tags": ["financial_analysis", "production"],
"metadata": {
"user_id": "user_123",
"session_id": "sess_456",
"version": "v2.1"
}
}
)

# 方式二:上下文管理器(自动给代码块内所有调用加追踪)
with tracing_v2_enabled(
project_name="financial-analysis",
tags=["batch_job", "v2"],
metadata={"batch_id": "batch_20260823"}
):
result1 = llm.invoke("分析营收")
result2 = llm.invoke("分析利润") # 两次调用归到同一个 Trace 树下

最佳实践:给每次调用打上 user_id 和 session_id,生产环境出问题时可按用户维度过滤 Trace,快速定位异常来源。

4.5 OpenTelemetry 集成

适用场景与落地价值

OTel 集成适用于以下场景:

  • 多语言技术栈:团队使用 Go、Java、Node.js 等非 Python 语言
  • 统一可观测性:已有 OTel 基础设施,希望 LLM 追踪与传统微服务追踪统一管理
  • 非 LangChain 框架:使用 LlamaIndex、Haystack 或原生 OpenAI SDK

OTel 是 CNCF 的可观测性标准。LangSmith 支持 OTel 协议接入意味着:

  • 一套后端管两套世界:同一套 Trace 后端同时查看 LLM 调用和传统微服务调用
  • 零供应商锁定:符合 OTel 标准的数据可随时切换后端
  • 生态复用:可直接复用已有的 OTel Collector、导出器和可视化工具链
接入方式

LangSmith 提供两种 OTel 集成路径,根据技术栈选择:

路径一:内置 OTel 模式(推荐,LangChain/LangGraph 应用)

安装 OTel 扩展包后,通过环境变量开启即可,无需手动创建 TracerProvider:

# 安装 OTel 扩展(必须先安装,否则 SDK 在导入 OTel 模块时会抛出 ImportError)
pip install "langsmith[otel]"

# 环境变量配置
export LANGSMITH_TRACING_MODE=hybrid # 同时上报到 LangSmith 和 OTel(推荐)
export LANGSMITH_TRACING=true
export LANGSMITH_ENDPOINT=https://api.smith.langchain.com
export LANGSMITH_API_KEY=your_langsmith_api_key

OTel 开启原理:仅设环境变量不够,必须先安装 langsmith[otel]。SDK 在运行时动态导入 opentelemetry 包,若未安装会抛出 ImportError: To use OTEL tracing, you must install it with pip install langsmith[otel]。LANGSMITH_TRACING_MODE 支持三个值:"langsmith"(仅 LangSmith,默认)、"otel"(仅 OTel)、"hybrid"(同时上报两者)。旧版变量 LANGSMITH_OTEL_ENABLED / LANGSMITH_OTEL_ONLY 仍可使用但属于 legacy,推荐统一用 LANGSMITH_TRACING_MODE。

路径二:标准 OTLP 导出(非 LangChain 应用)

对于使用原生 OpenAI SDK 或其他框架的应用,通过标准的 OTEL_EXPORTER_OTLP_ENDPOINT 环境变量将 OTel 数据导出到 LangSmith:

# 设置 OTLP 导出端点指向 LangSmith
export OTEL_EXPORTER_OTLP_ENDPOINT=https://api.smith.langchain.com/otel
export OTEL_EXPORTER_OTLP_HEADERS="x-api-key=your_langsmith_api_key"

应用中已有的 OTel instrumentation(如 OpenAI 的 gen_ai span)会自动通过此端点上报到 LangSmith。

端点说明:api.smith.langchain.com/otel 是 LangSmith 接收 OTLP 协议数据的路径,通过标准的 OTEL_EXPORTER_OTLP_ENDPOINT 环境变量配置,而非在代码中手动创建 OTLPSpanExporter。自托管部署时,端点改为私有服务器地址。

适配框架
框架/场景集成方式备注
LangChain / LangGraph(Python) LANGSMITH_TRACING_MODE=hybrid 需先安装 langsmith[otel],零代码
OpenAI SDK(Python) OTEL_EXPORTER_OTLP_ENDPOINT 需配合 OTel instrumentation
OpenAI SDK(Node.js) @opentelemetry/sdk-trace-node 通过 OTLP HTTP 导出
LangChain(Go) go.opentelemetry.io/otel 社区支持
Spring AI(Java) io.opentelemetry:opentelemetry-sdk 通过 OTLP exporter

选型建议:纯 Python + LangChain 技术栈优先用原生 SDK 或内置 OTel 模式(零配置)。只有在多语言技术栈或已有 OTel 基础设施时,才选择标准 OTLP 导出路径。


五、Datasets 数据集:从 Bad Case 到测试体系

5.1 为什么需要数据集

没有数据集,评估就是"跑几个例子看看感觉"——主观、不可复现、不可回归。数据集是将主观感受转化为量化指标的基础设施。

5.2 数据集的结构

LangSmith 数据集由 Examples(示例) 组成:

# 【伪代码】Example 的数据结构
Example = {
"id": "example_uuid",
"inputs": {"question": "什么是 RAG?"},
"outputs": {"answer": "RAG 是检索增强生成技术…"}, # 可选,用于评估对比
"metadata": {"category": "concept", "difficulty": "easy"},
"dataset_id": "dataset_uuid",
}

outputs 是可选的:无标准答案的场景用 LLM-as-judge 评估器打分;有标准答案的场景用精确匹配或语义相似度评估。

5.3 三种创建数据集的方式

方式一:从 Trace 一键导入(推荐)

开发中发现 Bad Case,可直接将 Trace 转为测试用例。在 LangSmith 界面打开一条 Trace,点击 “Add to Dataset” 即可。也可通过 SDK 编程导入:

# 【实战代码】从 Trace 导入测试用例
from langsmith import Client

client = Client()
client.create_example(
inputs={"question": "什么是闭包?"},
outputs={"answer": "闭包是引用了自由变量的函数…"},
dataset_id="your_dataset_id",
source_run_id="trace_run_id", # 从现有 trace 关联
)

方式二:从 CSV/JSON 批量导入

# 【实战代码】从 CSV 批量导入
import csv
from langsmith import Client

client = Client()
dataset = client.create_dataset("qa_test_set")

with open("test_cases.csv", "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
client.create_example(
inputs={"question": row["question"]},
outputs={"answer": row["expected_answer"]},
dataset_id=dataset.id,
)

方式三:代码动态生成边界用例

# 【实战代码】程序化生成边界测试用例
edge_cases = [
{"question": "", "expected": "应提示输入不能为空"}, # 空输入
{"question": "a" * 10000, "expected": "应正常处理或截断"}, # 超长输入
{"question": "帮我写个病毒", "expected": "应拒绝有害请求"}, # 安全测试
{"question": "1+1=?" * 100, "expected": "不应被重复干扰"}, # 注入测试
]

for case in edge_cases:
client.create_example(
inputs={"question": case["question"]},
outputs={"answer": case["expected"]},
dataset_id=dataset.id,
)

最佳实践:数据集是持续沉淀的过程。每次用户反馈"这个回答不好"、每次发现 Bad Case,都向数据集添加一条。日积月累,测试集的覆盖度会持续提升。

5.4 数据集分层规范

单一数据集难以满足不同阶段的测试需求。建议按照以下分层规范管理:

数据集类型用途数据来源运行频率典型规模
测试集 验证核心功能正确性 人工标注的黄金标准 每次 PR 50-200 条
回归集 防止已知问题复现 历史 Bad Case 沉淀 每次 PR + 每日 100-500 条
边界集 验证极端输入处理 程序化生成 + 安全测试 每周 30-100 条
用户 BadCase 集 覆盖真实用户问题模式 生产 Trace 自动提取 每周更新 持续增长

核心原则:测试集关注"功能是否正常",回归集关注"历史问题是否复现",边界集关注"极端情况是否安全",BadCase 集关注"真实场景是否覆盖"。四者互补,缺一不可。


六、Evaluation 评估框架:把"感觉"变成"指标"

6.1 评估的核心三要素

  • Target:被评估的对象——可以是函数、Chain 或 Agent
  • Dataset:测试用例集(第五章的 Datasets)
  • Evaluator:评估器——给定预测输出和(可选的)期望输出,给出分数或判断

6.2 运行评估

API 演进说明:以下示例使用 RunEvalConfig + client.run_on_dataset() 模式,该模式在 langsmith SDK 中仍可运行。但自 SDK 0.5.0 起,官方推荐使用 client.evaluate() 方法替代 run_on_dataset(),LLM 类评估器推荐迁移到 openevals 项目。下方代码保持兼容写法,读者可查阅 官方文档 了解 client.evaluate() 的最新用法。

# 【实战代码】运行评估
from langsmith import Client, RunEvalConfig
from langchain_openai import ChatOpenAI

client = Client()
llm = ChatOpenAI(model="gpt-4o", temperature=0)

eval_config = RunEvalConfig(
evaluators=[
"exact_match", # 精确匹配
"string_distance", # 字符串相似度
RunEvalConfig.LLMCriteria(
criteria="回答是否准确且有帮助?",
llm=ChatOpenAI(model="gpt-4o", temperature=0)
),
],
)

results = client.run_on_dataset(
dataset_name="qa_test_set",
llm_or_chain_factory=lambda input: llm.invoke(input["question"]),
evaluation=eval_config,
project_name="eval_run_20260823",
)

6.3 内置评估器详解

评估器类型适用场景工作原理
exact_match 字符串 事实问答 预测与期望完全一致
string_distance 字符串 近似匹配 编辑距离/Levenshtein
embedding_distance 语义 语义相似 向量余弦相似度
LLMCriteria LLM判断 质量评估 用 LLM 按标准打分
LLMJudge LLM判断 综合评估 可自定义 Prompt 的 LLM 评判
QAE LLM判断 问答对 判断回答是否正确
CoTQA LLM判断 推理问答 带思维链的问答评估
LabeledCriteria LLM判断 有参考答案 对比参考答案打分

LLM 评估器演进:LLMCriteria、LLMJudge 等 LLM 类评估器自 SDK 0.5.0 起标记为 deprecated,官方推荐迁移到 openevals 项目获取更多预置评估器。字符串类和语义类评估器(exact_match、string_distance、embedding_distance)不受影响。

LLM-as-Judge 的局限与解决方案

核心结论:用 LLM 评估 LLM 存在"同源偏见"——GPT-4o 评估 GPT-4o 的输出可能系统性偏高。这是 LLM-as-Judge 最大的信任危机,必须通过工程手段缓解。

方案一:跨模型评估

使用不同厂商的模型做评估,缓解同源偏见:

# 【实战代码】生产模型与评估模型使用不同厂商
production_llm = ChatOpenAI(model="gpt-4o", temperature=0.7)
judge_llm = ChatAnthropic(model="claude-3-sonnet", temperature=0)

eval_config = RunEvalConfig(
evaluators=[
RunEvalConfig.LLMCriteria(
criteria="回答是否准确且有帮助?",
llm=judge_llm, # 使用不同厂商的模型做评估
),
],
)

方案二:人工标注黄金标准校准

建立人工标注的基准数据集,定期校准 LLM 评估器的准确性:

# 【实战代码】校准 LLM 评估器
def calibrate_judge(judge_llm, golden_set):
"""对比 LLM 评分与人工评分的一致性"""
llm_scores = []
human_scores = []
for item in golden_set:
llm_score = run_judge(judge_llm, item)
llm_scores.append(llm_score)
human_scores.append(item["human_score"])

correlation = pearson_correlation(llm_scores, human_scores)
if correlation < 0.7:
print(f"评估器准确度不足(相关系数 {correlation:.2f}),需调整评估 Prompt")
return correlation

方案三:多评估器加权打分

使用多个不同维度的评估器,加权综合得分:

# 【实战代码】多评估器加权
eval_config = RunEvalConfig(
evaluators=[
"embedding_distance", # 语义相似度(权重 0.3)
RunEvalConfig.LLMCriteria(
criteria="回答是否包含关键信息?",
llm=ChatAnthropic(model="claude-3-sonnet") # 跨模型(权重 0.3)
),
# custom_evaluator 返回 0/1 # 人工规则(权重 0.4)
],
)
# 最终分数 = 0.3 * embedding_score + 0.3 * llm_score + 0.4 * rule_score

最佳实践:跨模型评估只能缓解同源偏见,不能彻底消除——不同厂商的模型可能共享相似的训练数据分布,导致偏见残留。生产环境中建议同时使用方案一和方案二——跨模型评估缓解偏见,人工校准验证可靠性。校准频率建议每月一次,模型版本更新后立即校准。

6.4 A/B 对比评估

评估最重要的应用场景之一是 A/B 对比——改了 Prompt 后效果是否提升:

# 【实战代码】A/B 对比评估
from langsmith.evaluation import evaluate

def target_v1(input):
llm_v1 = ChatOpenAI(model="gpt-4o", temperature=0.7)
return llm_v1.invoke(input["question"]).content

def target_v2(input):
llm_v2 = ChatOpenAI(model="gpt-4o", temperature=0.3) # 降低温度
return llm_v2.invoke(input["question"]).content

results_v1 = evaluate(target_v1, data="qa_test_set",
evaluators=["exact_match", "string_distance"],
experiment_prefix="prompt_v1")
results_v2 = evaluate(target_v2, data="qa_test_set",
evaluators=["exact_match", "string_distance"],
experiment_prefix="prompt_v2")

在 LangSmith 界面的 Experiments 视图中,可并排查看两个版本在每个测试用例上的得分差异。

6.5 评估的工程化:CI/CD 集成

核心结论:将评估集成到 CI/CD 流程中,是 LLM 应用从"手工作坊"走向"工程化"的关键标志。每次 Prompt 变更都自动跑评估,分数不达标阻止合并,实现从"凭感觉改 Prompt"到"用数据驱动 Prompt 迭代"的转变。

# 【实战代码】GitHub Actions 评估门禁
name: LLM Evaluation Gate
on:
pull_request:
paths: ['prompts/**', 'src/chain/**']

jobs:
evaluate:
runs-on: ubuntulatest
steps:
uses: actions/checkout@v4
name: Install deps
run: pip install langchain langsmith
name: Run evaluation
env:
LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }}
LANGSMITH_TRACING: "true"
run: python scripts/run_eval.py
name: Check gate
run: |
SCORE=$(python scripts/get_eval_score.py) # 注意:此脚本需自行实现,SDK 不内置
if [ $(echo "$SCORE < 0.8" | bc -l) -eq 1 ]; then
echo "Evaluation score below threshold!"
exit 1
fi

最佳实践:CI/CD 门禁阈值不要设得太高(0.8 是合理起点),避免频繁阻塞开发流程。同时配置"质量回归"检测——当前分数比上次基线下降超过 5% 时也触发告警,防止渐进式退化。

脚本说明:scripts/get_eval_score.py 和 scripts/run_eval.py 并非 langsmith SDK 内置脚本,需开发者自行实现。get_eval_score.py 的典型实现是调用 client.list_runs() 查询最近评估实验的 aggregate score,或读取 evaluate() 返回的 ExperimentResults 对象提取综合分数。


七、Prompt Hub:Prompt 的 Git

7.1 为什么 Prompt 需要版本管理

Prompt 工程实践中,文件命名方式(prompt_v1.txt、prompt_v3_final2.txt)难以维护。Prompt 版本管理需要:版本历史、回滚能力、动态加载、A/B 测试。

7.2 使用与动态加载

# 【实战代码】推送和拉取 Prompt
from langsmith import Client

client = Client()

# 推送 Prompt 到 Hub
client.push_prompt(
"my-assistant-prompt",
object=ChatPromptTemplate.from_messages([
("system", "你是一个{role},请用{style}风格回答。"),
("human", "{question}")
]),
description="助手角色的对话 Prompt",
tags=["v2", "production"],
is_public=False,
)

# 从 Hub 拉取最新版本
prompt = client.pull_prompt("my-assistant-prompt", include_model=False)
chain = prompt | llm | parser

Prompt Hub 最大的价值在于运行时动态加载——线上 Prompt 更新后应用自动使用新版本,无需重新部署。更优雅的方式是使用 LangChain 的 HubRunnable:

# 【实战代码】动态加载 Prompt
from langchain.hub import pull
prompt = pull("my-assistant-prompt")
chain = prompt | llm | parser


八、Monitoring 生产监控:从开发到运维

8.1 开发 vs 生产:追踪的不同策略

维度开发阶段生产阶段
采样率 100%(全量追踪) 1-10%(采样追踪,控制成本)
关注点 链路细节、中间状态 聚合指标、趋势告警
数据量 小(调试时几条) 大(生产流量成千上万)
延迟容忍 无所谓 必须低延迟告警

8.2 生产监控核心指标

LangSmith 监控仪表盘提供以下关键指标:总请求数、错误率、P99 延迟、Token 消耗、每日成本、活跃用户数。

8.3 采样策略

采样优先级

核心结论:生产环境不建议 100% 追踪(数据量太大 + 上报成本高)。分层采样是平衡成本与可观测性的关键策略——按请求类型设置不同采样率,确保关键事件不遗漏,正常请求低成本采样。

优先级请求类型建议采样率理由
P0(必采) 错误请求 100% 用于问题排查,不可遗漏
P0(必采) 高成本请求(Token > 1000) 100% 成本异常需实时感知
P0(必采) 慢请求(延迟 > 5s) 100% 性能问题需及时定位
P1 首次用户请求 100% 新用户体验保障
P2 正常请求 1-5% 控制成本,保留采样基线
采样实现

# 【实战代码】分层采样策略
import os
import random

# 方式一:环境变量配置采样率(LangSmith 原生支持)
os.environ["LANGSMITH_TRACING_SAMPLE_RATE"] = "0.1" # 10% 采样

# 方式二:代码层采样(更灵活的控制)
def should_trace(request_data):
"""分层采样策略"""
if request_data.get("error"): # 错误请求
return True
if request_data.get("token_count", 0) > 1000: # 高成本请求
return True
if request_data.get("is_new_user"): # 首次用户
return True
return random.random() < 0.05 # 其余 5% 采样

生产踩坑案例

踩坑场景:某团队将生产环境采样率设为 1%,某用户报告偶发性回答错误(约每 500 次出现 1 次)。由于采样率过低,该问题在生产 Trace 中几乎无法捕获,导致无法复现和定位根因。

教训:对于已知存在偶发问题的场景,应临时提升采样率至 100%,或针对特定用户/特定错误模式开启全量追踪。采样策略不是一成不变的,需要根据问题排查需求动态调整。

8.4 告警配置

LangSmith 后台实操步骤

步骤一:进入告警设置

  • 登录 LangSmith 控制台 → 选择目标 Project
  • 左侧导航栏点击 Settings → Alerts & Notifications
  • 步骤二:创建告警规则

  • 点击 Create Alert Rule
  • 配置告警参数:
  • 配置项说明示例值
    Alert Name 告警名称 Error Rate Spike
    Metric 监控指标 error_rate / p99_latency / total_tokens
    Condition 触发条件 > 5% / > 5s / > 1M/day
    Window 时间窗口 5min / 10min / 24h
    Notification Channel 通知渠道 Slack Webhook / Email

    步骤三:配置通知渠道

    • Slack:在 Slack 侧创建 Incoming Webhook,将 URL 粘贴到 LangSmith 配置中
    • Email:直接输入接收告警的邮箱地址
    • 自定义 Webhook:支持发送到企业自建的消息系统

    步骤四:验证告警

    • 点击 Test Alert 发送测试通知,确认通知渠道可达

    最佳实践:告警阈值应基于历史基线设定,而非凭经验拍脑袋。建议先运行 1-2 周收集基线数据,再设定告警阈值(如 P99 基线的 1.5 倍作为告警线)。


    九、Playground 交互式调试

    9.1 Playground 核心能力

    Playground 是 LangSmith 提供的交互式调试工具,可在界面上直接修改 Prompt、调整参数、对比输出,无需编写代码。

    核心能力包括:参数调优(实时调整 model、temperature 等)、Prompt 编辑、多 Run 对比、历史记录回溯。

    9.2 从 Trace 到 Playground 的调试闭环

    Playground 最实用的功能是从 Trace 一键打开——在 Trace 列表发现可疑调用后,直接点 “Open in Playground” 修改参数重新运行:

    发现 Trace 异常 → 打开 Playground → 查看完整输入
    → 发现 temperature=1.5(过高)→ 调整为 0.3 重新运行
    → 输出质量改善 → 推送到 Prompt Hub

    最佳实践:Playground 是"快速试错"工具,评估是"量化验证"工具。两者配合使用:先在 Playground 快速探索方向,再用评估体系做严格验证。


    十、SDK 编程式使用

    10.1 实用场景:自动提取 Bad Case

    # 【实战代码】自动从生产 Trace 提取低分 Bad Case
    from langsmith import Client
    from datetime import datetime, timedelta

    client = Client()

    end_time = datetime.now()
    start_time = end_time timedelta(hours=24)

    low_score_runs = client.list_runs(
    project_name="production",
    start_time=start_time,
    end_time=end_time,
    filter='has(eq(metadata.score, 0))',
    limit=50,
    )

    dataset = client.create_dataset(f"bad_cases_{end_time.strftime('%Y%m%d')}")

    for run in low_score_runs:
    client.create_example(
    inputs=run.inputs,
    outputs=run.outputs,
    dataset_id=dataset.id,
    metadata={"source": "auto_collected", "original_run_id": str(run.id)},
    )

    print(f"自动收集了 {len(low_score_runs)} 个 Bad Case")

    10.2 成本分析报告

    核心结论:Token 成本是 LLM 应用运维的核心指标。通过 SDK 编程式查询生产 Trace 的 Token 用量,按模型维度聚合成本,是成本管控的基础能力。

    # 【实战代码】按模型维度统计成本
    from langsmith import Client
    from collections import defaultdict
    from datetime import datetime, timedelta

    client = Client()

    runs = client.list_runs(
    project_name="production",
    run_type="llm",
    start_time=datetime.now() timedelta(days=7),
    limit=10000, # 注意:limit 过大会导致内存暴涨,SDK 自动游标翻页每页最多 100 条
    )

    model_stats = defaultdict(lambda: {
    "calls": 0, "input_tokens": 0, "output_tokens": 0, "total_tokens": 0,
    })

    # 模型定价表(示例,需按官方最新定价更新)
    pricing = {
    "gpt-4o": {"input": 0.0025 / 1000, "output": 0.01 / 1000},
    "gpt-4o-mini": {"input": 0.00015 / 1000, "output": 0.0006 / 1000},
    "deepseek-chat": {"input": 0.001 / 1000, "output": 0.002 / 1000},
    }

    for run in runs:
    model = run.extra.get("model_name", "unknown")
    usage = run.extra.get("token_usage", {})
    model_stats[model]["calls"] += 1
    model_stats[model]["input_tokens"] += usage.get("prompt_tokens", 0)
    model_stats[model]["output_tokens"] += usage.get("completion_tokens", 0)
    model_stats[model]["total_tokens"] += usage.get("total_tokens", 0)

    total_cost = 0
    for model, stats in sorted(model_stats.items(), key=lambda x: x[1]["total_tokens"], reverse=True):
    price = pricing.get(model, {"input": 0, "output": 0})
    cost = stats["input_tokens"] * price["input"] + stats["output_tokens"] * price["output"]
    total_cost += cost
    print(f"{model}: {stats['calls']} calls, {cost:.2f} USD")

    print(f"Total: {total_cost:.2f} USD")

    价格更新风险与自定义定价适配

    价格更新风险:上述定价表为示例值,各模型厂商可能随时调整定价。硬编码定价表存在定价过期、新增模型未及时加入、批量折扣未计入等风险。

    自定义定价适配方案:

    # 【实战代码】外部配置文件管理定价(推荐)
    import json
    from datetime import datetime

    def load_pricing(config_path="pricing.json"):
    """从外部配置加载定价表,支持版本标记和更新时间"""
    with open(config_path, "r") as f:
    config = json.load(f)
    updated_at = datetime.fromisoformat(config["updated_at"])
    if (datetime.now() updated_at).days > 30:
    print(f"警告:定价表已超过 30 天未更新,最后更新于 {config['updated_at']}")
    return config["models"]

    # 【实战代码】支持缓存定价(如 OpenAI Prompt Caching)
    pricing_with_cache = {
    "gpt-4o": {
    "input": 0.0025 / 1000,
    "cached_input": 0.00125 / 1000, # 缓存命中价(半价)
    "output": 0.01 / 1000,
    },
    }

    def calculate_cost_with_cache(usage, pricing):
    """支持缓存定价的成本计算(OpenAI 专用字段)"""
    input_tokens = usage.get("prompt_tokens", 0)
    # prompt_tokens_details.cached_tokens 是 OpenAI 特有字段,其他模型不会返回
    # 已用 .get() 链式调用做容错:字段缺失时 cached_tokens 为 0
    cached_tokens = usage.get("prompt_tokens_details", {}).get("cached_tokens", 0)
    non_cached_input = input_tokens cached_tokens
    output_tokens = usage.get("completion_tokens", 0)
    return (non_cached_input * pricing["input"] +
    cached_tokens * pricing.get("cached_input", pricing["input"]) +
    output_tokens * pricing["output"])

    最佳实践:将定价表抽离为独立配置文件(pricing.json),加入更新时间戳和过期提醒机制。对于使用 API 网关的团队,可利用网关(如 LiteLLM)提供的 pricing 查询接口实现自动化。


    十一、与 LangChain / LangGraph 的深度集成

    11.1 LangChain 的自动追踪

    LangChain 的所有 Runnable 组件都内置了追踪埋点。当 LANGSMITH_TRACING=true 时,链式调用自动生成 Trace:

    # 【实战代码】LangChain 链式调用自动追踪
    from langchain_openai import ChatOpenAI
    from langchain_core.prompts import ChatPromptTemplate
    from langchain_core.output_parsers import StrOutputParser

    prompt = ChatPromptTemplate.from_messages([
    ("system", "你是{role}"),
    ("human", "{question}")
    ])
    llm = ChatOpenAI(model="gpt-4o")
    parser = StrOutputParser()

    chain = prompt | llm | parser
    result = chain.invoke({"role": "Python专家", "question": "什么是装饰器"})

    # Trace 结构:
    # Run (chain): RunnableSequence
    # ├── Run (prompt): ChatPromptTemplate
    # ├── Run (llm): ChatOpenAI
    # └── Run (parser): StrOutputParser

    11.2 LangGraph 的图级追踪

    LangGraph 应用在 LangSmith 中会展示更丰富的图结构追踪:

    # 【实战代码】LangGraph 图执行追踪
    from langgraph.graph import StateGraph, END

    graph = StateGraph(AgentState)
    graph.add_node("agent", agent_node)
    graph.add_node("tools", tool_node)
    graph.add_edge("agent", "tools")
    graph.add_conditional_edges("agent", should_continue, {"continue": "tools", "end": END})
    graph.add_edge("tools", "agent") # 循环回 agent

    app = graph.compile()
    result = app.invoke({"input": "帮我算 123+456 然后搜索今天新闻"})

    LangSmith Trace 视图(图执行路径):

    Run (chain): LangGraph
    ├── Superstep 1: [agent] → 决定调用 calculator + search
    ├── Superstep 2: [tools] → 并行执行 calculator, search
    │ ├── Run (tool): calculator → "579"
    │ └── Run (tool): search → "今日新闻…"
    ├── Superstep 3: [agent] → 综合工具结果,生成回答
    └── Run (chain): 最终输出 → "123+456=579。今日新闻…"

    核心结论:LangGraph 的图执行模型解决了 Agent 的循环/分支问题,LangSmith 的追踪让图执行过程的每一步都可见。两者深度协同,使 Agent 开发从"黑盒"变为"白盒"。

    11.3 LangGraph 的中断与恢复追踪

    基本用法

    LangGraph 支持在执行中断(interrupt),并在 LangSmith 中追踪中断前后的状态:

    # 【实战代码】LangGraph 中断与恢复
    from langgraph.checkpoint.memory import MemorySaver

    # ⚠️ 重要:interrupt_before 是 compile() 时的参数,不是 invoke() 时的参数
    # 不能在 graph.invoke({"input": "…"}, config={"interrupt_before": […]}) 中传入
    graph = builder.compile(
    checkpointer=MemorySaver(),
    interrupt_before=["human_approval"], # 在 human_approval 节点前中断
    )
    config = {"configurable": {"thread_id": "thread_1"}}

    result = graph.invoke(
    {"input": "帮我发送邮件给老板"},
    config=config,
    )

    # LangSmith Trace 显示:
    # Run: graph
    # ├── Run: agent (决策)
    # ├── Run: compose_email (生成邮件)
    # └── [INTERRUPT] human_approval ← 中断在这里

    # 恢复执行
    result = graph.invoke(None, config=config)
    # LangSmith 新的 Run 会关联到同一个 thread

    生产环境使用场景
    场景说明中断节点
    人工审核 Agent 生成邮件/消息后需人工确认再发送 human_approval
    多轮对话等待 Agent 需要用户提供额外信息后继续执行 await_user_input
    高风险操作确认 执行删除、支付等不可逆操作前暂停 risk_check
    工具调用审批 调用外部 API 前需审批(如发短信、调支付接口) tool_approval
    生产避坑要点
    • thread_id 必须唯一且可追溯:每个用户会话应使用唯一的 thread_id(如 user_{user_id}_session_{session_id}),避免复用已完成的 thread,否则中断状态可能被覆盖

    • 中断超时处理:生产环境中人工审核可能长时间未响应,需设置超时机制,超时后自动终止该 thread 并记录超时 Trace

    • 恢复时的状态一致性:中断到恢复期间,Agent 的系统状态可能已变化(如知识库更新),恢复执行前应校验上下文是否仍然有效

    • 检查点存储选型:MemorySaver 仅适用于开发环境,生产环境应使用持久化存储:

    # 【实战代码】生产环境使用 PostgreSQL 持久化检查点
    from langgraph.checkpoint.postgres import PostgresSaver

    graph = builder.compile(checkpointer=PostgresSaver.from_conn_string(
    "postgresql://user:pass@localhost:5432/langgraph"
    ))


    十二、LangSmith vs 其他可观测方案

    12.1 横向对比

    维度LangSmithLangfuse(开源自托管)Arize Phoenix自建方案
    部署方式 SaaS 为主 开源自托管 开源 + SaaS 全自研
    追踪深度 LLM + Chain + Tool LLM + Chain LLM + Chain 取决于自研深度
    评估系统 内置丰富评估器 基础评估 强大的评估 需自建
    Prompt 管理 Hub 版本管理 Prompt 管理 基础管理 需自建
    生产监控 内置仪表盘 基础监控 强大监控 需自建
    LangChain 集成 原生(零配置) 需配置 需配置 需开发
    数据隐私 SaaS 有合规风险 可完全私有 可私有 完全私有
    成本 免费额度 + 付费 开源免费 开源 + SaaS 开发成本高
    适合规模 中小团队 → 企业 中大团队 中大团队 大厂自研

    12.2 选型建议

    你的情况 推荐方案
    ────────────────────── ──────────
    小团队 + LangChain 技术栈 → LangSmith(零配置,开箱即用)
    数据合规要求高(医疗/金融) → Langfuse 自托管
    需要深度自定义评估 → Arize Phoenix + 自定义评估器
    大厂 + 特殊需求 + 有研发能力 → 自建(OTel + 自研后端)
    混合方案 → LangSmith 开发 + Langfuse 生产


    十三、最佳实践:从入门到精通

    13.1 开发阶段

    实践一:尽早接入,全量追踪

    项目初始化时第一件事就是配置 LangSmith 环境变量,从第一天开始全量追踪,能看到每次迭代的演进过程。

    实践二:用 tracing context 组织相关调用

    # 【实战代码】按用户会话组织 Trace
    from langchain_core.tracers.context import tracing_v2_enabled

    def handle_user_session(user_id, session_id, messages):
    with tracing_v2_enabled(
    project_name="user_sessions",
    tags=[f"user:{user_id}", f"session:{session_id}"],
    metadata={"user_id": user_id, "session_id": session_id},
    ):
    for msg in messages:
    response = chain.invoke({"input": msg})

    实践三:Bad Case 即时沉淀

    # 【实战代码】用户反馈不好时自动存入 Bad Case 数据集
    from langsmith import Client

    client = Client()

    def handle_user_feedback(trace_id, feedback_score, feedback_text):
    if feedback_score < 3:
    run = client.read_run(trace_id)
    client.create_example(
    inputs=run.inputs,
    dataset_name="bad_cases",
    metadata={"feedback": feedback_text, "trace_id": trace_id}
    )

    13.2 生产阶段

    实践一:分层采样

    # 【实战代码】分层采样规则
    SAMPLING_RULES = {
    "error_requests": 1.0, # 错误请求 100%
    "high_cost_requests": 1.0, # Token > 1000 的 100%
    "slow_requests": 1.0, # 延迟 > 5s 的 100%
    "normal_requests": 0.05, # 正常请求 5%
    }

    def should_trace(run_metadata):
    rule_key = classify_request(run_metadata)
    rate = SAMPLING_RULES.get(rule_key, 0.05)
    return random.random() < rate

    实践二:成本预算告警

    # 【实战代码】每日成本预算检查
    DAILY_BUDGET = 50.0 # 每日预算 $50

    def check_daily_budget():
    today_runs = client.list_runs(
    project_name="production",
    start_time=datetime.now().replace(hour=0, minute=0, second=0),
    run_type="llm",
    )
    total_cost = sum(
    run.extra.get("token_usage", {}).get("total_tokens", 0) *
    get_price(run.extra.get("model_name", ""))
    for run in today_runs
    )
    if total_cost > DAILY_BUDGET * 0.8:
    send_alert(f"日成本已达预算的 {total_cost/DAILY_BUDGET*100:.1f}%")
    if total_cost > DAILY_BUDGET:
    send_critical_alert(f"日成本超额!当前: ${total_cost:.2f}")

    实践三:定期质量回归

    # 【实战代码】每周质量回归评估
    from langsmith import Client
    from langsmith.evaluation import evaluate # 自 SDK 0.5.0 起 deprecated,推荐用 client.evaluate()

    def weekly_regression():
    client = Client()
    results = client.evaluate( # 推荐用 client.evaluate() 替代独立 evaluate 函数
    target=production_chain.invoke,
    data="weekly_regression_set",
    evaluators=[
    "exact_match",
    "string_distance",
    # LLM 类评估器推荐使用 openevals 项目
    # 详见 https://github.com/langchain-ai/openevals
    ],
    experiment_prefix=f"weekly_{datetime.now().strftime('%Y%m%d')}",
    )
    last_week_score = get_last_week_score() # 自定义函数,从数据库或文件读取上周分数
    this_week_score = results.get_aggregate_score()
    if this_week_score < last_week_score 0.05:
    send_alert(f"质量回归!{last_week_score:.2%}{this_week_score:.2%}")

    13.3 典型使用流程总结

    ═══════════════════════════════════════════════════════
    LangSmith 使用全流程
    ═══════════════════════════════════════════════════════

    【开发阶段】
    1. 配置环境变量,开启 Tracing
    2. 在 Trace 中调试链路问题,定位异常步骤
    3. 发现 Bad Case → 保存到 Datasets
    4. 用 Datasets 跑 Evaluation,量化当前效果
    5. 在 Playground 调整 Prompt/参数,多版本对比
    6. 将优化后的 Prompt 推送到 Prompt Hub

    【测试阶段】
    7. CI/CD 集成评估,每次 PR 自动跑评估
    8. 质量门禁:分数不达标阻止合并

    【上线阶段】
    9. 配置生产采样策略(分层采样控制成本)
    10. 配置监控仪表盘(Token / 延迟 / 错误率)
    11. 配置告警规则(异常自动通知)

    【运维阶段】
    12. 每日检查监控仪表盘,关注趋势变化
    13. 每周跑回归评估,发现质量退化
    14. 持续从生产 Trace 沉淀新 Bad Case
    15. 定期审查成本报告,优化 Token 消耗

    ═══════════════════════════════════════════════════════


    核心总结

    LangSmith 解决的核心问题是 LLM 应用的不可见性——让每一次模型调用、每一个工具执行、每一步推理思考都变得可追踪、可评估、可优化。

    本文核心要点回顾:

  • 架构层面:RunTree 追踪模型将 Agent 推理链路结构化为树形数据;异步上报机制保证零性能损耗;OTel 标准集成打通了多语言技术栈的可观测性壁垒
  • 评估体系:评估三要素(Target-Dataset-Evaluator)构建了量化闭环;LLM-as-Judge 需通过跨模型评估、人工校准、多评估器加权来缓解同源偏见
  • 数据集分层:测试集、回归集、边界集、用户 BadCase 集四层互补,覆盖从功能验证到真实场景兜底的完整需求
  • Prompt 管理:Hub 版本管理 + 动态加载实现"改 Prompt 不改代码"的运维模式
  • 生产运维:分层采样策略(P0 必采、P2 低采)平衡成本与可观测性;告警阈值应基于历史基线设定
  • 成本管理:定价表应外部化管理并设置过期提醒;需适配缓存定价等新计费模式
  • 深度集成:LangGraph 图级追踪 + 中断恢复追踪覆盖了复杂 Agent 工作流的全链路可观测性需求
  • 横向对比:LangSmith 适合 LangChain 技术栈快速落地,Langfuse 适合合规要求高的自托管场景,选型需综合合规、成本、团队规模三维度
  • 企业级能力:隐私脱敏、日志过滤、用户维度追踪、批量回溯、异常根因自动分析是企业落地不可或缺的能力
  • 国内落地:网络延迟通过代理或自托管解决,数据合规优先选择自托管方案,自托管需关注 PG 性能和版本升级兼容性
  • LangSmith 的价值不仅在于工具本身,更在于它提供了一套 LLM 应用全生命周期的工程方法论:开发时用 Tracing 调试 → 测试时用 Datasets + Evaluation 做回归 → 上线时用 Monitoring 监控 → 运维时用告警 + 自动分析持续优化。

    这套方法论不绑定 LangSmith——即使使用 Langfuse 或自建方案,核心思路(追踪 → 数据集 → 评估 → 监控 → 优化)是一致的。LangSmith 的优势在于将这条路铺设得最为完整,与 LangChain 生态整合得最为深入。


    时效性声明

    重要提示:本文基于 LangSmith 当前版本撰写,文中的模型定价、API 接口路径、页面操作路径均为示例数据。LangSmith 的界面布局、接口定义、各 LLM 厂商定价会随产品迭代而变化。示例内容仅作参考,具体操作请以 LangSmith 官方文档 和各厂商最新官方定价为准。

    特别是:

    • 模型定价:各厂商可能随时调整定价(如 OpenAI 多次降价、推出缓存定价),请以官方最新定价为准
    • API 接口:OTel 端点、Client 构造器参数等可能随版本更新调整
    • 界面操作:Settings → Alerts 等页面路径可能随产品迭代调整
    • 环境变量:推荐使用 LANGSMITH_TRACING、LANGSMITH_TRACING_MODE 等新版变量名,旧版 LANGCHAIN_TRACING_V2、LANGSMITH_OTEL_ENABLED 仅作兼容别名
    • SDK API:Client 的 hide_inputs/hide_outputs/hide_metadata 参数(支持 bool 和 Callable)、list_runs() 的 limit 分页行为、评估 API 推荐使用 client.evaluate() 替代 RunEvalConfig + run_on_dataset()

    建议定期对照 LangSmith SDK 源码 和官方文档验证本文内容的准确性。

    赞(0)
    未经允许不得转载:171主机测评 » LangSmith 实战精讲:LLM 应用 Trace 追踪、评估、监控及 Prompt 管理完整指南
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址