从 request_id 到可视化 trace:Langfuse 全链路追踪实战(O02)
系列《AI 应用生产化手册》第 7 篇(共 30 篇)|配套开源项目:github.com/ChenYingbo/...
一、先看问题:看日志 = 脑内拼图
O01 有了结构化日志,但马上撞到天花板:
- 看日志 = 脑内拼图 ------
request_id能串起链路,但你要在终端翻几十行 key=value 才拼出"这次请求经历了什么"。 - 一次问答不是一次调用------RAG 是"检索→重排→生成",Agent 是十几轮工具调用,文本日志没法展示这种结构。
- "看看这个 trace 长什么样"------没有可视化,无法快速回答"哪一步最慢、模型看到了什么、哪一步失败"。
解法:上追踪平台------把 request_id 升级为可视化 trace,一次请求变成一棵 span 树。
核心认知:日志是"细节",追踪是"结构",指标是"聚合"------三者分工不同。追踪回答的是"这一次请求内部到底发生了什么",是排查线上问题最快的入口。
二、原理
OpenTelemetry 四个核心概念(30 秒版)
| 概念 | 是什么 | 类比 |
|---|---|---|
| Trace | 一次完整请求的全链路 | 一次"旅程" |
| Span | Trace 里的一个环节(名字/耗时/属性) | 旅程中的一站 |
| Parent/Child | Span 的父子关系 | 站与站之间的嵌套 |
| Context Propagation | 把 trace 上下文传给下游 | 旅行中的"接力棒" |
平台选型
| 平台 | 优势 | 短板 |
|---|---|---|
| Langfuse | LLM 专项(generation 记录 prompt/tokens)、自带提示词管理与评测面板、OpenAI SDK 包装器一行接入 | 自托管要 postgres |
| Phoenix | OpenTelemetry 原生、可做在线评测 | LLM 专项功能少 |
| 自建(OTel Collector + Grafana) | 可控性最强 | 成本高、维护重,学习阶段不建议 |
选型结论:用 Langfuse------可观测、看板、提示词管理一个平台管三件事。
一次问答的 span 树
ini
POST /api/chat ← root span(路由)
├── chat_request ← 请求入口(O01 日志同步打)
└── llm_call (generation) ← Langfuse 自动记录
├── input = 问题全文
├── output = 答案全文
├── model = deepseek-chat
└── usage: in_tokens=69 out_tokens=85
(RAG 接入后)├── retriever.search └── reranker.rerank
(Agent 接入后)└── agent.loop ├── tool.call(...) └── llm_call(第二轮)
每多一层能力,span 树就多一层------所以"先搭追踪再上复杂功能"是正确顺序。
追踪 vs 日志 vs 指标
| 粒度 | 回答的问题 | |
|---|---|---|
| 追踪 | 一次请求 | "这次请求内部发生了什么、哪一步慢/错" |
| 日志 | 一条事件 | "某个时刻的细节文本是什么" |
| 指标 | 聚合 | "整体表现如何、有没有退化" |
排查路径:指标发现异常 → 追踪定位请求 → 日志看细节。
三、动手:本地起 Langfuse 并接入追踪
bash
git clone https://github.com/ChenYingbo/ai-prod-demo.git && cd ai-prod-demo
cp .env.example .env && docker compose up -d postgres langfuse litellm
# 1. 验证 Langfuse 健康
curl http://localhost:3000/api/public/health
# 2. 一键验证"可观测链路打通"(脚本会写入一条 trace 并查回)
LANGFUSE_PUBLIC_KEY=pk-local-demo LANGFUSE_SECRET_KEY=sk-local-demo \
LANGFUSE_HOST=http://localhost:3000 python scripts/check_langfuse.py
# [1/3] health: 200 {"status":"OK","version":"2.95.11"}
# [2/3] POST trace: 200
# [3/3] 查询最近 trace: 命中 check_langfuse ✓
# 3. 启动应用,发一次请求
uvicorn app.main:app --port 8000
curl -X POST http://localhost:8000/api/chat -H "Content-Type: application/json" \
-d '{"question":"什么是 RAG?"}'
# 打开 http://localhost:3000 看 trace(项目 default-project,Key 已预置)
优雅降级验证(生产纪律)
bash
# 不配置 LANGFUSE_SECRET_KEY 时,应用照常运行(追踪自动关闭)
LANGFUSE_SECRET_KEY= uvicorn app.main:app --port 8001
curl http://localhost:8001/health # 正常返回,不报错
可观测是增强不是依赖------追踪平台挂了不能拖垮业务。
四、真实踩坑(都踩过)
- (实测)Langfuse 起不来 :必须配
NEXTAUTH_SECRET和SALT,否则容器反复重启 - (实测)postgres 竞态 :Langfuse 比 postgres 先就绪 → Prisma 报
P1001: Can't reach database server直接退出------postgres 起来后重启一次 langfuse 即可(生产用 healthcheck + depends_on) - (实测)SDK API 变了 :langfuse 4.x 移除了
start_trace,改用装饰器/上下文模型------验证脚本改用 Public API 直写 trace,不依赖 SDK 版本 - (实测)健康端点格式想当然 :
/health/liveliness返回纯文本"I'm alive!"不是 JSON;/spend/logs有的版本直接返回 list------脚本要兼容 - public key 和 secret key 混淆 :SDK 接入用 secret key(服务端写入用),public key 是展示用
- host 没配 :SDK 默认连云端
cloud.langfuse.com,自托管必须设LANGFUSE_HOST - 隐私:trace 记录 prompt/输出全文------生产要对输入做脱敏/截断(学习阶段全量记录)
五、小结
- OTel 四概念:Trace / Span / 父子 / 上下文传播
- 三层分工:指标发现异常 → 追踪定位请求 → 日志看细节
- 优雅降级:追踪平台挂了,业务照常------这是生产纪律
明天(O03):《质量与成本监控》------用指标 + 看板把"整体表现"可视化(含真实的 P95 vs 平均数对比)。 收藏 + 关注,每天一篇,30 天把 AI 应用送上生产。