链路追踪
先说结论
链路追踪是对一次用户请求在模型系统中的完整执行路径进行关联记录,覆盖入口请求、提示构造、检索、工具调用、模型生成、评测、缓存命中和最终响应。
为什么我会单独记这一篇
LLM 系统一旦接上 RAG、工具和多步工作流,问题就不再是“模型答错了”,而是要回答:
- 是 prompt 有问题?
- 是检索召回错了?
- 是工具返回坏了?
- 是哪个节点拖慢了延迟?
链路追踪的目标,就是让一次请求从入口到出口都可回放、可定位、可审计。
核心机制
基本对象
request_idtrace_idspan_idparent_span_id
典型 span 分层
request.receiveprompt.buildretrieval.searchretrieval.reranktool.callllm.generateguardrail.checkresponse.return
每个 span 常见属性
- 开始 / 结束时间
- 状态 / 错误
- model / provider
- token / cost
- 输入输出摘要
- user / tenant
- tool / document_id
与传统 APM 的区别
传统 APM 更关注服务调用和错误堆栈;LLM tracing 还需要记录:
- prompt 和 messages
- retrieval chunks
- tool calls
- token usage
- 模型版本
- 评测分数
- 人工反馈
设计时真正要权衡什么
- 追踪粒度 vs 存储成本:完整 prompt 很有价值,但日志成本和泄密风险都高。
- 全量采样 vs 抽样追踪:高流量系统通常要采样,但事故流量应强制保留。
- 可观测性 vs 隐私:需要对 prompt、用户输入和文档片段做脱敏或分层存储。
容易踩的坑
- 只有接口日志,没有跨服务 trace ID。
- 有 trace,但没有记录检索片段、工具参数和模型版本。
- 同步链路有追踪,异步任务和 webhook 丢失上下文。
- 只记录最终回答,不记录中间 decision points。
- tracing 与 eval 分离,无法从坏样本反查执行轨迹。
工程落地时我会怎么做
- 统一要求线上报障必须带 request ID。
- 把安全拦截、评测得分、人工反馈都挂到 trace 上,形成闭环。
- 对敏感字段做脱敏和分层存储,避免 tracing 系统变成泄密面。
- 从最小可用请求级追踪做起,再逐步扩展到工作流级追踪。
- 尽量采用标准化上下文传播,如 W3C Trace Context 和 OpenTelemetry。
LangSmith / Langfuse / OpenTelemetry
- LangSmith:更适合 LLM workflow 的 traces、runs、datasets、evals 一体化。
- Langfuse:更适合做开源可自建的 LLM observability、scores 和 prompt management。
- OpenTelemetry:更适合把 LLM 系统纳入通用 observability 栈。
如果要对外讲,可以怎么概括
“链路追踪在 LLM 系统里不是可选项,因为一个问题可能同时涉及 prompt、检索、工具和多步编排。真正有用的 tracing 不只是记录接口耗时,而是要把 request ID、trace ID、retrieval chunks、tool calls、model version 和 eval 分数都挂进同一条链路,做到坏样本可回放、可定位、可复盘。”
最后记几条
- tracing 是定位 LLM 系统问题的基础设施。
- request ID 和 trace ID 是最小可用单位。
- span 里要记录检索、工具、模型和评测信息。
- tracing 必须和隐私治理一起设计。
- LangSmith、Langfuse 和 OTel 各有定位,但目标都是可回放和可观测。
参考资料
- LangSmith observability
- Log traces to LangSmith
- Langfuse docs
- Langfuse tracing
- OpenTelemetry traces
- OpenTelemetry context propagation
- OpenTelemetry GenAI semantic conventions
- W3C Trace Context