大模型 API 协议不是网络协议:一次讲透 Chat Completions、Responses 和 Messages

发布于 · 2,180 字 · 约 5 分钟#Agent 基建#DevOps
大模型 API 协议不是网络协议:一次讲透 Chat Completions、Responses 和 Messages 封面图
  • 大模型 API 协议是应用层接口规范,不是 HTTP 那样的网络传输协议
  • Chat Completions 凭极简抽象成为事实兼容标准,几乎所有第三方都兼容
  • Responses 用多 Output Item 结构原生表达 Agent 多步骤执行过程
  • Anthropic Messages 的 system 顶层、内容块数组与结构化工具参数是三大差异点
  • 统一 AI SDK 的难点在工具调用、SSE 事件与 Usage 口径,而非文本聊天

上周帮一个同事排查问题,他要把项目里的模型供应商从 OpenAI 换成 Claude,改完 base URL 和 key 之后一顿报错。他挠着头问我:“不是说好都兼容 OpenAI 协议吗,怎么换个模型就崩了?”

我看了眼他的代码,问题很典型:他用的是 Anthropic 的 /v1/messages 端点,但请求体还是 OpenAI 的 messages + choices 那套结构。说白了,他把“OpenAI 协议”当成了一根万能充电线,以为所有手机插上就能充。

这事儿背后其实是一堆程序员天天在用、但很少真正搞清楚的概念:Chat Completions、Responses、Messages,这些天天在文档里见的“协议”到底是什么? 今天这篇一次讲透。内容基于 OpenAI、Anthropic、Google、Cohere 的官方文档整理。

三大主流大模型 API 协议对比总览
三大主流大模型 API 协议对比总览

一、先纠正一个误解:它们不是网络协议

很多人第一次听到“OpenAI 协议”这个词,下意识会想:是不是 OpenAI 发明了一套网络传输技术?

不是。Chat Completions、Responses、Messages、Gemini generateContent,这些都不是 HTTP、WebSocket 那一层的网络传输协议,而是大模型 API 的应用层接口规范:约定请求打到哪里、JSON 长什么样、怎么鉴权、消息有哪些角色、工具调用怎么表示、流式吐字的事件格式是什么。

把大模型接口拆开分层看,结构其实很清晰:

应用层接口规范(各家方言)
├── OpenAI Chat Completions
├── OpenAI Responses
├── Anthropic Messages
└── Gemini generateContent

传输与数据层(大家的公共底座)
├── HTTPS
├── JSON
└── SSE 流式事件

网络层
└── TCP / TLS / HTTP
大模型 API 接口的三层结构
大模型 API 接口的三层结构

理解了这张图,很多问题就有了答案。比如市面上常说的“某某服务 OpenAI 协议兼容”,真实含义是:请求和响应的 JSON 格式兼容,你拿 OpenAI 的 SDK 改个 base URL 就能用。底层大家走的都是一样的 HTTPS + JSON + SSE,并没有什么黑科技。

我那个同事的问题也就出在这:Claude 的原生端点说的是另一种“方言”,OpenAI 格式的请求体发过去,自然对不上。

二、三大主流协议速览

先上一张总表建立整体印象,后面逐个拆:

协议典型端点输入核心字段输出核心结构主要特点第三方兼容性
OpenAI Chat Completions/v1/chat/completionsmessageschoices[].message结构简单、生态成熟最强
OpenAI Responses/v1/responsesinput、instructionsoutput[]面向 Agent、多模态和内置工具持续增长
Anthropic Messages/v1/messagessystem、messagescontent[]Claude 原生能力表达完整较弱

如果用语言来打比方:Chat Completions 是事实上的“普通话”,几乎人人都得会;Responses 是 OpenAI 主推的“新官方语言”,为 Agent 时代设计;Messages 是 Claude 的“母语”,表达 Claude 的能力最完整。

三、Chat Completions:事实上的普通话

一个典型请求长这样:

{
  "model": "gpt-5",
  "messages": [
    { "role": "system", "content": "你是一名技术助手" },
    { "role": "user", "content": "解释一下 SSE" }
  ],
  "stream": true
}

响应的核心结构:

{
  "choices": [
    {
      "message": { "role": "assistant", "content": "SSE 是一种服务端推送技术……" },
      "finish_reason": "stop"
    }
  ],
  "usage": { "prompt_tokens": 20, "completion_tokens": 100, "total_tokens": 120 }
}

一组消息进去,一条助手消息出来——这个极简的抽象,是它成功的另一半原因。它已经成为大模型接口领域事实上的兼容标准:

  • OpenRouter、DeepSeek、Groq、vLLM、Ollama 等大量服务和框架都提供兼容端点;
  • SDK、社区工具、教程最丰富;
  • 换模型供应商时迁移成本最低;
  • 聊天、文本生成、简单多模态、Function Calling 都能覆盖。

一个命名陷阱要留意:配置里经常见到 openai-completions 这个名字,但它通常指的是 Chat Completions(/v1/chat/completions),而不是早已过时的 Legacy Completions(/v1/completions,旧式纯文本补全接口):

名称端点说明
Legacy Completions/v1/completions旧式纯文本补全接口
Chat Completions/v1/chat/completions当前广泛使用的消息接口

看到 openai-completions 时,最好查一下框架文档,确认它实际调用哪个端点。说实话,这个坑我自己也踩过,排查了半天才发现两个接口根本不是一回事。

四、Responses:为 Agent 而生的新一代接口

Responses API 是 OpenAI 面向新一代模型、Agent、多模态和工具调用设计的统一接口,典型端点 /v1/responses:

{
  "model": "gpt-5",
  "instructions": "你是一名技术助手",
  "input": [
    {
      "role": "user",
      "content": [
        { "type": "input_text", "text": "解释一下 SSE" }
      ]
    }
  ]
}

它和 Chat Completions 最本质的区别,是核心抽象换了。

Chat Completions 的世界观是:

一组消息 → 一条助手消息

而 Responses 的世界观是:

一个 Response
└── 多个 Output Item
    ├── message          (模型说的话)
    ├── reasoning        (推理过程)
    ├── function_call    (函数调用)
    ├── web_search_call  (联网搜索)
    ├── file_search_call (文件检索)
    └── computer_call    (操作电脑)
一个 Response 包含多个 Output Item
一个 Response 包含多个 Output Item

为什么这个变化重要?因为 Agent 的一次执行,产出往往不是“一句话”:它可能先推理、再调工具、再根据工具结果继续推理、最后才给出回答。Chat Completions 只能把这些硬塞进 choices[].message,而 Responses 用一个列表原生地表达整个多步骤过程。

适合的场景:

  • OpenAI 新模型;
  • Agent 与复杂工具调用;
  • Web Search、File Search;
  • Code Interpreter、Computer Use;
  • 多模态输入输出;
  • 服务端会话状态管理。

顺便澄清一个流传很广的说法——“只有 OpenAI 自家用 Responses”。更准确的表述是:它由 OpenAI 主推,第三方兼容生态正在扩大,但成熟度仍不如 Chat Completions。

五、Messages:Claude 的母语

Anthropic Messages(/v1/messages)是 Claude 的原生消息协议:

{
  "model": "claude-sonnet-4-5",
  "system": "你是一名技术助手",
  "max_tokens": 1024,
  "messages": [
    { "role": "user", "content": "解释一下 SSE" }
  ]
}

第一眼就能看出几个和 OpenAI 不一样的地方:

  • system 是顶层字段,不混在消息数组里;
  • max_tokens 通常需要显式传入;
  • content 是内容块数组而不是纯字符串:
[
  { "type": "text", "text": "我需要查询一下" },
  {
    "type": "tool_use",
    "id": "toolu_xxx",
    "name": "search",
    "input": { "query": "SSE" }
  }
]

它的最大价值在于:能最完整地表达 Claude 的原生能力——工具调用、提示词缓存、扩展思考,都只有走原生协议才能用到全部细节。

六、藏在细节里的设计分歧

协议之间的差异,最能在两个“不起眼”的地方看出来。

分歧一:工具调用参数——JSON 字符串 vs JSON 对象

同样是“模型决定调用 search 工具”,两家的表示是。

OpenAI Chat Completions:

{
  "tool_calls": [
    {
      "id": "call_xxx",
      "type": "function",
      "function": {
        "name": "search",
        "arguments": "{\"query\":\"SSE\"}"
      }
    }
  ]
}

Anthropic Messages:

{
  "type": "tool_use",
  "id": "toolu_xxx",
  "name": "search",
  "input": { "query": "SSE" }
}

注意 OpenAI 的 arguments 是 JSON 字符串——相当于把结构化数据塞进了字符串信封里,你的应用还得再 JSON.parse 一次;而 Anthropic 的 input 本身就是 JSON 对象,拿来即用。写统一 SDK 时,这是第一批要抹平的差异。

分歧二:流式输出——同是 SSE,方言不同

三种协议的流式输出都基于 SSE,但事件格式各说各话。同样是吐出一个“你”字:

Chat Completions:

data: {"choices":[{"delta":{"content":"你"}}]}

Responses:

event: response.output_text.delta
data: {"delta":"你"}

Anthropic Messages:

event: content_block_delta
data: {"delta":{"type":"text_delta","text":"你"}}

这带来一个重要推论:模型网关不能只做 HTTP 转发。它必须完整转换流式事件、结束原因(finish reason)、Usage 统计和工具调用状态,任何一个环节对不齐,客户端看到的就是乱码或截断。

七、协议圈里的其他玩家

除了三大主流,还有几个常见面孔:

协议端点 / 形态特点
Gemini generateContentPOST /v1beta/models/{model}:generateContent用 contents → parts 表达文本、图片、音频、视频等多模态内容;另有 streamGenerateContent、Embedding、Batch,以及更适合 Agent 的 Interactions API
Cohere Chat/v2/chat原生接口之外,还提供 OpenAI Compatibility API,已有 OpenAI SDK 可直接接入
Ollama/api/chat、/api/generate本地推理的代表;同样提供 OpenAI 兼容接口,通用客户端无需适配其原生格式
AWS Bedrock ConverseConverse / ConverseStream为 Claude、Llama、Mistral、Amazon Nova 等模型提供统一抽象,主要服务于 AWS 生态

可以看到一个清晰的模式:几乎每家都是“自己的原生协议 + 一层 OpenAI 兼容”。原生协议表达自家能力最完整,OpenAI 兼容层负责融入生态。

八、怎么选?一张表 + 一句话

使用场景推荐协议
不确定应该选择什么OpenAI Chat Completions
接入多个第三方模型供应商OpenAI Chat Completions
建设统一模型网关OpenAI Chat Completions 作为外部兼容层
使用 OpenAI Agent 与内置工具OpenAI Responses
使用 Claude 并追求完整原生能力Anthropic Messages
使用 Gemini 原生多模态能力Gemini generateContent / Interactions

一句话总结:

通用兼容 → Chat Completions
OpenAI Agent → Responses
Claude 原生 → Anthropic Messages

九、进阶:想造统一 AI SDK 的看这里

如果你的系统要同时接多家模型,最忌讳的就是让业务代码直接绑定任何一家的请求格式——我同事踩的坑,本质就是这个。正确姿势是先建立自己的统一领域模型:

统一模型
├── Message
├── ContentPart
├── ToolDefinition
├── ToolCall
├── ToolResult
├── Usage
├── FinishReason
└── StreamEvent

然后通过 Adapter 模式对接各家协议:

业务代码
    ↓
统一 AI SDK
    ├── OpenAIChatAdapter
    ├── OpenAIResponsesAdapter
    ├── AnthropicMessagesAdapter
    └── GeminiAdapter
统一 AI SDK 的 Adapter 架构
统一 AI SDK 的 Adapter 架构

提前预警:真正难以统一的并不是文本聊天——那部分各家几乎长得一样。难的是这些:

  • 工具调用参数和工具结果的表示;
  • 推理内容(reasoning)的暴露方式;
  • 多模态内容块;
  • SSE 事件粒度;
  • Usage 统计口径;
  • Finish Reason 枚举;
  • 服务端会话状态;
  • 各厂商特有的内置工具(Web Search、File Search、Computer Use……)。

把这些差异封装在 Adapter 层,业务代码才能做到“换模型只改配置”。

十、结语

回到开头我同事的问题:大模型“协议”不是网络协议,而是应用层的接口规范之争。Chat Completions 赢在了生态,Responses 赢在了抽象,Messages 赢在了原生表达力。作为工程师,理解它们的设计动机,比背下字段名更重要——因为字段会变,而“简单抽象 vs 富抽象”“兼容优先 vs 能力优先”这些设计权衡,会一直伴随着大模型应用的演进。

参考资料

评论互动

© 2026 王若风的技术博客 · Powered by Astro