协议参考
ai-proxy 和 ai-proxy-multi 插件使用相同的请求协议检测与转换流程。该流程会先识别客户端格式,再将请求路由到已配置的服务提供方或所选实例。
有关插件专用配置,请参阅 ai-proxy 和 ai-proxy-multi。
请求协议检测
插件会先识别客户端协议,再将其与所选服务提供方或实例支持的协议进行匹配。以下检测规则适用于两个插件。
请求要求
如果请求包含 Content-Type,其值必须为 application/json。如果省略该请求头,插件会将请求体视为 JSON。在选择服务提供方或实例前,插件会拒绝不支持的内容类型和无效请求体。
请求体不能超过 max_req_body_size,默认值为 67,108,864 字节。超过此限制的请求会收到 HTTP 413 响应。在 API7 网关中,此配置自 3.9.x 版本线的 3.9.14 和 3.10.x 版本线的 3.10.1 起可用;在 APISIX 3.17.0 及更高版本中可用。
检测顺序
插件按以下顺序检查规则:
| 客户端协议 | 请求体信号 | 路径要求 |
|---|---|---|
| Bedrock Converse | 请求体包含 messages 数组。 | 路径以 /converse 结尾;允许自定义前缀。 |
| Anthropic Messages | 请求体是 JSON 对象。 | 路径以 /v1/messages 结尾;允许自定义前缀。 |
| OpenAI Responses | 请求体包含 input。 | 路径以 /v1/responses 结尾;允许自定义前缀。 |
| OpenAI Chat Completions | 请求体包含 messages 数组。 | 路由匹配的任意路径。 |
| OpenAI Embeddings | 请求体包含 input,且前面的规则均不匹配。 | 路由匹配的任意路径。 |
路径特定规则会先于仅基于请求体的规则执行,从而避免将包含 messages 的 Bedrock Converse 和 Anthropic Messages 请求识别为 Chat Completions。Responses 和 Embeddings 请求都使用 input,因此包含 input 但不包含 messages 的请求会被识别为 Embeddings,除非其路径以 /v1/responses 结尾。
其他任何非空 JSON 对象都会按透传处理。只要请求转换未改变请求体,此模式会保留原始请求路径,并可以复用原始请求体。服务提供方身份认证和 override.endpoint 仍然生效。空请求体或无效请求体会被拒绝。
检测后处理
对于已命名的协议,如果所选服务提供方支持该协议,插件会直接使用检测到的协议而不执行转换。否则,插件会查找已注册的转换器,将请求转换为服务提供方支持的协议。如果既没有原生支持,也没有兼容的转换器,请求会被拒绝。
检测到的协议和请求体决定日志插件将 request_type 记录为 ai_stream 还是 ai_chat。响应解析则根据上游响应的内容类型区分流式与非流式 响应。
Anthropic 到 OpenAI 的转换
Anthropic Messages 客户端可以通过 ai-proxy 或 ai-proxy-multi 向支持 OpenAI Chat Completions 的后端发送请求。插件会将客户端请求转换为 OpenAI 格式,并将后端响应转换为 Anthropic 格式。此转换只支持 Anthropic Messages API 的一部分:保留部分字段、转换其他字段,并丢弃不支持的字段。
何时执行转换
当请求路径以 /v1/messages 结尾且请求体是 JSON 对象时,插件会将其识别为 Anthropic Messages 请求。如果所选服务提供方支持 Anthropic Messages,请求会直接使用该协议而不进行转换。如果服务提供方支持的是 OpenAI Chat Completions,共享转换器会转换请求和响应。
不支持相反的客户端/后端组合:OpenAI Chat Completions 客户端不能使用此转换器调用 Anthropic Messages 后端。
对于 ai-proxy-multi,是否需要转换由所选实例决定。转换配置示例使用 ai-proxy;有关多实例配置,请参阅 ai-proxy-multi。
请求转换
转换后 的请求体根据允许列表构建。下表汇总转换器会读取的 Anthropic 输入。无法识别的字段会在请求到达后端前被丢弃。
请求字段
| Anthropic 字段 | OpenAI 字段 | 行为 |
|---|---|---|
model | model | 转发;但如果路由通过 options.model 固定模型,则不转发。 |
max_tokens | max_completion_tokens | 重命名。 |
stop_sequences | stop | 重命名。 |
temperature、top_p | 同名字段 | 转发。 |
stream | stream,以及 stream_options.include_usage | 插件设置 stream_options.include_usage,使流中包含用量信息。 |
system | 位于消息开头且 role: system 的消息 | 文本块会拼接成一个字符串。 |
tools[](自定义工具) | tools[].function | 如果工具名称包含 [a-zA-Z0-9_-] 以外的字符,或长度超过 64 个字符,则会改写为符合 OpenAI 命名规则的名称;响应中会恢复原名称。 |
tool_choice | tool_choice | 转换:{"type": "auto"} 变为 "auto",{"type": "any"} 变为 "required",{"type": "none"} 变为 "none",{"type": "tool", "name": "..."} 变为指定该函数的对象。 |
tool_choice.disable_parallel_tool_use | parallel_tool_calls: false | 转换。 |
thinking | reasoning_effort | 近似转换。连续的 budget_tokens 值会映射到一个离散的推理强度级别;阈值取决于版本。 |
output_config.effort | reasoning_effort | 当 thinking.type 为 adaptive 时使用。不同版本支持情况不同,请参阅版本兼容性。 |
output_format、output_config.format | response_format | 不同版本支持情况不同,请参阅版本兼容性。 |
metadata.user_id | user | 重命名。 |
service_tier | service_tier | 转发。 |
消息内容
| Anthropic 内容 | OpenAI 等效形式 | 行为 |
|---|---|---|
字符串形式的 messages[].content | 内容相同的字符串形式 messages[].content | 转发。 |
text | 文本内容部分或纯字符串 | 具体形式取决于版本,请参阅版本兼容性。 |
使用 Base64 源的 image | 使用 data: URL 的 image_url | 转换。后端模型是否接受图片输入因模型而异。 |
使用 URL 源的 image | 使用相同 URL 的 image_url | 原样转发。 |
使用 Base64 源的 document | 使用 data: URL 的 image_url | 近似转换。文档字节会放入 OpenAI Schema 定义为图片的字段中,因此后端是否接受不在该 Schema 的保证范围内。 |
tool_use | 包含 tool_calls 的助手消息 | 转换。消息历史中的工具名称处理取决于版本,请参阅版本兼容性。 |
tool_result | role: tool 的消息 | 转换。其与普通文本的相对顺序取决于版本,请参阅版本兼容性。 |
丢弃的字段
后端不会收到以下字段,响应中也不会提示字段已被移除:
| Anthropic 字段 | 丢弃原因 |
|---|---|
top_k | OpenAI Chat Completions 没有等效参数。 |
cache_control | 没有等效字段;转换后的请求不包含缓存指令。 |
citations | 转换器在两个方向都不映射引用。 |
消息历史中的 thinking 和 redacted_thinking 块 | OpenAI Chat Completions 没有等效字段;同一助手消息中的普通文本会保留。 |
Anthropic 内置工具(computer_、bash_、text_editor_、web_search、code_execution_) | 转换器没有这些工具的映射。 |
请求头
如果请求包含 x-api-key 请求头但不包含 Authorization 请求头,转换器会将该 Key 作为 Bearer Token 放入 Authorization。它会移除原始 x-api-key 请求头,以及名称以 anthropic- 或 x-stainless- 开头的请求头。
响应转换
转换器只读取 choices[0] 中的补全字段;其他 OpenAI choice 会被丢弃。顶层 usage 和 error 字段会单独映射。
| OpenAI 响应字段 | Anthropic 响应 | 行为 |
|---|---|---|
message.content | text 内容块 | 转换。 |
message.reasoning_content 或 message.reasoning | thinking 内容块 | 后端返回非空字符串时转换。非流式块的签名为空,请参阅已知限制。 |
message.tool_calls | tool_use 内容块 | 转换。如果原始名称可用,会恢复经过规范化的工具名称。 |
finish_reason | stop_reason | stop 和 content_filter 变为 end_turn;length 变为 max_tokens;tool_calls 和 function_call 变为 tool_use。其他值默认为 end_turn。 |
usage | input_tokens、output_tokens 和可用的缓存 Token 字段 | prompt_tokens 变为 input_tokens,completion_tokens 变为 output_tokens。如果缓存详情可用,会从 input_tokens 中扣除缓存的提示词 Token,并报告为 cache_read_input_tokens;如果提供了 cache_creation_input_tokens,也会包含该字段。 |
error | Anthropic 错误对象 | 正常解析的上游响应体包含错误对象时转换。HTTP 429、5xx 和传输错误可能绕过此转换。 |
对于流式响应,转换器会为 OpenAI 文本、推理和工具调用增量发出 Anthropic 消息及内容块事件。初始 message_start 中的用量值为零;最终 Token 用量在 message_delta 中发出。如果后端在受支持的用量块中提供缓存 Token 字段,也可以包含这些字段。报告流式用量的客户端应读取最终事件,且不应假设缓存 Token 字段一定存在。
版本兼容性
API7 网关 3.9.x 和 3.10.x 会分别接收修复。请查看实际运行版本所在的列。
| 行为 | API7 网关 3.9.x | API7 网关 3.10.x | APISIX |
|---|---|---|---|
所有工具都被丢弃时,移除失去关联的 tool_choice | 3.9.16 及更高版本 | 3.10.2 及更高版本 | 3.17.0 中不支持 |
| 后端工具调用格式错误时降级处理,而不是使响应失败 | 3.9.16 及更高版本 | 3.10.2 及更高版本 | 3.17.0 中不支持 |
将 message_start.content 序列化为数组 | 3.9.16 及更高版本 | 3.10.3 及更高版本 | 3.17.0 中不支持 |
| 识别 Anthropic 当前的结构化输出形式 | 3.9.16 及更高版本 | 3.10.3 及更高版本 | 3.17.0 中不支持 |
thinking.type: adaptive 使用 output_config.effort | 3.9.16 及更高版本 | 3.10.3 及更高版本 | 3.17.0 中不支持 |
thinking.budget_tokens 使用下述四级映射 | 3.9.16 及更高版本 | 3.10.3 及更高版本 | 3.17.0 中不支持 |
| 将仅含一个文本块的用户消息作为内容数组发送,并把包含多个文本块的助手消息拼接为字符串 | 3.9.16 及更高版本 | 3.10.3 及更高版本 | 3.17.0 中不支持 |
| 消息历史中的工具名称与声明的工具保持一致地改写 | 3.9.16 及更高版本 | 3.10.3 及更高版本 | 3.17.0 中不支持 |
tool_result 消息放在同一用户消息的普通文本之前 | 3.9.16 及更高版本 | 3.10.3 及更高版本 | 3.17.0 中不支持 |
用户消息同时包含 tool_result 时保留媒体内容 | 3.9.16 及更高版本 | 3.10.3 及更高版本 | 3.17.0 中不支持 |
这些版本差异会影响结构化输出、消息内容、推理强度和工具历史,具体如下。
结构化输出
API7 网关 3.9.15 及更早版本、API7 网关 3.10.0 至 3.10.2,以及 APISIX 3.17.0,只能识别转换器过去预期的形式:output_config 或 output_format 包含 type: json_schema 及 json_schema 字段,或者包含 type: json 或 type: json_object。
Anthropic 当前会把 Schema 放在 output_format.schema 或 output_config.format 中。API7 网关 3.9.x 从 3.9.16 起识别这种形式;3.10.x 从 3.10.3 起识别。这些版本会规范化 Schema,并发送启用严格模式的 response_format。在更早版本中,后端不会收到 response_format,客户端也不会收到错误。
消息内容形式
在早于该项变更的版本中,只包含一个文本块的用户消息会以纯字符串发送;包含多个文本块的助手消息会以内容数组发送。只接受其中一种形式的后端,在升级前后会表现不同。
推理强度
不同版本使用不同的 budget_tokens 映射。较早的映射适用于 APISIX 3.17.0,以及 API7 网关对应版本线中早于 3.9.16 或 3.10.3 的版本。较新的映射分别从 API7 网关 3.9.16 和 3.10.3 起适用。
budget_tokens | 较早版本 | 较新版本 |
|---|---|---|
| 小于 1024 | low | minimal |
| 1024 至 2047 | low | low |
| 2048 至 4095 | low | medium |
| 4096 至 16383 | medium | high |
| 16384 或更高 | high | high |
| 未提供 | medium | minimal |
工具历史
在较早版本中,消息历史里的 tool_use 名称不会按照相应的已声明工具名称改写。同一用户消息中的普通文本也可能先于 tool_result 消息发送,并且该消息中的媒体内容会被丢弃。严格的后端可能会拒绝名称或顺序不匹配。API7 网关 3.9.16 及更高版本和 API7 网关 3.10.3 及更高版本会一致地改写历史名称、优先放置工具消息并保留媒体内容。
已知限制
以下限制可能会影响所有受支持版本中的转换请求和响应。
流式传输可能在没有终止事件的情况下结束
如果后端关闭流时没有发送格式正确、分隔完整的最后一帧,插件不会发出结尾的 message_delta 和 message_stop 事件。依赖 message_stop 的客户端可能无限等待,或将该流视为不完整。上述所有版本都会受到影响。请设置客户端超时,并将流意外结束视为失败。
转换后的 thinking 块不包含有效签名
对于非流式响应,插件会将该块的 signature 设置为空字符串;对于流式响应,插件会发出不含签名的 thinking 增量。要求有效签名的客户端无法将任一转换形式作为已签名的 Anthropic thinking 块重放。如果后端把推理内容嵌入普通消息内容,响应中的推理会显示为可见文本。
错误响应不一定采用 Anthropic 格式
HTTP 429、5xx 和传输超时响应可能绕过响应转换。客户端应做好接收不符合 Anthropic 错误 Schema 的上游或网关错误响应体的准备。
不验证后端能力
插件会转换请求,但不会检查后端模型是否支持转换结果。后端可能返回 HTTP 200,却静默忽略某项能力,例如丢弃图片、忽略 response_format 或不返回工具调用。
不同模型的后端行为不同,同一模型名称的不同日期快照也可能不同。请验证计划使用的具体模型,不要根据某个后端笼统推断。
验证后端兼容性
请针对每个后端模型测试以下转换输入,因为即使原始 Anthropic 请求有效,后端仍可能拒绝它们:
- 指定名称的
tool_choice。 转换器会输出指定函数的对象或"required"。有些后端在模型进行推理时只接受"auto"。如果后端拒绝转换后的形式,请从客户端发送{"type": "auto"}。 thinking与较小的max_tokens同时使用。thinking会变为reasoning_effort,可能使后端预留推理预算。如果该预算超过转换后的max_completion_tokens,后端会拒绝请求。启用thinking时请提高max_tokens。document块。 转换器只能将其作为图片提供给后端。无法读取它的模型可能会生成虚构内容,而不是报告错误。- 混合文本、媒体和
tool_result内容。 较早版本可能会把普通文本放在转换后的工具消息之前,并丢弃同一用户消息中的媒体内容。如果后端验证工具消息顺序,请测试这种形式,或升级到会先放置工具消息并保留媒体内容的版本。