给 AI agent 做可观测性:日志、trace、token 和错误分类
传统接口出问题时,你通常能查到请求日志、数据库查询、错误堆栈和监控指标。AI agent 出问题时,如果没有可观测性,排障会变成一句话:“它刚才不知道为什么乱跑了。”
这不够。
Agent 和普通聊天接口不同。一次用户请求内部可能包含多次模型调用、多次工具调用、检索、计划、反思、重试、权限判断和最终输出。只记录最后的回答,基本无法解释它为什么这样做、花了多少钱、哪里失败、能不能复现。
最小单位不是 message,而是 run
做 agent 可观测性时,先定义一个核心概念:run。
一个 run 表示一次用户意图从开始到结束的完整执行过程。它可能只调用一次模型,也可能包含十几个步骤。每个 run 都应该有稳定的 request_id 或 trace_id。
可以把层级想成这样:
run
step 1: model call
step 2: tool call
step 3: model call
step 4: final answer
如果你的系统已经有分布式追踪,就把 agent run 接进现有 trace。用户请求、业务服务、模型网关、工具服务、数据库查询应该能串起来。没有 trace,也至少要保证所有日志里都有同一个 request id。
每一步都要记录输入摘要、输出摘要和状态
不建议默认保存所有完整 prompt、工具返回和模型输出。那会带来隐私、合规和存储风险。但完全不记录内容,也无法排障。
一个折中方案是记录摘要和元数据:
| 字段 | 作用 |
|---|---|
| step_id | 当前 run 内的步骤编号 |
| step_type | model、tool、retrieval、policy、final |
| input_summary | 输入内容的脱敏摘要或哈希 |
| output_summary | 输出内容的脱敏摘要或结构化结果 |
| status | success、failed、skipped、retried |
| latency_ms | 这一阶段耗时 |
| error_type | 错误分类 |
对于调试环境或用户授权场景,可以短期保存完整内容。但生产默认策略应该更保守:优先保存可定位问题的结构化字段,而不是永久保存所有敏感文本。
这也应该写进团队规范里,参考 团队 AI 使用规范:密钥、数据、代码、审批和日志留存。
Token 账本要按 run 汇总,也要按 step 拆分
Agent 成本经常让人意外,是因为一次用户请求背后有多次模型调用。只看最终回答的 token,没有意义。
建议同时记录两个层级:
- step token:每次模型调用的输入 token、输出 token、缓存命中、模型名、估算成本。
- run token:整个 run 的总输入、总输出、总成本、调用次数、最高成本步骤。
这样你才能回答:
- 哪个工具调用后导致上下文暴涨?
- 哪个模型步骤输出太长?
- 哪类任务最容易重试?
- 是用户输入长,还是 agent 中间过程长?
- 成本高是因为强模型,还是因为循环次数太多?
如果你已经在做 AI API 成本治理,这部分应该和 AI API 成本控制实战手册 里的预算、限额和用量日志打通。
错误分类比错误文本更重要
模型和 agent 的失败很杂。如果只记录一段错误文本,很难统计和治理。
可以先从这些分类开始:
| 错误类型 | 含义 |
|---|---|
| provider_error | 模型供应商返回错误或超时 |
| rate_limited | 被限流或配额不足 |
| policy_denied | 权限、数据策略或安全策略拒绝 |
| tool_error | 工具执行失败 |
| tool_bad_input | agent 给工具的参数不合法 |
| parse_error | 模型输出无法解析 |
| validation_failed | 输出结构正确但业务校验失败 |
| max_steps_exceeded | agent 达到最大步骤数 |
| user_cancelled | 用户主动取消 |
有了分类,后续才能看趋势。比如 tool_bad_input 很高,可能是工具 schema 不清楚,或者提示词没有约束参数格式。max_steps_exceeded 很高,可能是 agent 没有收敛条件。policy_denied 很高,可能是产品入口没有提前告诉用户权限边界。
工具调用必须可复盘
Agent 的危险通常不在“想了一下”,而在“做了一下”。发邮件、改配置、查数据库、调用内部接口、提交代码、创建订单,这些工具调用必须可复盘。
每次工具调用建议记录:
- tool name 和版本
- 调用参数的脱敏版本
- 调用人或代表哪个用户执行
- 权限检查结果
- 外部系统返回状态
- 幂等键或业务对象 id
- 是否产生写操作
- 是否允许重试
写操作尤其要谨慎。可观测性不仅是为了排障,也是为了审计:谁让 agent 做了这件事,agent 传了什么参数,系统为什么允许它执行,执行后影响了哪个对象。
追踪视图应该像一条时间线
一个好用的 agent trace 视图,不应该只是一堆 JSON。它应该像时间线:
10:00:01 run started by user_123
10:00:02 model chose tool: search_orders
10:00:03 tool search_orders success, 3 records
10:00:04 model chose tool: refund_check
10:00:05 policy_denied: user lacks refund permission
10:00:06 final answer returned
时间线可以帮助工程师、产品和运营快速看懂发生了什么。底层仍然保留结构化字段,方便查询、聚合和告警。
如果 trace 只能由开发者读懂,排障会很慢。Agent 经常影响业务流程,所以非工程角色也需要能看懂基本过程。
告警不要只盯错误率
普通服务常看错误率、延迟和 QPS。Agent 还应该看一些特有指标:
- 平均每个 run 的模型调用次数
- 平均每个 run 的 token 和成本
- max steps 命中率
- parse error 和 validation failed 比例
- tool_bad_input 比例
- policy_denied 比例
- 高成本 run 数量
- 写操作工具的失败和重试次数
这些指标比单纯的 500 错误更早暴露问题。比如错误率没变,但平均步骤数从 3 涨到 9,成本和延迟都会上升;或者 parse error 上升,说明模型输出格式开始不稳定。
留存策略要分层
可观测性数据不是存得越多越好。
建议按敏感度分层:
- 指标聚合:长期保留,用于趋势分析。
- usage 记录:保留较长时间,用于对账、审计和成本分析。
- trace 元数据:保留中等时间,用于排障和质量分析。
- 完整 prompt、输出和工具返回:默认短期、脱敏、采样或按需开启。
具体保留多久取决于业务、合规和成本。关键是不要在没有意识的情况下永久保存用户输入、内部文档和工具返回。
结论
AI agent 的可观测性,核心是让一次自动执行变得可解释。
用 run 作为最小追踪单位;用 request id 或 trace id 串起模型、工具和业务系统;按 step 记录状态、token、耗时和错误分类;对工具调用保留可审计信息;用时间线视图帮助人理解过程;最后按敏感度设计留存策略。
没有这些基础设施,agent 出问题时很难判断是模型、提示词、工具、权限、重试还是业务数据出了问题。可观测性不是上线后的装饰,而是 agent 能进入生产环境的前提之一。