Messages(Anthropic 格式)
/v1/messages 与 count_tokens:用 Anthropic SDK 或 Claude Code 接入,以及它和对话补全不一样的地方。
更新于 2026-10-06约 12 分钟读完
httpPOST https://api.scirouter.cn/v1/messages
POST https://api.scirouter.cn/v1/messages/count_tokens请求与响应是 Anthropic Messages API 的形状。Anthropic SDK、Claude Code 这类按 Anthropic 格式发请求的客户端,换掉 base URL 和 Key 就能用; 平台上的对话模型都能这样调,不限于 Claude——背后线路不是 Anthropic 协议的,网关会替你转换(见下文「请求怎么到上游」)。
接入
#Anthropic SDK 与 Claude Code 会自己在 base URL 后面拼 /v1/messages,所以 base URL 写到域名为止,不带 /v1:
把 https://api.scirouter.cn/v1 末尾的 /v1 去掉。Key 就是控制台新建的那一把(见认证与 API Key)。
Python:
pythonimport os
import anthropic
client = anthropic.Anthropic(
api_key=os.environ["SCIROUTER_API_KEY"],
base_url="https://api.scirouter.cn/v1".removesuffix("/v1"), # SDK 自己会拼 /v1/messages
)
msg = client.messages.create(
model="YOUR_MODEL_ID",
max_tokens=1024,
messages=[{"role": "user", "content": "这段序列的二级结构倾向?"}],
)
print(msg.content)TypeScript:
tsimport Anthropic from '@anthropic-ai/sdk'
const client = new Anthropic({
apiKey: process.env.SCIROUTER_API_KEY,
baseURL: 'https://api.scirouter.cn/v1'.replace(/\/v1$/, ''),
})
const msg = await client.messages.create({
model: 'YOUR_MODEL_ID',
max_tokens: 1024,
messages: [{ role: 'user', content: '这段序列的二级结构倾向?' }],
})curl(anthropic-version 可以不带,转发给 Anthropic 协议的上游时默认 2023-06-01):
bashcurl https://api.scirouter.cn/v1/messages \
-H "x-api-key: $SCIROUTER_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "YOUR_MODEL_ID",
"max_tokens": 1024,
"messages": [{"role": "user", "content": "这段序列的二级结构倾向?"}]
}'x-api-key 与 Authorization: Bearer 两种写法都认;两个都带时必须是同一把 Key,否则 401 unauthenticated。
Authorization: Bearer 后面是空的,等于没带这个头。
Claude Code
#bashexport SCIROUTER_GATEWAY="https://api.scirouter.cn/v1"
export ANTHROPIC_BASE_URL="${SCIROUTER_GATEWAY%/v1}" # 去掉末尾的 /v1
export ANTHROPIC_AUTH_TOKEN="$SCIROUTER_API_KEY" # 以 Authorization: Bearer 发送
export ANTHROPIC_MODEL="YOUR_MODEL_ID"
export ANTHROPIC_DEFAULT_HAIKU_MODEL="YOUR_MODEL_ID" # 后台小任务用的模型,也要换成平台上的
export CLAUDE_CODE_MAX_OUTPUT_TOKENS=8192 # 写所选模型的输出上限,Claude Code 才按真实上限规划
claude- Key 设一个变量就够:
ANTHROPIC_AUTH_TOKEN(发Authorization: Bearer)或ANTHROPIC_API_KEY(发x-api-key)。变量名是 Claude Code 定的,值填你在 SciRouter 控制台创建的 API Key(sk-sr-开头),不是 Anthropic 官方的 Key。两个都设、却不是同一把 Key 的请求会被 401 拒绝; 其中一个是空串(发出空的Authorization: Bearer)没关系,按没带处理。 - 输出上限:Claude Code 不认识平台的模型 id 时,默认每次要 32000 个输出 token。超过模型或套餐的单次上限时,平台按上限发出(不报错),
响应头
X-SciRouter-Max-Tokens-Clamped(如requested=32000; effective=8192; limit=model)与扩展块的scirouter.max_tokens_clamped写明请求值、 实际发出的值与是哪一道上限;回答写到上限时stop_reason是max_tokens,和厂商自己截断时一样。想让 Claude Code 按真实上限规划, 用CLAUDE_CODE_MAX_OUTPUT_TOKENS设成模型的上限,上限在模型中心的详情页里。用/model切换 sonnet / opus 时, 还要设ANTHROPIC_DEFAULT_SONNET_MODEL、ANTHROPIC_DEFAULT_OPUS_MODEL。 - WebSearch 用不了:它是厂商的服务端工具,平台暂不支持(400,
details.reason为server_tool_unsupported)。 - 模型列表:设了
CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY=1时,Claude Code 启动时取一次平台的模型列表放进/model,但它只留 id 里带claude或anthropic的; 其余模型用ANTHROPIC_MODEL直接写平台的模型 id。 - 上下文窗口:Claude Code 不认识的模型 id 一律按 20 万 token 算何时压缩对话。所选模型的窗口更小时,按 Claude Code 文档在它的模型配置里写明真实窗口, 否则对话长了会撞上模型的上限。
- 背后是别家的 Anthropic 兼容接口时:Claude Code 发的是 Claude 官方接口认的全套字段(
thinking的adaptive、对话中途的system消息、context_management、output_config),这类线路原样转发,厂商不认就会 400。前几样 Claude Code 会自己去掉后重试;context_management不会, 遇到 400context_management: Extra inputs are not permitted时设CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1。转换走法(OpenAI 等协议的线路)不受影响。
请求
#| 字段 | 必填 | 说明 |
|---|---|---|
model | 是 | 平台的模型 id;也可以写后台给这个模型配的别名(例如厂商官方的模型名),名字末尾带 -YYYYMMDD 日期时会去掉日期再找。响应里的 model 是解析后的平台 id |
max_tokens | 是 | 正整数。超过模型或套餐的单次输出上限时按上限发出,并在响应头 X-SciRouter-Max-Tokens-Clamped 与 scirouter.max_tokens_clamped 里写明(不会悄悄截短);这时 thinking.budget_tokens 若不再小于发出的值,一并降到它减 1(厂商要求思考预算小于 max_tokens)。对话补全的 max_tokens 超限仍是 400 |
messages | 是 | 不能为空。role 可以是 user、assistant,以及对话中途的 system(Claude Code 每个请求都有一条) |
stream | 否 | true 时流式,见下文 |
tools | 否 | 自定义工具照常用。厂商的服务端工具(web_search_*、web_fetch_*、code_execution_*、tool_search_tool_*、mcp_toolset)与 mcp_servers、container 暂不支持:400 validation_failed,details.reason 为 server_tool_unsupported |
metadata | 否 | 不转给上游 |
| 其他字段 | 否 | 按线路处理,见下一节 |
请求体上限 32 MB(整段对话加截图常常超过对话补全的 4 MB),超过 413 payload_too_large。
请求怎么到上游
#- 模型背后是 Anthropic 协议的线路:请求原样转发,只改几处——
model换成上游的名字、去掉metadata、max_tokens写生效值、 按平台的提示词缓存策略处理cache_control断点、去掉签名为空的思考块(它们来自别家模型的思考过程,厂商会因签名无效拒绝整个请求)。 厂商自定义参数、思考块与签名、文档块、anthropic-beta都会到达上游,响应也原样带回。 「原样」说的是请求的格式与字段:鉴权、计费、限额与选线路照旧由平台做,发给厂商的x-api-key是平台在那家的凭据,你的 SciRouter Key 不会到达厂商。 - 其他协议的线路(OpenAI、Gemini 等):网关把请求转成 OpenAI 格式再调,结果再转回 Anthropic 的形状。只有对得上的字段会留下,
能转换的内容块是
text、image、tool_use、tool_result、thinking、redacted_thinking:工具结果里的图片挪进紧随的用户消息(前面标注来自哪个工具调用), 对话中途的system消息就地成为一条 system 消息,system第一块若是 Claude Code 的归因块(x-anthropic-billing-header: …)则去掉(Anthropic 的接口同样去掉它); 思考块、cache_control断点与thinking、top_k、speed这类 Anthropic 特有参数不带过去;output_format/output_config.format的 JSON Schema 转成response_format;发给 OpenAI 官方时输出上限写max_completion_tokens。字段对照见多厂商差异。 转回来的响应与原生的几处差别:流式的message_start.usage为 0,真实用量在message_delta.usage;工具调用在流的末尾整块发出(参数完整); 命中停止序列时stop_reason是end_turn、stop_sequence为 null(OpenAI 不报告命中的是哪一条);上游给出 Anthropic 没有的结束原因时原样写进stop_reason(如insufficient_system_resource),不当成正常结束。 - 请求里有只能原样转发的内容(
document、search_result、工具结果里的文档、context_management——只清思考块的编辑除外,转换走法本来就不带思考块——、非 JSON Schema 的输出格式):只走 Anthropic 协议的线路; 这个模型没有这种线路时返回 503model_unavailable,details.reason为no_capable_endpoint,details.unsupported_content列出是哪些内容 (如["block:document"])——平台不会丢掉它们再作答。
响应
#非流式:
json{
"id": "msg_…",
"type": "message",
"role": "assistant",
"model": "YOUR_MODEL_ID",
"content": [{ "type": "text", "text": "…" }],
"stop_reason": "end_turn",
"usage": { "input_tokens": 42, "output_tokens": 318 },
"scirouter": { "request_id": "req_…", "attempts": 1, "cost_quota": 18240, "…": "…" }
}顶层的 scirouter 是平台的扩展块,内容与对话补全里的相同,SDK 会忽略它。一次调用扣了多少配额看 scirouter.cost_quota。
流式("stream": true)按 Anthropic 的事件发:每条带 event: 行,事件与 Anthropic 的相同(message_start、content_block_delta……message_stop)。和对话补全的流不一样的地方:
- 没有
data: [DONE],流以message_stop结束。平台把message_stop扣到结算之后再发,里面多一个scirouter字段(含这次的cost_quota); - 开始输出之后才出错时,发一个
event: error事件(内容是下文的错误体),然后断开。没收到message_stop就结束的流,一律按失败处理; - 流里会有以
:开头的心跳注释行,SDK 会忽略。
非流式请求最长约 300 秒,回答可能很长时用流式(见 SDK 与框架「重试与超时」)。
错误
#/messages 与 /messages/count_tokens 的错误是 Anthropic 的形状,连鉴权失败、路径或方法写错(404 / 405)也是:
json{
"type": "error",
"error": {
"type": "rate_limit_error",
"message": "请求过于频繁,请稍后再试",
"code": "rate_limited",
"details": { "retry_after_seconds": 12 }
},
"request_id": "req_88a1"
}状态码与对话补全逐码相同,error.code 也是同一套小写的码;error.type 按状态码给。按 code 分支,对照见错误码。
计价参数与模型变体
#有些参数会让厂商按另一档单价收费。哪些参数算由平台配置,目前是 Anthropic 协议线路上的 speed(取 standard 以外的值)、inference_geo
与 service_tier(取 auto、standard_only 以外的值);模型只有其他协议的线路时这些参数本来就带不过去,不检查。请求里带了它们时:
- 平台上架了覆盖这些参数的模型变体(id 形如
厂商/模型名:fast):自动改走变体,按变体的价格结算,响应里的model是变体的 id, 响应头X-SciRouter-Variant-Switch写触发的参数(逗号分隔); - 没有对应的变体:400
validation_failed,details.reason为price_param_unsupported,details.params列出参数。
也可以直接把 model 写成变体的 id,或在别名后面加后缀(别名:fast)。
某个模型有哪些变体、各自强制什么参数、哪种格式会自动改走,看模型中心的详情页或 GET /models 扩展段里的
variant_params 与 variant_switch_formats(见模型列表)。对话补全(OpenAI 格式)默认只记录、不改走。
统计 token:count_tokens
bashcurl https://api.scirouter.cn/v1/messages/count_tokens \
-H "x-api-key: $SCIROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "YOUR_MODEL_ID",
"messages": [{"role": "user", "content": "这段序列的二级结构倾向?"}]
}'json{
"input_tokens": 1834,
"scirouter": { "model": "YOUR_MODEL_ID", "estimated": false, "request_id": "req_…" }
}- 请求体与
/messages相同,不用写max_tokens; - 模型解析与授权和真正调用时一样,算一次每分钟请求数;不计费,不进请求日志;
- 模型有可用的 Anthropic 协议线路时由厂商计数;没有、厂商 5 秒内没回或报错时由平台估算(同一条线路出故障后约 1 分钟内直接估算),
scirouter.estimated为true。
模型列表
#GET /models 与 GET /models/{id} 带了 anthropic-version 请求头时,按 Anthropic 的形状返回(Claude Code 和 Anthropic SDK 列模型时会带):
json{
"data": [{ "type": "model", "id": "YOUR_MODEL_ID", "display_name": "…", "created_at": "2026-09-01T00:00:00Z" }],
"has_more": false,
"first_id": "YOUR_MODEL_ID",
"last_id": "YOUR_MODEL_ID"
}一次给全,has_more 恒为 false;查单个模型时也认别名。不带这个头时是 OpenAI 的形状,见模型列表。
请求头与响应头
#| 头 | 方向 | 说明 |
|---|---|---|
x-api-key | 请求 | 带 Key 的另一种写法,见上文 |
anthropic-version | 请求 | 透传给 Anthropic 协议的上游;不带时默认 2023-06-01。在 /models 上它决定返回哪种形状 |
anthropic-beta | 请求 | 可以写多个头或逗号分隔,透传给 Anthropic 协议的上游 |
anthropic-dangerous-direct-browser-access | 请求 | Anthropic SDK 在浏览器里直连时带的头,网关的跨源预检放行它。但 Key 不要放进浏览器(见认证与 API Key) |
request-id | 响应 | 与 X-Request-Id 同一个值,Anthropic SDK 读这个名字;每个响应都带,含鉴权与请求体校验失败的 |
X-SciRouter-Variant-Switch | 响应 | 这次请求被自动改走了模型变体,值是触发的参数,见上文 |
X-SciRouter-Max-Tokens-Clamped | 响应 | max_tokens 超过模型或套餐的单次上限、按上限发出时出现,形如 requested=32000; effective=8192; limit=model(limit 为 model 或 plan),见上文 |
x-should-retry | 响应 | 值为 false 时这次错误重试不会好(不带 Retry-After 的 503,见错误码):Anthropic SDK 与 Claude Code 看到它就不再自动重试 |
其余 X-SciRouter-*、x-ratelimit-* 头与对话补全相同,见可观测性。
缓存、幂等与重试
#Idempotency-Key 与平台响应缓存的规则和对话补全相同,见缓存与幂等。
Anthropic SDK 默认也会自动重试 429 与 5xx,同样不看 error.code,但会先看 x-should-retry:平台知道重试没用的 503 带 x-should-retry: false,SDK 与 Claude Code 就不再重试。哪些值得重试见错误码。