最近审阅:2026-10
不只知道报错了,还要知道为什么
可观测性(observability)要帮助我们还原整个过程:Agent 当时看到了什么、做了什么、状态怎样变化,以及问题最早出在哪一步。 只知道接口成功或失败,还不够排查:问题可能出在检索(retrieval)、过期记忆、工具行为、状态转换、循环或评估标准不一致,也可能是证据都对、模型却做错了决定。
一次失败运行里发生了什么
用户让 Agent 订周五的餐厅,最后却订成了周六。
只看最终回答,我们只知道日期错了。假设记录里能看到:
用户原始请求:周五
记忆读取:上周对话里提到周六聚餐
模型输出的工具参数:date=Saturday
工具调用:date=Saturday
工具返回:success
最终回答:预订成功
工具执行成功了,但收到的日期参数就不对。旧记忆与错误日期一致,所以“旧记忆干扰了当前指令”值得检查;这还不是因果证明。可以在不实际下单的测试环境里,固定其他输入,比较保留、移除和更新这条记忆时的行为。模型事后说“我是因为旧记忆才这样做”,也不能单凭这句话确认原因。
Metrics、Logs 和 Traces 有什么区别
| 形式 | 最适合回答什么 |
|---|---|
| Metrics | 今天整体错误率、延迟和成本有没有变化? |
| Logs | 某个组件在某个时间报告了什么事件? |
| Traces | 一次请求按什么顺序经过了哪些决策和依赖? |
| Replay | 用相同版本和证据,能不能重现这次失败? |
| Evaluation | 这条完整轨迹是否满足任务要求? |
| 分组检查(Slicing) | 哪些用户、任务、工具或环境更容易出错? |
Agent 特别需要 trace,因为一次结果通常由多次模型、检索和工具调用共同产生。
但保留下来的 trace 不一定代表全部流量。按错误或延迟选择轨迹有助于排障,却会改变样本分布。比如 100 次请求有 10 次失败,全部保留失败、只保留 9 次成功,记录里的失败率就是 10 / 19,不是实际的 10 / 100。统计整体指标要有可靠的总体计数或说明采样校正;需要完整审计的操作,也不能只依赖抽样 trace。
一次运行应该记录什么
版本
模型、prompt、retriever、索引、工具、memory policy、evaluator、数据和配置分别是什么版本;用 task、trace 和实验 ID 关联一次运行。只有确实需要时才记录用户标识,不把邮箱等信息当作默认日志字段。这些字段在 OpenTelemetry 的 GenAI 约定里叫什么、截至 2026-10 还处在哪个稳定性级别,见评估接到线上。
输入证据
模型看到了哪些指令、记忆、检索结果和工具返回;哪些内容被截断、过滤或重新排序。也记下 token、延迟和费用预算,才能区分“没找到”和“预算到了,被迫停止”。
记录证据不等于保存全部原文。能用版本化 ID 和受控引用定位的,就不额外复制内容;确需保留原文时,限制访问、保留时间和用途,屏蔽凭证及无关个人信息。哈希一个可枚举的用户 ID 也不等于匿名化,参见 OpenTelemetry 的敏感数据处理说明。
优先在采集端避免写入敏感内容,导出前再按允许的字段检查和脱敏,而不是仅在面板上隐藏。自动埋点、异常文本、URL 查询参数和工具返回也要检查;过滤几个顶层字段,并不能保证自由文本里没有秘密。
例如下面这条合成记录保留了排查重试所需的关联,不复制退款请求正文或凭证:
trace_id=demo-17 tool=refund attempt=1
operation_ref=demo-refund-8 transport_status=timeout
business_outcome=unknown
timeout 不等于退款失败。应通过受控的 operation_ref 查询实际结果;引用本身也要限制访问。这只是最小示意,不是适用于所有业务的安全日志格式。
决策过程
每一步实际选择了什么 action,触发了哪条继续或停止规则,是否发生重试、fallback、timeout 或人工接管。系统规则、可见输出和事后推测分开记录,不要求读取模型内部思维过程。
状态变化
执行前后,用户状态、任务状态(task state)和外部系统状态发生了什么改变。
最终结果
任务是否真正完成,而不是只看是否生成了一段看似合理的文字。把确定性检查、judge 版本、用户纠正和后续结果与运行关联,区分工具报告成功和实际任务成功。
Trace 不应该只是更长的日志
trace 先把调用依赖和状态变化连起来;它帮助提出原因假设,不自动证明哪个组件导致了失败。常见 span 可以包括:
model:上下文、输出、token、延迟和版本;retrieval:query、候选(candidate)、分数、过滤和最终证据;tool:参数、返回、异常、重试和副作用;memory:读取、写入、压缩、遗忘和置信度变化;policy:路由、停止、fallback 和风险判断;evaluation:标准、证据、结论和 evaluator 版本;human_review:为什么转人工、人工改了什么,以及修改理由。
常见 Agent 失败
- 循环:重复调用同一个工具,状态却没有实质变化。
- 目标漂移:执行到后面已经偏离用户最初任务。
- 记忆污染:错误、过期或属于其他上下文的信息进入长期状态。
- 工具语义不一致:模型理解的 API 行为和实际实现不同。
- 静默降级(fallback):系统 fallback 后仍返回正常口吻,用户不知道质量已经下降。
- 评估盲区:只检查最终文本,不检查过程、工具和副作用。
- 成本失控:更多 token、搜索和重试没有带来新的进展。
记录之后要做什么
有了监控面板还不够。这些记录最好能进一步帮我们得到:
- 一个能明确描述输入、环境和失败条件的案例;
- 一条可以加入离线 eval set 的完整轨迹;
- 一个清楚的修改方向:应该改 prompt、Search、工具、记忆、policy,还是训练数据。
“回放(replay)”也要说清是哪一种:
| 做法 | 能回答什么 | 不能混淆什么 |
|---|---|---|
| 查看历史记录 | 当时记录了哪些输入、调用和结果 | 不等于再次执行,也可能有采样或脱敏造成的缺口 |
| 固定工具返回,在沙箱重跑 | 更换一个组件后,行为是否变化 | 外部环境被冻结了,不是线上效果 |
| 在测试环境重新调用服务 | 当前依赖下还能否复现问题 | 版本、随机采样和外部状态可能已经改变 |
订餐、付款、发邮件等写操作不能在回放时默认再执行一次。先用 stub 或 dry-run;确需执行时重新检查授权、幂等与恢复方案。即使版本和随机种子相同,也不要承诺外部 API 或不同硬件一定逐字复现。先挑一个失败案例,把这些条件记完整,比一开始接很多面板更有用。
和其他章节的连接
- Evaluation 决定怎样判断一条轨迹成功或失败。
- Human-in-the-Loop 决定哪些轨迹需要人工介入。
- 表征与记忆 解释状态怎样被写入和污染。
- Search 解释证据是怎样进入上下文的。
快速学习:Agent 可观测性要观察什么
把调用记录和状态变化连起来,才能复现问题
先记住这三个词:指标(metrics)看整体有没有异常,日志(logs)记具体事件,调用轨迹(traces)把一次运行中的模型调用、检索、工具和状态变化串起来。
面试回答
排查 Agent,不能只看某一次 API 调用,要看它完成任务的全过程。每一步的记录(span)要能关联版本、输入依据、所选动作、工具结果、状态变化和开销,再用 trace ID 串起来。敏感内容不能直接全量入库;先还原发生了什么,再用受控测试判断原因。
再想一步:为什么把提示词全存下来,还是不够?
只存原始文本,很难看出调用之间的先后和依赖关系,还可能留下敏感信息。更有用的记录应包含结构化 span、父子调用关系、版本和状态变更,并对个人信息(PII)脱敏。目的是分清检索、模型、工具或评估哪一步出了问题,不是把日志越存越长。
本页术语 6
- 可观测性 observability
- 能从外部信号推断系统内部状态的程度
- 检索 retrieval
- 从外部语料里找出相关内容
- 任务状态 task state
- 执行任务时保存的目标、已知信息、进度和待确认事项
- 候选 candidate
- 召回阶段捞出来、等待精排挑选的内容
- 降级 fallback
- 主路径不可用时切换到较简单但语义明确的备用行为
- 回放 replay
- 用固定输入重新执行一段数据或模型链路,检查结果是否一致