
如果你在 2026 年打开任意一家主流模型服务商的文档,大概率会看到同一个模型同时提供三个端点:
/v1/chat/completions
/v1/messages
/v1/responses很多开发者把它们当成"同一能力的三种表达",选哪个只看团队习惯。但我认为这是一个重要的误解。这三个端点不是平行选项,而是三代产物,每一代都在解决上一代在构建 Agent 时暴露出的问题。把它们并排摆出来选,就像把蒸汽机、内燃机、电动机并排问"你选哪个当发动机"——答案取决于你要跑什么。
判断任何一次技术选型,第一件事是先看时间。2026 年这个节点,有几件事已经不再是"传闻"或"预告",而是板上钉钉的时间表:
一句话概括这条时间线:过去的两年,是"让模型说话"的接口,向"让模型干活"的运行时演进的两年。 而协议,是这场演进最先落地的载体。
在过去的两年里,我们经历了从 ChatGPT 式的单轮问答,到能自主执行多步任务(读代码、调工具、跑测试、修改文件)的 Coding Agent 的转变。这个转变的底层,其实是 LLM API 协议本身的进化:从"让模型回答问题",走向"让模型执行一次 Agent Turn"。
本文沿着这条进化线展开:先给出评价协议的三个维度,再分别解剖 Chat、Messages、Responses 三代协议,然后总结三条进化主线(无状态到有状态、单轮到多轮工具、文本接口到执行接口),最后给出工程落地建议和选型判断。文章里所有关于"未来"的判断,你都能在上面这条时间线上找到它们已经发生的证据。
在对比协议之前,先想清楚一个问题:一套 LLM API 协议,对构建 Agent 来说,到底要支撑什么?
一个 Agent 的实际运行循环是:
Perceive(感知)→ Reason(推理)→ Act(行动)→ Observe(观察)→ Reason → ...这比"问一句、答一句"复杂得多。模型要输出推理过程、发起工具调用、接收工具结果、再继续推理。一套协议能否支撑这个循环,我认为只需要看三个维度:
后文分别用这三个维度解剖三代协议。你会发现,每一代的进步,本质上是这三个模型之一的升级——而且有一个清晰的规律:先升级数据模型(怎么表达),再升级状态模型(存在哪),最后升级事件模型(能被观测到什么)。这个顺序不是巧合,它对应着 Agent 从"能表达动作"到"能记住状态"再到"能被可靠编排"的成熟过程。
Chat Completions 自 2022 年 GPT-3.5/ChatGPT 时代引入,设计哲学非常纯粹:stateless by design(无状态设计)。协议不记忆任何东西,每次请求都携带完整的历史消息,模型回复一条 assistant 消息,然后结束。
Agent
↓
重新构造 messages[]
↓
POST /chat/completions请求是一个 messages 数组,每项带 role(system/user/assistant)和 content:
POST /v1/chat/completions
{
"model": "gpt-5.6",
"messages": [
{"role": "system", "content": "你是有帮助的助手。"},
{"role": "user", "content": "今天天气如何?"}
],
"functions": [ { "name": "get_weather", "description": "获取天气", ... } ]
}响应包在 choices 里,工具调用通过 message.tool_calls(旧版 function_call)表达:
{
"id": "chatcmpl-xyz",
"model": "gpt-5.6",
"choices": [
{
"message": {
"role": "assistant",
"content": null,
"tool_calls": [
{
"type": "function",
"function": {"name": "get_weather", "arguments": "{\"city\":\"Paris\"}"}
}
]
},
"finish_reason": "tool_calls"
}
],
"usage": {"prompt_tokens": 20, "completion_tokens": 10, "total_tokens": 30}
}注意两个细节,它们暴露了这套模型的天花板:
"arguments": "{...}"),不是对象,客户端还要再 JSON.parse 一次;Chat 的流式是所有协议中最简单的,SSE 里每帧一个 delta:
{"id":"chatcmpl-xyz","object":"chat.completion.chunk","choices":[{"delta":{"content":"今"},"index":0,"finish_reason":null}]}客户端逻辑几乎是恒定的:
content += delta简单是它最大的优点,也是它成为事实标准(lingua franca)的原因。几乎每家服务商——OpenRouter、阿里云、Ollama、vLLM——都提供 OpenAI 兼容接口。
理解 Chat 的历史地位,需要回到 2022–2023 年。那时候没人谈 Agent,大家要的只是"让模型回答一句话"。Chat 的 messages 数组是那个时代最自然、最省事的抽象:你脑子里想的就是"一段对话",那就发一段对话过去。
这种"最省事"带来的一个后果,是它形成了事实标准(lingua franca)的锁定效应。因为够简单,任何一家想快速接入模型的厂商——OpenRouter、阿里云、Ollama、vLLM——都选择"做 OpenAI 兼容接口"。于是 Chat 格式从一个厂商的私有协议,变成了整个行业的通用语言。今天大量开源工具链、框架、网关默认只认 messages 数组,这个生态惯性本身,就是 Chat 最大的护城河。
但锁定效应是一把双刃剑:当一个为"单轮问答"设计的格式成为通用语言,所有在其上生长出来的 Agent 框架,都被迫在错误的抽象层上打补丁。
一旦开始构建多轮工具调用的 Agent,问题就暴露了:
reasoning → tool_call → tool_result → reasoning 这个过程,在 Chat 里退化成了一堆混在一起的 role 消息;Chat Completions 的本质是:无状态对话接口。它设计来"让模型回答我",而不是"让模型持续干活"。 它不是"做错了",而是在它诞生的那个时代,这就是全部需求。
2023 年 Anthropic 推出 Messages API。它和 Chat 表面相似,但有一个关键差异:消息的 content 不是字符串,而是一个 Content Block 数组。
在历史叙事里,Messages 常常被一笔带过。但我要给它一个更公允的评价:它是第一个真正意识到"Agent 的输出不是一段话,而是多种东西混杂"的协议。 当 OpenAI 还在让工具调用内嵌在消息字符串里时,Anthropic 已经把 text、image、tool_use、thinking 拆成了平等的块类型。这个洞察,直接启发了后来 Responses 的 Item 设计。
请求里,系统提示被独立成顶层 system 字段,不再混在消息数组里:
POST /v1/messages
{
"model": "claude-opus-5",
"system": "你是一个问答机器人。",
"messages": [
{"role": "user", "content": [{"type": "text", "text": "今天天气如何?"}]}
],
"tools": [
{
"name": "get_weather",
"description": "获取天气信息",
"input_schema": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"]
}
}
]
}响应也是块数组。工具调用是一个独立的 tool_use 块,参数直接是 JSON 对象:
{
"id": "msg_01ABC",
"role": "assistant",
"stop_reason": "tool_use",
"content": [
{
"type": "tool_use",
"id": "toolu_01",
"name": "get_weather",
"input": {"city": "Paris"}
}
],
"usage": {"input_tokens": 10, "output_tokens": 5}
}工具结果通过 tool_result 块回传,用 tool_use_id 关联:
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_01",
"content": [{"type": "text", "text": "现在是15摄氏度"}]
}
]
}content 数组可以同时包含 thinking、text、tool_use 三种块,这在语义上第一次让"思考"和"行动"有了明确的边界;extended thinking(返回 thinking 块)、prompt caching(cache_control 细粒度控制缓存)。但用我们的三个维度来量,Messages 只升级了数据模型,状态模型原地踏步:
message_start / content_block_delta / message_delta),但本质上还是在描述"一条消息的形成过程",不是"一次任务执行的过程"。所以我的判断是:Anthropic Messages 是"Agent-oriented 的对话协议",比 Chat 更接近执行模型,但停在了结构化对话这一步,没有走到状态化执行。
这个"停在半路"是有代价的。Anthropic 在 2026 年 4 月推出的 Claude Managed Agents,本质上是在用一层独立的托管服务来补齐 Messages API 缺失的那块——状态、编排、沙箱、权限。换句话说:当协议本身没有内建状态和编排能力时,你只能靠"协议外面再包一层服务"来补。这个补法的意义我们留到结论部分展开,但它已经暗示了一条规律:协议缺什么,生态就会在协议外面长出什么来补。
也正因如此,Messages 和 Responses 一起构成了当前真正值得对比的两个 Agent 设计——它们的架构哲学其实很近:
Anthropic
Message
└── Content Blocks
OpenAI
Response
└── Items2025 年 3 月 OpenAI 发布 Responses API,官方定位是"构建 Agent 的新 API 原语(primitive)"。结合 Chat 的简易性和 Assistants API(已于 2026 年 8 月 26 日下线)的工具能力,并明确表示 Responses 是 Chat Completions 的超集,建议新集成优先采用。到 2026 年,GPT-5 及更新的模型只通过 Responses 提供,Chat Completions 进入维护模式——新功能只迭代在 Responses 上。
这条"官方押注"的信号强度,比任何第三方评测都更能说明方向:OpenAI 用产品路线图,而不是营销文章,表达了它对 Responses 的信心。 2026 年 3 月新增的 Shell 工具和托管容器工作空间,进一步把 Responses 从"对话 + 工具"推向了"可操作真实世界"。
Responses 把对话拆成了 input/output 两个 Item 数组,一次响应 = 一次完整的 Agent Turn:
POST /v1/responses
{
"model": "gpt-5.6",
"instructions": "你是有帮助的助手。",
"input": [
{"type": "message", "role": "user", "content": "今天天气如何?"}
],
"tools": [ {"type": "web_search_preview"} ]
}响应不再是一个 message,而是一串不同类型的 Item:
{
"id": "resp_abc",
"model": "gpt-5.6",
"output": [
{"type": "reasoning", "content": [], "summary": []},
{"type": "message", "role": "assistant", "content": [{"type": "text", "text": "巴黎今天多云"}]},
{"type": "function_call", "function": {"name": "store_data", "arguments": {}}},
{"type": "function_call_output", "call_id": "...", "content": [{"type": "text", "text": "OK"}]}
],
"usage": {}
}这里藏着全篇最核心的变化。Chat 里"模型 = 回复一条消息";Responses 里"模型 = 执行一组事件/动作"。
用前面三个维度,Responses 是三料全升级:
① 数据模型:Message → Item
一个 Coding Agent 的真实输出,根本不是"好的,我来修改代码",而是:
Reasoning
↓
Tool Call: grep
↓
Tool Call: read_file
↓
Reasoning
↓
Tool Call: edit_file
↓
Tool Call: run_test
↓
Reasoning
↓
Final Message这已经不是"聊天"了,这是一条 Agent Execution Trace。Responses 的 Item 机制(reasoning / message / function_call / function_call_output / web_search_call)正是为表达这种执行轨迹设计的。它本质上接近一个 Agent 的 IR(中间表示)/ 执行事件模型。
② 状态模型:客户端 → 协议字段 → 服务端对象
Chat → 客户端每次拼接完整历史
Responses → previous_response_id 链式续接
→ Conversations API 服务端持久会话previous_response_id 允许你引用上一条响应继续对话,而不必重发全部历史。更进一步,Conversations API 把整个会话变成服务端对象,自动累积多轮状态。
③ 事件模型:delta → event stream
流式事件按类型分发,运行时能精确感知每一个动作:
response.created
response.output_item.added
response.reasoning_summary_text.delta
response.output_text.delta
response.function_call_arguments.delta
response.output_item.done
response.completed官方迁移文档明确要求流式消费端根据 event.type 分流处理。这对 Coding Agent 的价值是实打实的:你的 UI 可以真实显示 🤔 推理中 → 🔎 搜索中 → 📖 读取 main.go → ✏️ 修改中 → 🧪 运行测试 → ✅ 完成,而不是一行干巴巴的 Assistant: ......。
Chat 里 tool_calls 是 assistant message 的一部分;Responses 里 function_call 与 function_call_output 是两个独立 Item,通过 call_id 关联。这看起来只是格式差异,实际上是一次抽象升级:
Chat: "模型说了一段 JSON"
Responses: "模型产生了一个 Agent Action"动作(调用什么、参数是什么)与观察(结果是什么)被协议分离,Agent 运行时处理起来不再需要从消息里抠字段。
把三代串起来看,第一条主线是状态的位置在不断下移:
Chat → 状态在客户端,每次请求重传
Messages → 状态在客户端,每次请求重传
Responses → 状态进入协议字段(previous_response_id)
→ 状态进入服务端对象(Conversations)这里要澄清一个非常普遍的误解。很多人以为:"既然用了 previous_response_id,是不是就不用再发历史 Token 了?"
不能这么理解。 模型做推理终究需要这些上下文。真正的区别在于下面这四个概念是完全不同的东西:
逻辑上下文
≠ HTTP 请求体中手工传输的 JSON
≠ 模型实际计算的 Token
≠ 最终计费 Token真正影响成本的是 Provider 后端如何复用 KV Cache / Prompt Cache,而不是你 HTTP 请求体里少了多少 JSON。
Responses 的缓存优势,本质是它给了 Provider 一个更好的"状态化 Agent 执行"模型,而不是
previous_response_id这几个字段本身神奇地减少了 Token。
Coding Agent 的上下文结构高度稳定:
┌───────────────────────────────┐
│ Stable Prefix │
│ System Prompt │
│ Tool Definitions │
│ Coding Rules │
│ Repository Metadata │
├───────────────────────────────┤
│ Dynamic Suffix │
│ User Request │
│ Tool Calls / Tool Results │
│ New Findings │
└───────────────────────────────┘Prompt Cache 最喜欢的就是 Stable Prefix,而 Agent 的天然结构恰好是"大量 Stable Prefix + 少量 Dynamic Suffix"。OpenAI 内部测试称 Responses 相比 Chat 可通过更好的 cache utilization 带来 40%–80% 的成本改善——注意这是内部测试数字,不是对所有场景成立的固定收益,但它指出了方向。
第二条主线是工具调用的地位从"附庸"变成"一等公民"。
Chat 时代,工具调用是模型输出里的一个字段,agent loop 完全靠客户端手写:
Client: 调用 chat.completions
Model: 返回 tool_calls
Client: 执行工具
Client: 把结果拼进 messages
Client: 再次调用 chat.completions
...Messages 时代,tool_use/tool_result 变成独立块,有了块级关联(tool_use_id),但循环依然在客户端。
Responses 时代,循环本身成为协议的一部分:function_call 和 function_call_output 是协议的输入输出 Item,服务端能在单次请求内组合多个工具调用和多个 model turn。OpenAI 官方也明确把 Responses 定位为面向 Agent 的 primitive,强调它可以在一次工作流里组合多个工具和多个 model turns。
用能力矩阵对比会更直观(建议实测验证,不同服务商的实现差异很大):
能力 | Chat | Responses | Anthropic |
|---|---|---|---|
Tool Calling | ✅ | ✅ | ✅ |
Parallel Tool | 看服务商 | 看服务商 | ✅(默认) |
Reasoning | 受限 | ✅(reasoning Item) | ✅(thinking 块) |
Previous Response | ❌ | ✅ | ❌ |
Server-side Context | ❌ | ✅ | ❌ |
Built-in Search | ❌ | ✅ | ✅(server tools) |
MCP | 看服务商 | ✅ | ✅ |
Structured Output | ✅ | ✅ | ✅ |
Streaming Events | 基础 | 丰富 | 丰富 |
Long Agent Loop | 一般 | 优秀 | 优秀 |
第三条主线,也是最高层的一条:协议的定位从 LLM API 变成了 LLM + Agent Runtime Protocol。
2024 年的 AI 应用是"模型外面包一层聊天框";2026 年的 Agent 产品是"模型外面包一层 runtime"——模型负责想,runtime 负责让模型安全、可恢复、可审计地做事。而一套 Agent runtime,通常包含任务状态、工具注册表、上下文管理、权限系统、沙箱、评测、可观测性这几块。
在这个语境下:
Chat 更像一个 stdin/stdout 程序
Responses 更像带事件总线的服务Responses 输出的 Item 序列,天然就是 runtime 需要的事件流。Anthropic 的 Messages 也在往这个方向走(thinking 块、server tools),但从状态化和事件化的完整度看,Responses 走得更远。
这也是为什么 OpenAI 在 2026 年 4 月用 WebSocket 优化 agentic workflows 时,可以直接把上一轮 response 状态、工具定义、采样中间物缓存进连接——协议层面的状态化,让连接层的优化成为可能。
这个案例是"执行接口"论点的最强证据,值得展开。2026 年 4 月,OpenAI 公开了一个细节:GPT-5.3-Codex-Spark 这种超高速 coding 模型,推理速度从上一代的约 65 TPS 跃升到 1000+ TPS。但用户几乎感觉不到提速——因为瓶颈已经从 GPU 推理,转移到了围绕推理的那条运行时链路。
他们拆解了 agent loop 的三段延迟:
API services(请求校验、会话重建、网络 hop)
Model inference(GPU 生成 token)
Client-side time(本地跑工具、拼上下文)以前 inference 最慢,API 的开销被掩盖了。一旦模型快到某个临界点,那个被掩盖的开销就会原形毕露——每一轮 follow-up 请求都被当成全新请求,即便历史没变也要重建整段上下文。
OpenAI 的解法,不是换协议,而是换传输层:从多轮 HTTP 往返,改成一条持久 WebSocket 连接 + 连接级内存缓存。缓存的内容包括 previous response、工具定义、已渲染的 token、路由状态。于是 agent loop 从"N 次无状态请求"变成"一条连接里的增量状态机"。结果:alpha 用户反馈提速高达 40%,Codex 很快把大部分 Responses 流量切到了 WebSocket mode。
这个案例真正的启示,不在于"WebSocket 比 HTTP 快",而在于一个更根本的判断:
Agent runtime 已经成为独立的竞争层。 模型再快,如果外层编排仍是无状态 HTTP 叠罗汉,用户照样会等到烦躁。未来的性能竞争,不只是模型速度,更是"工具型长任务能不能跑顺"的 runtime 总效率。
而这一切的前提,正是协议层面的状态化——没有 previous_response_id 和 Item 化的输出,就没有"连接内缓存状态"这件事。Responses 的数据模型升级,在两年后兑换成了传输层的性能红利。
说了这么多"为什么 Responses 好",但落地时我的建议恰恰是:不要在 Agent 核心代码里绑定任何协议。
原因很简单:协议还在快速进化(Conversations、WebSocket loop、未来的新能力),绑定任何一家等于把架构押在一次迁移上。
推荐的架构是三层:
Agent Core
↓
Canonical Agent IR(内部统一事件模型)
↓
Provider Adapter(Responses / Anthropic / Chat)内部定义一个统一的事件模型:
type Event struct {
Type EventType
Data any
}
type EventType int
const (
ReasoningDelta EventType = iota
ToolCall
ToolResult
TextDelta
Usage
Completed
Error
)Provider 层暴露统一接口:
type ModelProvider interface {
Run(ctx context.Context, req *Request) (Response, error)
Stream(ctx context.Context, req *Request) (<-chan Event, error)
}然后分别实现 Responses Adapter、Anthropic Adapter、Chat Adapter,各自负责把内部 IR 映射到对应协议的输入输出。这样 Responses 可以作为一等公民 Backend,Chat 和 Anthropic 作为兼容 Backend,切换成本只剩"换一个 Adapter"。
假设同一个模型服务商同时原生提供三个协议:
场景 | 首选 |
|---|---|
普通聊天、传统 OpenAI 兼容生态 | Chat |
Claude 系 Coding Agent | Anthropic Messages |
OpenAI 系 Coding Agent | Responses |
Reasoning Agent | Responses |
多 Tool Agent | Responses |
长上下文 Coding Agent | Responses |
需要原生 Web/File/Computer/MCP 工具 | Responses |
追求最大 Provider 兼容性 | Chat |
需要完全控制上下文序列化 | Chat / Messages |
构建 Coding Agent 时,不要只看 total_tokens,重点监控四个:
input_tokens
cached_input_tokens
output_tokens
reasoning_tokens并计算 Cache Hit Rate:
Cache Hit Rate = cached_input_tokens / input_tokens一个健康的多轮 Agent 会话,cache hit rate 会随轮次上升:
第 1 次: input=30K cached=0
第 2 次: input=35K cached=28K
第 3 次: input=40K cached=32K
第 20 次: input=100K cached=85K写到这里,如果不提那个真实的反对声音,这篇文章就不诚实。2026 年的开发者社区里,确实出现了一批"从 Responses 迁回 Chat Completions"的声音,理由集中在成本:
previous_response_id 当"免发历史"用,或框架仍在每轮重建完整上下文,input token 反而会累计放大。社区里甚至有人报出"月费从 Chat 时代的
这个反例,恰恰印证了我前面反复强调的一个判断:协议升级 ≠ Token 自动减少。 而且它还暴露了一个更深层的事实——Responses 的"缓存红利"不是免费的,它要求你的 Agent 框架真正理解并使用状态化接口。
具体说,两件事必须做对:
previous_response_id 的意义不是"少发 JSON",而是"让服务端能从连接/会话缓存里复用状态"。如果你仍然每轮重建完整 messages 再塞进去,缓存命中率趋近于零,你会同时付出"更贵的单价"和"没吃到缓存红利"的双重代价;reasoning_effort 是可控的旋钮,不是开关。对一个简单任务开满 reasoning,就是在为不必要的思考付费。所以"迁回 Chat"的案例,本质上不是"Responses 错了",而是"在没搞懂状态化模型时提前用了 Responses"。这也解释了为什么我在第九节反复强调 Canonical IR:只有当你清楚自己在状态模型、事件模型、工具模型上到底需要什么,才能判断 Responses 的复杂度是不是你现在就该付的学费。
一句话总结这条思辨:Responses 的收益上限更高,但对使用者的架构理解要求也更高。Chat 的收益上限低,但几乎不需要理解成本。 两者不是谁取代谁,而是"你是否准备好为更高的上限,承担更高的驾驭成本"。
最后,也是最容易被忽略的一点:协议升级 ≠ 推理 Token 自动减少。Responses 让模型更愿意做 reasoning → tool → reasoning → tool 的循环,reasoning_tokens 反而可能增加。
所以真正该盯的指标不是 /1M token,而是 /successful coding task:
Chat: 100K input, 10K output, 8 次 API, 成功率 72%
Responses: 85K 有效 input, 9K output, 6 次 API, 成功率 84%即使 Token 单价完全一样,Responses 也可能明显更便宜——因为 Agent 做同一个任务少走了几步、少调了几次模型、tool loop 更稳定、上下文复用更好。
把三套协议的本质压成三句话:
Chat Completions = "让模型回答我"(无状态对话) Anthropic Messages = "让模型在 Content Block 中与我协作"(结构化对话,仍未状态化) OpenAI Responses = "让模型执行一次 Agent Turn"(状态化执行协议)
所以对 Coding Agent 来说:Chat 是 Conversation API,Responses 是 Agent Execution API。
有一个坑必须提醒:不要因为服务商"同时支持三个协议"就认为三者能力等价。 有可能是同一模型原生支持 Responses,Chat/Anthropic 只是兼容层(Adapter),此时 Responses 通常更完整;也可能三个都只是同一内部 API 的适配器,此时三者能力趋同,选型只看你的 runtime 适配度。动手前先按能力矩阵实测一遍。
最后说说我对未来的判断。 协议会继续朝 Agent Runtime 方向收敛,三个趋势已经可见——注意,它们不是预言,而是 2026 年已经发生的事实:
还有一个值得单独点出的对称现象:Anthropic 也在走同一条路,只是路径不同。 OpenAI 选择把状态和编排内建进协议(Responses),Anthropic 选择在 Messages API 外面再包一层托管服务(Claude Managed Agents,2026 年 4 月公测)。前者是"协议内建",后者是"协议外包",但两者指向同一个终点:让 Agent Loop 不再由每个开发者手写。 这恰恰验证了我的判断——不管走哪条路,Agent Runtime 化都是不可逆的方向。
选择协议时,按"它离执行模型多近"来判断,比按厂商生态判断更不容易过时。 而如果你的 Agent 已经要自己实现 Agent Loop + 工具调度 + SubAgent + Coding Tool,我的建议是:主协议选 Responses,但内部永远保留 Canonical IR,把 Chat / Anthropic 都做成 Adapter。 这样架构上最稳,也最经得起下一次协议进化。
最后留一个值得持续观察的问题:当"执行接口"继续往下走,下一个升级的会是什么? 我的猜想是——从"一次 Agent Turn"走向"一个可暂停、可恢复、可迁移的长期计算过程"。WebSocket 的"暂停—执行—恢复"原语、Managed Agents 的"长运行会话、断线仍持续",都已经露出了这个方向的苗头。协议的下一个战场,很可能不再是"怎么表达一次调用",而是"怎么表达一个会持续数小时、甚至跨越多台机器的 Agent 进程"。
参考资源: