Skip to content

[Bug] 思考模式 max 下请求体静默从 Responses 回落为 Chat Completions 且回传空 reasoning_content,网关 400 reasoning_text(retryable=false,整轮失败) #676

Description

@wezhouji1-art

类型 / Type

Bug(偶发 / intermittent)。思考模式(thought level = max)下,会话中途请求体从 Responses 形态静默回落到 Chat Completions 形态,且历史助手消息携带空字符串 reasoning_content,被网关以 400 拒收,整轮失败且不可重试。

环境 / Environment

  • 系统:Windows 10 x64 10.0.19045;ZCode 桌面端 v3.11.2user-agent: ZCode/3.11.2x-zcode-app-version: 3.11.2x-title: Z Code@electron,production 通道)
  • Provider:自定义 OpenAI 兼容providerKind: openai),baseURL https://api.bankofai.io/v1(one-api / new-api 类中转网关),声明 apiFormat: openai-responses,paths.openai = /responses
  • 模型:deepseek-v4.1-flash;思考档位 maxthinking: {type: enabled}reasoningEffort: max
  • 会话形态:主链会话(x-zcode-session-type: main),querySource: main_turn,工具调用密集的长任务(该轮请求体 50 条消息 / 25 次 tool-call)

现象 / Symptom

界面弹出错误:「Turn execution failed / provider_code=invalid_request_error / model=deepseek-v4.1-flash / status=400 / retryable=false」,完整报文为:

The `reasoning_text` in the thinking mode must be passed back to the API.
  • TraceID:00f83c03-746e-4528-94d0-ec966278e581
  • 客户端 requestId:cccf80b9-ea16-47a7-bc5b-471bd81818ca
  • 网关侧 request-id(响应头 x-oneapi-request-id):20260916144416867069803c955d568e70zkCcj
  • 日志定位:~/.zcode/cli/log/zcode-2026-09-16.jsonl 事件 model.request.failed / model.network.failedreason: invalid_request, retryable: false, canRetry: false, statusCode: 400)→ turn.failed

关键证据:请求体形态在会话中途被切换 / Evidence

对比留存于 ~/.zcode/cli/rollout/model-io-*.jsonl 的请求记录(本地时间 2026-09-16 22:43–22:44,UTC 14:43–14:44):

记录 时间 (UTC) body 形态 结果
前一条 14:43:44 input(Responses) 200 成功
失败条 14:44:15 messages(Chat Completions) 400 失败
后一条 14:45:29 input(Responses) 200 成功

该会话全部请求记录中,唯一一次 Chat Completions 形态的请求就是失败这一条;同一时段另两个并行会话(共 90 条请求记录)全部为 Responses 形态、零失败。当天全部请求记录合计 139 条,Chat Completions 形态仅此 1 条。

失败请求体的关键特征(同时具备三处异常):

  1. 顶层字段从 Responses 的 input 变成 Chat Completions 的 messages
  2. 全部 18 条历史助手消息都被写入 providerOptions.openaiCompatible.reasoning_content = ""空字符串,一条不落);
  3. 请求体附带 bodySource: "ai_sdk_options"experimental_include: {requestBody: true, responseBody: true}stream: true —— 正常请求都不带这些字段。
"messages": [
  ...,
  { "role": "assistant",
    "content": [ { "type": "text", "text": "..." },
                 { "type": "tool-call", "toolCallId": "call_00_...", "toolName": "Read", "input": {...} } ],
    "providerOptions": { "openaiCompatible": { "reasoning_content": "" } } }   <-- 空串,18 条全部如此
]

对比正常(Responses)请求体:顶层为 input 数组,助手消息以 function_call / function_call_output 条目承载,完全不出现 reasoning 类字段(既不回传、也不送空串)。

排除项 / What it is NOT

  • 不是模型或账号问题:同一 provider、同一模型、同一档位的前后请求均 200 成功。
  • 不是网关故障:同一网关在失败前 30 秒与失败后 70 秒均正常返回;网关这次是正确地拒绝了不合规请求体(思考模式下必须回传思考内容)。
  • 不是请求体超限(区别于已知的 >1MB 400 案例):本次请求体 50 条消息,远未触及上限。
  • 不是 CASE-09 那类 SSE 瞬断:本次 reasoninvalid_requestretryable: false,客户端没有自动重试(retryReason: network_errorcanRetry: false),失败是确定性的,不是等自愈型。

期望行为 / Expected

  1. 会话中途不应无提示地在 Responses 与 Chat Completions 两种报文形态之间切换;若确有回退逻辑,应有显性日志/告警,并保证切换后报文仍然合规。
  2. 走 Chat Completions 形态且处于思考模式时,历史助手消息应真实回传其思考内容;若客户端拿不到思考内容,应整个省略 reasoning_content 字段,而不是送空字符串——空串在网关看来正是"该带的没带",必然 400。
  3. 若配置的 apiFormat(openai-responses)与实际发出的报文形态不一致,UI/日志应提示,而不是静默发出。

实际行为 / Actual

报文形态静默回退为 Chat Completions,历史助手消息的 reasoning_content 全为空串,网关 400 且标记不可重试 → 整个回合直接失败。用户只能看到一句报错,无从判断原因;重发一条消息(新回合)后即恢复正常(本机实测:14:45 续问,后续 20+ 次请求全部 200)。

重现步骤 / Repro(偶现,尽力描述)

  1. 配置自定义 OpenAI 兼容 provider(baseURL 指向网关,模型为 deepseek 类),思考档位置 max
  2. 在一个工具调用密集的长会话中持续推进(本机触发时该回合已累计 25 次 tool-call、上下文 50 条消息);
  3. 观察 ~/.zcode/cli/rollout/model-io-*.jsonl:偶发某一次请求的 body 从 input 变为 messages,助手消息带 reasoning_content: ""
  4. 该请求必然被网关以 400 reasoning_text ... must be passed back 拒绝,回合失败。

影响 / Impact

单次发生即导致整轮对话作废(不可重试),长任务需手动重发;由于报文形态切换无任何用户可见线索,极易误判为网关/账号故障。期望至少做到"回退后仍合规"或"送空串改为省略字段"。

相关 / Related

Activity

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions