DeepSeek V4 + Claude Code thinking mode 400 错误修复方案
DeepSeek V4 + Claude Code thinking mode 400 错误修复方案
问题描述
使用 DeepSeek V4 Pro / V4 Flash 的 thinking mode + tool calls 时,第一轮工具调用后的每次请求都返回 400 错误:
复制代码
API Error: 400 The content[].thinking in the thinking mode must be passed back to the API.
根因
复制代码
Claude Code → DeepSeek API(返回 reasoning_content / thinking 块)
↓
Claude Code 保存对话历史时丢弃非标准的 thinking 字段
↓
下一轮请求 → DeepSeek API:检测到 assistant 消息缺少 thinking 块 → 400
DeepSeek V4 要求 multi-turn 对话中,每个 role: assistant 的消息必须保留 thinking 块。Claude Code / cc-switch 在序列化历史时把它丢弃了。
解决方案
在 Claude Code 和 DeepSeek API 之间插入一个本地 Node.js 代理,自动补全被丢弃的 thinking 字段。
拓扑
复制代码
Claude Code → cc-switch → 本地代理 (127.0.0.1:15722) → api.deepseek.com
↑
注入 thinking 块
步骤
- 创建代理脚本 ds-proxy.js
js
复制代码
const http = require('http');
const { Readable } = require('stream');
const DEEPSEEK_BASE = 'https://api.deepseek.com';
const PORT = 15722;
function fixMessages(data) {
if (!data.messages && !Array.isArray(data.messages)) return;
for (const msg of data.messages) {
if (msg.role !== 'assistant') continue;
if (Array.isArray(msg.content)) {
const hasThinking = msg.content.some(b => b.type === 'thinking');
if (!hasThinking) {
msg.content.unshift({ type: 'thinking', thinking: '' });
}
} else {
msg.reasoning_content = msg.reasoning_content || '';
}
}
}
const server = http.createServer(async (req, res) => {
console.log(${req.method} ${req.url});
res.setHeader('Access-Control-Allow-Origin', '*');
if (req.method === 'OPTIONS') {
res.writeHead(204);
res.end();
return;
}
if (req.method === 'GET') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ id: 'root', object: 'list' }));
return;
}
if (req.method !== 'POST') {
res.writeHead(404);
res.end('Not Found');
return;
}
let body = '';
req.on('data', chunk => body += chunk);
req.on('end', async () => {
try {
const data = JSON.parse(body);
fixMessages(data);
const target = DEEPSEEK_BASE + req.url;
console.log('->', target);
const apiRes = await fetch(target, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': req.headers.authorization,
'anthropic-version': req.headers['anthropic-version'] || ''
},
body: JSON.stringify(data)
});
console.log('<-', apiRes.status);
const headers = {};
apiRes.headers.forEach((v, k) => { headers[k] = v; });
res.writeHead(apiRes.status, headers);
if (apiRes.body) {
Readable.fromWeb(apiRes.body).pipe(res);
} else {
res.end();
}
} catch (err) {
console.error('Proxy error:', err.message);
res.writeHead(500);
res.end(JSON.stringify({ error: 'Proxy Error: ' + err.message }));
}
});
});
server.listen(PORT, () => {
console.log('DS4 Proxy on http://127.0.0.1:' + PORT);
});
- 启动代理
powershell
复制代码
node ds-proxy.js
保持在后台运行。
- 配置 cc-switch
DeepSeek provider 的 Base URL 设为:
复制代码
http://127.0.0.1:15722/anthropic
或跳过 cc-switch,直连代理:
powershell
复制代码
$env:ANTHROPIC_BASE_URL = "http://127.0.0.1:15722/anthropic"
$env:ANTHROPIC_API_KEY = "你的DeepSeek API Key"
claude
- 重启 Claude Code
代理处理逻辑
场景 操作
Anthropic 格式(content 为数组) 在 content 最前面插入 {type:"thinking",thinking:""}
OpenAI 格式 注入 reasoning_content: ""
连通性检测(GET) 返回 {"id":"root","object":"list"} 模拟 API