Skip to content

DeepSeek 思考模式多轮对话报 reasoning_content 错误

问题

使用 DeepSeek v4 系列模型并开启思考模式(thinking: {type: "enabled"}interleaved)时,第一轮对话正常,从第二轮开始报错:

The `reasoning_content` in the thinking mode must be passed back to the API.

报错后会话卡死,无法继续对话。涉及模型:deepseek-v4-prodeepseek-v4-flash 等。

原因

DeepSeek API 要求对话历史中所有 assistant 消息都必须包含 reasoning_content 字段(即使为空字符串)。OpenCode 在将历史消息回传时,涉及工具调用的助手消息被 normalizeMessages() 中的条件跳过,导致 reasoning_content 丢失。

解决方案

临时绕过

等待官方 patch。可以关注 PR/修复进度

社区临时修复(fork 分支)

社区用户 fkyah3 提供了修复分支,已有用户验证有效:

仓库:fkyah3/opencode-fkyah3
分支:fix/permission-reasoning-truncation
关键文件:packages/opencode/src/provider/transform.ts

修复思路:将 hasReasoningContent 检查从只覆盖 interleaved 模型扩展为所有带 capabilities.reasoning 的模型,同时移除了跳过历史回放中 assistant 消息的窄条件。

配置层绕过

如果不方便编译 fork,可以临时禁用思考模式:

jsonc
// opencode.json
{
  "model": "opencode/deepseek-v4-pro",
  "modelConfig": {
    "thinking": { "type": "disabled" }
  }
}

关闭思考模式后多轮对话恢复正常,但会失去 Chain-of-Thought 推理能力。

来源:GitHub #24104

社区补充方法

transformRequestBody 手动补全缺失字段(#24122)

社区用户 AutumnSun1996 提供了一种更通用的 workaround,通过 transformRequestBody 钩子在请求发出前补全缺失字段,兼容工具调用场景:

javascript
// 在自定义 provider 的 options 中添加:
transformRequestBody: (body) => {
  if (body.messages) {
    for (const msg of body.messages) {
      if (msg.role === 'assistant') {
        if (msg.tool_calls && msg.tool_calls.length > 0) {
          if (!msg.content) msg.content = 'call tool';
          if (!msg.reasoning_content) msg.reasoning_content = 'call tool';
        } else {
          if (!msg.content) msg.content = '';
          if (!msg.reasoning_content) msg.reasoning_content = '';
        }
      }
    }
  }
  return body;
}

这个方法比 fork 分支更轻量,不需要重新编译,适合等待官方 patch 期间的临时应对。

补充来源:GitHub #24122