问题描述
Claude Code 2.1.172 配合自定义模型名(通过 ANTHROPIC_DEFAULT_OPUS_MODEL 等指向 cchub 渠道模型,如 aws-claude-opus)使用时,请求经 cchub 转发到严格校验的上游(Vertex / Bedrock 类 Anthropic 兼容端点)会被拒绝。cchub 重试耗尽全部供应商后触发熔断,客户端最终收到:
{"statusCode": 503, "errorMessage": "所有供应商暂时不可用,请稍后重试"}
首次请求的流式响应为:
event: error
data: {"type": "error", "error": {"type": "api_error", "message": "Upstream returned an error event (request_id: ...)"}}
由于错误被包装成 api_error / 503,且重试导致熔断殃及后续请求,排查非常困难。
根因(已通过本地抓包确认)
Claude Code 2.1.172(2.1.153 之后引入的行为变化)会根据模型名是否为内置官方 Claude 模型 ID 切换 skills 列表的注入格式:
| 模型名 |
skills 注入方式 |
官方 ID(claude-opus-4-7 等) |
user 消息内 <system-reminder> 文本块(旧行为) |
任何非官方名(aws-claude-opus、甚至 claude-test-fake-9) |
messages 数组中独立的 {"role": "system", "content": "..."} 消息 |
抓包验证(同一 CC 版本、本地 HTTP 捕获服务器):
--model claude-opus-4-7 → messages roles: ['user'] ✅
--model aws-claude-opus → messages roles: ['user', 'system'] ❌
--model claude-test-fake-9 → messages roles: ['user', 'system'] ❌
Anthropic 官方 API 接受 messages 中的 role: "system",但 Vertex / Bedrock 等转换层严格校验 messages 角色只能为 user / assistant,直接返回 400 类错误("Bad request - check request format and parameters")。cchub 目前原样透传该消息,导致:
CC 2.1.172(自定义模型名)发出 role:"system" 消息
→ cchub 原样转发
→ 严格上游 400 拒绝
→ cchub 重试其余供应商全部失败
→ 熔断 → 503 "所有供应商暂时不可用"
由于同一模型可能挂多个渠道(宽容的渠道能成功),故障表现为间歇性,进一步增加排查难度。
影响范围
所有满足以下条件的用户:
- Claude Code ≥ 2.1.172(2.1.153 确认无此行为,具体引入版本未逐版定位)
- 渠道模型名为自定义命名(如
aws-claude-opus、qwen-xx、glm-xx、MiniMax-xx 等,这是 cchub 用户的常见用法)
- 上游为严格校验 messages 角色的 Anthropic 兼容端点
复现步骤
# 对任意 Vertex/Bedrock 类严格上游渠道发送:
curl -s "https://<cchub>/v1/messages" \
-H "x-api-key: $KEY" -H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "<自定义模型名>", "max_tokens": 100,
"messages": [
{"role": "user", "content": "hi"},
{"role": "system", "content": "The following skills are available: ..."}
]
}'
# → 400/503;去掉 role:"system" 那条消息后同样请求成功
或直接用 Claude Code 2.1.172 + ANTHROPIC_MODEL=<自定义模型名> 发送任意消息(只要本地启用了任意 skill/plugin 就会注入该消息)。
建议修复
参照现有 src/app/v1/_lib/proxy/billing-header-rectifier.ts 的模式(同样是处理 Claude Code 新版本注入的、上游不兼容的内容),新增一个 proactive rectifier:
- 在转发前扫描
messages,将 role: "system" 的消息取出
- 其内容合并到顶层
system 数组末尾(string content 转为 {type: "text", text} block)
- 语义上与 Anthropic 官方对该写法的处理一致,对宽容上游无副作用,对严格上游消除 400
如方案可接受,我可以提交 PR。
环境
- claude-code-hub: v0.8.5(self-hosted)
- Claude Code: 2.1.172(user-agent:
claude-cli/2.1.172 (external, cli))
- 对照版本: Claude Code 2.1.153 无此问题
问题描述
Claude Code 2.1.172 配合自定义模型名(通过
ANTHROPIC_DEFAULT_OPUS_MODEL等指向 cchub 渠道模型,如aws-claude-opus)使用时,请求经 cchub 转发到严格校验的上游(Vertex / Bedrock 类 Anthropic 兼容端点)会被拒绝。cchub 重试耗尽全部供应商后触发熔断,客户端最终收到:{"statusCode": 503, "errorMessage": "所有供应商暂时不可用,请稍后重试"}首次请求的流式响应为:
由于错误被包装成
api_error/ 503,且重试导致熔断殃及后续请求,排查非常困难。根因(已通过本地抓包确认)
Claude Code 2.1.172(2.1.153 之后引入的行为变化)会根据模型名是否为内置官方 Claude 模型 ID 切换 skills 列表的注入格式:
claude-opus-4-7等)<system-reminder>文本块(旧行为)aws-claude-opus、甚至claude-test-fake-9)messages数组中独立的{"role": "system", "content": "..."}消息抓包验证(同一 CC 版本、本地 HTTP 捕获服务器):
Anthropic 官方 API 接受 messages 中的
role: "system",但 Vertex / Bedrock 等转换层严格校验 messages 角色只能为user/assistant,直接返回 400 类错误("Bad request - check request format and parameters")。cchub 目前原样透传该消息,导致:由于同一模型可能挂多个渠道(宽容的渠道能成功),故障表现为间歇性,进一步增加排查难度。
影响范围
所有满足以下条件的用户:
aws-claude-opus、qwen-xx、glm-xx、MiniMax-xx等,这是 cchub 用户的常见用法)复现步骤
或直接用 Claude Code 2.1.172 +
ANTHROPIC_MODEL=<自定义模型名>发送任意消息(只要本地启用了任意 skill/plugin 就会注入该消息)。建议修复
参照现有
src/app/v1/_lib/proxy/billing-header-rectifier.ts的模式(同样是处理 Claude Code 新版本注入的、上游不兼容的内容),新增一个 proactive rectifier:messages,将role: "system"的消息取出system数组末尾(string content 转为{type: "text", text}block)如方案可接受,我可以提交 PR。
环境
claude-cli/2.1.172 (external, cli))