Anthropic 格式

根据对话历史生成模型回答,支持流式、图片输入和工具调用。兼容 Anthropic Messages API:系统提示词放在 system,对话放在由内容块组成的 messages,响应的 content 也是内容块数组;Anthropic 官方 SDK 和 Claude Code 等 Anthropic 协议客户端,把 Base URL 设为网关根地址 https://api.lyrouter.com 即可接入。网关会在 Messages 与上游协议之间转换,所以这个接口除了 Claude 系列,也能调用平台上的其他对话模型。

POST/v1/messages

鉴权

在请求头中携带 API Key,以下两种写法任选其一:

x-api-key: <API Key>
Authorization: Bearer <API Key>

两者同时存在时只读取 Authorization,Bearer 区分大小写。Anthropic SDK 的 api_key 参数发送 x-api-key,auth_token 参数发送 Authorization: Bearer;Claude Code 的 ANTHROPIC_AUTH_TOKEN 用的是后者。API Key 在工作空间的 API 密钥 页面创建,只用于 LYRouter 鉴权,不会转发给上游服务商。完整说明见接入地址与鉴权。

Anthropic SDK 和 Claude Code 会自己拼接 /v1/messages,Base URL 不要再带 /v1,否则请求路径变成 /v1/v1/messages,返回 404。

请求头

请求头 必填 说明
Content-Type 否 建议携带 application/json。不带时网关按 JSON 解析请求体;写成其他值(如 application/x-www-form-urlencoded)时返回 400
x-api-key 或 Authorization 是 LYRouter API Key,写法见上文「鉴权」。只用于网关鉴权,不会转发给上游
anthropic-version 否 网关不校验。调用 Anthropic 上游时版本由通道决定,通常为 2023-06-01
anthropic-beta 否 原样转发给上游。请求中带有 "ttl": "1h" 的缓存标记、且发往 Anthropic 上游时,网关把它设为 extended-cache-ttl-2025-04-11,替换请求中原有的值
x-gateway-passthrough 否 LYRouter 扩展请求头,写 require 表示请求体必须原样发给 Anthropic 上游,做不到就返回 400。公共网关目前没有开启原生直通,不需要时不要发送,见网关扩展请求头与响应头

请求体

参数 类型 必填 说明
model string 否 模型 ID,也可以写 @vmodel/<名称>(虚拟模型)或 lyrouter/auto(智能路由)。省略、为 "" 或 null 时使用工作空间的默认模型,没有默认模型时返回 400。Anthropic SDK 要求必须填写
max_tokens integer 是 输出上限。省略时网关不报错:发往 Anthropic 上游时补为 4096,发往 OpenAI 兼容上游时不发送,由上游默认值决定。思考是否计入这个上限由上游决定,例如阿里云百炼不计入:qwen3.7-plus 设为 16 时,output_tokens 为 100,stop_reason 为 end_turn
messages array 是 每项为 {"role": "user" 或 "assistant", "content": 字符串或内容块数组},见下文「内容块」
system string / array 否 系统提示词。可以是字符串,也可以是 text 块数组(块上可带 cache_control);多个块会合并成一段,块之间空一行
stream boolean 否 true 时以 SSE 事件流返回,见下文「流式响应」
temperature、top_p、top_k number 否 原样发给上游,是否生效取决于模型
stop_sequences array 否 停止序列。发往 OpenAI 兼容上游时转为 stop
tools array 否 自定义工具 {"name", "description", "input_schema"},可带 cache_control,见下文「工具调用」
tool_choice object 否 {"type": "auto"}、{"type": "any"} 或 {"type": "tool", "name": "..."}。{"type": "none"} 和 disable_parallel_tool_use 不会发给上游;不希望模型调用工具时,请不要传 tools
thinking object 否 {"type": "enabled", "budget_tokens": 2048}、{"type": "adaptive"} 或 {"type": "disabled"},转换规则见下文「网关行为」
metadata object 否 只有 user_id 会发给 Anthropic 上游;OpenAI 兼容上游不发送
service_tier string 否 原样发给上游
context_management、output_config object 否 只发给 Anthropic 上游

表中未列出的其他字段不会转发给上游。

内容块

块类型 出现位置 说明
text system、user、assistant 文本,可带 cache_control
image user、tool_result 内 source 为 {"type": "base64", "media_type", "data"} 或 {"type": "url", "url"}。发往 OpenAI 兼容上游时转为 image_url,需要模型支持图片输入,见多模态
tool_use assistant 模型发起的工具调用:id、name、input
tool_result user 工具执行结果:tool_use_id 与 content(字符串,或 text / image 块)
thinking、redacted_thinking assistant 历史 上一轮返回的思考块,回传时保留 signature

其他类型的块(如 document)不会转发给上游。

提示词缓存

在 system 块、消息中的 text 块或工具定义上加 "cache_control": {"type": "ephemeral"}(1 小时缓存写 {"type": "ephemeral", "ttl": "1h"}),标记可缓存前缀的结束位置:

标记位置 发往 Anthropic 协议上游 发往 OpenAI 兼容上游
system 块 保留;多个块合并后,以最后一个带标记的块为准 删除
消息中的 text 块 保留 删除
tools 中的工具定义 保留 删除
image 块、tool_result 块 不转发 删除

写入缓存的部分记为「显式缓存创建」,之后命中的部分记为「输入(缓存命中)」。OpenAI 兼容上游只有上游自动进行的缓存,不产生「显式缓存创建」。标记方法和命中率优化见降低成本与优化缓存。

请求示例

先安装 SDK:pip install anthropic 或 npm install @anthropic-ai/sdk。

curl https://api.lyrouter.com/v1/messages \
  -H "x-api-key: $LYROUTER_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "MODEL_ID",
    "max_tokens": 1024,
    "system": "你是一个简洁的助手。",
    "messages": [
      { "role": "user", "content": "用一句话解释什么是 API 网关。" }
    ]
  }'

将 MODEL_ID 替换为工作空间中已开通的模型 ID。改用 Authorization: Bearer 时,cURL 把 x-api-key 头换成 -H "Authorization: Bearer $LYROUTER_API_KEY";SDK 把 api_key / apiKey 换成 auth_token / authToken。

响应

非流式请求返回一个 message 对象;出错时返回 Anthropic 格式的错误对象。下面的 200 是 Anthropic 协议上游的典型响应,400 是没有写 model 且工作空间没有默认模型,401 是 API Key 无效,429 是 API Key 当天的 Token 配额已用完(见429:限流与配额)。

{
  "id": "msg_01HCDu5LRGeP2o7s2xGmxyZa",
  "type": "message",
  "role": "assistant",
  "model": "claude-sonnet-4-5-20250929",
  "content": [
    {
      "type": "text",
      "text": "API 网关是位于客户端与后端服务之间的统一入口,负责鉴权、路由、限流和监控。"
    }
  ],
  "stop_reason": "end_turn",
  "usage": {
    "input_tokens": 294,
    "output_tokens": 46,
    "cache_read_input_tokens": 1536,
    "cache_creation_input_tokens": 212
  }
}
字段 说明
id 沿用上游返回的标识。Anthropic 上游以 msg_ 开头,其他上游的格式不同,不要依赖它的前缀
model 上游返回的实际模型名,可能与请求中的模型 ID 不同。对应日志的「模型(实际)」
content 非流式响应只包含 text 和 tool_use 块;需要拿到思考内容时,请使用流式。例外见表下说明
stop_reason end_turn、max_tokens 或 tool_use,按上游的结束原因换算。上游的其他结束原因(如 stop_sequence、refusal)都返回为 end_turn。用 {"type": "tool"} 指定工具时目前可能是 end_turn,见下文「工具调用」
stop_sequence 目前响应中没有这个字段,流式的 message_start、message_delta 中也没有。用官方 SDK 读取时,Python 为 None,Node.js 为 undefined
usage 本次 Token 用量,见下表
  • content 可能是 {}:上游只输出了思考、并且在思考阶段就被 max_tokens 截断时,非流式响应的 content 目前是空对象 {},而不是空数组 [](glm-5.3、kimi-k2.7-code、deepseek-v4 上都出现过)。请把 max_tokens 留足,解析时把不是数组的 content 当作没有内容处理。
  • <think> 标签:部分模型(如 minimax-m3)把思考过程以 <think>…</think> 写在 text 块里,非流式和流式都是如此。网关不会剥离,需要时请自行去掉。

usage 与日志中的四项 Token

usage 与日志「Token 消耗」四项一一对应,四个字段互不重叠:

usage 字段 含义 日志中的对应项
input_tokens 没有命中缓存的输入,不含缓存读取和缓存写入 「输入(缓存未命中)」
cache_read_input_tokens 命中提示词缓存的输入 「输入(缓存命中)」
cache_creation_input_tokens 本次写入缓存的输入,只在 Anthropic 协议上游出现 「显式缓存创建」
output_tokens 输出,包含思考内容 「输出」

两个缓存字段为 0 时不返回。上游是 OpenAI 兼容协议时,网关从上游的 prompt_tokens 中减去缓存命中量得到 input_tokens,口径与 Anthropic 一致,本次全部输入是 input_tokens + cache_read_input_tokens + cache_creation_input_tokens。计费方法见调用费用与缓存计费。

工具调用

请求中声明工具:

{
  "model": "MODEL_ID",
  "max_tokens": 1024,
  "tools": [
    {
      "name": "get_weather",
      "description": "查询城市的实时天气",
      "input_schema": {
        "type": "object",
        "properties": { "city": { "type": "string" } },
        "required": ["city"]
      }
    }
  ],
  "messages": [{ "role": "user", "content": "上海现在天气怎么样?" }]
}

模型决定调用工具时,content 中出现 tool_use 块,stop_reason 一般为 tool_use:

{
  "type": "tool_use",
  "id": "toolu_01A09q90qw90lq917835lq9",
  "name": "get_weather",
  "input": { "city": "上海" }
}

判断是否需要执行工具,请看 content 中有没有 tool_use 块,不要只看 stop_reason:目前 tool_choice 为 {"type": "tool", "name": "..."} 时,响应带有 tool_use 块,stop_reason 却是 end_turn;any、auto 时为 tool_use。

执行工具后,把助手这一轮原样放回 messages,再用一条 user 消息回传 tool_result,tool_use_id 与调用的 id 一致:

{
  "model": "MODEL_ID",
  "max_tokens": 1024,
  "tools": ["……与第一次请求相同……"],
  "messages": [
    { "role": "user", "content": "上海现在天气怎么样?" },
    {
      "role": "assistant",
      "content": [
        {
          "type": "tool_use",
          "id": "toolu_01A09q90qw90lq917835lq9",
          "name": "get_weather",
          "input": { "city": "上海" }
        }
      ]
    },
    {
      "role": "user",
      "content": [
        {
          "type": "tool_result",
          "tool_use_id": "toolu_01A09q90qw90lq917835lq9",
          "content": "{\"temp_c\":22,\"condition\":\"多云\"}"
        }
      ]
    }
  ]
}

示例中 tools 的值为省略写法,实际请求要放入完整的工具定义。使用时注意:

  • 只使用带 input_schema 的自定义工具。Anthropic 服务端工具(如 web_search)会被当作普通自定义工具发出,不会在服务端执行。
  • 包含 tool_result 的 user 消息里,与它并列的 text、image 块不会转发。需要补充说明时,放进 tool_result 的 content,或放在下一条 user 消息中。
  • tool_result 的 is_error 不会转发;执行失败时请在 content 中写明错误信息。

与 Chat Completions 的写法对比见工具调用。

流式响应

设置 "stream": true 后,响应是 text/event-stream,每个事件由 event: 行和 data: 行组成:

event: message_start
data: {"type":"message_start","message":{"id":"msg_01HCDu5LRGeP2o7s2xGmxyZa","type":"message","role":"assistant","model":"claude-sonnet-4-5-20250929","content":[],"usage":{"input_tokens":294,"output_tokens":0}}}

event: content_block_start
data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}

event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"API 网关是"}}

event: content_block_stop
data: {"type":"content_block_stop","index":0}

event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"end_turn"},"usage":{"input_tokens":294,"output_tokens":46,"cache_read_input_tokens":1536,"cache_creation_input_tokens":212}}

event: message_stop
data: {"type":"message_stop"}
  • 事件顺序:message_start → 每个内容块的 content_block_start、content_block_delta、content_block_stop → message_delta → message_stop。正常结束的标记是 message_stop。
  • 增量类型:文本为 text_delta;工具调用参数为 input_json_delta(partial_json 拼接后才是完整 JSON);思考内容为 thinking_delta,Anthropic 上游的思考块在 content_block_stop 之前还有一条完整的 signature_delta。OpenAI 兼容上游返回的思考内容同样以 thinking 块输出,但没有签名。
  • 用量:完整的 usage 在 message_delta 中,包括缓存字段。message_start 的 usage 只有 input_tokens 和为 0 的 output_tokens,上游是 OpenAI 兼容协议时 input_tokens 也为 0,请以 message_delta 为准。
  • 中途出错:输出开始后上游中断时,网关补发 event: error,数据为 {"type": "error", "error": {"type": "api_error", "message": "upstream timed out after the response had started"}},之后不再有 message_stop。上游自己发出的错误事件(如 overloaded_error)按同样格式转给客户端。没有收到 message_stop 就按失败处理,见超时与流式中断。
curl -N https://api.lyrouter.com/v1/messages \
  -H "x-api-key: $LYROUTER_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{"model":"MODEL_ID","max_tokens":1024,"stream":true,"messages":[{"role":"user","content":"写一首两行的小诗"}]}'

各协议流式格式的对比见流式响应。

网关行为

网关内部统一用 OpenAI Chat Completions 格式处理对话请求。/v1/messages 的请求先转换为内部格式,再按选中通道的协议发出:Anthropic 协议的通道还原成 Messages 请求,OpenAI 兼容的通道转换为 Chat Completions 请求;响应和流式事件再转换回 Messages 格式。上游是 Anthropic 时也经过这一转换,请求和响应不会逐字节原样转发。

请求内容 发往 Anthropic 协议上游 发往 OpenAI 兼容上游
system 合并为一段文本 转为 system 消息
text、image 块 保留 转为 content 中的 text、image_url
tool_use、tool_result 保留 转为 tool_calls 和 tool 消息
tools、tool_choice 保留(none 除外) 转为函数工具;any 转为 required,指定工具转为指定函数
thinking 参数 enabled 保留预算,adaptive 保留,disabled 不发送 转为 enable_thinking、thinking_budget,已知不支持的上游会删除
历史中的思考块 带签名的原样回传;历史里有没有签名的思考块时,这一轮删除全部思考块并关闭思考 删除
max_tokens 保留,省略时补为 4096 保留,省略时不发送
stop_sequences 保留 转为 stop
metadata 只保留 user_id 删除
context_management、output_config 保留 删除
cache_control 见上文「提示词缓存」 删除
  • 思考块与切换模型:同一会话中途从 OpenAI 兼容上游的模型换到 Anthropic 上游时,历史中的思考块没有签名,这一轮会关闭思考后再发送,避免上游拒绝请求。
  • 模型名:model 换成所选通道的实际模型名,响应中的 model 是上游返回的名称。
  • 虚拟模型:请求没有 system 时,网关填入虚拟模型的系统提示词;已有 system 时不注入,见虚拟模型。
  • 键顺序:发往上游的请求 JSON 中,对象的键会被重新排列(数组顺序不变),让相同前缀稳定命中上游缓存。
  • 失败回退:开始输出之前上游返回错误或连接失败时,网关按失败重试与备用模型换通道,必要时改用备用模型和工作空间默认模型。流式输出开始后不再换通道。
  • 响应头:上游的 Retry-After 会转发给客户端。响应带 anthropic-ratelimit-* 头:上游返回了这组头时原样转发,否则在配置了配额时按网关配额生成;x-aigw-quota-* 见网关扩展请求头与响应头。

常见错误

/v1/messages 上的错误一律转换为 Anthropic 格式。message 保持原文,不再带 error.code,error.type 按状态码确定:

{
  "type": "error",
  "error": {
    "type": "permission_error",
    "message": "Model is not available in the model plaza"
  }
}
HTTP 状态码 error.type
400、402、422 invalid_request_error
401 authentication_error
403 permission_error
404 not_found_error
413 request_too_large
429 rate_limit_error
503、529 overloaded_error
其他 5xx api_error
状态码 error.message 原因与处理
401 missing credentials / invalid api key 没有携带 API Key,或 Key 无效、已删除、已过期。检查 x-api-key 或 Authorization,见401 / 403:鉴权与权限
400 you must provide a model parameter 请求没写 model,工作空间也没有设置默认模型
400 tool_choice 'required' is incompatible with thinking enabled tool_choice 为 any 或指定工具时,上游在思考模式下拒绝强制调用。改用 {"type": "auto"},或用 thinking: {"type": "disabled"} 关闭思考。kimi-k2.7-code 上关闭思考不起作用,仍返回这个错误,请改用 auto;阿里云百炼的 qwen 模型上关闭有效
403 Model is not available in the model plaza 工作空间没有开通该模型。Claude Code 的后台任务常用官方模型名发起请求,按 Claude Code 补齐模型配置
402 insufficient credit balance 账户 Credits 余额不足,见模型不可用
429 rate limit exceeded on <对象> <指标>/<窗口> 配额或预算已用完。Anthropic SDK 会自动重试 429,但配额用完时重试无效,见429:限流与配额
503 No configured credential can serve this model 模型在本工作空间没有可用的通道或凭证,见模型不可用
503 all routed candidates exhausted 找不到可服务这次请求的通道,例如 @vmodel/<名称> 写错、这个虚拟模型不存在。error.type 为 overloaded_error,Anthropic SDK 会自动重试,但名称写错时重试无效。核对名称,见模型不可用

完整列表见错误码与请求标识。需要区分同一状态码下的具体原因时,以 message 为准,或在请求日志中查看这次请求的「状态说明」。网关的响应中不包含请求 ID,排查时请在日志详情顶部复制 Request ID。