Skip to content

[BUG] 流式节点未正常完成时,下一轮对话消息序列结构错乱(导致LLM 拒绝请求) #25

Closed

Description

Activity

  1. added this to the 2.2.0 milestone on Aug 29, 2026
  2. zeng-bohan commented on Sep 4, 2026

    @zeng-bohan
    Contributor

    在本仓 main 用离线桩模型(ReactAgent + 单工具 + MemorySaver + stub 流式模型)复现确认了这个 bug 依然存在,并补了一个可离线运行的回归测试:

    复现:订阅 streamMessages 后在流式过程中 dispose(),检查 checkpoint:

    • 完整跑完的流:USER -> ASSISTANT(tool_call) -> TOOL(toolResponse) -> ASSISTANT(final) — 合法;
    • 中途取消的流:checkpoint 停在 USER -> ASSISTANT(tool_call) — 悬空的 tool_call,下一轮拼接 user 后同样会被 LLM API 拒绝(assistant tool_calls 后必须紧跟 tool 消息)。

    与本报告观察到的「toolResponse 已落库但 assistant 缺失」是同一类问题的两个变体:取消信号让一个多步 turn 只持久化了一半。

    根因(与报告分析一致):NodeExecutor.processGraphResponseFlux 的尾部 processedFlux.concatWith(updateContextMono.thenMany(...)) —— 状态合并与 buildNodeOutputAndAddCheckpoint 完全依赖下游订阅拉动,取消即跳过;而嵌套异步路径上后续 tool 节点的落库与之不同步。

    修复方向(倾向 A,欢迎反馈):

    • A. turn 边界回滚:运行开始时快照进入本 turn 前的状态,取消时把 checkpoint 回写为该快照。语义干净——「取消的 turn 视为未发生」,天然覆盖悬空 tool_call 与孤儿 toolResponse 两个变体;
    • B. 取消时补完在途节点的持久化(salvage):实现最小,但实测会留下悬空 tool_call,覆盖不全;
    • C. 加载侧序列清洗:能救历史脏数据,但治标。

    确认方向后我提交带回归测试的 PR。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions