主题
专题 05 调试、观测与链路追踪
本专题解决的是 AI Agent 工程里一个非常真实的问题:为什么系统一旦出错,就会进入“好像哪里都可能有问题,但又不知道先查哪里”的状态。
传统前端问题通常还能靠浏览器控制台、接口日志、埋点数据快速缩小范围;而 Agent 系统的问题往往跨越了 Prompt、检索、工具调用、模型输出、工作流状态和前端展示多个层次。如果没有一套清晰的观测与调试方法,系统越复杂,定位故障就越慢。
1. 为什么 Agent 系统更需要可观测性
前端系统里,一次异常往往发生在比较明确的层次:
- 页面渲染错了。
- 某个请求失败了。
- 某个状态更新丢了。
但 Agent 系统的问题链路更长:
- 用户输入本身可能有歧义。
- Prompt 组织方式可能引导错了方向。
- 检索没召回到对的证据。
- 工具调用可能超时、失败或返回脏数据。
- 模型可能误选工具或输出格式漂移。
- 前端可能把中间状态展示得过于模糊,导致用户感知为“卡住了”。
这意味着你不能只看最终输出,而要能够还原“这次回答是怎么一步一步形成的”。
2. 可观测性到底要观测什么
建议把观测拆成四层:
- 输入层:用户输入、上下文槽位、检索证据、工具参数。
- 决策层:模型选择了什么路径、为什么走这条路径。
- 执行层:工具调用结果、工作流节点状态、重试与回退。
- 输出层:最终回答、结构化字段、引用、前端展示状态、用户反馈。
只有四层都可见,问题才能被定位,而不是靠猜。
3. 用前端视角理解 tracing
前端工程师通常已经熟悉以下调试方式:
- network 面板看请求链路。
- error monitoring 看异常栈。
- 埋点分析看用户路径。
- source map 回溯前端代码位置。
在 Agent 系统里,tracing 可以类比成“把一次用户请求从输入到输出的整个执行过程串起来”。 一个完整 trace 最好能回答:
- 这次请求的唯一 ID 是什么。
- 触发了哪些模型调用。
- 调用了哪些工具。
- 每一步花了多长时间。
- 哪一步失败了。
- 最终返回给用户的是什么。
4. 最应该先观测的 8 类信息
4.1 请求标识
每次用户请求都应该有唯一请求 ID 或 trace ID。 没有它,跨服务排查几乎不可能高效进行。
4.2 Prompt 版本
不要只记录“调用了模型”,还要记录:
- 系统指令版本。
- 模板版本。
- 关键参数。
- 是否开启了某些策略开关。
否则你很难知道问题是代码逻辑导致,还是 Prompt 版本回退导致。
4.3 检索结果摘要
不要把整个大上下文原样堆到日志里,但至少要记录:
- 召回了哪些文档。
- top-k 是多少。
- 最终被送进模型的片段有哪些。
- 是否经过重排和压缩。
4.4 工具调用日志
至少记录:
- 工具名。
- 参数摘要。
- 是否成功。
- 耗时。
- 错误类型。
- 是否重试。
4.5 工作流节点状态
如果系统用了工作流编排,建议每个节点都有明确状态:
- pending
- running
- succeeded
- failed
- cancelled
- waiting_human
4.6 输出结构校验结果
模型说“我输出了 JSON”并不代表它真的可用。 建议记录:
- 是否解析成功。
- 哪个字段缺失。
- 是否触发了 fallback。
- 是否转成了人工复核。
4.7 前端感知状态
从用户体验角度,前端状态同样重要:
- 是否正在流式输出。
- 是否处于等待确认。
- 是否显示了引用与依据。
- 用户是否主动取消了流程。
4.8 用户反馈
很多问题不是日志里直接能看出的,而是从用户反馈暴露的:
- “回答不准确”
- “引用不匹配”
- “流程卡住了”
- “明明已经执行成功,但页面还在转圈”
这些反馈应该能和 trace 串起来。
5. 一套推荐的调试顺序
第一步:先判断问题属于哪一层
建议先粗分为:
- 输入问题。
- 检索问题。
- 工具问题。
- 模型决策问题。
- 输出解析问题。
- 前端展示问题。
如果一开始就陷入所有层都看,很容易越查越乱。
第二步:固定复现场景
调试前先固定:
- 用户输入。
- Prompt 版本。
- 模型版本。
- 检索配置。
- 工具版本。
否则你今天复现的是 A 问题,明天环境变了又变成 B 问题。
第三步:查看完整 trace
排查顺序建议是:
- 用户问题进入后被如何标准化。
- 检索返回了什么。
- 模型拿到了哪些上下文。
- 是否发生了工具调用。
- 工具结果是什么。
- 输出是否通过结构校验。
- 前端最终展示了什么。
第四步:对失败样本归类
不要每个问题都单独处理,建议做失败归类,例如:
- 检索召回为空。
- 检索召回正确但生成错误。
- 工具成功但结果解释错误。
- 输出格式漂移。
- 前端状态未同步。
归类后才更容易集中修一类问题。
6. 前端工程师最能发挥价值的部分
6.1 设计前后端一致的状态模型
前端最怕的是:
- 后端说流程完成了,但前端还在 loading。
- 后端说等待确认,前端却没有展示确认入口。
- 后端已 fallback,前端还当正常结果展示。
所以需要设计统一状态枚举和清晰的 UI 映射关系。
6.2 把黑盒变成半透明
不是所有内部推理都要展示给用户,但至少应该展示关键状态和关键依据。 前端可以负责把:
- 当前步骤
- 关键引用
- 工具执行摘要
- 风险提示 合理地展示出来。
6.3 用埋点补足“技术成功但体验失败”的问题
有些系统日志看起来都正常,但用户体验还是差。 比如:
- 平均 15 秒才有第一段可见反馈。
- 用户在等待确认时不知道要点击什么。
- 用户频繁在某一步取消。
这类问题很适合通过前端行为埋点发现。
7. 一个推荐的日志字段清单
可以先从最小集合开始:
trace_idsession_iduser_id或匿名标识prompt_versionmodel_nameretrieval_docstool_nametool_statusnode_statuslatency_msfallback_triggeredneed_human_reviewui_statususer_feedback
日志字段命名一旦统一,后续排查效率会大幅提高。
8. 一个实战排查案例
假设你有一个企业知识问答 Agent,用户反馈“明明引用了制度文档,答案还是错的”。 推荐排查顺序如下:
- 看 trace 确认检索是否真的召回了正确文档。
- 看最终注入模型的上下文里是否还保留了关键条款。
- 看是否有无关证据挤掉了关键证据。
- 看模型输出是否误解了条款。
- 看前端展示的引用是否和后端返回一致。
这样可以快速区分:
- 是检索问题。
- 是上下文压缩问题。
- 是生成解释问题。
- 还是前端展示错位问题。
9. 常见失败模式
9.1 只记录错误,不记录成功路径
如果没有成功样本做对照,你就很难知道失败样本到底偏离了哪里。
9.2 日志太碎,没有 trace 串联
每个服务各打一段日志,但没有统一 trace_id,最终还是很难排查。
9.3 只看后端,不看前端状态
很多“系统卡住”的问题其实不是模型卡,而是前端状态没更新或事件没收敛。
9.4 记录太多原始敏感内容
观测不是无上限收集。 企业环境下要特别注意脱敏、最小化记录和权限控制。
9.5 没有失败分类体系
团队每次都靠“临时口头描述问题”,问题就很难被系统性修复。
10. 验证方式
你可以用以下问题验证自己的观测体系是否成型:
- 一次失败请求能否在 5 分钟内定位到问题层级。
- 是否能从 trace 中完整还原一次请求的执行路径。
- 是否能区分检索失败、工具失败、生成失败和展示失败。
- 发布后质量回退时,是否能快速定位是哪次变更引入。
- 用户投诉是否能绑定到具体 trace 做复盘。
11. 可复用模板
11.1 失败排查记录模板
text
trace_id:
问题现象:
影响范围:
所属层级:输入 / 检索 / 工具 / 模型 / 输出 / 前端
复现条件:
根因分析:
修复动作:
是否加入回归集:是 / 否11.2 Trace 事件模板
text
时间:
trace_id:
节点:
动作:
输入摘要:
输出摘要:
耗时:
状态:成功 / 失败 / 回退 / 等待确认11.3 前端体验埋点模板
text
事件名:agent_step_visible
触发时机:某一步状态首次对用户可见
关键字段:trace_id / step_name / duration_ms / user_action12. 面试表达
你可以这样讲:
“我在做 Agent 工程时,很早就把可观测性当成系统设计的一部分,而不是上线后补日志。我的做法是把一次请求拆成输入、决策、执行、输出四层,并用 trace_id 串起检索、工具调用、工作流节点和前端状态。这样出了问题时,我能很快定位到底是检索召回、模型决策、工具异常,还是 UI 状态同步出了问题。”