协议转换说明
RouteAPI 作为统一 API 网关,在内部自动完成不同协议格式之间的转换。当你用 OpenAI 协议调用 Claude 模型,或用 Claude Messages 协议调用 Gemini 模型时,RouteAPI 会处理消息结构、参数映射和响应格式的差异,让你无需关心底层协议细节。
转换机制概述
Section titled “转换机制概述”RouteAPI 作为协议适配层
Section titled “RouteAPI 作为协议适配层”RouteAPI 支持三种主流协议入口:
- OpenAI 兼容协议:
/v1/chat/completions、/v1/responses - Claude Messages 协议:
/v1/messages - Google Gemini 协议:
/v1beta/models/{model}:generateContent
当请求到达时,RouteAPI 根据路径识别协议类型,根据模型 ID 确定目标上游,然后在两者之间执行必要的格式转换。
何时需要协议转换
Section titled “何时需要协议转换”| 场景 | 是否转换 | 说明 |
|---|---|---|
| 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 |
转换的透明性
Section titled “转换的透明性”协议转换对客户端是透明的。你发送 OpenAI 格式的请求,就会收到 OpenAI 格式的响应,即使底层调用了 Claude 或 Gemini。
但转换有局限性:
- 目标协议不支持的参数会被忽略或使用默认值。
- 某些协议特有的能力(如 Claude 的扩展思考、提示缓存)在转换后可能无法完整表达。
- 转换过程会引入轻微的延迟(通常在 10ms 以内)。
最佳实践:优先使用目标模型原生支持的协议,可以获得最完整的功能支持和最佳性能。
消息格式转换
Section titled “消息格式转换”OpenAI messages ↔ Claude messages
Section titled “OpenAI messages ↔ Claude messages”system prompt 处理差异
Section titled “system prompt 处理差异”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数组开头。
role 映射
Section titled “role 映射”| OpenAI | Claude | Gemini | 说明 |
|---|---|---|---|
system | 顶层 system 字段 | systemInstruction | 系统提示词位置不同 |
user | user | user | 用户消息,一致 |
assistant | assistant | model | 助手/模型回复,名称不同 |
tool | user 中的 tool_result | user 中的 functionResponse | 工具结果归属不同 |
转换注意事项:
- Claude 不接受连续两条同角色消息,转换时需要合并或插入占位消息。
- Gemini 的
model角色在转换为 OpenAI 时映射为assistant。 - OpenAI 的
role: "tool"在 Claude 和 Gemini 中都被合并到user消息里。
OpenAI messages ↔ Gemini contents
Section titled “OpenAI messages ↔ Gemini contents”Gemini 的消息结构叫 contents,每条消息的角色叫 role,内容在 parts 数组中:
{ "contents": [ { "role": "user", "parts": [{ "text": "解释什么是 API 网关" }] } ]}转换规则:
- OpenAI
messages↔ Geminicontents - OpenAI
content↔ Geminiparts - OpenAI
assistant↔ Geminimodel - system prompt 转为
systemInstruction顶层字段
采样参数对照
Section titled “采样参数对照”| OpenAI | Claude | Gemini | 说明 |
|---|---|---|---|
temperature | temperature | temperature | Claude 上限 1,OpenAI 上限 2,Gemini 上限 2 |
top_p | top_p | topP | nucleus sampling,三者都支持 |
| 不支持 | top_k | topK | OpenAI 不支持,转换时丢弃 |
max_tokens / max_completion_tokens | max_tokens(必填) | maxOutputTokens | Claude 必须显式设置 |
n | 不支持 | candidateCount | Claude 不支持生成多个候选 |
stop | stop_sequences | stopSequences | 字段名不同,语义一致 |
温度范围转换:
当 OpenAI 请求的 temperature 超过 1 且目标是 Claude 时,RouteAPI 会自动将其截断到 1,避免请求被上游拒绝。
输出控制参数
Section titled “输出控制参数”| OpenAI | Claude | Gemini | 说明 |
|---|---|---|---|
response_format | 不支持 | responseMimeType | OpenAI 支持 JSON mode 和 JSON Schema |
frequency_penalty | 不支持 | frequencyPenalty | Claude 不支持惩罚参数 |
presence_penalty | 不支持 | presencePenalty | Claude 不支持惩罚参数 |
stream | stream | stream | 三者都支持,但事件格式完全不同 |
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 不支持多候选生成。
元信息与控制
Section titled “元信息与控制”| OpenAI | Claude | Gemini | 说明 |
|---|---|---|---|
user | metadata.user_id | 不支持 | 用于滥用检测 |
seed | 不支持 | seed | Claude 不支持确定性采样 |
logprobs / top_logprobs | 不支持 | 不支持 | 只有 OpenAI 系模型支持 |
| 不支持 | thinking | 不支持 | Claude 特有的扩展思考配置 |
工具调用转换
Section titled “工具调用转换”工具定义格式差异
Section titled “工具定义格式差异”OpenAI tools 格式
Section titled “OpenAI tools 格式”{ "tools": [ { "type": "function", "function": { "name": "get_weather", "description": "查询指定城市的当前天气", "parameters": { "type": "object", "properties": { "city": { "type": "string", "description": "城市名" } }, "required": ["city"] } } } ]}Claude tools 格式
Section titled “Claude tools 格式”{ "tools": [ { "name": "get_weather", "description": "查询指定城市的当前天气", "input_schema": { "type": "object", "properties": { "city": { "type": "string", "description": "城市名" } }, "required": ["city"] } } ]}Gemini tools 格式
Section titled “Gemini tools 格式”{ "tools": [ { "functionDeclarations": [ { "name": "get_weather", "description": "查询指定城市的当前天气", "parameters": { "type": "object", "properties": { "city": { "type": "string", "description": "城市名" } }, "required": ["city"] } } ] } ]}工具定义转换规则
Section titled “工具定义转换规则”| OpenAI | Claude | Gemini | 转换说明 |
|---|---|---|---|
tools[].type: "function" | 无此层级 | 无此层级 | 转换时去掉 type 包装 |
tools[].function | 平铺在 tools[] | 放在 functionDeclarations[] | 层级结构不同 |
function.parameters | input_schema | parameters | Claude 字段名不同 |
tool_choice 映射
Section titled “tool_choice 映射”| OpenAI | Claude | Gemini | 说明 |
|---|---|---|---|
"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"] } } | 强制调用指定工具,结构差异大 |
工具结果格式转换
Section titled “工具结果格式转换”OpenAI 工具结果
Section titled “OpenAI 工具结果”{ "role": "tool", "tool_call_id": "call_abc123", "content": "北京,晴,23°C"}Claude 工具结果
Section titled “Claude 工具结果”{ "role": "user", "content": [ { "type": "tool_result", "tool_use_id": "toolu_01A09q90qw90lq917835lq9", "content": "北京,晴,23°C" } ]}Gemini 工具结果
Section titled “Gemini 工具结果”{ "role": "user", "parts": [ { "functionResponse": { "name": "get_weather", "response": { "result": "北京,晴,23°C" } } } ]}转换要点:
- OpenAI 的
role: "tool"在转换为 Claude/Gemini 时合并到user消息中。 - 工具调用 ID 字段名不同:
tool_call_idvstool_use_idvs Gemini 的函数名识别。 - Claude 和 Gemini 要求所有工具结果必须在同一条
user消息内,OpenAI 允许分开多条tool消息。
多模态内容转换
Section titled “多模态内容转换”图像 URL 格式转换
Section titled “图像 URL 格式转换”OpenAI 格式
Section titled “OpenAI 格式”{ "role": "user", "content": [ { "type": "image_url", "image_url": { "url": "https://example.com/image.jpg", "detail": "high" } }, { "type": "text", "text": "描述这张图" } ]}Claude 格式
Section titled “Claude 格式”{ "role": "user", "content": [ { "type": "image", "source": { "type": "url", "url": "https://example.com/image.jpg" } }, { "type": "text", "text": "描述这张图" } ]}Gemini 格式
Section titled “Gemini 格式”{ "role": "user", "parts": [ { "fileData": { "mimeType": "image/jpeg", "fileUri": "https://example.com/image.jpg" } }, { "text": "描述这张图" } ]}Base64 编码处理
Section titled “Base64 编码处理”OpenAI base64 格式
Section titled “OpenAI base64 格式”{ "type": "image_url", "image_url": { "url": "data:image/jpeg;base64,/9j/4AAQSkZJRg..." }}Claude base64 格式
Section titled “Claude base64 格式”{ "type": "image", "source": { "type": "base64", "media_type": "image/jpeg", "data": "/9j/4AAQSkZJRg..." }}Gemini base64 格式
Section titled “Gemini base64 格式”{ "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 没有对应概念。
不支持的参数处理
Section titled “不支持的参数处理”哪些参数无法转换
Section titled “哪些参数无法转换”| 参数 | 原协议 | 无法转换到 | 原因 |
|---|---|---|---|
top_k | Claude, Gemini | OpenAI | OpenAI 不支持 top-k 采样 |
n | OpenAI, Gemini | Claude | Claude 不支持多候选生成 |
frequency_penalty / presence_penalty | OpenAI, Gemini | Claude | Claude 没有惩罚参数 |
logprobs | OpenAI | Claude, Gemini | 只有 OpenAI 系模型返回对数概率 |
thinking | Claude | OpenAI, Gemini | Claude 特有的扩展思考配置 |
cache_control | Claude | OpenAI, Gemini | Claude 特有的提示缓存控制 |
reasoning_effort | OpenAI | Claude, Gemini | OpenAI o1 系列特有参数 |
response_format (JSON Schema) | OpenAI | Claude, Gemini | 完整的 JSON Schema 约束只有 OpenAI 支持 |
如何处理不兼容参数
Section titled “如何处理不兼容参数”RouteAPI 采用以下策略:
- 静默忽略:不支持的参数在转换时直接丢弃,不影响请求成功(如
detail、logprobs)。 - 自动调整:超出范围的值被截断到合法区间(如
temperature > 1转发到 Claude 时截断为 1)。 - 保守降级:复杂功能用简单方式模拟(如 OpenAI 的 JSON Schema 在 Claude 上降级为工具调用或提示词约束)。
- 拒绝请求:极少数情况下,如果核心参数无法转换且没有合理默认值,返回 400 错误(如 Claude 协议缺少
max_tokens)。
警告和错误提示
Section titled “警告和错误提示”RouteAPI 在响应头和日志中提供转换信息:
X-RouteAPI-Protocol-Conversion: openai-to-claudeX-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" }}- 使用原生协议:尽量用模型原生协议调用,避免转换损失。
- 避免依赖特定协议特性:不要依赖
logprobs、thinking等单一协议特有能力,除非确定只用该协议的模型。 - 检查响应头:关注
X-RouteAPI-Dropped-Params头,了解哪些参数被忽略。 - 测试跨协议兼容性:在测试环境验证同一请求在不同协议/模型组合下的行为。
- 记录模型 ID:日志中记录实际调用的模型 ID 和协议类型,便于排查差异。
响应格式统一
Section titled “响应格式统一”usage 字段标准化
Section titled “usage 字段标准化”| 协议 | input token 字段 | output token 字段 | total token 字段 |
|---|---|---|---|
| OpenAI | prompt_tokens | completion_tokens | total_tokens |
| Claude | input_tokens | output_tokens | 无(需自行相加) |
| Gemini | promptTokenCount | candidatesTokenCount | totalTokenCount |
转换规则:
- 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 }}finish_reason 标准化
Section titled “finish_reason 标准化”| OpenAI | Claude | Gemini | 含义 |
|---|---|---|---|
stop | end_turn | STOP | 自然结束 |
length | max_tokens | MAX_TOKENS | 达到长度上限 |
tool_calls | tool_use | STOP (含 functionCall) | 请求调用工具 |
content_filter | 无对应 | SAFETY | 内容被安全过滤器拦截 |
stop | stop_sequence | STOP | 命中停止序列 |
转换规则:
- Claude
end_turn→ OpenAIstop - Claude
max_tokens→ OpenAIlength - Claude
tool_use→ OpenAItool_calls - Gemini
STOP根据是否有functionCall映射为stop或tool_calls - Gemini
SAFETY→ OpenAIcontent_filter
错误响应统一
Section titled “错误响应统一”所有协议的错误响应都转换为 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.argumentsJSON 字符串。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结构。
最佳实践总结
Section titled “最佳实践总结”1. 选择合适的协议
Section titled “1. 选择合适的协议”根据客户端和模型类型选择协议:
| 客户端类型 | 目标模型 | 推荐协议 | 原因 |
|---|---|---|---|
| OpenAI SDK | OpenAI 系模型 | OpenAI | 原生支持,零转换 |
| Claude Code | Claude 系模型 | Claude Messages | 原生支持,零转换 |
| LangChain / LiteLLM | 任意模型 | OpenAI | 生态兼容性最好 |
| Anthropic SDK | Claude 系模型 | Claude Messages | 访问扩展思考、提示缓存 |
| 自研客户端 | 任意模型 | 取决于需求 | 优先用目标模型原生协议 |
2. 避免依赖特定协议的特性
Section titled “2. 避免依赖特定协议的特性”如果业务需要跨模型切换,避免使用以下特性:
- 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)
3. 测试跨协议兼容性
Section titled “3. 测试跨协议兼容性”在测试环境验证以下场景:
- 同一协议,不同模型:确保 OpenAI 协议能正确调用 Claude 和 Gemini 模型。
- 不同协议,同一模型:验证 Claude Messages 和 OpenAI 协议调用同一 Claude 模型的结果一致性。
- 工具调用往返:测试跨协议的工具定义、调用和结果传递是否正确。
- 边界参数:测试
temperature: 1.5(OpenAI 合法,Claude 需截断)、n: 2(OpenAI 支持,Claude 不支持)等边界情况。 - 错误处理:验证上游错误是否正确转换为客户端协议格式。
4. 监控和日志
Section titled “4. 监控和日志”记录以下信息便于排查协议转换问题:
{ "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。
5. 渐进式迁移策略
Section titled “5. 渐进式迁移策略”如果要从一个协议迁移到另一个协议:
- 阶段 1:双写测试:新协议调用结果仅用于对比,不影响业务。
- 阶段 2:灰度切换:小流量切换到新协议,监控错误率和响应质量。
- 阶段 3:全量切换:确认无异常后全量切换。
- 阶段 4:清理旧代码:移除旧协议的适配代码。
每个阶段都需要验证:
- 功能正确性(工具调用、多模态、流式输出)
- 响应质量(不同协议/模型组合的输出差异)
- 性能指标(延迟、token 用量、成本)
- 错误处理(网络异常、限流、上游故障)
协议转换让你可以灵活选择客户端和模型,但最佳实践仍然是优先使用目标模型的原生协议。如果必须跨协议调用,请在测试环境充分验证,并在生产环境监控转换相关的错误和性能指标。