返回案例和资讯
技术分享2026/07/088 分钟阅读华胥星辰团队

Agent 可观测性:用三张表回答"它当时到底做了什么"

用户说"这个答案不对"的时候,你能还原当时发生了什么吗?我们把 Agent 的每一次运行、每一步、每一次工具调用都落成结构化数据。

可观测性链路追踪Agent排障
Agent 可观测性:用三张表回答"它当时到底做了什么"

写在前面 传统 Web 服务出问题,看日志和链路追踪就行。Agent 系统不一样——它的"故障"往往不是报错,而是成功返回了一个错误的答案。这种问题在日志里长得和正常请求一模一样。


一、问题的特殊性

一次 Agent 请求内部可能发生:路由判断、若干次检索、若干次模型调用、若干次工具调用、一次质量校验。

当用户反馈"答得不对"时,你需要知道:

  • 它把这个问题判成了哪一类?判错了吗?
  • 检索出了哪些片段?相关吗?
  • 模型看到的完整上下文是什么?
  • 有没有调用工具?调用参数对吗?返回了什么?
  • 质量校验通过了吗?

普通的应用日志回答不了这些问题。你需要为 Agent 的执行结构专门设计一套记录。

传统日志为什么不够

一个典型的传统 Web 服务请求日志长这样:

[2026-07-08 10:23:15] GET /api/search?q=xxx → 200 OK in 45ms

排查这个请求:用 query 参数查数据库、看索引命中率、判断是否慢了。链路很短、因果关系清晰。

一个 Agent 请求的内部日志如果只记一行"请求完成",你完全不知道中间发生了什么。而如果把每一步都打印到标准日志里,会得到几百行混杂的文本,排查时靠 grep 大海捞针。问题不是日志不够多,是日志没有结构。


可观测性三张表的层级关系
可观测性三张表的层级关系


二、三张表

我们的结构是三层:

agent_runs — 一次完整运行

记录:请求标识、用户、进入了哪个 Profile、开始与结束时间、最终状态、总耗时、总消耗。这是排查的入口。

agent_steps — 运行中的每一步

记录:所属运行、步骤序号、步骤类型(检索/生成/校验等)、输入摘要、输出摘要、耗时、报错信息。这里能看出流程走到哪一步开始不对。

agent_tool_calls — 每一次工具调用

记录:所属步骤、工具名、调用参数、返回结果、耗时、成功与否。工具调用是最容易出问题的一环,单独一张表值得。

三张表通过外键串起来,从一次运行可以下钻到每一步、每一次调用。

一个真实的排查路径

用户反馈:"我上传论文问摘要,它给的内容好像不是这篇论文的。"

排查步骤:

  1. 在 agent_runs 找到这次请求 → Profile 是 paper_analysis,耗时 3.2 秒,状态正常
  2. 在 agent_steps 看步骤 → 检索步骤耗时 0.8 秒,返回了 5 个片段
  3. 点进去看检索结果 → 发现检索返回的是另一篇论文的片段
  4. 问题定位:用户上传了同名文件覆盖了旧文件,但向量索引没有更新——是索引同步问题,不是 Agent 理解问题

整个过程从用户反馈到定位,三分钟。没有这套记录,我们可能要在对话记录里翻半天。


三、记录什么、不记录什么

这里有几个实际的取舍:

完整上下文要不要存? 存了非常有用,但体积大、含用户数据。我们的做法是存摘要和引用,配合原始资源的标识——需要还原时可以按标识重新组装,而不是把全文冗余一份。

模型的思考过程要不要存? 要。这是判断"它为什么这么答"最直接的依据。对于支持 thinking/reasoning 的模型,这一部分的 token 往往是最终回答的好几倍,也是排查中最有价值的。

存多久? 按数据敏感度和存储成本设保留期,超期归档或清理。这一点在企业私有化交付里通常有明确的合规要求,需要提前对齐。我们内部按"最近 30 天热存储 + 归档到 12 个月"来规划。

同步写还是异步写? 我们选异步。可观测性数据不应该拖慢主链路,更不应该因为它写失败而让用户的请求失败。用一个内存 buffer + 批量写入的机制,既能保证延迟不增加,又能控制写入压力。

不该存的内容

  • 原始密码、API Key 等敏感凭证——即使加密也不该存,因为排查场景不需要这些信息
  • 完整的多媒体文件——可以存文件路径和哈希,但文件本身留在对象存储里
  • 每次模型调用的完整 token 流——这个数据量增长极快。改为保留输入/输出的完整内容(非流式记录),以及 token 消耗的统计值

四、这套数据的三个用途

排障

最直接的用途。用户反馈问题时,凭请求标识就能还原完整过程。这把"我们查一下"从几小时缩短到几分钟。

成本分析

哪类请求最贵、哪个环节的调用次数超预期、哪些工具调用经常超时后重试——这些只有落成结构化数据才看得出来。凭感觉估算通常偏差很大。

一个实例:我们跑了一个月的可观测数据后发现,literature_review 这个 Profile 的平均调用次数是 retrieval_qa 的 5 倍——因为它要跨多份材料检索。如果没有这个数据,我们可能会一直以为是"所有请求都差不多贵"。

质量迭代

质量门控拦截了哪些回答、被拦截的原因分布如何、哪个 Profile 的拦截率最高——这些直接指向下一轮该优化什么。

第三点是我们做这套东西的初衷。没有数据,Agent 的优化就只能靠"感觉这次好像好一点"。


五、观测模式:先看,再拦

我们在质量门控上用了一个值得推荐的做法:新的校验规则上线时,先只记录不拦截。

跑一段真实流量后,你会看到:

  • 这条规则实际触发的频率是多少
  • 触发的样本里,有多少是真问题、多少是误伤
  • 不同场景下的触发率差异

有了这些数据,再决定哪些场景开启强制拦截、阈值定在哪里。

直接上强制拦截的风险很实在:一条设计时觉得很合理的规则,可能会误伤大量正常回答,而你要等到用户投诉才知道。

观测模式的数据怎么用

在观测模式下,每一条被"标记"的记录都会触发一条标记日志,包含:

  • 触发了哪条规则
  • 当前的输出内容和引用
  • 规则判断的依据

这些数据会被定期抽查。一个可操作的建议:至少抽查 100 条标记记录,确认误伤率低于 5% 之后再考虑开启强制拦截。 100 条是凭经验定的人为判断阈值——太少不可信,太多成本高。


六、一个建议

如果你正在从零做 Agent 系统,建议把可观测性放在第一批要做的事里,而不是"等有空再补"。

原因很直接:这套记录需要 Agent 的执行结构本身是可拆解的。如果你先做了一个大黑盒,之后想加观测点,会发现根本没有"点"可加——你得先把黑盒拆开,那基本等于重写。

反过来,先有分层结构和记录,后续无论是调优、排障还是做成本控制,都有据可依。

想在你的业务里试试同样的做法?

告诉我们业务问题与数据现状,我们会给出方案建议与落地路径。