问题描述
当客户端使用标准的 Claude Code CLI 调用 Anthropic 的 /v1/messages/count_tokens (计算 Token 数) 端点,且匹配到的供应商配置了客户端限制规则(例如允许客户端开启了 claude-code 或 claude-code-cli)时,请求会被拒绝并返回 503 Service Unavailable (no_available_providers),供应商原因提示为 client_restriction。
根源分析
-
客户端精确检测逻辑 (confirmClaudeCodeSignals)
在 src/app/v1/_lib/proxy/client-detector.ts 中,confirmClaudeCodeSignals(session) 要求必须同时收集到以下 4 个信号 才会设置 confirmed = true(确认属于 Claude Code 客户端):
x-app-cli (x-app: cli Header)
ua-prefix (User-Agent: claude-cli/... Header)
betas-present (anthropic-beta Header)
metadata-user-id (Body 中存在 request.message.metadata.user_id)
-
count_tokens 端点行为
Anthropic 规范和 CLI 实际实现中,POST /v1/messages/count_tokens 的请求 Payload 仅包含 model, messages, system, tools, thinking 等字段,不会也不应该包含 metadata 或 metadata.user_id。
-
误判过程
- 对于
count_tokens 请求,CCH 只能收集到前 3 个 Header 信号,缺少第 4 个 metadata-user-id 信号。
confirmClaudeCodeSignals 判定 signals.length === 3 !== 4,导致 claudeCode.confirmed = false。
- 供应商在检查客户端限制时,
matchClientPattern(session, "claude-code") 返回 false,判定为 allowlist_miss,记录 reason: "client_restriction" 并剔除该供应商。
- 若匹配的模型仅有该 Claude 供应商可用,请求最终报错
503 Service Unavailable (no_available_providers)。
客户端请求与响应示例 (已脱敏)
HTTP Request:
POST /v1/messages/count_tokens?beta=true HTTP/1.1
Accept: application/json
Authorization: Bearer sk-***
Content-Type: application/json
User-Agent: claude-cli/2.1.220 (external, cli)
X-Claude-Code-Session-Id: e08f04cb-****-****-****-************
anthropic-beta: claude-code-20250219,interleaved-thinking-2025-05-14,context-management-2025-06-27,token-counting-2024-11-01
anthropic-dangerous-direct-browser-access: true
anthropic-version: 2023-06-01
x-app: cli
Host: cch.example.com
{"model":"claude-opus-5","messages":[{"role":"user","content":"..."}]}
HTTP Response:
HTTP/1.1 503 Service Unavailable
Server: nginx
Content-Type: application/json; charset=utf-8
{
"error": {
"message": "No available providers (cch_session_id: sess_****)",
"type": "no_available_providers",
"code": "no_available_providers",
"details": {
"totalAttempts": 1,
"excludedCount": 0,
"filteredProviders": [
{ "id": 124, "reason": "client_restriction" },
{ "id": 119, "reason": "format_type_mismatch" }
],
"clientRestrictedProviders": [
{ "id": 124, "reason": "client_restriction" }
]
}
}
}
建议解决方案
在 src/app/v1/_lib/proxy/client-detector.ts 中:
- 识别请求端点是否为
count_tokens(或非对话端点)。
- 如果是
count_tokens 请求且前 3 个 Header 信号(x-app-cli + ua-prefix + betas-present)均满足,或允许在缺少 metadata.user_id 时进行合理的适配判定,避免误判。
问题描述
当客户端使用标准的 Claude Code CLI 调用 Anthropic 的
/v1/messages/count_tokens(计算 Token 数) 端点,且匹配到的供应商配置了客户端限制规则(例如允许客户端开启了claude-code或claude-code-cli)时,请求会被拒绝并返回503 Service Unavailable (no_available_providers),供应商原因提示为client_restriction。根源分析
客户端精确检测逻辑 (
confirmClaudeCodeSignals)在
src/app/v1/_lib/proxy/client-detector.ts中,confirmClaudeCodeSignals(session)要求必须同时收集到以下 4 个信号 才会设置confirmed = true(确认属于 Claude Code 客户端):x-app-cli(x-app: cliHeader)ua-prefix(User-Agent: claude-cli/...Header)betas-present(anthropic-betaHeader)metadata-user-id(Body 中存在request.message.metadata.user_id)count_tokens端点行为Anthropic 规范和 CLI 实际实现中,
POST /v1/messages/count_tokens的请求 Payload 仅包含model,messages,system,tools,thinking等字段,不会也不应该包含metadata或metadata.user_id。误判过程
count_tokens请求,CCH 只能收集到前 3 个 Header 信号,缺少第 4 个metadata-user-id信号。confirmClaudeCodeSignals判定signals.length === 3 !== 4,导致claudeCode.confirmed = false。matchClientPattern(session, "claude-code")返回false,判定为allowlist_miss,记录reason: "client_restriction"并剔除该供应商。503 Service Unavailable (no_available_providers)。客户端请求与响应示例 (已脱敏)
HTTP Request:
HTTP Response:
建议解决方案
在
src/app/v1/_lib/proxy/client-detector.ts中:count_tokens(或非对话端点)。count_tokens请求且前 3 个 Header 信号(x-app-cli+ua-prefix+betas-present)均满足,或允许在缺少metadata.user_id时进行合理的适配判定,避免误判。