问题现象
使用 Claude Code(VSCode/Cursor 插件或 CLI)配合 DeepSeek API 时,报错:
text
API Error: 400 Failed to deserialize the JSON body into the target type:
messages[1].role: unknown variant system, expected user or assistant
claude --print 模式正常,但交互模式(IDE 插件)必现。
根本原因
Claude Code v2.1.153+ 在交互模式下,会将某些上下文指令(如 CLAUDE.md 内容、skills 注入等)以 role: "system" 的形式直接放入 messages 数组,而非 Anthropic 规范要求的顶层 system 参数。DeepSeek 的 /anthropic 兼容端点对此做了严格校验,直接拒绝。
本质上是 DeepSeek 的 Anthropic 兼容层对消息格式的容错不如官方 API。
环境变量方案(治标)
在 ~/.claude/settings.json 的 env 中添加:
json
{
"env": {
"ANTHROPIC_MODEL": "deepseek-v4-pro",
"CLAUDE_CODE_DISABLE_NON_ESSENTIAL_BETAS": "1",
"CLAUDE_CODE_BETAS": "",
"DISABLE_AUTOUPDATER": "1"
}
}
此方案通过禁用 Beta 功能来减少不兼容性,但实测不一定对所有版本/场景生效。
本地代理方案(治本,推荐)
写一个 Python 代理,拦截 Claude Code 发出的请求,自动把 messages 数组中的 system 角色消息移到顶层 system 参数,再转发给 DeepSeek。
创建代理脚本 claude_proxy.py
python
import http.server, json, urllib.request
TARGET = "https://api.deepseek.com/anthropic"
API_KEY = "你的DeepSeek-API-Key"
PORT = 9877
class Proxy(http.server.BaseHTTPRequestHandler):
def do_POST(self):
length = int(self.headers.get("Content-Length", 0))
body = self.rfile.read(length)
try:
parsed = json.loads(body)
msgs = parsed.get("messages", [])
extra, cleaned = [], []
for m in msgs:
if m.get("role") == "system":
c = m.get("content", "")
extra.append(c if isinstance(c, str)
else " ".join(x.get("text","") for x in c
if x.get("type") == "text"))
else:
cleaned.append(m)
if extra:
existing = parsed.get("system", "")
if isinstance(existing, list):
existing = " ".join(
x.get("text","") for x in existing
if x.get("type") == "text")
parsed["system"] = (existing + "\n\n" if existing else "") + "\n\n".join(extra)
parsed["messages"] = cleaned
body = json.dumps(parsed).encode()
except:
pass
url = TARGET + self.path
req = urllib.request.Request(url, data=body, method="POST")
for k, v in self.headers.items():
if k.lower() not in ("host", "content-length"):
req.add_header(k, v)
try:
resp = urllib.request.urlopen(req, timeout=60)
rbody = resp.read()
self.send_response(resp.status)
for k, v in resp.headers.items():
if k.lower() not in ("transfer-encoding", "content-length", "connection"):
self.send_header(k, v)
self.end_headers()
self.wfile.write(rbody)
except Exception as e:
self.send_response(502)
self.end_headers()
self.wfile.write(str(e).encode())
def log_message(self, f, *a):
pass
http.server.HTTPServer(("127.0.0.1", PORT), Proxy).serve_forever()
启动代理
bash
python claude_proxy.py
修改配置
修改 ~/.claude/settings.json,将 ANTHROPIC_BASE_URL 指向代理:
json
{
"env": {
"ANTHROPIC_BASE_URL": "http://localhost:9877",
"ANTHROPIC_MODEL": "deepseek-v4-pro"
}
}
重启 Claude Code 即可
开机自启(可选)
代理默认只在当前会话运行,重启电脑后会停。设为开机自启:
Win+R → 输入 shell:startup → 回车,在该文件夹新建 claude_proxy.bat:
batch
@start /min python "文件路径\claude_proxy.py"
之后每次开机代理都会自动在后台运行,无需手动启动。
如果还不行:例如你装了别的智能体
在 Cursor/VSCode 的 settings.json 中加上:
batch
{
"claudeCode.environmentVariables": [
{ "name": "CLAUDE_CODE_DISABLE_NON_ESSENTIAL_BETAS", "value": "1" },
{ "name": "CLAUDE_CODE_BETAS", "value": "" },
{ "name": "DISABLE_AUTOUPDATER", "value": "1" }
]
}
CLAUDE_CODE_DISABLE_NON_ESSENTIAL_BETAS=1 禁掉了 Claude Code 新版本自动启用的 Beta 功能(如 interleaved-thinking、prompt-caching-scope),这些 Beta 会导致请求格式与 DeepSeek 的 Anthropic 兼容代理不兼容。
注意事项
- 重启电脑后代理会自动停止,需重新启动
python claude_proxy.py - 如果 DeepSeek 后续修复了兼容性问题,可去掉代理恢复直连
- 建议同时设置
DISABLE_AUTOUPDATER=1防止 Claude Code 自动升级引入新的不兼容