# Agent 流式协议前后端对齐 决策记录 ## 1. 基本信息 - 记录编号:FDR-009 - 功能名称:Agent Chat SSE 协议前后端对齐(去伪思考化) - 记录日期:2026-04-18 - 决策状态:提议(评审后执行) - 负责人:SmartFlow 团队 - 关联需求 / Issue: - 工具调用信息前端可视化(折叠式、通俗文案) - 降低“深度思考”误导(当前为伪装块) ## 2. 背景与问题 - 业务背景: - 目前聊天页已经在做流式展示、确认卡片、会话管理; - 计划将“工具调用过程”以专属样式内联展示。 - 现状问题: 1. 后端阶段状态/工具状态,会通过 `reasoning_content` 回传给前端,形成“看起来像深度思考”的内容; 2. 前端目前只消费 `extra.kind=confirm_request`,其他 `extra` 结构化事件并未真正用于渲染; 3. 用户感知层面会误以为模型正在“深度思考”,但其中大量内容其实是流程状态(非真实思考)。 - 不做此决策的后果: 1. 前端即使先移除“深度思考框”,也会连同状态可见性一起丢失; 2. 前后端协议继续漂移,工具可视化落地会重复返工; 3. 后续“真流式 speak”与“工具事件流”会相互干扰,排查困难。 ## 3. 决策目标 - 目标 1:统一 SSE 协议语义边界:`reasoning_content` 仅承载真实思考文本,不再承载阶段/工具状态文案。 - 目标 2:以 `extra.kind` 作为结构化事件主通道,前端据此渲染工具/状态专属 UI。 - 目标 3:明确迁移顺序:先后端协议就位,再前端切换展示,最后清理兼容层。 - 非目标(本次不解决): - 不在本轮实现“每一次 speak 都改成 chat 节点流式消息头”; - 不在本轮重构全部历史会话数据存储格式。 ## 4. 备选方案 ### 方案 A:先改前端,先隐藏深度思考区 - 描述:前端先把思考区关闭或默认不展示,后端暂不改。 - 优点: - 见效快,UI 即刻变“干净”。 - 缺点: - 只是遮罩,不是协议治理; - 状态可见性与思考内容耦合,后续仍要返工。 - 复杂度 / 成本:低(短期)/ 高(长期返工) ### 方案 B:先改后端协议,再改前端渲染(采纳) - 描述:后端先把状态/工具事件改为结构化主通道,前端再切换消费逻辑与样式。 - 优点: - 语义边界清晰,长期维护成本低; - 前端可直接做“折叠式工具行”,不再依赖伪思考文本; - 可通过双写/开关平滑迁移,风险可控。 - 缺点: - 首轮需要前后端并行协作与联调。 - 复杂度 / 成本:中 ### 方案 C:前后端同一轮同时硬切 - 描述:单次发布同时切后端协议和前端展示,不保留兼容层。 - 优点: - 路径最短,代码最“干净”。 - 缺点: - 回归风险高,灰度与回滚空间小; - 一旦线上混部或缓存命中旧逻辑,容易出现空白块/重复块。 - 复杂度 / 成本:中(开发)/ 高(上线风险) ## 5. 最终决策 - 采纳方案:方案 B(先后端协议,再前端渲染,最后清理兼容层)。 - 关键理由: 1. 先解决协议语义,再做视觉层改造,避免 UI 层“治标不治本”; 2. 与“工具调用可视化”目标一致,能直接对接折叠式工具行; 3. 具备可灰度、可回滚的工程路径。 ## 6. 影响范围 - 涉及模块: - 后端:`backend/newAgent/stream`、`backend/newAgent/node` - 前端:`frontend/src/components/dashboard/AssistantPanel.vue` - 数据与存储影响: - 无数据库结构变更; - 仅影响实时 SSE 事件解释方式。 - 接口 / 协议影响: - `POST /api/v1/agent/chat` 的 SSE chunk 语义调整(见第 7/8 节)。 - 监控与日志影响: - 需新增“事件类型计数”与“前端解析命中率”观测。 ## 7. 前后端接口现状(AS-IS) ### 7.1 SSE 外层协议(当前) - 后端已定义 OpenAI 兼容壳 + `extra` 扩展,代码位置: - `backend/newAgent/stream/openai.go` - `backend/newAgent/stream/emitter.go` - `extra.kind` 已有枚举:`status`、`tool_call`、`tool_result`、`confirm_request` 等。 ### 7.2 当前关键现象 1. 后端 `EmitStatus` 会把阶段文案同时写入: - `extra.kind=status` - `choices[0].delta.reasoning_content`(降级文本) 2. 执行节点多数工具过程仍通过 `EmitStatus(code=tool_call/tool_blocked)` 推送; 3. 前端 `processSseBlock` 当前只显式处理: - `parsed.extra?.kind === 'confirm_request'` 4. 结果:大量状态文案作为“reasoning”显示,形成伪“深度思考”体验。 ### 7.3 当前事件样例(简化) ```json { "choices": [ { "delta": { "reasoning_content": "阶段:execute\n正在调用工具:queue_status" } } ], "extra": { "kind": "status", "status": { "code": "tool_call", "summary": "正在调用工具:queue_status" } } } ``` ## 8. 目标协议(TO-BE) ### 8.1 总体原则 1. `reasoning_content`:只承载真实模型思考文本; 2. `extra.kind`:承载流程状态和工具事件(前端主消费通道); 3. 前端渲染:默认不把状态事件塞入“深度思考区”,而是进入工具/状态专属样式。 ### 8.2 目标事件约定 | 事件类型 | `extra.kind` | 前端默认表现 | 是否进入 reasoning 区 | |---|---|---|---| | 阶段状态 | `status` | 轻量状态行 / 提示条 | 否 | | 工具调用开始 | `tool_call` | 折叠工具行(默认摘要) | 否 | | 工具调用结果 | `tool_result` | 更新同一工具行状态与详情 | 否 | | 待确认 | `confirm_request` | 确认卡片 | 否 | | 真思考 | `reasoning_text` | 思考区(可折叠) | 是 | | 正文输出 | `assistant_text` | 正文区 | 否 | ### 8.3 目标工具事件样例(简化) ```json { "choices": [], "extra": { "kind": "tool_call", "stage": "execute", "tool": { "name": "queue_status", "status": "start", "summary": "已调用工具:查看任务队列", "arguments_preview": "默认参数" } } } ``` ```json { "choices": [], "extra": { "kind": "tool_result", "stage": "execute", "tool": { "name": "queue_status", "status": "done", "summary": "待处理 3 项,已完成 1 项" } } } ``` ## 9. 实施计划(先后端、再前端) ### 里程碑 1:后端协议对齐(先做) - 目标:状态/工具事件走结构化主通道,不再依赖伪 reasoning 文本。 - 开工清单(后端): 1. `execute` 工具链路改用 `EmitToolCallStart/EmitToolCallResult`; 2. `EmitStatus` 增加策略开关:支持“仅 extra,不回写 reasoning_content”模式; 3. `tool_blocked` 统一归类到工具事件(或结构化 status),避免文本拼接歧义; 4. 输出契约补充到 `backend/newAgent/ARCHITECTURE.md`。 ### 里程碑 2:前端事件消费切换 - 目标:前端按 `extra.kind` 渲染,不再把流程状态当“深度思考”。 - 开工清单(前端): 1. `processSseBlock` 增加 `status/tool_call/tool_result` 解析; 2. 新增“折叠式工具行”状态机(默认摘要、展开详情); 3. 深度思考区默认只接收真 `reasoning_text`; 4. 确认卡片逻辑保持兼容。 ### 里程碑 3:兼容层收敛 - 目标:确认稳定后去除伪思考降级写法。 - 开工清单: 1. 关闭后端状态写入 `reasoning_content`; 2. 清理前端旧降级路径; 3. 补齐回归用例与文档。 ## 10. 风险与应对 - 风险 1:前端未及时消费 `extra.kind`,导致状态缺失。 - 应对策略:后端先双写一段窗口期(可配置开关),灰度切换。 - 风险 2:工具事件顺序乱序导致 UI 折叠状态错位。 - 应对策略:使用 `block_id + tool.name + stage` 做关联键,按到达顺序幂等更新。 - 风险 3:历史会话与新会话混合展示不一致。 - 应对策略:仅对新流式消息生效,历史消息维持只读展示。 ## 11. 验证与回滚 - 验证方式: 1. 后端单测:事件序列与 payload 结构校验; 2. 前端联调:`tool_call -> tool_result -> summary` 顺序回放; 3. 手工场景:普通问答 / 工具调用 / confirm / tool_blocked。 - 成功判定标准: 1. 状态类文本不再出现在“深度思考区”; 2. 工具事件能稳定渲染为折叠行; 3. confirm 卡片行为不回归。 - 回滚方案: - 后端切回“状态写 reasoning_content + 旧前端渲染”兼容模式; - 前端保留旧路径开关,必要时回退版本。 ## 12. 后续计划 - 后续优化项 1:把 speak 也统一到更细粒度真流式事件头(下一轮决策)。 - 后续优化项 2:工具详情文案模板化(通俗中文 + 可本地化)。 - 后续优化项 3:工具事件接入埋点(点击展开率、阅读停留、错误率)。 ## 13. 复盘结论(上线后补充) - 实际效果:待补充 - 与预期偏差:待补充 - 后续是否需要二次决策:待补充