为什么要看见工具轨迹
Agent 最容易给人一种错觉:屏幕上只出现最后一段回答,好像它凭空完成了所有事情。但在真实项目里,最后答案只是结果,真正重要的是过程。它有没有查网页?有没有调用视频解析?有没有失败重试?有没有把错误吞掉?
所以我在 ShayuAgent 里把 SSE 流式输出和工具轨迹拆成两条线。聊天区负责承接用户感受到的回答,Trace 面板负责展示 Agent 的行动记录。这样用户既能保持阅读节奏,又能在需要时追到每一步。
事件流怎么组织
一次 Agent 响应可以拆成几类事件:推理文本、工具开始、工具结果、结构化输出和错误。前端的 useAgentStream 做的事情并不复杂,它就是打开 EventSource,按事件类型更新界面状态。
工具调用开始时,界面可以先显示「正在读取网页」或「正在解析视频」。工具返回后,Trace 面板再补上耗时、状态和结果摘要。如果工具失败,不应该只在控制台里打印错误,而是要给用户一个能理解的失败原因。
后端需要保存什么
只靠前端临时状态不够。用户刷新页面之后,工具轨迹最好还能回放,所以后端需要保存工具调用记录。至少应该包括工具名、输入摘要、输出摘要、状态、错误信息、耗时、所属会话和所属消息。
这里有一个小原则:不要把敏感原文无脑存进去。比如 cookie、token、完整请求头这类东西不应该进入日志。Trace 的目标是解释行为,不是复制所有内部细节。
结构化输出比纯文本更稳
当 Agent 要生成选题卡片、网页总结、视频摘要时,我更倾向于让它输出结构化数据。前端可以基于 Schema 渲染卡片,后端也能把字段写进数据库,后面筛选、收藏和二次加工都会更方便。
纯文本当然灵活,但一旦进入工作流,就会遇到复用困难。结构化输出像是一条窄一点的路,少了一些自由,但换来了稳定。
这件事的价值
SSE 让回答有呼吸感,Trace 让过程有证据。两者合在一起,Agent 才不像一个神秘黑箱,而像一个可以一起工作的搭档。
这也是我现在做 AI 工具时越来越在意的东西:不是让模型看起来无所不能,而是让每一次行动都能被理解、被检查、被继续接上。