跳转到内容

Agent 可观测性:Trace、事件、成本与故障定位

Eval 告诉你“这个版本在退款切片上退步了”,可观测性要继续回答:究竟是模型选错工具、检索返回旧政策、参数被截断、审批超时,还是工具已经成功但响应丢了?

普通应用也需要日志、指标和 Trace。Agent 系统更难,因为决策部分是概率性的,执行路径动态变化,模型调用、工具、副作用和多 Agent 交接交织在一起。

可观测性不是把 Prompt 全量存下来。它是为一次运行建立可追踪的因果链,并在隐私、成本和调试价值之间做选择。

一、为什么“最终答案日志”远远不够

Section titled “一、为什么“最终答案日志”远远不够”

考虑一个研究 Agent 的失败回答。只看输入输出,你只能知道结论错了。真实原因可能是:

  • Router 把任务发给了错误专业 Agent;
  • 搜索工具命中了旧页面;
  • 网页抓取返回 403,模型没有显式报错;
  • 上下文裁剪丢了日期限定;
  • 工具参数中的年份被模型写错;
  • 验证器未运行;
  • 达到预算后系统提前终止;
  • 正确证据被最终摘要误写。

这些故障分别属于编排、工具、上下文、模型、验证和预算层。没有结构化事件,只能从一大段对话猜测。

二、Logs、Metrics、Traces、Artifacts 各管什么

Section titled “二、Logs、Metrics、Traces、Artifacts 各管什么”

例如 tool_call_deniedcheckpoint_savedhandoff_started。日志适合离散事件和错误详情,但单条日志不天然表达父子关系。

成功率、P95 延迟、Token、费用、工具错误率、人工接管率和循环次数。指标适合告警与趋势,不能单独解释某一次失败。

Trace 包含多个 Span。每个 Span 代表一段工作,例如模型生成、工具调用、检索、Guardrail 或 Handoff,并记录父子关系、耗时、状态和属性。

代码 Diff、报告、截图、测试结果、工具原始响应和检查点。大工件不应全塞进 Span,可以保存引用、哈希和访问策略。

四者组合起来,才既能发现系统异常,又能解释单次运行。

一个 Trace 至少需要:

trace_id 一次端到端运行
span_id 当前步骤
parent_span_id 父步骤
name agent.run / model.generate / tool.call ...
start/end 时间与耗时
status ok / error / cancelled
attributes 模型、工具、Token、版本、重试等
events 审批、异常、状态变化
links 与异步任务或其他 Trace 的关系

OpenAI Agents SDK 的 Tracing 覆盖 Agent、Generation、Tool、Guardrail 和 Handoff 等事件。[1] OpenTelemetry 的 Generative AI Semantic Conventions 则尝试为模型、Agent、工具和评测定义跨平台语义。[2]

统一语义很重要:如果每个框架都把工具名称、Token 和错误写在不同字段,跨服务检索与仪表盘会不断重做。

不是每一行代码都需要 Span。优先覆盖会改变决策、成本或外部状态的边界:

  • agent.run:顶层任务;
  • model.generate:模型与参数版本;
  • context.build:检索、裁剪与输入预算;
  • tool.call:工具、参数摘要、结果状态;
  • policy.check:允许、拒绝和规则版本;
  • handoff:来源、目标和交接包;
  • checkpoint:状态版本和存储结果;
  • eval.score:Judge 与分项分数;
  • human.approval:请求、决定和等待时长。

Span 命名应描述稳定的操作类型,不要把用户 ID 或完整问题拼进名称,否则指标维度爆炸。

五、不要把 Chain-of-Thought 当可观测性

Section titled “五、不要把 Chain-of-Thought 当可观测性”

调试系统需要的是输入来源、动作、参数、状态和结果,不需要存储模型不可验证的内在推理独白。

更有价值的记录是:

  • 模型收到哪些经过裁剪的消息类型;
  • 选择了什么工具;
  • 参数通过了哪版 Schema;
  • 工具返回什么状态码和结果摘要;
  • 验证器依据什么环境证据作出判定;
  • 最终状态如何迁移。

这样既能诊断,也减少保存敏感推理和无边界文本的风险。

第 10、11 讲把 Harness 拆成上下文、工具、控制、状态、验证和运行环境。Trace 应沿这些边界记录。

例如一次状态迁移:

RUNNING
-> tool.call(send_email)
-> response_timeout
-> checkpoint(UNKNOWN_EXTERNAL_STATE)
-> tool.call(query_by_idempotency_key)
-> verifier(email_exists)
-> SUCCEEDED

只记录“模型重试了两次”无法判断是否重复发送;记录外部状态查询和幂等键,才能重建真实因果。

对长时任务,Trace 还要与持久化 run_id、检查点版本和业务对象 ID 关联。进程重启后可以产生新的 Trace Segment,但仍属于同一领域运行。

七、多 Agent Trace 最容易断在哪里

Section titled “七、多 Agent Trace 最容易断在哪里”

Manager 启动 Worker、A2A 委派远程 Agent、消息进入队列时,父子调用可能跨进程甚至跨组织。此时简单的同步父子 Span 不够。

常用方法包括:

  • 传递 Trace Context;
  • link 连接异步任务;
  • 记录 task_idagent_idattempthandoff_id
  • 把消息生产与消费分别建 Span;
  • 保留 Worker 工件哈希,不复制全部内容。

同时要明确租户边界。跨组织 A2A 不应无条件传递内部 Trace、Prompt 或用户数据;只传必要的关联 ID 和经过批准的上下文。

  • 业务终态成功率;
  • 验证通过率;
  • 人工纠正与回退率;
  • 按任务类别的 Eval 分数。
  • 工具错误与超时率;
  • 重试、重复副作用和卡死率;
  • 检查点恢复成功率;
  • 各状态停留时间。
  • 端到端 P50/P95/P99;
  • 模型、检索、工具、审批各段耗时;
  • 输入/输出 Token;
  • 每个成功任务成本,而不是每次调用成本;
  • 并行峰值和队列等待。
  • 策略拒绝次数;
  • 高风险工具批准率;
  • 未知 Server 或能力变化;
  • Prompt Injection 告警;
  • 敏感字段脱敏失败。

“每个成功任务成本”特别重要。一个便宜模型如果需要更多重试和人工接管,总成本可能更高。

九、Langfuse、Phoenix 与 OpenTelemetry 分别处在哪一层

Section titled “九、Langfuse、Phoenix 与 OpenTelemetry 分别处在哪一层”

Langfuse 提供 Trace、Prompt、Evaluation、Dataset 等 LLM 工程能力,适合把线上运行与离线评测连接起来。[3]

Langfuse GitHub 页面

图 1:Langfuse 是开源 Agent/LLM 可观测项目之一。GitHub 热度代表关注度,不代表适合所有部署。来源见文末。

Phoenix 关注 AI Observability 与 Evaluation,支持 Trace、实验和 RAG/Agent 分析。[4]

Phoenix GitHub 页面

图 2:Phoenix 将 AI Observability 与 Evaluation 放在同一产品面。来源见文末。

OpenTelemetry 更接近跨语言、跨服务的遥测标准与生态,不是完整的 Agent 产品控制台。工程上可以用 OpenTelemetry 采集和传输,再选择后端存储、分析与评测。

选择平台时要看:是否支持自托管、数据保留与脱敏、Trace 标准、Dataset/Eval 连接、成本、访问控制和导出能力。

十、隐私:最有用的 Trace 往往最敏感

Section titled “十、隐私:最有用的 Trace 往往最敏感”

Prompt、Tool 参数和返回值可能包含姓名、订单、代码、医疗数据和 Secret。全量记录虽然方便调试,却可能制造一个新的敏感数据仓库。

应在采集前设计:

  • 字段白名单与结构化脱敏;
  • Prompt/Response 只存哈希、摘要或受控引用;
  • Secret 永不进入遥测;
  • 按租户和角色控制访问;
  • 设定保留期与删除流程;
  • 调试临时提级有审批和时效;
  • 导出和第三方平台符合组织政策。

不要依赖事后在日志平台里搜索并删除。敏感信息一旦复制到多个后端,治理成本会迅速扩大。

十一、采样:不是所有成功 Trace 都要永久保存

Section titled “十一、采样:不是所有成功 Trace 都要永久保存”

可以组合三类采样:

  • 头部采样:运行开始时按比例决定,成本低,但可能漏掉稀有错误;
  • 尾部采样:运行结束后保留错误、慢请求和高风险任务,更有诊断价值;
  • 规则采样:对付款、删除、策略拒绝、人工接管等事件强制保留。

指标可以全量聚合,详细内容按风险采样。错误 Trace 的保留期不必无限,修复后应沉淀成脱敏 Eval Case。

十二、真实实验:把三段运行聚合成一条 Trace

Section titled “十二、真实实验:把三段运行聚合成一条 Trace”

本讲的 trace_budget.py 构造 agent.plantool.searchagent.answer 三个 Span,并实际聚合耗时、Token 和工具错误。

运行结果:总耗时 1040ms,总 Token 1030,工具错误为 0,终态 success

{
"trace_id": "trace-demo-001",
"total_latency_ms": 1040,
"total_tokens": 1030,
"tool_error_count": 0
}

完整结果见 experiment-result.json

这组数据是教学 Fixture,不是线上测量。它展示的是聚合原则:每个 Span 保存局部事实,Trace 提供端到端预算和因果关系。

在实验中加入一个失败的 tool.fetch Span,设置两次重试。分别计算:

  • 首次尝试错误率;
  • 最终工具失败率;
  • 重试带来的额外延迟;
  • 每个成功任务 Token;
  • 最慢 Span。

再给 Span 增加 model_versionprompt_versiontool_version,模拟某次发布后 P95 变高,验证能否按版本切片定位。

最后加入一个看似真实的邮箱字段,在写文件前做脱敏,并写测试确认结果中不包含原始值。

遇到失败时,按顺序问:

  1. 用户目标对应的领域终态是什么;
  2. 运行在哪个状态停止;
  3. 最后一个成功 Span 是什么;
  4. 错误是模型、工具、政策、传输还是环境;
  5. 是否产生了未知副作用;
  6. 当前 Trace 与哪个版本、Commit 和 Fixture 绑定;
  7. 这是单例还是同一切片的系统性变化;
  8. 修复后能否变成一个自动回归 Case。

这比从几千行字符串日志里搜索“error”更接近工程诊断。

Agent 可观测性的核心不是“存更多对话”,而是建立从目标、状态、模型、工具到环境终态的因果链。

Trace 解释一次运行,Metrics 发现整体变化,Artifacts 保存证据,Eval 判断质量。四者通过版本和任务 ID 连接,才形成能诊断、能回归的生产系统。

下一讲进入可靠性工程:超时之后究竟能不能重试,怎样用错误分类、幂等、检查点和补偿控制副作用。


[1] OpenAI Agents SDK, Tracing. https://openai.github.io/openai-agents-python/tracing/

[2] OpenTelemetry, Generative AI Semantic Conventions. https://opentelemetry.io/docs/specs/semconv/gen-ai/

[3] Langfuse. https://github.com/langfuse/langfuse

[4] Arize Phoenix. https://github.com/Arize-ai/phoenix

[5] Google Cloud, A developer’s guide to production-ready AI agents. https://cloud.google.com/blog/products/ai-machine-learning/a-devs-guide-to-production-ready-ai-agents/