LangSmith 可观测性实战:给 AI 装上"监控摄像头"

LangSmith 可观测性实战:给 AI 装上”监控摄像头”

系列文章第二篇,深入理解 LangSmith 的可观测性原理,让你的 Agent 调试不再”盲人摸象”


1. 引言 - 为什么需要可观测性?

在上一篇文章《从零理解 LangChain》中,我们构建了一个天气查询 Agent。它能理解用户意图、调用工具、保持对话记忆——一切看起来都很完美。

但当你真正开始使用时,会遇到这些问题:

1
2
3
4
5
6
用户: "帮我查一下上海今天天气"
Agent: (沉默...)...
(30秒后...)
Agent: "抱歉,我暂时无法回答"

你: 😱 - "到底哪里出错了??"

没有可观测性时,Agent 就像一个黑盒子

1
2
3
4
5
6
7
8
9
10
11
12
13
┌─────────────────────────────────────┐
│ Agent 黑盒子 │
├─────────────────────────────────────┤
│ │
│ 输入 ──────────────────► 输出 │
│ │
│ ❓ 中间发生了什么? │
│ ❓ 哪个工具被调用了? │
│ ❓ 为什么花了这么长时间? │
│ ❓ LLM 收到了什么 Prompt? │
│ ❓ 工具返回了什么结果? │
│ │
└─────────────────────────────────────┘

这就是 LangSmith 要解决的问题。

你可以把 LangSmith 想象成:

给 AI Agent 装上的”监控摄像头”——记录每一个决策、每一次调用、每一秒耗时

2. LangSmith 是什么?

核心概念:AI 应用的”监控录像”

LangSmith 是 LangChain 官方推出的可观测性平台,它让你能够:

能力 说明
完整追踪 记录 Agent 执行的每一步
性能监控 统计 Token 使用、API 调用延迟
可视化调试 图形化展示执行流程
会话回放 重新运行历史对话,验证修改效果
异常诊断 捕获并分析错误发生的位置和原因

一个形象的类比:

1
2
3
4
5
6
7
8
9
10
11
12
13
传统调试 vs LangSmith

┌─────────────────────┐ ┌─────────────────────────────┐
│ 传统调试方式 │ │ 使用 LangSmith │
├─────────────────────┤ ├─────────────────────────────┤
│ │ │ │
│ print("调试信息") │ │ 📸 自动录制完整执行过程 │
│ print("工具调用") │ │ 📊 Token/延迟自动统计 │
│ print("结果...") │ │ 🔍 点击查看任意步骤详情 │
│ print("...") │ │ 🎬 一键回放历史会话 │
│ │ │ │
│ 😰 代码到处是日志 │ │ ✨ 零侵入,自动追踪 │
└─────────────────────┘ └─────────────────────────────┘

LangSmith 的工作原理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
┌─────────────────────────────────────────────────────────────────┐
│ LangSmith 追踪原理 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 你的代码 │
│ ┌──────────────────────────────────────────────┐ │
│ │ agent.invoke({"messages": "北京天气怎么样?"}) │ │
│ └──────────────────────┬───────────────────────┘ │
│ │ │
│ ▼ │
│ LangChain 自动注入追踪层 │
│ ┌──────────────────────────────────────────────┐ │
│ │ 每个步骤开始 → 记录时间戳、输入参数 │ │
│ │ ↓ │ │
│ │ 执行 LLM 调用 → 记录 Prompt、响应、Token │ │
│ │ ↓ │ │
│ │ 执行工具调用 → 记录工具名、参数、返回值 │ │
│ │ ↓ │ │
│ │ 每个步骤结束 → 记录输出、耗时 │ │
│ └──────────────────────┬───────────────────────┘ │
│ │ │
│ ▼ │
│ 数据上传到 LangSmith 云端 │
│ ┌──────────────────────────────────────────────┐ │
│ │ https://smith.langchain.com/ │ │
│ │ │ │
│ │ 项目: langchain-langsmith-demo │ │
│ │ ├── 追行记录 2024-01-15 10:23 │ │
│ │ │ ├── LLM 调用 (1.2s, 156 tokens) │ │
│ │ │ ├── 工具调用 get_weather (0.1s) │ │
│ │ │ └── 最终响应生成 (0.8s) │ │
│ │ └── ... │ │
│ └──────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘

3. 快速开始:三步集成 LangSmith

步骤 1:获取 LangSmith API Key

  1. 访问 https://smith.langchain.com/
  2. 注册/登录账号
  3. 进入 Settings → API Keys
  4. 创建新的 API Key(格式:lsv2_...

步骤 2:配置环境变量

在你的 .env 文件中添加:

1
2
3
4
# LangSmith 可观测性配置
LANGCHAIN_API_KEY=lsv2_xxx... # 你的 LangSmith API Key
LANGCHAIN_TRACING_V2=true # 启用 V2 追踪
LANGCHAIN_PROJECT=langchain-langsmith-demo # 项目名称

步骤 3:自动生效

关键点:不需要修改任何代码!

LangChain 会自动检测环境变量,启用追踪:

1
2
3
4
5
6
# 你的代码完全不需要改动
from src.agent.factory import build_advanced_agent

agent = build_advanced_agent()
response = agent.invoke({"messages": "北京天气怎么样?"})
# ↑ 这一步的完整追踪会自动上传到 LangSmith

原理揭秘:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# LangChain 内部(简化版)
if os.getenv("LANGCHAIN_TRACING_V2") == "true":
# 自动包装每个函数调用
def traced_wrapper(original_func):
def wrapper(*args, **kwargs):
# 开始追踪
trace_id = start_trace()
start_time = time.time()

# 执行原函数
result = original_func(*args, **kwargs)

# 结束追踪并上传
duration = time.time() - start_time
upload_trace(trace_id, {
"input": args,
"output": result,
"duration": duration
})
return result
return wrapper

# 自动应用到 LLM、工具调用等
_original_invoke = traced_wrapper(_original_invoke)

4. LangGraph Studio:可视化调试界面

什么是 LangGraph Studio?

LangGraph Studio 是 LangSmith 的本地开发伴侣,它让你能够:

  • 在本地运行和调试 Agent
  • 实时查看执行流程
  • 可视化展示状态变化
  • 修改后立即看到效果

启动 Studio

1
2
3
4
5
# 确保已安装(需要 Python >= 3.11)
pip install --upgrade "langgraph-cli[inmem]"

# 启动 Studio 服务器
langgraph dev

启动后你会看到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌────────────────────────────────────────────────────────────┐
│ LangGraph Studio 已启动 │
├────────────────────────────────────────────────────────────┤
│ │
│ 🌐 API 端点: │
│ http://127.0.0.1:2024 │
│ │
│ 🎨 Studio 界面: │
│ https://smith.langchain.com/studio/?baseUrl=... │
│ │
│ 📊 可用的 Graph: │
│ • agent - 高级 Agent(带记忆) │
│ • basic_agent - 基础 Agent(单工具) │
│ │
└────────────────────────────────────────────────────────────┘

Studio 界面一览

打开 Studio 界面后,你会看到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
┌─────────────────────────────────────────────────────────────────┐
│ LangGraph Studio 界面 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────────────────────────┐ │
│ │ Graph 列表 │ │ 执行追踪详情 │ │
│ │ │ ├─────────────────────────────────────┤ │
│ │ ▶ agent │ │ Thread: user-001 │ │
│ │ basic_agent │ │ │ │
│ │ │ │ ┌─ Step 1: LLM 调用 ────────┐ │ │
│ │ │ │ │ 时间: 2024-01-15 10:23:01 │ │ │
│ │ │ │ │ 耗时: 1.2s │ │ │
│ │ │ │ │ Tokens: 156 input / 42 out │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ │ 输入: │ │ │
│ │ │ │ │ "北京天气怎么样?" │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ │ 输出: │ │ │
│ │ │ │ │ [工具调用] │ │ │
│ │ │ │ │ get_weather_for_location │ │ │
│ │ │ │ │ {"city": "北京"} │ │ │
│ │ │ │ └────────────────────────────┘ │ │
│ │ │ │ │ │
│ │ │ │ ┌─ Step 2: 工具调用 ───────┐ │ │
│ │ │ │ │ 耗时: 0.1s │ │ │
│ │ │ │ │ 结果: "晴朗,约 12C" │ │ │
│ │ │ │ └────────────────────────────┘ │ │
│ └─────────────────┘ └─────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘

5. 追踪数据的解读

完整的执行链路

当你在 LangSmith 中查看一次 Agent 执行,会看到类似这样的追踪:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
┌─────────────────────────────────────────────────────────────────┐
│ Agent 执行追踪示例 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 📅 2024-01-15 10:23:45 │
│ 🧵 Thread: user-001 │
│ ⏱️ 总耗时: 2.1s │
│ 💰 总 Tokens: 234 │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Step 1: agent:LLM (理解意图并决策) │ │
│ │ ├─ 耗时: 1.2s │ │
│ │ ├─ Tokens: 156 in / 42 out │ │
│ │ ├─ 输入: "北京天气怎么样?" │ │
│ │ └─ 输出: [工具调用] get_weather_for_location("北京") │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Step 2: agent:tools:get_weather_for_location │ │
│ │ ├─ 耗时: 0.1s │ │
│ │ ├─ 参数: {"city": "北京"} │ │
│ │ └─ 结果: "晴朗,约 12C" │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Step 3: agent:LLM (生成最终回复) │ │
│ │ ├─ 耗时: 0.8s │ │
│ │ ├─ Tokens: 36 in / 89 out │ │
│ │ ├─ 输入: (工具结果 "晴朗,约 12C") │ │
│ │ └─ 输出: "北京今天天气晴朗,温度约12度..." │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘

关键指标解读

指标 说明 用途
Latency 单个步骤的耗时 定位性能瓶颈
Tokens 输入/输出 Token 数量 估算成本、优化 Prompt
Cost API 调用成本(估算) 监控花费
Error 错误信息(如果有) 快速定位问题

6. 实战:调试一个真实问题

让我们通过一个实际例子,展示 LangSmith 如何帮助调试。

问题场景

用户反馈:Agent 有时返回”抱歉,我暂时无法回答”

没有 LangSmith 时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 你能做的:
def run_agent(question):
try:
response = agent.invoke({"messages": [question]})
return response
except Exception as e:
print(f"出错了: {e}")
# 😰 但问题可能不是异常,而是 LLM 决策导致的

# 实际问题可能出在:
# - 工具参数解析错误?
# - 城市名解析失败?
# - Prompt 写得不清楚?
# - LLM 能力不足?

使用 LangSmith 后

  1. 在 LangSmith 中找到失败的那次执行
  2. 展开每个步骤查看详情
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
问题定位过程:

┌─────────────────────────────────────────────────────┐
│ Step 1: LLM 调用 │
├─────────────────────────────────────────────────────┤
│ 输入: "查一下三藩市天气" │
│ │
│ 输出: [工具调用] │
│ get_weather_for_location({"city": "三藩市"}) │
│ │
│ ✅ LLM 理解正确,知道要调用天气工具 │
└─────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────┐
│ Step 2: 工具调用 get_weather_for_location │
├─────────────────────────────────────────────────────┤
│ 参数: {"city": "三藩市"} │
│ │
│ 结果: "暂无 三藩市 的实时数据" │
│ │
│ ❌ 找到问题了! │
│ 城市别名解析不支持"三藩市"这个称呼 │
└─────────────────────────────────────────────────────┘
  1. 修复问题
1
2
3
4
5
# 在 CITY_ALIASES 中添加别名
CITY_ALIASES = {
"San Francisco": ["sf", "san francisco", "旧金山", "三藩市"], # ← 新增
...
}
  1. 验证修复:在 Studio 中回放同一条对话,确认现在能正确处理

7. langgraph.json 配置详解

langgraph.json 是 LangGraph Studio 的配置文件:

1
2
3
4
5
6
7
8
{
"dependencies": ["."],
"graphs": {
"agent": "./graphs.py:agent",
"basic_agent": "./graphs.py:basic_agent"
},
"env": ".env"
}

字段解释:

字段 说明
dependencies Python 包依赖(. 表示当前目录)
graphs 定义的 Graph 列表,格式为 文件路径:变量名
env 环境变量文件路径

graphs.py 的作用:

1
2
3
4
5
6
7
8
9
10
11
12
"""
graphs.py 导出已编译的 agent,供 Studio 使用
"""

from src.agent.factory import build_advanced_agent, build_basic_agent

# 基础版 agent
basic_agent = build_basic_agent()

# 高级版 agent
# 注意:不传入 checkpointer,由 Studio 自动处理
agent = build_advanced_agent(with_checkpointer=False)

8. 高级功能

8.1 会话回放(Replay)

LangSmith 允许你重新运行历史对话:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
场景:你修改了 Prompt 或工具实现

┌─────────────────────────────────────────────────────────┐
│ LangSmith 回放功能 │
├─────────────────────────────────────────────────────────┤
│ │
│ 历史执行 #1234 │
│ ├── 步骤 1: LLM 调用 │
│ ├── 步骤 2: 工具调用 │
│ └── 步骤 3: 最终回复 │
│ │
│ [🔄 Replay 按钮] │
│ │ │
│ ▼ │
│ 用最新代码重新运行同一条输入 │
│ → 对比新旧结果,验证修改效果 │
│ │
└─────────────────────────────────────────────────────────┘

8.2 项目管理

你可以为不同环境创建不同项目:

1
2
3
4
5
6
7
8
# 开发环境
LANGCHAIN_PROJECT=langchain-dev

# 测试环境
LANGCHAIN_PROJECT=langchain-test

# 生产环境
LANGCHAIN_PROJECT=langchain-prod

8.3 性能优化建议

通过 LangSmith 追踪,你可以发现:

问题 追踪中的表现 优化方案
Prompt 太长 输入 Token 过高 精简 Prompt,去除冗余内容
串行调用 总耗时 = 各步骤耗时之和 改为并行调用
重复调用同一工具 同一工具被多次调用 添加结果缓存
LLM 响应慢 单次 LLM 调用耗时过长 换更快的模型或优化 Prompt

9. 总结

核心概念回顾

概念 一句话理解
LangSmith AI 应用的”监控摄像头”
Trace(追踪) 一次完整的执行记录
Span(跨度) 执行中的一个步骤
LangGraph Studio 本地可视化调试工具

LangSmith 的核心价值

  1. 调试不再”盲人摸象”

    • 看见每一步的输入输出
    • 定位错误的精确位置
  2. 性能优化有据可依

    • 识别耗时最长的步骤
    • 计算 Token 成本
  3. 团队协作效率提升

    • 分享追踪链接给同事
    • 复现和定位问题
  4. 持续改进的依据

    • 对比不同版本的效果
    • 回放验证修改

与上一篇文章的关联

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
┌─────────────────────────────────────────────────────────┐
│ 系列文章知识体系 │
├─────────────────────────────────────────────────────────┤
│ │
│ 第一篇:LangChain Agent 原理 │
│ ├── Agent = LLM + Tools + 规划 │
│ ├── 工具调用(Function Calling) │
│ ├── 对话记忆(Memory) │
│ └── 结构化输出(Structured Output) │
│ │ │
│ ▼ │
│ 第二篇:LangSmith 可观测性(本文) │
│ ├── 为什么需要可观测性 │
│ ├── LangSmith 工作原理 │
│ ├── LangGraph Studio 可视化调试 │
│ └── 追踪数据解读与实战调试 │
│ │ │
│ ▼ │
│ 下一阶段(待续) │
│ ├── 更复杂的 Agent 编排 │
│ ├── RAG(检索增强生成) │
│ └── 多 Agent 协作 │
│ │
└─────────────────────────────────────────────────────────┘

10. 快速上手

运行本项目的 LangSmith Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 1. 克隆项目
git clone https://git.liupx.com/study/langchain_langsmith_demo
cd langchain_langsmith_demo

# 2. 创建虚拟环境
python3 -m venv .venv
source .venv/bin/activate

# 3. 安装依赖
pip install langchain langgraph python-dotenv openai
pip install --upgrade "langgraph-cli[inmem]"

# 4. 配置环境变量
cp .env.example .env
# 编辑 .env,填入 DEEPSEEK_API_KEY 和 LANGCHAIN_API_KEY

# 5. 启动 LangGraph Studio
langgraph dev

# 6. 访问 Studio 界面
# https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024

查看追踪数据

启动 Studio 并执行一些查询后,访问 https://smith.langchain.com/ 查看完整的追踪记录。

11. 参考资料

相关文档

本项目文档

源码索引

文件 功能
langgraph.json Studio 配置文件
graphs.py Agent 导出(Studio用)
src/agent/llm.py DeepSeek 模型配置
.env.example 环境变量示例(含LangSmith)

系列文章导航

关于作者:本文基于 langchain_langsmith_demo 项目编写,延续上一篇文章的风格,专注于 LangSmith 可观测性的原理与实践。欢迎 Star 和 Fork!