大模型 API 协议差异:OpenAI、Anthropic、Gemini

29 min

接入大模型时,最先绑定的通常不是模型本身,而是接口协议。消息怎么组织、工具怎么调用、流式事件长什么样,三家的做法都不一样,坑也大多藏在这里。

三套协议形态各异,不只是字段命名习惯不同。先聊聊它们为什么会长成这样——模型能力的起点、商业竞争的考量、历史包袱的累积——再逐一看具体形态,很多设计选择就不再是”奇怪的差异”,而是”必然的结果”。

一、协议为什么会长成这样

1. OpenAI:从 Chat 到 Responses,上下文膨胀倒逼的协议升级

Chat Completions 的设计前提是”每次请求自包含所有上下文”——客户端把 messages 数组完整传来,模型完整处理。这在早期没问题:用户问一句、模型答一句,messages 数组不过几十条。

但当工具调用、多模态内容、推理摘要、多轮对话全部塞进 messages 之后,问题来了。一次请求的 messages 可能包含几十条工具调用历史、base64 编码的图片、推理摘要文本——信息膨胀严重,每次请求都在重复传输已经发过的内容。而且 Chat Completions 对”接着上一次继续”没有原生支持——模型不记得上一轮用了什么工具、推理到哪一步,全靠客户端把历史原封不动地传回来。

Responses 在一定程度上就是为了解这个结。OpenAI 的 conversation state 文档previous_response_id 作为跨轮传递上下文的方式之一;reasoning models 文档 也建议 reasoning model 优先使用 Responses,并要求在函数调用后把 reasoning item、function call 和 function output 一起带回去。换句话说,Responses 不只是换了一个 endpoint,它也把消息、工具、推理这些东西拆成了更明确的 typed items。代价同样明显:服务端状态、存储策略、上下文继承规则都要理解清楚,客户端也会失去一部分手工拼上下文的可控性。

另一个角度看,OpenAI 同时维护两套聊天协议,本身也是历史包袱。Chat Completions 已经有海量存量应用,不能简单停掉;Responses 承载新能力,又必须往前推。市场领先者经常会遇到这种尴尬:新接口更合理,但老接口更有生态。

2. 模态差异决定了接口形态

三家协议的差异,根源上是因为各家模型的起点不同。

OpenAI 的早期 API 是按能力线长出来的。最早的 OpenAI API 以文本补全为核心;后来 DALL·E 通过独立的 DALL·E API 进入应用;语音转文字则由 Audio APItranscriptionstranslations 端点承载,文档里也明确说这两个端点历史上由 Whisper 支撑。每种模型的输入输出格式都不同,API 自然按这个边界来设计:聊天的归聊天,图片的归图片,音频的归音频。后来 OpenAI 模型页 开始写“最新模型支持 text/image input 和 vision”,原本清楚的资源边界就变模糊了:聊天接口里有图片、工具、推理,Responses 又试图把这些重新整理成 typed items。

Gemini 走的是另一条路。Google 在 Gemini 1.0 发布文 里就说 Gemini 是从头构建的多模态模型,可以跨文本、代码、音频、图片和视频工作。对应到 API,Gemini API reference 也把 Content 定义成一轮消息的容器,把 Part 定义成承载文本、图片、视频等内容的基本单元。文本是一个 part,图片是一个 part,函数调用也是一个 part。这不是单纯的设计审美差异,而是模型能力和平台目标共同推出来的接口形态。

Claude 的位置介于两者之间。Anthropic 的 模型概览 写得很直接:当前 Claude 模型支持文本和图片输入、文本输出、多语言和视觉能力。工具调用和 thinking 则都通过 Messages API 的 content blocks 表达。也就是说,Claude 的重点更像是“多模态输入、文本/工具输出”的对话代理,而不是为图片、音频、视频分别开一组资源端点。这个定位很适合用 /v1/messages 和 content blocks 承载。模型的输入输出模态,本质决定了它的协议更像一份”资源目录”,还是一条”统一内容流”。

3. 协议是商业竞争的一部分

协议从来不只是技术问题。用自己的协议有几个直接好处:新字段和新能力可以按自己的节奏加;SDK、文档、最佳实践都围绕自己的产品来写;开发者一旦深度接入,切换成本会越来越高。

反过来,使用别人的协议就会被动。OpenAI 加了一个字段,你要不要跟?Anthropic 改了 tool_use 行为,兼容层要不要修?所以各家都有动力推原生协议。不是为了”故意不一样”,而是为了掌握迭代节奏。

但兼容生态明显偏向 OpenAI。OpenAI-compatible 已经是大模型 API 的事实标准之一:很多 SDK 默认支持,很多网关默认暴露,很多新模型提供商也会先做 OpenAI 兼容。Google 不只提供 Gemini 原生 API,也提供 OpenAI 兼容端点,官方示例里直接用 OpenAI SDK、改 base_url 调 Gemini。原因未必是 OpenAI 协议最优,而是生态惯性足够强。

三家都不返回原始思维链,只给摘要——表面上是隐私和安全的考虑,但更深一层的原因是防止模型蒸馏。完整思维链是高价值资产。OpenAI 在 Learning to reason with LLMs 里解释为什么不展示 raw chain-of-thought,理由包括用户体验、competitive advantage,以及保留 chain-of-thought monitoring 的可能性;OpenAI 的 服务条款 也禁止用输出开发与 OpenAI 竞争的模型。所以,把 raw CoT、reasoning.encrypted_content、Anthropic signature、Gemini thoughtSignature 放在同一个框架里看,它们至少都在处理同一个问题:模型需要跨轮延续推理状态,但厂商不愿意把完整推理过程变成可自由使用的明文训练材料。

不过,各家协议都在往”统一内容表示”靠近:OpenAI 的 Responses 把输出拆成 typed items,Anthropic 用 content blocks,Gemini 从一开始就是 parts。长远看,字段名还会不同,但概念差异可能会缩小。真正决定选型的,更多会回到模型能力、价格、延迟、区域和合规这些问题。

4. 协议定位背后的公司哲学

当 OpenAI 兼容格式成为事实标准之一,协议之争就不再只是”谁的字段更好看”。但不争不等于原生协议会消失:原生协议通常是新能力的第一落点,也是最少被兼容层裁剪的入口。

从这个角度重新看三种协议,它们确实有不同气质:

  • OpenAI:产品线痕迹很重。Chat、Images、Audio、Videos 各自有资源端点,Responses 再把新一代模型能力收拢起来。
  • Anthropic:概念更少。Messages API、content blocks、tools、thinking,主要围绕对话代理和工具使用展开。
  • Google:平台痕迹最明显。Gemini Developer API 适合直接开发;Vertex AI 路线则服务于 Google Cloud 的认证、区域、配额和企业治理。Google 自己的 迁移文档 也提醒,两条路线的区域、模型训练和密钥管理并不完全一样。

理解这些,不只是为了选协议,也在提醒自己:兼容层能解决 80% 的接入问题,但最后 20% 的能力差异,往往只在原生协议里最清楚。

有了这些背景,下面逐一看三套协议的具体形态——以 OpenAI 为主线展开,Anthropic 和 Gemini 作为对比,讲清楚每一种协议里”内容放在哪里”。

二、OpenAI 接口协议

从兼容层看,OpenAI 仍然是生态最厚的一套协议。大量 SDK、Agent 框架和代理网关都先支持 OpenAI 格式,再去适配其他厂商。它的核心思路是按资源端点拆能力:聊天、图片、音频、视频各有各的接口。以下内容主要参考 OpenAI 官方文档

但聊天这件事本身,OpenAI 就给了两个入口,先把这个理清楚。

1. Chat Completions:最广的兼容面

POST /v1/chat/completions 是最经典、兼容面最广的聊天入口,详见 Chat Completions API。核心结构是 messages 数组,靠 role 区分角色。

1.1 非流式

不带 stream 参数时,一次请求返回完整结果。

请求:

{
  "model": "gpt-5.5",
  "messages": [
    { "role": "system", "content": "用清楚、准确的中文回答。" },
    { "role": "user", "content": "用一句话解释什么是大模型 API。" }
  ]
}

响应的 objectchat.completion,内容在 choices[].message 里:

{
  "id": "chatcmpl_123",
  "object": "chat.completion",
  "model": "gpt-5.5",
  "choices": [{
    "index": 0,
    "message": {
      "role": "assistant",
      "content": "大模型 API 是应用调用模型能力的一组 HTTP 接口和对象格式。"
    },
    "finish_reason": "stop"
  }],
  "usage": { "prompt_tokens": 24, "completion_tokens": 18, "total_tokens": 42 }
}

1.2 SSE 流式

加上 "stream": true,服务端通过 SSE(Server-Sent Events)逐段推送。每个事件是一行 data: 加一段 JSON,客户端持续把 delta.content 拼起来,最后遇到 data: [DONE] 结束:

data: {"id":"chatcmpl_123","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}

data: {"id":"chatcmpl_123","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"大模型"},"finish_reason":null}]}

data: {"id":"chatcmpl_123","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"API"},"finish_reason":null}]}

data: {"id":"chatcmpl_123","object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}

data: [DONE]

注意几个细节:第一个 chunk 通常只带 delta.role,没有文本内容;最后一个有效 chunk 的 delta 可能为空,只带 finish_reason[DONE] 不是 JSON,必须单独处理。

1.3 工具调用

Chat Completions 的工具声明放在 tools[] 里,用 JSON Schema 描述参数。

请求:

{
  "model": "gpt-5.5",
  "messages": [
    { "role": "user", "content": "查询杭州天气,判断是否适合露天活动。" }
  ],
  "tools": [{
    "type": "function",
    "function": {
      "name": "get_weather",
      "description": "获取指定城市的天气。",
      "parameters": {
        "type": "object",
        "properties": { "city": { "type": "string" } },
        "required": ["city"]
      }
    }
  }]
}

模型请求调用工具时,assistant message 里会出现 tool_calls

{
  "choices": [{
    "index": 0,
    "message": {
      "role": "assistant",
      "content": null,
      "tool_calls": [{
        "id": "call_abc123",
        "type": "function",
        "function": { "name": "get_weather", "arguments": "{\"city\":\"杭州\"}" }
      }]
    },
    "finish_reason": "tool_calls"
  }]
}

应用执行工具后,把结果作为一条 role: "tool" 消息放回 messages,模型继续生成最终回复:

{
  "model": "gpt-5.5",
  "messages": [
    { "role": "user", "content": "查询杭州天气,判断是否适合露天活动。" },
    {
      "role": "assistant",
      "content": null,
      "tool_calls": [{
        "id": "call_abc123",
        "type": "function",
        "function": {
          "name": "get_weather",
          "arguments": "{\"city\":\"杭州\"}"
        }
      }]
    },
    { "role": "tool", "tool_call_id": "call_abc123", "content": "{\"temp\":22,\"condition\":\"\"}" }
  ]
}

流式场景下,tool_calls 的增量可能分多个 chunk 到达——arguments 字段会逐段拼接,不能假定一次收全。

1.4 思考控制

Chat Completions 通过 reasoning_effort 控制推理模型的思考强度。这个字段不要硬编码:API 枚举和具体模型支持范围不是一回事。以当前 gpt-5.5 为例,模型页列出的 reasoning 取值是 nonelowmediumhighxhigh;有些接口说明里还会出现 minimal,但不是每个模型都支持。

它不返回原始思维链。需要让用户看到推理过程时,只能看模型支持的摘要或解释字段,不能假设能拿到完整 chain-of-thought。详见 OpenAI Reasoning 文档

2. Responses:新项目的推荐入口

POST /v1/responses 是 OpenAI 后来推出的新入口,把一次生成建模成一个 response 对象。和 Chat Completions 最大的不同在于,它把文本、工具调用、推理内容都统一放进 output[] 数组里,结构更规整。

2.1 基本请求

请求:

{
  "model": "gpt-5.5",
  "instructions": "用清楚、准确的中文回答。",
  "input": "用一句话解释什么是大模型 API。"
}

响应的 objectresponse,内容在 output[] 里:

{
  "id": "resp_123",
  "object": "response",
  "status": "completed",
  "model": "gpt-5.5",
  "output": [{
    "type": "message",
    "role": "assistant",
    "content": [{
      "type": "output_text",
      "text": "大模型 API 是应用调用模型能力的一组 HTTP 接口和对象格式。"
    }]
  }],
  "usage": { "input_tokens": 20, "output_tokens": 18, "total_tokens": 38 }
}

2.2 多模态输入和工具

input 不只是字符串,也可以是带 rolecontent[] 的消息数组,多模态内容作为不同类型的 content item:

{
  "model": "gpt-5.5",
  "input": [{
    "role": "user",
    "content": [
      { "type": "input_text", "text": "解释这张图的主要内容。" },
      { "type": "input_image", "image_url": "https://example.com/image.png" },
      { "type": "input_file", "file_id": "file_123" }
    ]
  }],
  "tools": [
    { "type": "web_search" },
    {
      "type": "function",
      "name": "get_weather",
      "description": "获取指定城市的天气。",
      "parameters": {
        "type": "object",
        "properties": { "city": { "type": "string" } },
        "required": ["city"]
      }
    }
  ]
}

工具调用结果也出现在 output[] 里,类型为 function_call。应用执行完后,下一轮请求在 input 里用 function_call_output item 回填结果,并用 call_id 对上原来的调用:

{
  "type": "function_call_output",
  "call_id": "call_abc123",
  "output": "{\"temp\":22,\"condition\":\"\"}"
}

2.3 推理控制

Responses 对推理的支持更精细,通过 reasoning 字段控制:

{
  "model": "gpt-5.5",
  "input": "分析这个接口设计的风险。",
  "reasoning": {
    "effort": "high",
    "summary": "auto"
  }
}

effort 控制思考强度,具体取值仍然看模型页。当前 gpt-5.5 支持 nonelowmediumhighxhighsummary 控制是否返回推理摘要。和 Chat Completions 一样,这里控制的是推理强度和摘要,不等于返回原始思维链。

如果需要无状态地延续推理上下文,可以在请求里加 include: ["reasoning.encrypted_content"]。这样返回的 reasoning item 会带加密内容,下一轮把它原样带回去即可。这个机制尤其适合 store: false 或 Zero Data Retention 场景。

2.4 上下文延续

Responses 不会因为你在同一个进程里调用两次就自动记住前文。第二轮只发一句”继续”,模型拿不到上一轮上下文。主动管理上下文有三种常见方式:

  1. 把历史和上一轮 output item 继续放进 input
  2. previous_response_id,让服务端引用上一轮 response。
  3. 用 Conversations API 管一条持久会话。

这里有两个容易漏掉的细节:previous_response_id 不会继承上一轮顶层 instructions,稳定的系统/开发者指令要每轮重发;它也不等于免费引用历史,链路里的前文 token 仍然会计入输入。

2.5 流式事件

Responses 的流式输出也是 SSE,但事件更语义化:

event: response.output_text.delta
data: {"type":"response.output_text.delta","response_id":"resp_123","item_id":"msg_1","output_index":0,"content_index":0,"delta":"大模型"}

event: response.completed
data: {"type":"response.completed","response":{"id":"resp_123","status":"completed"}}

每种事件有明确的 type,不像 Chat Completions 全部是 chat.completion.chunk。这对写解析逻辑的人更友好。

3. 其他能力一览

除聊天外,OpenAI 还为不同能力提供了独立端点。它们都不走 messages 结构:

图片POST /v1/images/generations 做文生图,返回 data[]。当前 GPT Image 系列,包括 gpt-image-2,主要返回 base64 图片数据;可以用 output_format 控制 png/jpeg/webp。/v1/images/edits 做图像编辑,/v1/images/variations 仍主要是旧 DALL·E 2 时代的变体接口。Responses 也能通过内置 image_generation 工具在对话里生成或编辑图片。

向量化POST /v1/embeddings,输入文本数组,返回向量列表。dimensions 参数影响索引维度,不能随便换。

音频/v1/audio/speech(文本转语音,返回音频二进制)、/v1/audio/transcriptions(语音转文字)、/v1/audio/translations(音频翻译,输出英文)。后两个用 multipart 表单上传音频文件。

视频POST /v1/videos 是异步任务,当前模型包括 sora-2sora-2-pro。先创建 job,再用 GET /v1/videos/{id} 轮询状态,完成后通过 GET /v1/videos/{id}/content 下载 MP4。和普通图像生成不同,视频生成不要按一次请求直接返回文件来设计。详见 Videos API

实时语音:走 WebSocket(wss://api.openai.com/v1/realtime),建连后通过事件对象通信,和普通 HTTP JSON 请求形态完全不同。

其他/v1/models 列出模型,/v1/moderations 做内容审核,/v1/files 上传文件,/v1/completions 是老的文本补全接口(新项目一般不优先用它)。

小结:OpenAI 的优势是端点覆盖广、生态成熟。需要留意的点是 Chat Completions 和 Responses 两个聊天入口的差异,以及图片、音频、视频各有独立对象格式。做统一抽象时,别把所有能力都强行塞成一条”聊天消息”。

三、Anthropic 接口协议(Claude)

Anthropic 的 Messages API 是 Claude 生成内容的主入口:/v1/messages。它的核心设计很克制:文本、图片、工具调用、工具结果、thinking 都是 content blocks。

一个同时包含工具声明和推理控制的请求:

{
  "model": "claude-sonnet-4-6",
  "max_tokens": 16000,
  "system": "用简洁的中文回答。",
  "thinking": { "type": "adaptive", "display": "summarized" },
  "output_config": { "effort": "high" },
  "tools": [{
    "name": "get_weather",
    "description": "获取指定城市的天气。",
    "input_schema": {
      "type": "object",
      "properties": { "city": { "type": "string" } },
      "required": ["city"]
    }
  }],
  "messages": [{
    "role": "user",
    "content": [{ "type": "text", "text": "查询杭州天气,判断是否适合户外活动。" }]
  }]
}

响应里,各种内容都是 content[] 里的 block:

{
  "role": "assistant",
  "content": [
    { "type": "thinking", "thinking": "需要先查天气再判断……", "signature": "EosnC..." },
    { "type": "tool_use", "id": "toolu_01", "name": "get_weather", "input": { "city": "Hangzhou" } }
  ],
  "stop_reason": "tool_use"
}

工具调用请求(tool_use)和 thinking 都只是 content[] 里的一种 block,结构很统一。应用执行工具后,把结果作为 tool_result block 放回下一轮 messages 即可。

推理控制方面,新版 Claude 推荐用 thinking: { type: "adaptive" } 让模型自行判断什么时候需要 thinking,再用 output_config.effort 控制整体 token 花费和深度。当前 API effort 常见取值包括 lowmediumhighxhighmax,具体见 Anthropic Effort 文档。部分旧模型仍支持 thinking: { type: "enabled", budget_tokens: 10000 } 这种固定 token 预算,但在 Opus/Sonnet 4.6 之后已经不是推荐路径。

Claude 的 thinking block 可能返回摘要,也可能只返回空 thinking 加 signature,取决于模型和 display 设置。原始思维链不作为稳定可用的 API 输出。如果跨轮延续推理上下文,尤其是工具调用场景,需要保留 signature,不要自己改写 thinking block。详见 Anthropic Extended Thinking

流式输出也围绕 block 事件展开:content_block_startcontent_block_deltacontent_block_stop。工具参数的增量和文本增量可能交替出现,不能只按”文本 delta”处理。

小结:Anthropic 协议设计简洁,content blocks 让工具调用和多模态输入很自然。代价是兼容生态不如 OpenAI 广。接入 Claude 时,很多项目最后还是要写一层从 OpenAI message 到 Anthropic block 的转换。

四、Gemini / Vertex AI 接口协议

Gemini 的协议核心是 generateContent,所有内容围绕 contents[]parts[] 组织,详见 Gemini API 文档。这里最容易混的是入口:同一个 Gemini 模型可以通过 Gemini Developer API 调用,也可以通过 Vertex AI 调用。前者走 generativelanguage.googleapis.com 和 API key,后者走 Google Cloud 的区域端点和 IAM。路径、鉴权、配额体系不同,但主体请求结构都围绕 contents/parts。

1. contents 和 parts

contents[] 是对话轮次,parts[] 是一轮里的具体内容。文本、图片、文件、函数调用全都是 part:

请求:

{
  "contents": [{
    "role": "user",
    "parts": [
      { "text": "生成一张夜间咖啡馆的图片,并用一句话描述风格。" }
    ]
  }],
  "generationConfig": {
    "responseModalities": ["TEXT", "IMAGE"],
    "thinkingConfig": { "thinkingLevel": "medium" }
  }
}

响应里,各种内容都在 candidates[].content.parts[] 里:

{
  "candidates": [{
    "content": {
      "role": "model",
      "parts": [
        { "thought": true, "text": "需要同时给出描述和图片。" },
        { "text": "暖色调夜间咖啡馆,轻微电影感。" },
        { "inlineData": { "mimeType": "image/png", "data": "iVBORw0KGgo..." } }
      ]
    },
    "finishReason": "STOP"
  }],
  "usageMetadata": { "promptTokenCount": 120, "candidatesTokenCount": 52, "totalTokenCount": 1300 }
}

2. 工具调用和推理

工具调用走 parts:模型请求工具时返回 functionCall part,里面有 nameargs。Gemini 3 系列会给每个 function call 一个 id;手写 REST 或自己维护历史时,回填 functionResponse 必须带上同一个 id,否则模型可能对不上是哪次调用的结果。详见 Gemini Function Calling

推理控制放在 generationConfig.thinkingConfig。Gemini 3 系列用 thinkingLevelminimal / low / medium / high),Gemini 2.5 系列常见写法是 thinkingBudget(具体 token 数,0 关闭、-1 动态分配)。详见 Gemini Thinking。如果模型在 parts 里返回了 thoughtSignature,下一轮请求要把它放回原来的 part;尤其是函数调用链路里,丢掉 signature 会破坏模型的跨轮推理上下文。

小结:Gemini 的优势是多模态统一,所有模态都是一种 part,不需要在不同端点间跳转。代价是 Developer API 和 Vertex AI 两个入口容易搞混,OpenAI 兼容层也只是方便迁移,不等于覆盖 Gemini 原生能力。

五、对比与选型

1. 整体设计

维度OpenAIAnthropicGemini
核心抽象按资源拆端点按 content blocks 组织按 parts 组织
主入口chat/completionsresponses/v1/messages(唯一入口)generateContent
多模态方式不同能力走不同端点不同内容的 block 类型不同内容的 part 类型
流式输出chat.completion.chunk 或 response eventcontent block 事件streamGenerateContent chunk
上下文管理客户端传历史(Responses 可引用已有 response)客户端传 messages 历史客户端传 contents 历史
生态兼容最强,已成事实标准原生体验好,适配较少多模态统一,但生态最窄

2. 工具调用差异

这是写 Agent 和协议转换层时最容易踩坑的地方——三家”模型请求工具”和”应用回填结果”的位置各不相同:

协议模型请求工具应用回填结果
OpenAI Chatassistant message 的 tool_calls[]下一条 role: "tool" 消息
OpenAI Responsesoutput[] 里的 function_call item下一轮 input 里的 function_call_output item
Anthropicassistant content 里的 tool_use blockuser content 里的 tool_result block
Geminimodel parts 里的 functionCalluser parts 里的 functionResponse

这个差异的本质是”工具调用放在哪一层”。OpenAI(Chat Completions)把工具调用作为消息的一个附属字段——assistant message 除了 content 正文,额外挂了一个 tool_calls[],回填时也要专门开一条 role: "tool" 消息。Anthropic 和 Gemini 则把工具调用和文本放在同一层——tool_use 就是一个 block 类型,functionCall 就是一个 part 类型,和 text 类型平级,都在同一个 content[] / parts[] 数组里。

3. 思考控制差异

协议控制参数返回值跨轮延续
OpenAI Chatreasoning_effort推理摘要(部分模型)不直接支持
OpenAI Responsesreasoning.effort + reasoning.summary推理摘要,可选加密内容include: ["reasoning.encrypted_content"]
Anthropicthinking.type + output_config.effortthinking block 摘要或省略文本保留 signature
GeminithinkingConfig.thinkingLevelthinkingBudgetthought: true part保留 thoughtSignature

三家都不应该按”能拿到原始思维链”来设计。需要跨轮延续推理上下文时,各自有不同机制:Responses 传加密 reasoning item,Anthropic 保留 thinking block 的 signature,Gemini 保留 thoughtSignature。

4. 选型建议

对比表看完,具体怎么选?分三种情况:

以 OpenAI 协议作为对外接口:如果你在做需要对接多个下游的应用或网关,OpenAI 协议通常最省事。客户端最多,SDK 支持最广,很多兼容服务换 base URL 和模型名就能先跑起来。

直接接入某个模型:如果只用一家,走原生协议更自然。Anthropic 的 content blocks 对工具调用很友好,Gemini 的 parts 对多模态最统一。

多模态优先:Gemini 的 parts 设计让文本、图片、音频、视频共用同一套结构,不需要在不同端点间跳转。OpenAI 也在往这个方向补,尤其是 Responses 里的输入 item 和内置工具,但独立资源端点仍然存在。

5. 协议兼容方案

跨协议接入时,常见的兼容方案分两类:

服务端网关负责对客户端暴露一种协议、对上游转成另一种。AxonHub 同时暴露 OpenAI、Anthropic、Gemini 三种入口,内部用统一中间结构做转换;New API 把各家协议拆成更细的 relay format,适合做模型分发和计费。

应用层库负责代码里统一调用、底层处理差异。LangChain 用 ChatModel 接口统一调用不同 provider,Vercel AI SDKgenerateTextstreamText 等函数屏蔽底层协议细节。

无论用哪种方案,协议转换的核心都是同一件事:把一种协议里”内容放在哪里”映射到另一种。理解这个,很多看起来零散的字段差异就会变得好处理。