大模型 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 的官方文档整理。
一、先纠正一个误解:它们不是网络协议
很多人第一次听到“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
理解了这张图,很多问题就有了答案。比如市面上常说的“某某服务 OpenAI 协议兼容”,真实含义是:请求和响应的 JSON 格式兼容,你拿 OpenAI 的 SDK 改个 base URL 就能用。底层大家走的都是一样的 HTTPS + JSON + SSE,并没有什么黑科技。
我那个同事的问题也就出在这:Claude 的原生端点说的是另一种“方言”,OpenAI 格式的请求体发过去,自然对不上。
二、三大主流协议速览
先上一张总表建立整体印象,后面逐个拆:
| 协议 | 典型端点 | 输入核心字段 | 输出核心结构 | 主要特点 | 第三方兼容性 |
|---|---|---|---|---|---|
| OpenAI Chat Completions | /v1/chat/completions | messages | choices[].message | 结构简单、生态成熟 | 最强 |
| OpenAI Responses | /v1/responses | input、instructions | output[] | 面向 Agent、多模态和内置工具 | 持续增长 |
| Anthropic Messages | /v1/messages | system、messages | content[] | 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 (操作电脑)
为什么这个变化重要?因为 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 generateContent | POST /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 Converse | Converse / 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
提前预警:真正难以统一的并不是文本聊天——那部分各家几乎长得一样。难的是这些:
- 工具调用参数和工具结果的表示;
- 推理内容(reasoning)的暴露方式;
- 多模态内容块;
- SSE 事件粒度;
- Usage 统计口径;
- Finish Reason 枚举;
- 服务端会话状态;
- 各厂商特有的内置工具(Web Search、File Search、Computer Use……)。
把这些差异封装在 Adapter 层,业务代码才能做到“换模型只改配置”。
十、结语
回到开头我同事的问题:大模型“协议”不是网络协议,而是应用层的接口规范之争。Chat Completions 赢在了生态,Responses 赢在了抽象,Messages 赢在了原生表达力。作为工程师,理解它们的设计动机,比背下字段名更重要——因为字段会变,而“简单抽象 vs 富抽象”“兼容优先 vs 能力优先”这些设计权衡,会一直伴随着大模型应用的演进。

评论互动