Agent 可观测性:Trace、事件、成本与故障定位
Eval 告诉你“这个版本在退款切片上退步了”,可观测性要继续回答:究竟是模型选错工具、检索返回旧政策、参数被截断、审批超时,还是工具已经成功但响应丢了?
普通应用也需要日志、指标和 Trace。Agent 系统更难,因为决策部分是概率性的,执行路径动态变化,模型调用、工具、副作用和多 Agent 交接交织在一起。
可观测性不是把 Prompt 全量存下来。它是为一次运行建立可追踪的因果链,并在隐私、成本和调试价值之间做选择。
一、为什么“最终答案日志”远远不够
Section titled “一、为什么“最终答案日志”远远不够”考虑一个研究 Agent 的失败回答。只看输入输出,你只能知道结论错了。真实原因可能是:
- Router 把任务发给了错误专业 Agent;
- 搜索工具命中了旧页面;
- 网页抓取返回 403,模型没有显式报错;
- 上下文裁剪丢了日期限定;
- 工具参数中的年份被模型写错;
- 验证器未运行;
- 达到预算后系统提前终止;
- 正确证据被最终摘要误写。
这些故障分别属于编排、工具、上下文、模型、验证和预算层。没有结构化事件,只能从一大段对话猜测。
二、Logs、Metrics、Traces、Artifacts 各管什么
Section titled “二、Logs、Metrics、Traces、Artifacts 各管什么”Logs:发生了什么事件
Section titled “Logs:发生了什么事件”例如 tool_call_denied、checkpoint_saved、handoff_started。日志适合离散事件和错误详情,但单条日志不天然表达父子关系。
Metrics:整体是否异常
Section titled “Metrics:整体是否异常”成功率、P95 延迟、Token、费用、工具错误率、人工接管率和循环次数。指标适合告警与趋势,不能单独解释某一次失败。
Traces:一次运行的因果结构
Section titled “Traces:一次运行的因果结构”Trace 包含多个 Span。每个 Span 代表一段工作,例如模型生成、工具调用、检索、Guardrail 或 Handoff,并记录父子关系、耗时、状态和属性。
Artifacts:运行产生了什么证据
Section titled “Artifacts:运行产生了什么证据”代码 Diff、报告、截图、测试结果、工具原始响应和检查点。大工件不应全塞进 Span,可以保存引用、哈希和访问策略。
四者组合起来,才既能发现系统异常,又能解释单次运行。
三、Agent Trace 的最小结构
Section titled “三、Agent Trace 的最小结构”一个 Trace 至少需要:
trace_id 一次端到端运行span_id 当前步骤parent_span_id 父步骤name agent.run / model.generate / tool.call ...start/end 时间与耗时status ok / error / cancelledattributes 模型、工具、Token、版本、重试等events 审批、异常、状态变化links 与异步任务或其他 Trace 的关系OpenAI Agents SDK 的 Tracing 覆盖 Agent、Generation、Tool、Guardrail 和 Handoff 等事件。[1] OpenTelemetry 的 Generative AI Semantic Conventions 则尝试为模型、Agent、工具和评测定义跨平台语义。[2]
统一语义很重要:如果每个框架都把工具名称、Token 和错误写在不同字段,跨服务检索与仪表盘会不断重做。
四、应该为哪些步骤建 Span
Section titled “四、应该为哪些步骤建 Span”不是每一行代码都需要 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;
- 工具返回什么状态码和结果摘要;
- 验证器依据什么环境证据作出判定;
- 最终状态如何迁移。
这样既能诊断,也减少保存敏感推理和无边界文本的风险。
六、Trace 怎样连接 Harness 与 Loop
Section titled “六、Trace 怎样连接 Harness 与 Loop”第 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_id、agent_id、attempt和handoff_id; - 把消息生产与消费分别建 Span;
- 保留 Worker 工件哈希,不复制全部内容。
同时要明确租户边界。跨组织 A2A 不应无条件传递内部 Trace、Prompt 或用户数据;只传必要的关联 ID 和经过批准的上下文。
八、从 Trace 聚合哪些生产指标
Section titled “八、从 Trace 聚合哪些生产指标”- 业务终态成功率;
- 验证通过率;
- 人工纠正与回退率;
- 按任务类别的 Eval 分数。
- 工具错误与超时率;
- 重试、重复副作用和卡死率;
- 检查点恢复成功率;
- 各状态停留时间。
- 端到端 P50/P95/P99;
- 模型、检索、工具、审批各段耗时;
- 输入/输出 Token;
- 每个成功任务成本,而不是每次调用成本;
- 并行峰值和队列等待。
- 策略拒绝次数;
- 高风险工具批准率;
- 未知 Server 或能力变化;
- Prompt Injection 告警;
- 敏感字段脱敏失败。
“每个成功任务成本”特别重要。一个便宜模型如果需要更多重试和人工接管,总成本可能更高。
九、Langfuse、Phoenix 与 OpenTelemetry 分别处在哪一层
Section titled “九、Langfuse、Phoenix 与 OpenTelemetry 分别处在哪一层”Langfuse 提供 Trace、Prompt、Evaluation、Dataset 等 LLM 工程能力,适合把线上运行与离线评测连接起来。[3]

图 1:Langfuse 是开源 Agent/LLM 可观测项目之一。GitHub 热度代表关注度,不代表适合所有部署。来源见文末。
Phoenix 关注 AI Observability 与 Evaluation,支持 Trace、实验和 RAG/Agent 分析。[4]

图 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.plan、tool.search 和 agent.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 提供端到端预算和因果关系。
十三、20:40 分钟扩展实践
Section titled “十三、20:40 分钟扩展实践”在实验中加入一个失败的 tool.fetch Span,设置两次重试。分别计算:
- 首次尝试错误率;
- 最终工具失败率;
- 重试带来的额外延迟;
- 每个成功任务 Token;
- 最慢 Span。
再给 Span 增加 model_version、prompt_version 和 tool_version,模拟某次发布后 P95 变高,验证能否按版本切片定位。
最后加入一个看似真实的邮箱字段,在写文件前做脱敏,并写测试确认结果中不包含原始值。
十四、故障定位的标准问题
Section titled “十四、故障定位的标准问题”遇到失败时,按顺序问:
- 用户目标对应的领域终态是什么;
- 运行在哪个状态停止;
- 最后一个成功 Span 是什么;
- 错误是模型、工具、政策、传输还是环境;
- 是否产生了未知副作用;
- 当前 Trace 与哪个版本、Commit 和 Fixture 绑定;
- 这是单例还是同一切片的系统性变化;
- 修复后能否变成一个自动回归 Case。
这比从几千行字符串日志里搜索“error”更接近工程诊断。
十五、这一讲的结论
Section titled “十五、这一讲的结论”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/