Agent-snapshot-text-重复拼接根因

## 1. 问题背景

by 于成季 ·
知与行 CloudBase

1. 问题背景

Case 001 测试发现:confirm 两轮流程跑通后,snapshot_text_join(events) 返回的内容重复了 3 次:

[工具成功] create_insight\n{"success": true, ...}\n✅ 感悟已保存!\n[工具成功] create_insight\n{"success": true, ...}\n✅ 感悟已保存!\n[工具成功] create_insight\n{"success": true, ...}\n✅ 感悟已保存!

实际 SSE 中 MESSAGES_SNAPSHOT 只有 1 条、最终文本正确,但 snapshot_text_join 拼接了多个 STATE_SNAPSHOT 导致重复。

2. 问题列表

2.1 snapshot_text_join 遍历所有 STATE_SNAPSHOT 导致内容重复

根因(链式证据):

  • why1(直接):snapshot_text_joinfor ev in events 遍历所有 STATE_SNAPSHOT 事件,将每条消息 content 拼接到 parts 列表。
  • why2(机制):confirm 流程经历 intent_recognition → execute_tools → finalize → END,LangGraph SDK 在每个节点出口都会打一次 STATE_SNAPSHOT(共 4 个)。
  • why3(触发点):SDK 源码 ag_ui_langgraph_patch.py:566-576:节点切换且状态有差异时触发 STATE_SNAPSHOT;ag_ui_langgraph_patch.py:614-615:END 后额外打一次最终快照。
  • why4(内容相同):4 个快照中前 3 个 messages 逐条递增(0 → 1 → 2),最后一个与第三个内容完全相同。遍历全部导致同一文本出现多次。

方案

  • 短期方案:只取最后一个 STATE_SNAPSHOT 的消息内容。snap = snaps[-1].get("snapshot"),加 docstring 说明"过程中会产生多个 STATE_SNAPSHOT"。
  • 长远方案:重新设计 SSE 事件结构,由 SDK 提供唯一最终快照事件,而非依赖客户端过滤。

采纳方案

sse_util.pysnapshot_text_join 改为取 snaps[-1](最后一个 STATE_SNAPSHOT),并补充 docstring 说明原因。

2.2 测试未覆盖 SSE 事件数量场景

根因

测试用例 test_create_insight_two_round 断言了 TOOL_CALL_RESULT 存在和最终文本非空,但未验证 snapshot_text_join 的返回格式正确性,无法发现重复拼接问题。

方案

  • 短期方案:直接修复 snapshot_text_join 实现,对齐正确行为。
  • 长远方案:增加 SSE 事件结构层面的断言(如 MESSAGES_SNAPSHOT 唯一性)。

补充用例

现有用例已足够覆盖(修复后再次运行 test_create_insight_two_round 通过)。

3. 小结

  • 核心修复snapshot_text_join 只取最后一个 STATE_SNAPSHOT,避免多快照拼接导致内容重复。
  • 根因理解:LangGraph confirm 流程产生多节点 STATE_SNAPSHOT 是正常行为(每步出口各一 + END 后最终快照),客户端必须正确取最终快照而非遍历全部。
  • 参考tests/sse_util.pycloudbase_agent/langgraph/ag_ui_langgraph_patch.py
← 所有文章