Skip to content

任务会话把「截断的 tool call」写入历史后,每次点「继续」都被上游 400 拒绝并静默回到待审阅 #538

Description

@pia

项目:codeg(桌面端 · 待办任务 · ACP + Codex CLI)
严重度:高(任务空转、无输出、无报错,用户无法自行恢复)
影响模块:工作区任务引擎、ACP 会话持久化、模型网关转发

问题描述

在上下文很大的待办任务里,模型偶发地生成一条「写到一半」的工具调用(function_call 的 arguments 不是合法 JSON)。Codex CLI 解析失败后,把这条坏记录连同「解析失败」的结果一起写进了会话历史。此后每次在该任务点击「继续」,完整历史都会被原样重发给模型接口,上游因 Assistant tool call function.arguments must be valid JSON 返回 400,本地网关把 400 包装成 502,客户端把任务静默置回「待审阅」——没有产出,界面上也看不到真实错误。用户反复点「继续」都会同样失败(本机观察到的现象是约 5~6 秒内空转后回到 review)。

复现特征 / 触发条件

  • 待办任务经过多轮反馈,上下文非常大(本案例约 50 万+ token,第 9~12 轮)
  • 模型生成的是超长工具调用(多为 shell_command,命令内嵌大段文本 / heredoc),输出中途被截断
  • 第一次断掉后,后续每一轮都稳定失败,失败轮次没有任何 diff 或消息产出
  • 会话 JSONL 中存在 arguments 无法被 json.loads 解析的 function_call(报错形如 Unterminated string starting at ... / EOF while parsing a string

根因分析

  1. 模型输出被截断(疑似命中单次输出长度上限或上游流中断),产出的 function_call.arguments 不是合法 JSON;客户端解析失败,记录 failed to parse function arguments: EOF while parsing a string ...
  2. 客户端把这条坏 function_call 连同它的「解析失败」output 一起持久化进会话历史(rollout JSONL)
  3. 之后每次 resume / 点「继续」,完整历史(含这条坏记录)被重新提交给模型 API;上游严格校验每条 assistant tool call 的 arguments 必须是合法 JSON,返回 400
  4. 本地网关把上游 400 转成 HTTP 502;客户端统一按失败处理,任务引擎静默归为 review,不落 failure_reason / last_error,用户看不到真实原因

期望行为

  • 会话历史在持久化或下一次提交前,对无法解析的 function_call 做清洗(丢弃该条及其 output,或修复 / 重新生成),避免坏记录永远卡死后续轮次
  • 单轮内若模型产出无法解析 arguments 的 tool call,客户端应主动重试一次让模型重新生成,而不是直接落历史
  • 任务轮次失败时,必须把真实错误(上游 400 的具体 message)写入任务并向用户展示,不能静默回到待审阅
  • 网关转发失败时透传上游状态码与错误体,不要统一升级成 502、丢失真实原因

建议方案

  1. 会话历史加载 / 追加时做合法性校验:function_call.arguments 非合法 JSON 的项(及其对应 output)从后续请求输入中剔除
  2. 对解析失败的 tool call 触发一次修复重试(让模型重新生成该调用)
  3. 失败路径透传:work_task 记录 failure_reason / last_error 为上游原文(如 Assistant tool call function.arguments must be valid JSON.),并在 UI 展示
  4. 网关 forward_failed 保留上游 status / message,避免 400 → 502 的信息丢失

诊断样例(本机已复现两次)

  • 客户端:unexpected status 502 Bad Gateway: Upstream request failed, url: http://localhost:8080/responses
  • 网关:openai.forward_failed ... error="upstream error: 400 message=Error from provider (Console Go): Upstream request failed: [400] Assistant tool call function.arguments must be valid JSON."
  • 会话历史:一条截断的 shell_command(如 python -m pytest ... 或内嵌文档 heredoc),解析报 Unterminated string starting at: line 1 column ...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions