OpenAI、Claude 和 Gemini API 格式有什么区别?
对比 OpenAI Responses 与 Chat Completions、Claude Messages、Gemini GenerateContent 的认证、消息、系统指令、流式输出、工具调用、多模态和结构化输出格式。


OpenAI、Claude 和 Gemini 都能完成聊天、图片理解、工具调用和 JSON 输出,但它们的原生 API 不是换个模型名就能互相调用。
最常见的错误是:
- 把 OpenAI 的
messages原样发给 Claude; - 把 Claude 的
system放进 Gemini 的contents; - 只替换 Base URL,却没有转换认证 Header;
- 把三家的工具调用都当作
tool_calls; - 流式响应只按
data: ...文本拼接; - 假设正文永远位于同一个
content字段。
如果你正在写多模型客户端、API 网关或 Agent,真正需要统一的是应用内部数据模型,而不是假设上游协议天然相同。
先看结论:三家核心格式对照
| 项目 | OpenAI Responses | Claude Messages | Gemini GenerateContent |
|---|---|---|---|
| 典型路径 | POST /v1/responses | POST /v1/messages | POST /v1beta/models/{model}:generateContent |
| 模型位置 | 请求体 model | 请求体 model | URL 路径 {model} |
| 认证 | Authorization: Bearer ... | x-api-key: ... | x-goog-api-key: ... |
| 版本 Header | 通常不需要固定日期 Header | anthropic-version | 版本通常体现在 URL,如 v1beta |
| 输入入口 | input | messages | contents |
| 系统指令 | instructions | 顶层 system | systemInstruction |
| 内容单元 | input/output items 与 content parts | content blocks | parts |
| 输出正文 | output 中的 output_text,SDK 常提供聚合属性 | content[] 中的 text block | candidates[].content.parts[] 中的 text |
| 最大输出 | max_output_tokens | max_tokens | generationConfig.maxOutputTokens |
| 工具定义 | tools 中的 function tool | tools + input_schema | tools[].functionDeclarations |
| 工具调用 | function call item | tool_use block | functionCall part |
| 工具结果 | function call output item | tool_result block | functionResponse part |
OpenAI 自己还存在两套常见文本协议:较新的 Responses API 和仍广泛使用的 Chat Completions API。因此“OpenAI 格式”本身也不是单一格式。
消息结构为什么不能直接复制

OpenAI Responses:input 是字符串或输入项
最简单的请求:
curl https://api.openai.com/v1/responses \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "YOUR_MODEL_ID",
"instructions": "Answer concisely.",
"input": "Explain API adapters in one sentence.",
"max_output_tokens": 300
}'
复杂对话可把 input 写成 item 数组。响应的 output 也可能包含消息、工具调用、推理相关项目等,不应硬编码读取:
response.output[0].content[0].text
OpenAI 官方明确提醒,output 往往不止一个 item。官方 SDK 提供的 output_text 聚合属性更适合简单取正文;自己写协议层时则应遍历类型。
OpenAI Chat Completions:messages + choices
旧客户端和大量 OpenAI 兼容网关仍使用:
{
"model": "YOUR_MODEL_ID",
"messages": [
{ "role": "developer", "content": "Answer concisely." },
{ "role": "user", "content": "Explain API adapters." }
],
"max_completion_tokens": 300
}
正文通常在:
choices[0].message.content
这和 Responses API 的 input、instructions、output 不是同一结构。某个服务宣称“OpenAI 兼容”时,还要继续确认它兼容的是 Chat Completions、Responses,还是二者。
Claude Messages:messages 中只有 user 与 assistant 对话角色
基础请求:
curl https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "YOUR_MODEL_ID",
"system": "Answer concisely.",
"max_tokens": 300,
"messages": [
{ "role": "user", "content": "Explain API adapters." }
]
}'
Claude 的 content 可以是字符串,也可以是 block 数组。响应正文不是一个固定字符串,而是:
{
"content": [
{ "type": "text", "text": "..." }
],
"stop_reason": "end_turn",
"usage": {}
}
工具调用、思考、引用等能力也通过不同 block 类型表达。解析器必须按 type 分支。
Gemini:contents → parts
Gemini REST 请求把模型放在 URL 中:
curl "https://generativelanguage.googleapis.com/v1beta/models/YOUR_MODEL_ID:generateContent" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"systemInstruction": {
"parts": [{ "text": "Answer concisely." }]
},
"contents": [{
"role": "user",
"parts": [{ "text": "Explain API adapters." }]
}],
"generationConfig": {
"maxOutputTokens": 300
}
}'
常见正文路径为:
candidates[0].content.parts[].text
但 parts 还可能包含 functionCall、functionResponse、图片或其他模态,因此同样不能只假设第一个 part 一定是文本。
Google 当前文档还提供新的 Interactions API,并建议用它访问最新功能和模型。本文聚焦仍有明确官方参考且广泛使用的
generateContent原生格式;选择接口时应以目标模型当前文档为准。
Role 和系统指令有什么不同
OpenAI
Responses API 使用顶层 instructions,并可在输入 item 中使用角色。Chat Completions 常见 developer、system、user、assistant 等角色;具体优先级和模型支持应看当前官方文档。
Claude
传统 Messages 请求把主要系统提示放在顶层 system,对话消息通常在 user 与 assistant 之间交替。不要简单塞入一条 { "role": "system" } 并假设原生 Claude Messages 会按 OpenAI 方式处理。
Gemini
系统指令使用 systemInstruction,对话历史放入 contents。模型回复角色通常表示为 model,不是 OpenAI/Claude 常用的 assistant。
适配时可建立内部角色:
instruction
user
assistant
再映射为各 Provider 的顶层指令、消息角色与内容结构。
工具调用的字段差异

三家流程都可抽象成:
定义工具
→ 模型请求调用
→ 应用执行函数
→ 把结果连同调用标识发回
→ 模型生成最终回答
但线上格式并不相同。
OpenAI Responses
工具定义通常带:
{
"type": "function",
"name": "get_weather",
"description": "Get current weather",
"parameters": {
"type": "object",
"properties": {
"city": { "type": "string" }
},
"required": ["city"]
}
}
模型产生 function call item,应用执行后用对应 call_id 发送 function call output。不要把 Chat Completions 的 tool_call_id 或 Claude 的 tool_use_id 原样套过来。
OpenAI Chat Completions
模型返回 message.tool_calls[];工具结果作为 role: "tool" 的消息回传,并使用 tool_call_id 关联。
Claude Messages
工具定义使用 name、description、input_schema。Claude 返回:
{
"type": "tool_use",
"id": "toolu_...",
"name": "get_weather",
"input": { "city": "Shenzhen" }
}
应用把结果放进后续用户消息的 tool_result block,并通过 tool_use_id 关联。
Gemini GenerateContent
函数声明放入 tools[].functionDeclarations。模型在 part 中返回 functionCall,应用通过 functionResponse part 回传结果。
因此,跨模型 Tool Runner 至少需要统一:
type ToolCall = {
provider: 'openai' | 'claude' | 'gemini';
id?: string;
name: string;
arguments: unknown;
};
同时保留 Provider 原始 ID 和原始 payload,避免多轮调用时丢失关联信息。
图片和多模态输入怎么表示
| Provider | 常见内容表示 |
|---|---|
| OpenAI Responses | input_text、input_image 等 content item |
| OpenAI Chat Completions | message content 中的 text / image content parts |
| Claude | text、image、document 等 content block,source 描述 URL 或 Base64 |
| Gemini | parts 中使用 text、inlineData、fileData 等 |
不要只改图片字段名。还应转换:
- MIME type;
- URL、Base64 或文件引用方式;
- 单次请求的文件数量与尺寸限制;
- 图片在消息中的顺序;
- PDF、音频和视频支持范围;
- Provider 的文件上传与缓存机制。
客户端内部可以统一为:
type ContentPart =
| { type: 'text'; text: string }
| { type: 'image_url'; url: string; mimeType?: string }
| { type: 'image_base64'; data: string; mimeType: string };
适配层再决定目标 API 是否支持,以及应该变成哪种原生 part/block。
流式响应不是同一种 SSE
OpenAI Responses
Responses API 会发送带明确类型的语义事件,例如文本增量与完成事件。解析器应根据 type 处理,而不是把所有 data 直接拼成字符串。
OpenAI Chat Completions
常见流式正文位于:
choices[0].delta.content
工具参数也可能分多个 delta 到达,需要按调用索引或 ID 累积。
Claude
Claude 流式事件包括:
message_start
content_block_start
content_block_delta
content_block_stop
message_delta
message_stop
文本通常由 text_delta 累积;工具输入可能以部分 JSON delta 形式到达。
Gemini
Gemini 提供 streamGenerateContent。每个流式 chunk 仍围绕 candidates、content 和 parts 组织。不能套用 OpenAI 的 choices[].delta 解析器。
建议内部统一事件:
type NormalizedEvent =
| { type: 'text_delta'; text: string }
| { type: 'tool_delta'; callId?: string; data: string }
| { type: 'usage'; input: number; output: number }
| { type: 'done'; reason?: string }
| { type: 'error'; error: unknown };
但同时保存未知原生事件,避免 Provider 新增类型后被静默丢弃。
结构化输出也不是复制同一个 schema 字段
三家都支持受约束的 JSON 输出,但入口不同:
- OpenAI:Responses 或 Chat Completions 中配置文本/响应格式与 JSON Schema;
- Claude:通过
output_config.format等当前官方能力声明结构; - Gemini:通过
generationConfig.responseMimeType和responseJsonSchema/responseSchema等字段声明。
支持 JSON Schema 不代表完整支持所有关键字。生产代码应:
- 使用各 Provider 官方支持的 Schema 子集;
- 在客户端再次解析和校验;
- 处理拒答、截断、工具调用和空响应;
- 保存原始响应便于排错;
- 不把“JSON mode”误认为一定符合业务 Schema。
关于 Schema 设计,后续可参考专门的结构化输出文章;如果当前接口返回成功但正文为空,可先读 AI API 返回空内容排查。
认证和错误响应也要转换
认证 Header
OpenAI: Authorization: Bearer YOUR_API_KEY
Claude: x-api-key: YOUR_API_KEY
anthropic-version: 2023-06-01
Gemini: x-goog-api-key: YOUR_API_KEY
不要在浏览器前端直接放这些 Key。安全保存方式可参考 API Key 安全指南。
错误格式
即使三家都返回 HTTP 400、401、429 或 5xx,错误 JSON 的嵌套结构、错误类型、请求 ID Header 和重试信息仍不同。
适配器可统一业务错误:
type ProviderError = {
provider: string;
status: number;
code?: string;
type?: string;
message: string;
requestId?: string;
retryable: boolean;
raw: unknown;
};
但不要抹掉原始状态码和 payload。详细状态码处理可参考 AI API 错误排查指南。
如何设计真正可靠的多模型适配层

1. 定义内部 Canonical Model
至少统一:
- system instruction;
- messages 与多模态 parts;
- generation options;
- tool definitions;
- structured output;
- text、tool call、usage、finish reason 与 errors。
2. 每个 Provider 独立编码和解析
Canonical request
├─ OpenAI Responses adapter
├─ OpenAI Chat Completions adapter
├─ Claude Messages adapter
└─ Gemini GenerateContent adapter
不要构造一个包含所有 Provider 字段的巨大 JSON,再期望上游忽略陌生字段。
3. 做能力协商,而不是静默降级
例如目标模型不支持图片、并行工具调用或某个 Schema 关键字时,应明确报错或由策略层决定降级,不能悄悄删除输入。
4. 保留原生响应
统一对象方便业务使用,原生对象方便调试、审计和支持新特性。二者都要保留。
5. 分协议测试
至少测试:
纯文本
多轮消息
系统指令
图片输入
单工具调用
并行工具调用
工具结果回传
流式文本
流式工具参数
结构化输出
截断与拒答
429 和 5xx
“基础聊天成功”不能证明 Agent、流式和工具调用兼容。
使用 Nbility 时如何选格式
Nbility 提供多种协议入口,典型路径包括:
OpenAI Chat Completions: https://api.nbility.ai/v1/chat/completions
OpenAI Responses: https://api.nbility.ai/v1/responses
Claude Messages: https://api.nbility.ai/v1/messages
开始前在 Nbility 模型广场确认:
- 精确 Model ID;
- 该模型支持的协议;
- 工具调用、图片和结构化输出能力;
- 客户端最终请求的 Endpoint;
- Token 权限和额度。
如果现有 SDK 只支持 OpenAI 格式,优先选择平台明确支持的 OpenAI 兼容入口;如果应用依赖 Claude 原生 content blocks,则使用 Messages 入口。不要根据模型品牌猜协议。
遇到兼容问题时,可通过 Nbility 工单提交脱敏后的请求路径、Model ID、状态码和响应类型,不要附带真实 API Key 或完整敏感 Prompt。
FAQ
OpenAI SDK 能直接调用 Claude 或 Gemini 原生 API 吗?
不能直接调用原生格式。只有目标服务额外提供 OpenAI 兼容层时,才可以按它声明的兼容范围使用。
只改 Base URL 和 model 可以吗?
只有 Provider 明确实现了当前客户端所用协议时才可能。认证、路径、工具、流式和响应结构必须同时兼容。
Claude 的 system 能放进 messages 吗?
基础 Messages API 通常使用顶层 system。不要照搬 OpenAI 的 system-role 消息;以当前 Claude 文档和所用功能为准。
Gemini 的 assistant role 是什么?
Gemini contents 中模型回复通常使用 model 角色,而不是 assistant。
三家的 JSON Schema 完全兼容吗?
不完全兼容。入口字段和支持的 Schema 子集可能不同,输出仍需在应用端校验。
为什么普通聊天成功,工具调用却失败?
因为兼容层可能只转换文本消息,没有完整转换工具定义、调用 ID、结果回传和流式参数。
总结
OpenAI、Claude 和 Gemini API 的核心区别不只是字段名:
- Endpoint、认证方式和模型位置不同;
input、messages、contents的语义不同;- 系统指令、角色和多模态内容结构不同;
- 工具调用 ID 与结果回传协议不同;
- 流式事件必须分别解析;
- 结构化输出和 Schema 支持范围不同;
- 多模型系统应使用内部统一模型加独立 Provider Adapter。
先确认客户端实际发送的协议,再选择对应 Endpoint 和 Model ID,能避免大多数“换了模型却 400/404、正文为空或工具不工作”的问题。

