Skip to content

协议转换说明

RouteAPI 作为统一 API 网关,在内部自动完成不同协议格式之间的转换。当你用 OpenAI 协议调用 Claude 模型,或用 Claude Messages 协议调用 Gemini 模型时,RouteAPI 会处理消息结构、参数映射和响应格式的差异,让你无需关心底层协议细节。

RouteAPI 支持三种主流协议入口:

  • OpenAI 兼容协议:/v1/chat/completions、/v1/responses
  • Claude Messages 协议:/v1/messages
  • Google Gemini 协议:/v1beta/models/{model}:generateContent

当请求到达时,RouteAPI 根据路径识别协议类型,根据模型 ID 确定目标上游,然后在两者之间执行必要的格式转换。

场景是否转换说明
OpenAI 协议 → OpenAI 系模型否原样透传
Claude Messages → Claude 系模型否原样透传
OpenAI 协议 → Claude 系模型是OpenAI → Claude Messages
OpenAI 协议 → Gemini 系模型是OpenAI → Gemini contents
Claude Messages → OpenAI 系模型是Claude Messages → OpenAI
Claude Messages → Gemini 系模型是Claude Messages → Gemini

协议转换对客户端是透明的。你发送 OpenAI 格式的请求,就会收到 OpenAI 格式的响应,即使底层调用了 Claude 或 Gemini。

但转换有局限性:

  • 目标协议不支持的参数会被忽略或使用默认值。
  • 某些协议特有的能力(如 Claude 的扩展思考、提示缓存)在转换后可能无法完整表达。
  • 转换过程会引入轻微的延迟(通常在 10ms 以内)。

最佳实践:优先使用目标模型原生支持的协议,可以获得最完整的功能支持和最佳性能。

OpenAI 把 system prompt 作为 messages 数组的第一条消息:

{
"messages": [
{ "role": "system", "content": "你是一个严谨的技术助手。" },
{ "role": "user", "content": "解释什么是 API 网关" }
]
}

Claude 把 system prompt 放在顶层独立字段:

{
"system": "你是一个严谨的技术助手。",
"messages": [
{ "role": "user", "content": "解释什么是 API 网关" }
]
}

转换规则:

  • OpenAI → Claude:提取第一条 role: "system" 消息,移到 system 字段。
  • Claude → OpenAI:将 system 字段内容转为 role: "system" 消息,插入 messages 数组开头。
OpenAIClaudeGemini说明
system顶层 system 字段systemInstruction系统提示词位置不同
useruseruser用户消息,一致
assistantassistantmodel助手/模型回复,名称不同
tooluser 中的 tool_resultuser 中的 functionResponse工具结果归属不同

转换注意事项:

  • Claude 不接受连续两条同角色消息,转换时需要合并或插入占位消息。
  • Gemini 的 model 角色在转换为 OpenAI 时映射为 assistant。
  • OpenAI 的 role: "tool" 在 Claude 和 Gemini 中都被合并到 user 消息里。

Gemini 的消息结构叫 contents,每条消息的角色叫 role,内容在 parts 数组中:

{
"contents": [
{
"role": "user",
"parts": [{ "text": "解释什么是 API 网关" }]
}
]
}

转换规则:

  • OpenAI messages ↔ Gemini contents
  • OpenAI content ↔ Gemini parts
  • OpenAI assistant ↔ Gemini model
  • system prompt 转为 systemInstruction 顶层字段
OpenAIClaudeGemini说明
temperaturetemperaturetemperatureClaude 上限 1,OpenAI 上限 2,Gemini 上限 2
top_ptop_ptopPnucleus sampling,三者都支持
不支持top_ktopKOpenAI 不支持,转换时丢弃
max_tokens / max_completion_tokensmax_tokens(必填)maxOutputTokensClaude 必须显式设置
n不支持candidateCountClaude 不支持生成多个候选
stopstop_sequencesstopSequences字段名不同,语义一致

温度范围转换:

当 OpenAI 请求的 temperature 超过 1 且目标是 Claude 时,RouteAPI 会自动将其截断到 1,避免请求被上游拒绝。

OpenAIClaudeGemini说明
response_format不支持responseMimeTypeOpenAI 支持 JSON mode 和 JSON Schema
frequency_penalty不支持frequencyPenaltyClaude 不支持惩罚参数
presence_penalty不支持presencePenaltyClaude 不支持惩罚参数
streamstreamstream三者都支持,但事件格式完全不同
stream_options.include_usage始终返回generateContentRequest.stream=true 时自动返回用量统计返回方式不同

转换行为:

  • frequency_penalty 和 presence_penalty 转发到 Claude 时会被忽略。
  • response_format: { type: "json_object" } 转发到 Claude 时会通过工具调用模拟,或在 system prompt 中添加 JSON 输出提示。
  • n > 1 转发到 Claude 时会被重置为 1,因为 Claude 不支持多候选生成。
OpenAIClaudeGemini说明
usermetadata.user_id不支持用于滥用检测
seed不支持seedClaude 不支持确定性采样
logprobs / top_logprobs不支持不支持只有 OpenAI 系模型支持
不支持thinking不支持Claude 特有的扩展思考配置
{
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "查询指定城市的当前天气",
"parameters": {
"type": "object",
"properties": {
"city": { "type": "string", "description": "城市名" }
},
"required": ["city"]
}
}
}
]
}
{
"tools": [
{
"name": "get_weather",
"description": "查询指定城市的当前天气",
"input_schema": {
"type": "object",
"properties": {
"city": { "type": "string", "description": "城市名" }
},
"required": ["city"]
}
}
]
}
{
"tools": [
{
"functionDeclarations": [
{
"name": "get_weather",
"description": "查询指定城市的当前天气",
"parameters": {
"type": "object",
"properties": {
"city": { "type": "string", "description": "城市名" }
},
"required": ["city"]
}
}
]
}
]
}
OpenAIClaudeGemini转换说明
tools[].type: "function"无此层级无此层级转换时去掉 type 包装
tools[].function平铺在 tools[]放在 functionDeclarations[]层级结构不同
function.parametersinput_schemaparametersClaude 字段名不同
OpenAIClaudeGemini说明
"auto"{ "type": "auto" }"AUTO"模型自动决定
"none"{ "type": "none" }"NONE"禁止调用工具
"required"{ "type": "any" }"ANY"必须调用工具
{ "type": "function", "function": { "name": "get_weather" } }{ "type": "tool", "name": "get_weather" }{ "functionCallingConfig": { "allowedFunctionNames": ["get_weather"] } }强制调用指定工具,结构差异大
{
"role": "tool",
"tool_call_id": "call_abc123",
"content": "北京,晴,23°C"
}
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_01A09q90qw90lq917835lq9",
"content": "北京,晴,23°C"
}
]
}
{
"role": "user",
"parts": [
{
"functionResponse": {
"name": "get_weather",
"response": { "result": "北京,晴,23°C" }
}
}
]
}

转换要点:

  • OpenAI 的 role: "tool" 在转换为 Claude/Gemini 时合并到 user 消息中。
  • 工具调用 ID 字段名不同:tool_call_id vs tool_use_id vs Gemini 的函数名识别。
  • Claude 和 Gemini 要求所有工具结果必须在同一条 user 消息内,OpenAI 允许分开多条 tool 消息。
{
"role": "user",
"content": [
{
"type": "image_url",
"image_url": {
"url": "https://example.com/image.jpg",
"detail": "high"
}
},
{ "type": "text", "text": "描述这张图" }
]
}
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "url",
"url": "https://example.com/image.jpg"
}
},
{ "type": "text", "text": "描述这张图" }
]
}
{
"role": "user",
"parts": [
{
"fileData": {
"mimeType": "image/jpeg",
"fileUri": "https://example.com/image.jpg"
}
},
{ "text": "描述这张图" }
]
}
{
"type": "image_url",
"image_url": {
"url": "data:image/jpeg;base64,/9j/4AAQSkZJRg..."
}
}
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/jpeg",
"data": "/9j/4AAQSkZJRg..."
}
}
{
"inlineData": {
"mimeType": "image/jpeg",
"data": "/9j/4AAQSkZJRg..."
}
}

转换规则:

  • OpenAI 的 data: URI 会被解析,media_type 从 URI 前缀提取,纯 base64 部分传给目标协议。
  • Claude 要求单独的 media_type 字段,不接受 data: URI。
  • Gemini 使用 inlineData 而非 fileData 来表示 base64 内容。
  • OpenAI 的 detail 参数(low/high)在转换时丢失,Claude 和 Gemini 没有对应概念。
参数原协议无法转换到原因
top_kClaude, GeminiOpenAIOpenAI 不支持 top-k 采样
nOpenAI, GeminiClaudeClaude 不支持多候选生成
frequency_penalty / presence_penaltyOpenAI, GeminiClaudeClaude 没有惩罚参数
logprobsOpenAIClaude, Gemini只有 OpenAI 系模型返回对数概率
thinkingClaudeOpenAI, GeminiClaude 特有的扩展思考配置
cache_controlClaudeOpenAI, GeminiClaude 特有的提示缓存控制
reasoning_effortOpenAIClaude, GeminiOpenAI o1 系列特有参数
response_format (JSON Schema)OpenAIClaude, Gemini完整的 JSON Schema 约束只有 OpenAI 支持

RouteAPI 采用以下策略:

  1. 静默忽略:不支持的参数在转换时直接丢弃,不影响请求成功(如 detail、logprobs)。
  2. 自动调整:超出范围的值被截断到合法区间(如 temperature > 1 转发到 Claude 时截断为 1)。
  3. 保守降级:复杂功能用简单方式模拟(如 OpenAI 的 JSON Schema 在 Claude 上降级为工具调用或提示词约束)。
  4. 拒绝请求:极少数情况下,如果核心参数无法转换且没有合理默认值,返回 400 错误(如 Claude 协议缺少 max_tokens)。

RouteAPI 在响应头和日志中提供转换信息:

X-RouteAPI-Protocol-Conversion: openai-to-claude
X-RouteAPI-Dropped-Params: frequency_penalty,presence_penalty

如果转换失败或参数冲突,返回标准错误响应:

{
"error": {
"message": "Parameter 'max_tokens' is required for Claude models",
"type": "invalid_request_error",
"param": "max_tokens",
"code": "missing_required_parameter"
}
}
  1. 使用原生协议:尽量用模型原生协议调用,避免转换损失。
  2. 避免依赖特定协议特性:不要依赖 logprobs、thinking 等单一协议特有能力,除非确定只用该协议的模型。
  3. 检查响应头:关注 X-RouteAPI-Dropped-Params 头,了解哪些参数被忽略。
  4. 测试跨协议兼容性:在测试环境验证同一请求在不同协议/模型组合下的行为。
  5. 记录模型 ID:日志中记录实际调用的模型 ID 和协议类型,便于排查差异。
协议input token 字段output token 字段total token 字段
OpenAIprompt_tokenscompletion_tokenstotal_tokens
Claudeinput_tokensoutput_tokens无(需自行相加)
GeminipromptTokenCountcandidatesTokenCounttotalTokenCount

转换规则:

  • Claude → OpenAI:input_tokens → prompt_tokens,output_tokens → completion_tokens,计算 total_tokens = input_tokens + output_tokens。
  • Gemini → OpenAI:promptTokenCount → prompt_tokens,candidatesTokenCount → completion_tokens,totalTokenCount → total_tokens。
  • OpenAI → Claude:prompt_tokens → input_tokens,completion_tokens → output_tokens,丢弃 total_tokens。

Claude 的提示缓存字段也会保留:

{
"usage": {
"prompt_tokens": 120,
"completion_tokens": 45,
"total_tokens": 165,
"cache_creation_input_tokens": 80,
"cache_read_input_tokens": 40
}
}
OpenAIClaudeGemini含义
stopend_turnSTOP自然结束
lengthmax_tokensMAX_TOKENS达到长度上限
tool_callstool_useSTOP (含 functionCall)请求调用工具
content_filter无对应SAFETY内容被安全过滤器拦截
stopstop_sequenceSTOP命中停止序列

转换规则:

  • Claude end_turn → OpenAI stop
  • Claude max_tokens → OpenAI length
  • Claude tool_use → OpenAI tool_calls
  • Gemini STOP 根据是否有 functionCall 映射为 stop 或 tool_calls
  • Gemini SAFETY → OpenAI content_filter

所有协议的错误响应都转换为 OpenAI 格式(当客户端用 OpenAI 协议请求时):

{
"error": {
"message": "Invalid API key",
"type": "invalid_request_error",
"param": null,
"code": "invalid_api_key"
}
}

Claude 原始错误:

{
"type": "error",
"error": {
"type": "authentication_error",
"message": "invalid x-api-key"
}
}

转换为 OpenAI 格式后,type 映射为 invalid_request_error,code 设置为 invalid_api_key。

示例 1:OpenAI 请求 → Claude 格式

Section titled “示例 1:OpenAI 请求 → Claude 格式”

原始 OpenAI 请求:

{
"model": "claude-sonnet-4-5",
"messages": [
{
"role": "system",
"content": "你是一个严谨的技术助手,回答保持简洁。"
},
{
"role": "user",
"content": "解释什么是 API 网关"
}
],
"temperature": 0.7,
"max_tokens": 150,
"stream": false
}

转换后的 Claude 请求:

{
"model": "claude-sonnet-4-5",
"system": "你是一个严谨的技术助手,回答保持简洁。",
"messages": [
{
"role": "user",
"content": "解释什么是 API 网关"
}
],
"temperature": 0.7,
"max_tokens": 150,
"stream": false
}

关键变化:

  • system 消息从 messages 数组提取到顶层 system 字段。
  • messages 现在只包含 user 和 assistant 消息。

示例 2:Claude 工具调用 → OpenAI 格式

Section titled “示例 2:Claude 工具调用 → OpenAI 格式”

Claude 工具调用响应:

{
"id": "msg_01XFDUDYJgAACzvnptvVoYEL",
"type": "message",
"role": "assistant",
"model": "claude-sonnet-4-5",
"content": [
{
"type": "text",
"text": "我来查一下北京的天气。"
},
{
"type": "tool_use",
"id": "toolu_01A09q90qw90lq917835lq9",
"name": "get_weather",
"input": { "city": "北京" }
}
],
"stop_reason": "tool_use",
"usage": {
"input_tokens": 120,
"output_tokens": 45
}
}

转换为 OpenAI 格式:

{
"id": "msg_01XFDUDYJgAACzvnptvVoYEL",
"object": "chat.completion",
"created": 1726567890,
"model": "claude-sonnet-4-5",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "我来查一下北京的天气。",
"tool_calls": [
{
"id": "toolu_01A09q90qw90lq917835lq9",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\":\"北京\"}"
}
}
]
},
"finish_reason": "tool_calls"
}
],
"usage": {
"prompt_tokens": 120,
"completion_tokens": 45,
"total_tokens": 165
}
}

关键变化:

  • content 数组拆分:text 块提取为 content 字段,tool_use 块转为 tool_calls 数组。
  • tool_use.input 对象序列化为 function.arguments JSON 字符串。
  • stop_reason: "tool_use" → finish_reason: "tool_calls"。
  • input_tokens → prompt_tokens,output_tokens → completion_tokens,增加 total_tokens。
  • 增加 OpenAI 格式的顶层字段:object、created、choices 数组。

示例 3:Gemini 多模态 → OpenAI 格式

Section titled “示例 3:Gemini 多模态 → OpenAI 格式”

Gemini 响应:

{
"candidates": [
{
"content": {
"parts": [
{
"text": "这张图片显示了一个现代化的用户界面,包含导航栏、内容区域和侧边栏。"
}
],
"role": "model"
},
"finishReason": "STOP",
"index": 0
}
],
"usageMetadata": {
"promptTokenCount": 258,
"candidatesTokenCount": 32,
"totalTokenCount": 290
}
}

转换为 OpenAI 格式:

{
"id": "chatcmpl-gemini-abc123",
"object": "chat.completion",
"created": 1726567890,
"model": "gemini-2.0-flash-exp",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "这张图片显示了一个现代化的用户界面,包含导航栏、内容区域和侧边栏。"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 258,
"completion_tokens": 32,
"total_tokens": 290
}
}

关键变化:

  • candidates[0].content.parts[0].text → choices[0].message.content。
  • role: "model" → role: "assistant"。
  • finishReason: "STOP" → finish_reason: "stop"(转为小写)。
  • usageMetadata 字段名映射到 OpenAI 的 usage 结构。

根据客户端和模型类型选择协议:

客户端类型目标模型推荐协议原因
OpenAI SDKOpenAI 系模型OpenAI原生支持,零转换
Claude CodeClaude 系模型Claude Messages原生支持,零转换
LangChain / LiteLLM任意模型OpenAI生态兼容性最好
Anthropic SDKClaude 系模型Claude Messages访问扩展思考、提示缓存
自研客户端任意模型取决于需求优先用目标模型原生协议

如果业务需要跨模型切换,避免使用以下特性:

  • OpenAI 特有:logprobs、seed、完整 JSON Schema 约束、reasoning_effort(o1 系列)
  • Claude 特有:thinking、cache_control、mcp_servers
  • Gemini 特有:grounding、codeExecution

通用特性集合(三者都支持):

  • 基础聊天对话(messages / contents)
  • 流式输出(stream)
  • 温度控制(temperature,注意范围差异)
  • 工具调用(tools,注意格式差异)
  • 多模态输入(图像,注意格式差异)
  • 停止序列(stop / stop_sequences / stopSequences)

在测试环境验证以下场景:

  1. 同一协议,不同模型:确保 OpenAI 协议能正确调用 Claude 和 Gemini 模型。
  2. 不同协议,同一模型:验证 Claude Messages 和 OpenAI 协议调用同一 Claude 模型的结果一致性。
  3. 工具调用往返:测试跨协议的工具定义、调用和结果传递是否正确。
  4. 边界参数:测试 temperature: 1.5(OpenAI 合法,Claude 需截断)、n: 2(OpenAI 支持,Claude 不支持)等边界情况。
  5. 错误处理:验证上游错误是否正确转换为客户端协议格式。

记录以下信息便于排查协议转换问题:

{
"request_id": "req_abc123",
"client_protocol": "openai",
"model_id": "claude-sonnet-4-5",
"upstream_protocol": "claude",
"conversion_required": true,
"dropped_params": ["frequency_penalty", "logprobs"],
"adjusted_params": {"temperature": {"original": 1.8, "adjusted": 1.0}},
"latency_ms": 856,
"conversion_overhead_ms": 8
}

关键指标:

  • 转换成功率:协议转换失败导致的 400 错误占比。
  • 转换延迟:协议转换引入的额外延迟(通常 5-15ms)。
  • 参数丢弃率:哪些参数最常被丢弃,是否影响业务。
  • 跨协议错误率:OpenAI → Claude 调用的错误率是否高于 OpenAI → OpenAI。

如果要从一个协议迁移到另一个协议:

  1. 阶段 1:双写测试:新协议调用结果仅用于对比,不影响业务。
  2. 阶段 2:灰度切换:小流量切换到新协议,监控错误率和响应质量。
  3. 阶段 3:全量切换:确认无异常后全量切换。
  4. 阶段 4:清理旧代码:移除旧协议的适配代码。

每个阶段都需要验证:

  • 功能正确性(工具调用、多模态、流式输出)
  • 响应质量(不同协议/模型组合的输出差异)
  • 性能指标(延迟、token 用量、成本)
  • 错误处理(网络异常、限流、上游故障)

协议转换让你可以灵活选择客户端和模型,但最佳实践仍然是优先使用目标模型的原生协议。如果必须跨协议调用,请在测试环境充分验证,并在生产环境监控转换相关的错误和性能指标。