四个 API 一张表:Chat Completions、Responses、Messages、Embedding 差在哪
四个 API 一张表:Chat Completions、Responses、Messages、Embedding 差在哪
上两篇我们聊了 vLLM Semantic Router 和它的 Decision 3.0。但无论路由怎么选模型,请求本身总得有个形状——它是长成 OpenAI 的 Chat Completions、还是 Responses、还是 Anthropic 的 Messages,直接决定了你的代码怎么写、历史怎么存、成本怎么算。
这篇就把这几个 API 摆在一起看:它们的调用例子、上下文历史存哪、OpenAI 为什么留了两个,顺便把不说话的 Embedding 和只回答"是/否"的 System One 也一起说了。
目录
- 一、总览:四个 API,四种"对话形状"
- 二、Chat Completions:兼容生态的"普通话"
- 三、Responses:为 Agent 重造的那一个
- 四、Anthropic Messages:把 system 拎出来,把内容变成块
- 五、上下文历史到底存在哪
- 六、为什么 OpenAI 有两个 API
- 七、Embedding:不生成文本的那一个
- 八、System One:只回答是/否的第五个 API
一、总览:四个 API,四种"对话形状"
先把差异摆到一张表里,后面逐一展开:
| API | 端点 | 输入 | 输出 | 服务端有无状态 |
|---|---|---|---|---|
| Chat Completions | POST /v1/chat/completions |
messages[](含 system 角色) |
choices[0].message |
无状态 |
| Responses | POST /v1/responses |
input + 顶层 instructions |
output[] / output_text |
可选有状态 |
| Anthropic Messages | POST /v1/messages |
messages[] + 顶层 system |
content[](内容块) |
无状态 |
| Embeddings | POST /v1/embeddings |
input(文本数组) |
向量数组 | 无状态 |
一句话记住它们的性格:
- Chat Completions 是行业普通话——几乎所有厂商和框架都兼容它。
- Responses 是Agent 原生接口——推理状态、内置工具、服务端历史都在这。
- Messages 是Anthropic 的方言——把
system拎到顶层,把内容拆成"块"。 - Embeddings 是唯一不生成文本的——它只把文本变成向量。
二、Chat Completions:兼容生态的"普通话"
2023 年就定型的接口,也是被抄得最多的一份。请求就是一组 messages,system 是其中一种角色:
curl https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o",
"messages": [
{"role": "system", "content": "你是一个简洁的助手。"},
{"role": "user", "content": "用一句话解释 embedding。"}
]
}'
返回里读 choices[0].message.content:
{
"id": "chatcmpl-...",
"choices": [
{ "index": 0, "message": { "role": "assistant", "content": "Embedding 是把文本映射成..." } }
]
}
关键点:它是无状态的。服务端不记得你上一次问过什么,每一轮你都要把完整的历史 messages 再发一遍:
{
"model": "gpt-4o",
"messages": [
{"role": "system", "content": "你是一个简洁的助手。"},
{"role": "user", "content": "用一句话解释 embedding。"},
{"role": "assistant", "content": "Embedding 是把文本映射成..."},
{"role": "user", "content": "再举一个例子。"}
]
}
它的好处也正是"无状态":逻辑简单、跨供应商可移植、历史完全在你手里。DeepSeek、Qwen、vLLM、Ollama、甚至 Anthropic 自己都提供了兼容层——这就是它能当"普通话"的原因。
三、Responses:为 Agent 重造的那一个
2025 年推出的新接口,端点是 /v1/responses。它在形状上像 Chat Completions,但在能力上是为推理模型和 Agent 从零设计的。
最简调用,注意 instructions 是顶层字段,input 可以直接是字符串:
curl https://api.openai.com/v1/responses \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4.1",
"instructions": "你是一个简洁的助手。",
"input": "用一句话解释 embedding。",
"store": true
}'
返回是一个输出项数组 output[],而且很方便地给了一个拼好的 output_text:
{
"id": "resp_abc123",
"output": [
{ "type": "reasoning", "summary": [] },
{ "type": "message", "role": "assistant", "content": [{"type": "output_text", "text": "Embedding 是把文本映射成..."}] }
],
"output_text": "Embedding 是把文本映射成..."
}
它和 Chat Completions 拉开距离的地方,全在这几项:
- 推理项(reasoning items):推理模型产生的思考状态能作为
output里的一类项被保留和回传,这是 Chat Completions 的扁平message表达不了的。 - 内置工具:Web Search、File Search、Code Interpreter、Computer Use 都是原生
tools,不用你自己搭。 - 服务端历史:
store: true存下这次响应,下次直接用previous_response_id续上(下一节细说)。 - 后台执行:长任务可以
background方式跑,再回来取结果。 - 更细的流式事件:按语义事件流式返回,而不是只吐 delta。
官方现在的口径也很明确:新模型、新功能优先只在 Responses 上做,Chat Completions 进入"维护兼容"状态。
四、Anthropic Messages:把 system 拎出来,把内容变成块
Claude 的接口是 /v1/messages,和 OpenAI 有两个一眼可见的差异:
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": "claude-sonnet-4",
"max_tokens": 1024,
"system": "你是一个简洁的助手。",
"messages": [
{"role": "user", "content": "用一句话解释 embedding。"}
]
}'
system是顶层参数,不是一条 message。OpenAI 把 system 当成第一种角色塞进messages,Anthropic 则把它拎出来单独放。这不只是美观差异——它意味着 system 的语义被独立对待。max_tokens是必填的。OpenAI 里它是可选,Anthropic 里你必须显式给出上限。
返回的 content 是一个内容块数组,而不是一段字符串:
{
"content": [
{ "type": "text", "text": "Embedding 是把文本映射成..." }
],
"stop_reason": "end_turn"
}
这个"块"的设计在工具调用上体现得最明显。Claude 要调工具时,返回一个 tool_use 块,其中 input 是已经解析好的对象;而 OpenAI 的 function call 返回的是 JSON 字符串 arguments,你还得自己 json.loads 一次。工具结果则以一个 tool_result 块放在 user 消息里回传。
Messages 同样是无状态的——多轮就是把历史 messages 一路拼下去。
五、上下文历史到底存在哪
这是最容易被忽略、却最影响成本和架构的一处差异。历史有三种存法:
MERMAID_BLOCK_0
第一种:客户端持有(Chat Completions / Messages)
服务端不存任何东西。历史躺在你的数据库、内存或队列里,每次请求把整段 messages 重新发一遍。
- 好:完全可控,能随意裁剪、摘要、改角色;换供应商不用迁移数据。
- 坏:重复计费——第 10 轮的请求里,前 9 轮的内容要再算一次 token;上下文越长越贵越慢。
Anthropic 和 OpenAI 都提供了提示缓存(prompt caching)来缓解:命中的前缀部分按更低价格计费。但注意——缓存的是计算,不是历史,你仍然要把 messages 发过去。
第二种:服务端持有(Responses 的 previous_response_id)
store: true 之后,历史存在服务端。下一轮你只传一个 id:
curl https://api.openai.com/v1/responses \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4.1",
"previous_response_id": "resp_abc123",
"input": "再举一个例子。"
}'
- 好:省带宽、省心智,推理项等复杂状态自动保留。
- 坏:状态在别人机器上——不可跨供应商移植,涉及数据驻留时要格外小心;也可以用
store: false自己带历史,但那等于退回第一种。
需要显式管理时,还有一层 Conversation 资源:创建一次对话,把多轮 response 挂上去,适合一个会话要跨多个 Agent 或多次运行的场景。
第三种:外部向量库(Embeddings + 检索)
严格说这不是"对话历史",而是长期记忆。你把历史切片成文本、算成向量存近邻库,需要时检索出最相关的几段,拼进当前请求。它和上面两种是互补关系,不是替代。
一句话总结:Chat Completions 和 Messages 把历史放在你这边,Responses 把历史放在它那边。 你的 Harness 里那个"agent 循环 + 任务状态",其实就是第一种存储模型的具体实现——这也是为什么上一篇文章里说,路由层不负责存历史,那是 Harness 的活。
六、为什么 OpenAI 有两个 API
每次讲到这里都有人问:既然 Responses 更好,为什么不直接换掉 Chat Completions?
因为这两个 API 服务的是两类完全不同的诉求。
Chat Completions 是"标准接口"。 它 2023 年定型,被几乎所有厂商和框架兼容——它已经是生态里的"最大公约数"。无数 SDK、Agent 框架、自建推理服务只认这一个形状。动它,等于动整个生态。
Responses 是"Agent 原生接口"。 Agent 需要的东西——保留推理状态、内置工具、服务端会话、后台执行——Chat Completions 一件件往外挂(打补丁)都很别扭,不如重做。所以 OpenAI 选择新旧并存:
- 旧项目、兼容性优先、只想换个模型 → 继续用 Chat Completions。
- 新项目、要跑 Agent、要用推理模型的内置能力 → 用 Responses。
- 官方策略是渐进迁移,并给了迁移指南,而不是一刀切停用。
还有一个现实原因:Chat Completions 是"方言最多"的接口。Anthropic 的 Messages、各家国产模型的兼容层,都在往它对齐。OpenAI 保留它,等于保留了一个通用的对接面——这跟前面 vLLM SR 那个"统一 API 后面站一群模型"的思路是一回事:接口稳定,后端随便换。
七、Embedding:不生成文本的那一个
上面三个 API 都在"生成",而 Embedding 只做一件事:把文本变成向量。
curl https://api.openai.com/v1/embeddings \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "text-embedding-3-small",
"input": ["今天天气不错", "外面阳光很好"]
}'
返回一个向量数组,每个输入对应一个浮点数组:
{
"data": [
{ "index": 0, "embedding": [0.021, -0.004, 0.113, ...] }
],
"usage": { "prompt_tokens": 6, "total_tokens": 6 }
}
它没有 choices,没有 content,没有"对话"这个概念——因为它根本不是对话接口。它的用途是相似度:语义相近的两段文本,向量夹角就小。RAG、语义搜索、去重、聚类、分类,全靠它。
两个容易踩的坑:
- 维度要固定:存进向量库之前先定好维度(比如 1536),换模型可能不兼容。
- 别指望 Anthropic 有独立的 embedding 端点:Claude 那边不提供第一方 embedding API,官方建议用 Voyage AI 之类的第三方。所以"用 Claude 做对话 + 用 OpenAI 做 embedding"是很常见的组合。
八、System One:只回答是/否的第五个 API
最后说一个不在上面体系里、但和它们并列的接口。前面聊 Decision 3.0 时提过 System One——决策模型的 API,端点长这样:
curl -sS http://localhost:8801/v1/systemone \
-H 'Content-Type: application/json' \
-d '{
"model": "vllm-sr/auto",
"state": "I cannot sign into my account.",
"questions": {
"task": {
"type": "choice",
"instructions": "Which team should handle this request?",
"criteria": {
"account": "Account access or authentication",
"billing": "Payments, invoices or refunds"
}
}
}
}'
看形状就懂了:这里既没有 messages(因为不对话),也没有 input(因为它不生成)。它给的是 state(一段文本或 JSON)+ questions(Choice / Yes-No / Score),拿回来的是每个选项的概率。
放进同一张表里对比一下:
| 维度 | 语言 API(Chat/Responses/Messages) | System One |
|---|---|---|
| 输入 | messages / input |
state + questions |
| 输出 | 生成的文本 | 每个选项的概率 |
| 用途 | 说话 | 判断 |
| 历史 | 客户端或服务端持有 | 无对话,无历史 |
为什么值得单独列一个:路由、护栏、工具选择这些高频动作,本质上都是判断,不是生成。让一个 27B 模型"生成一段话"再解析,既慢又贵还容易出错;换成 System One,几十毫秒内直接给你概率,还能设阈值。这就是"System One(快思考)"和"System Two(慢思考)"的分工——日常判断走前者,真正的推理才交给后者。
而且它和语言 API 可以共用一个前端:vLLM SR 既代理 /v1/chat/completions、/v1/responses、/v1/messages 这三种语言接口,也代理 /v1/systemone 这一个决策接口。你的应用只管发请求,选哪个模型、走哪条路,交给路由层。
把这五个接口排在一起,其实是一条清晰的演化线:
Embedding 把文本变成向量(不生成)→ Chat Completions / Messages 把对话变成标准化请求(无状态)→ Responses 把 Agent 的状态收进服务端(有状态)→ System One 把判断从生成里剥离出来(只给概率)。
理解了"历史存在哪"和"是生成还是判断"这两把尺子,再选 API 就不会迷路:要兼容用 Chat Completions,要 Agent 用 Responses,要接 Claude 用 Messages,要检索用 Embeddings,要快速做判断用 System One。
作者: itech001
来源: 公众号:AI人工智能时代(the-ai-era)
网站: https://www.theaiera.top/
关注每日最新AI新闻和技术博客,主页有更多的文章的AI 技术参考:https://www.theaiera.top
本文首发于 AI人工智能时代,转载请注明出处。

浙公网安备 33010602011771号