
如果你做过大模型应用,大概率从这个接口开始:
POST /v1/chat/completions
在 GPT-3.5、GPT-4 时代,它几乎就是 OpenAI API 的代名词。开发者传入一组 messages,模型基于上下文生成下一条回复。
但当应用从“聊天机器人”走向“能调用工具、执行任务、处理多模态内容的 Agent”时,接口形态也开始变化。OpenAI 推出了更统一的:
POST /v1/responses
它并不意味着 Chat Completions 已经过时,而是为更复杂的 Agent 工作流提供了更合适的抽象。
Chat Completions:以对话消息为中心
Chat Completions 的核心数据结构是 messages。每一轮请求,客户端都要提交模型理解当前任务所需的上下文。
例如,用户要求查询北京天气:
{
"model": "gpt-5.6",
"messages": [
{
"role": "user",
"content": "帮我查询北京天气"
}
],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "查询天气",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string"
}
},
"required": ["city"]
}
}
}
]
}
模型决定调用工具后,会返回类似结果:
{
"choices": [
{
"message": {
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_weather_001",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\":\"北京\"}"
}
}
]
}
}
]
}
应用执行 get_weather 后,下一轮请求需要把此前的对话、模型发起的工具调用,以及工具执行结果一起传回去:
{
"model": "gpt-5.6",
"messages": [
{
"role": "user",
"content": "帮我查询北京天气"
},
{
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_weather_001",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\":\"北京\"}"
}
}
]
},
{
"role": "tool",
"tool_call_id": "call_weather_001",
"content": "北京晴,25°C"
}
]
}
这种方式直观、成熟,也仍然适合大多数聊天场景。
但它有一个明显的工程短板:上下文管理主要由客户端承担。 随着会话变长、工具调用变多,应用需要不断维护和重放历史消息。
Responses:以一次“任务响应”为中心
Responses API 的思路不同:它不只把模型输出看作一段文本,而是看作一次可能包含文本、推理、工具调用、图像或结构化结果的“响应”。
同样以天气查询为例:
{
"model": "gpt-5.6",
"input": "帮我查询北京天气",
"tools": [
{
"type": "function",
"name": "get_weather",
"description": "查询天气",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string"
}
},
"required": ["city"]
}
}
]
}
模型返回一个 response,其中包含函数调用:
{
"id": "resp_123",
"output": [
{
"type": "function_call",
"call_id": "call_weather_001",
"name": "get_weather",
"arguments": "{\"city\":\"北京\"}"
}
]
}
工具执行完成后,下一轮只需要提交新增结果,并关联上一轮响应:
{
"model": "gpt-5.6",
"previous_response_id": "resp_123",
"input": [
{
"type": "function_call_output",
"call_id": "call_weather_001",
"output": "北京晴,25°C"
}
]
}
OpenAI 可以通过 previous_response_id 关联此前的上下文和工具调用关系。客户端不必每次手工重放完整消息历史,Agent 编排代码会更简洁。
不过要注意:这也不代表“上下文不再消耗成本”。使用 previous_response_id,它降低的是客户端自己构造和维护 messages 历史的复杂度,响应链中此前的输入 token 仍会按输入 token 计费。
为什么 Agent 更需要 Responses API?
一问一答时,messages 很自然;但 Agent 往往要在对话、工具调用、工具结果和结构化数据之间不断切换。
Chat Completions 也能完成这些事,但步骤变多后,客户端需要自己维护复杂的 messages 历史,并确保工具调用与结果正确对应。
Responses API 的重点不是增加了某项新能力,而是把这些内容统一为响应项,并支持基于上一轮响应继续任务,因此更适合复杂的 Agent 工作流。
做 API Gateway 时,应该如何设计?
如果 Gateway 同时接入 OpenAI、Claude、Gemini、DeepSeek 等模型,关键不是把所有请求都改写成 Responses。
更实用的做法是:对外保留 Chat Completions、Responses 等客户端熟悉的接口;请求进入系统后,再由对应的转换器解析,并进入同一条处理链路。
OwlVigil 采用的正是这种方式:不是用 Responses 替代 Chat,而是让不同协议共用同一套网关能力。
客户端
├─ Chat Completions
├─ Responses
├─ Anthropic Messages
└─ Gemini API
↓
入站转换器
↓
统一 LLM 请求模型
↓
模型映射、路由、限流、重试
↓
出站转换器
↓
OpenAI
├─ Claude
├─ Gemini
└─ DeepSeek 等上游
这里的“统一”,不是强行绑定某一家厂商的协议,而是把消息、工具调用、工具结果、模型参数和流式响应放进同一条处理链路。
这样,客户端可以继续使用熟悉的接口;底层则根据模型能力和渠道配置选择合适的上游协议。新增渠道时,主要补充转换器和配置,而不需要改动上层业务。
不过也有边界:previous_response_id 这类依赖上游状态的能力,并不能天然跨厂商迁移。要完整保留这类语义,网关需要持续使用兼容 Responses 状态链的上游,或由客户端自行携带完整上下文。
写在最后
Chat Completions 和 Responses 不是非此即彼。前者仍是最广泛的兼容入口,后者则更适合工具调用频繁、状态更复杂的 Agent 工作流。
真正困难的地方,不是选择哪个接口,而是让上层业务不必跟着每一家模型、每一次接口升级反复改造。
这正是 OwlVigil 想解决的问题:客户端继续按熟悉的协议接入,网关在内部完成转换、路由、限流、重试和观测。模型与接口会持续演进,但业务调用模型的方式不必每次推倒重来。
本站原创文章皆遵循“署名—非商业性使用—相同方式共享 4.0 协议 (CC BY-NC-SA 4.0)”。共享、演绎请保留以下标注:
原文作者:Sunny Zhang,来源:「从 Chat Completions 到 Responses:OpenAI 为什么要升级核心接口?」