online branch: main

2026-08-29

RSS llms.txt GitHub

AI 出错不可怕,可怕的是你不知道它经过了哪里

$
AI 应用可观测性与评估:AI 出错不可怕,可怕的是你不知道它经过了哪里

单进程里的 Agent 很容易观察。一次请求进入函数,函数依次完成检索、模型生成和工具调用,运行时可以自动维持父子关系。系统拆成网关、Agent 服务、检索服务、MCP Server 和模型网关后,同一个任务会跨越多个进程,甚至跨越不同团队管理的系统。每一处都能生成日志,但把日志放在一起,并不会自然长成一条完整链路。

高级追踪要解决的,是一次执行如何在边界之间保持因果关系。这里先分清两个经常混用的对象:Trace 描述一次连续执行,Session 把多轮请求归入同一个业务会话。用户连续追问三次,可以得到三条 Trace,同时共享一个 Session ID。Session 能回答“这些请求属于同一段对话”,却不能说明检索服务的某个步骤由哪次模型决策触发。把 Session ID 当作 Trace ID,会造出一条跨越很久的假链路,耗时、错误和父子关系都会失真。

让上下文跨过进程边界

一条分布式 Trace 至少需要三类信息:全局 trace_id、当前步骤的 span_id,以及采样决定。上游发出 HTTP 请求或队列消息前,把这份上下文注入协议载体;下游收到后提取上下文,恢复当前父步骤,再创建自己的 Span。各服务可以独立结束和上报,后端仍能按 Trace ID 和父子 ID 还原调用树。

trace T1
网关 S1
└─ Agent 服务 S2
   ├─ 检索服务 S3
   │  └─ 向量数据库 S4
   ├─ MCP Client 调用 S5
   │  └─ MCP Server S6
   │     └─ 广告数据 API S7
   └─ 模型生成 S8

session = conversation_42

W3C Trace Context 规定了常见的传播格式,OpenTelemetry(OTel)提供注入、提取和运行时上下文管理。采用它们的意义很实际:不必为 HTTP、消息队列和不同语言各造一套 Header,也更容易把 AI 链路接入已有 APM。

异步任务不总能画成同步嵌套。生产者结束后,消费者可能过几分钟才开始工作;这时仍然存在因果关系,但展示时更适合使用 link 或异步关系,而不是制造一段虚假的同步耗时。上下文无法传播时,可以保留外部请求 ID 供相关查询。相关查询能帮助找记录,却不等于父子链已经建立。

传播也有安全边界。Trace Context 本身应保持精简,租户、用户或业务参数要通过受控的业务字段传递。向第三方系统发送 Header 前,需要确认对方是否可信、是否会继续转发。Baggage 尤其容易被滥用,它不是携带完整 Prompt 和用户资料的通道。

OTel 还是平台 SDK

OTel 和厂商 SDK 解决的问题有交集,但侧重点不同。OTel 擅长统一跨语言 Trace、上下文传播和导出管道;平台 SDK 更了解自家对象,通常能直接记录模型消息、Token、成本、Prompt 版本、Score 或媒体附件。选择时不用追求形式上的纯粹。

已有 OTel 基础设施、服务语言较多,或数据需要同时进入 APM 与 AI 观测平台,可以让 OTel 承担主干。项目刚起步,又依赖某个平台的 Prompt、评估和框架自动集成,平台 SDK 往往更省时间。两种方式也可以组合:OTel 维护 Trace Context,平台 SDK 补充 GenAI 语义。

组合接入前要做一次小规模验证。同一次模型调用如果被两个自动集成都捕获,就会出现重复 Span、冲突 ID 和双倍成本。检查它们是否共享同一个 Tracer Provider、是否继承同一份当前上下文,以及谁负责最终导出。能接收 OTLP 只说明协议相通,不代表模型消息、Token、媒体或评估对象在每个后端都能无损显示。

Langfuse 的 Python SDK v3 和 JS/TS SDK v4 起采用 OTel 架构,也提供 OTLP 接收端点。使用 Langfuse SDK 时,可以获得较完整的平台语义;已有 OTel 链路或其他语言服务也可以通过 OTLP 发送数据。具体版本和兼容范围会变化,升级时应查官方兼容矩阵,不能只凭“支持 OTel”判断所有能力都可用。

MCP 追踪要同时看到决策和执行

MCP 是 Agent 访问工具和数据源的协议,并不负责质量判断。一次 MCP 调用至少跨越 Client 和 Server 两侧:Client 记录 Agent 选择了哪个 Tool、传了什么参数;Server 记录工具内部又访问了什么系统、耗时多久、在哪里报错。

只追踪 Server,会看到接口执行成功,却不知道是哪次 Agent 决策触发;只追踪 Client,则看不到 Server 内部的数据库或外部 API。端到端链路可以把几类问题分开:模型选错 Tool、Tool 选对但参数错、Server 执行失败,以及返回正确却被模型误读。

MCP Client 与 Server 各自生成 Trace 并非一定有问题。双方由不同团队维护、数据权限不允许打通,或只关心各自服务健康度时,分开更合适。需要复盘完整任务时,再传播上下文。Langfuse 官方方案通过 MCP Tool Call 的 _meta 字段注入 W3C Trace Context,Server 提取后恢复上下文。这里传的是当前 Trace,不是 Session ID。

Agent Graph 也要摆在正确位置。轨迹由嵌套 Observation、Generation 和工具调用等记录采集而来,Graph 负责把已有关系画出来。图能帮助人阅读,不能替代采集,更不能证明 Agent 的路径合理。路径质量仍要交给前一章讨论的工具调用和轨迹评估。

多模态追踪记录的不是缩略图

图片、音频、视频和文档进入 Agent 后,仅保存“上传成功”无法复现问题。有效记录包含三部分:媒体引用、必要描述,以及它与具体步骤的关系。描述通常包括 MIME 类型、大小、哈希、时长、页数或分辨率;关联信息要说明媒体属于哪条 Trace、哪个 Observation,是输入、输出还是中间产物。

不要把大段 Base64 塞进普通 Trace 字段。它会放大网络载荷和存储压力,也让查询变慢。更稳妥的方式是把文件放进对象存储,在 Trace 中保留受控引用和元数据。外部 URL 可以省去上传,但要处理过期、鉴权、源文件删除和浏览器可访问性。哈希则用于确认模型当时处理的究竟是哪一版文件。

Langfuse SDK 能识别常见载荷中的 Base64 Data URI,把媒体单独上传到对象存储,再在 Trace 中留下引用;也支持外部 URL、LangfuseMedia 和媒体 API。自托管时需要配置 S3 兼容存储。平台能显示缩略图,只是操作体验;真正的验收是给定一次失败请求,能够确认模型接收的媒体、版本和处理步骤,并在权限允许时复现。

高级追踪的验收不是节点数量,而是能否从一次用户请求下钻到跨服务步骤、MCP Tool 和媒体附件,同时保持 Trace 与 Session 的边界。

参考资料


系列目录:AI 应用可观测性与评估

上一篇:会聊天不等于会办事:复杂 Agent 应该怎么评?

下一篇:AI 上线以后,哪些数据该留,哪些绝不能留?