OpenAI Responses API 是什么:与 Chat Completions 的区别与选型
详解 OpenAI Responses API (/v1/responses) 是什么,并对比其与 Chat Completions (/v1/chat/completions) 在输入输出、多轮状态、内置工具、SSE 流式及 Codex 中的差异。
UniRoute ·
OpenAI Responses API(POST /v1/responses)是 OpenAI 基于条目(Item-based)的响应生成接口,支持接收文本与图像输入,并返回由 reasoning、message、function_call 等强类型条目组成的文本或 JSON output[] 数组。根据 OpenAI 官方 Responses API 概览与迁移指南,该接口支持有状态的多轮交互、内置工具以及自定义函数调用。与此同时,Chat Completions(POST /v1/chat/completions)仍受官方持续支持且并未废弃;OpenAI 推荐新项目、多步推理与工具混合的 Agent 工作流,以及像官方 Codex CLI 这样的原生客户端采用 Responses API。
如果您的线上服务已经基于 /v1/chat/completions 稳定运行在标准 messages[] 对话或常规自定义函数调用场景,无需为了更换路径而立即重写代码。当您构建需要保留多轮推理项的新型 Agent 循环、接入强制要求 Responses 协议的开发工具,或使用在官方规范下对 Chat Completions 存在限制的新模型特性(例如 OpenAI 自 GPT-5.4 起在 reasoning_effort 非 none 时不再支持 Chat Completions 工具调用)时,应优先选用 /v1/responses。
在对比具体字段前,请先区分三代不同的 OpenAI 接口路径,避免将早期补全接口与对话接口混为一谈:
- Legacy Completions(
POST /v1/completions): OpenAI 早期的单字符串文本补全接口(传入prompt字符串,返回纯文本续写),请勿将其与 Chat Completions 混淆。 - Chat Completions(
POST /v1/chat/completions): 广泛采用的messages[]消息数组接口(包含system、developer、user、assistant与tool角色),返回choices[].message,可作为跨 SDK 与网关的常见兼容基线(接入时请逐一核实目标提供方支持情况)。 - Responses API(
POST /v1/responses): OpenAI 面向 Agent 工作流设计的基于条目(Item-based)原语接口,接收字符串或强类型input条目数组(配合顶层instructions),并返回由reasoning、message、function_call等多态条目组成的output[]数组。
30 秒接口选型速查表
| 业务场景或客户端类型 | 推荐接口路径 | 选型依据 |
|---|---|---|
已稳定运行、使用 messages[] 与常规 JSON Schema 的现有生产服务 | POST /v1/chat/completions | OpenAI 官方与 UniRoute OpenAI 兼容路由均持续支持,无需改动现有序列化与流式解析逻辑 |
| 需要以最小改动在多厂商非 OpenAI 模型间切换的通用后端 | POST /v1/chat/completions | 以 messages[] 和 choices[0].message 作为常见兼容基线;具体需逐一核实各目标提供方 |
| 新建面向 OpenAI 推理模型的多步工具调用与 Agent 循环 | POST /v1/responses | 原生保留 reasoning 与 function_call 强类型条目;规避 OpenAI 在 GPT-5.4+ 上对 Chat Completions 非 none 推理强度的工具调用限制 |
| 接入官方 OpenAI Codex CLI 或 IDE 插件 | POST /v1/responses | Codex 配置项 model_providers.<id>.wire_api 仅接受 "responses"(缺省默认值亦为 "responses") |
通过 UniRoute(https://api.uniroute.app/v1)调用 GPT 模型 | 按目标模型与路由实测选择 | UniRoute 同时公开 /v1/chat/completions 与 /v1/responses;切流前请先查阅 UniRoute 模型目录并验证当前 Key 命中的路由能力 |
1. 核心协议结构对比:/v1/responses vs. /v1/chat/completions vs. /v1/completions
虽然 /v1/chat/completions 与 /v1/responses 都接收 model 参数并返回模型生成结果,但二者的请求体结构、输出容器、工具定义格式以及流式 SSE 事件完全不同——不能只把请求 URL 从 /v1/chat/completions 改成 /v1/responses 而沿用原有解析器。
| 对比维度 | Responses API (POST /v1/responses) | Chat Completions (POST /v1/chat/completions) | Legacy Completions (POST /v1/completions) |
|---|---|---|---|
| 主要输入字段 | input(字符串或强类型 Item 数组)+ 可选顶层 instructions | messages[] 角色消息对象数组 | 单一 prompt 字符串或 token 数组 |
| 主要输出容器 | output[] 多态 Item 数组(reasoning、message、function_call 等);无 n 参数 | choices[] 数组(choices[0].message.content、tool_calls);支持 n 候选生成 | choices[].text 文本续写 |
| 纯文本提取方式 | 官方 SDK 提供 response.output_text 辅助属性;原生 HTTP 需遍历 output[] 筛选 type === "message" | SDK 与原生 HTTP JSON 均直接读取 choices[0].message.content | choices[0].text |
| 多轮上下文基线 | 跨平台稳妥基线:将上一轮 output 条目追加到下一轮 input[];OpenAI 官方另支持 previous_response_id / Conversations | 跨平台稳妥基线:每轮请求完整携带历史 messages[] 数组 | 手动拼接提示词字符串 |
| OpenAI 官方默认存储 | OpenAI 官方默认存储(store: true);可设 store: false 关闭(ZDR 场景可配合 encrypted_content) | OpenAI 新账户默认存储;可设 store: false 关闭 | 早期兼容行为 |
| 自定义函数工具定义 | 内部标记(Internally tagged):{ "type": "function", "name": "...", "parameters": {...} };默认尝试开启 strict 模式 | 外部包装(Externally tagged):{ "type": "function", "function": { "name": "...", "parameters": {...} } };默认非 strict | 不支持 |
| 工具调用与结果关联 | 独立的 function_call 与 function_call_output 条目,通过 call_id 关联 | Assistant message.tool_calls[] 与 role: "tool" 消息通过 tool_call_id 关联 | 不支持 |
| 结构化输出(JSON Schema) | text: { format: { type: "json_schema", name, strict, schema } } | response_format: { type: "json_schema", json_schema: { name, strict, schema } } | 不支持 |
流式响应(stream: true) | 语义化 SSE 生命周期事件(如 response.output_text.delta、response.completed、response.incomplete) | 增量分片对象(choices[].delta.content、choices[].delta.tool_calls) | 文本分片流 |
为什么 response.output_text 不能等同于原生 HTTP JSON 字段
从官方 Python 或 TypeScript SDK 切换到原生 HTTP 请求时,最常见的解析错误就是直接读取 output_text 或写死数组下标 output[0]:
- 在 OpenAI 官方 SDK 中:
response.output_text是 SDK 客户端封装的便捷属性,它会自动遍历output[]数组,将所有type: "message"条目下content[]中type: "output_text"的文本片段拼接为一个字符串。 - 在原生 HTTP JSON 响应中:
POST /v1/responses返回的原始 JSON 并不保证包含顶层output_text字段。同时,切勿写死response.output[0].content[0].text——在推理模型或包含工具调用的回合中,output[0]往往是reasoning(推理项)或function_call(函数调用项),而非面向用户的message。原生 HTTP 调用方应始终遍历output[],先判断item.type === "message",再读取content[]中part.type === "output_text"的内容。
2. Python SDK 请求与响应结构对照(示意代码)
以下 Python 代码为基于 OpenAI 官方迁移规范编写的请求与响应结构示意模板(撰写本文未执行付费在线推理实测;实际接入时请通过环境变量 MODEL_ID 传入您账户与目标路由已核实支持的准确模型 ID)。
A. Chat Completions(POST /v1/chat/completions —— OpenAI 官方结构示意)
import os
from openai import OpenAI
# 官方第一方接口结构示意:OPENAI_API_KEY 仅用于 OpenAI 官方默认地址
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"], max_retries=0)
MODEL_ID = os.environ["MODEL_ID"] # 请设置为您账户已核实可用的模型 ID
completion = client.chat.completions.create(
model=MODEL_ID,
messages=[
{"role": "developer", "content": "请提供简洁的后端接口架构建议。"},
{"role": "user", "content": "什么情况下现有服务应该继续使用 Chat Completions?"},
],
)
print(completion.choices[0].message.content)
B. Responses API(POST /v1/responses —— 官方 SDK 对象与原生 JSON 字典遍历)
import os
from openai import OpenAI
# 官方第一方接口结构示意
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"], max_retries=0)
MODEL_ID = os.environ["MODEL_ID"] # 请设置为您账户已核实可用的模型 ID
response = client.responses.create(
model=MODEL_ID,
instructions="请提供简洁的后端接口架构建议。",
input=[
{
"role": "user",
"content": "新建 Agent 工作流在什么场景下应优先选用 Responses API?",
}
],
)
# 1. 使用 OpenAI 官方 SDK 提供的客户端便捷属性:
print(response.output_text)
# 2. 遍历官方 SDK 强类型条目对象(Pydantic/SDK 模型实例):
sdk_text_segments = []
for item in response.output:
if getattr(item, "type", None) == "message":
for part in getattr(item, "content", []):
if getattr(part, "type", None) == "output_text":
sdk_text_segments.append(part.text)
print("".join(sdk_text_segments))
# 3. 遍历原生 HTTP JSON 字典(例如 requests/httpx 的 response.json() 返回值):
raw_payload = response.model_dump()
dict_text_segments = [
part.get("text", "")
for item in raw_payload.get("output", [])
if item.get("type") == "message"
for part in item.get("content", [])
if part.get("type") == "output_text"
]
print("".join(dict_text_segments))
C. 跨平台稳妥的多轮上下文维护(纯文本回合手动追加 input 列表)
无论是直连 OpenAI 还是通过兼容网关调用,手动将上一轮返回的 response.output 条目列表追加到下一轮 input 数组中,都是跨环境保持多轮上下文最稳妥的基线方式:
# 不依赖服务端有状态存储的纯文本回合上下文回放示意。
# (若某轮响应包含 function_call 条目,业务代码还需执行对应函数并在下一轮追加
# 匹配的 function_call_output 条目,不能仅追加 first_turn.output。)
conversation_input = [
{"role": "user", "content": "用两条简短要点概括 messages[] 与 input[] 的区别。"}
]
first_turn = client.responses.create(
model=MODEL_ID,
instructions="请用两条简短要点回答。",
input=conversation_input,
)
# 将上一轮输出的条目(如 reasoning 与 assistant message 条目)追加到下一轮输入
conversation_input.extend(first_turn.output)
conversation_input.append(
{"role": "user", "content": "再给出一句迁移时的注意要点。"}
)
second_turn = client.responses.create(
model=MODEL_ID,
instructions="请用两条简短要点回答。",
input=conversation_input,
)
D. 将 OpenAI SDK 指向 UniRoute(独立的网关接入配置)
当您通过 UniRoute 转发请求时,请单独配置 base_url="https://api.uniroute.app/v1" 并仅使用 UNIROUTE_API_KEY 环境变量认证。切勿将 OpenAI 官方平台签发的 Key 发往 UniRoute,或将 UniRoute Key 发往 OpenAI 官方地址,也不要在命令行参数或公开配置文件中明文写入密钥:
import os
from openai import OpenAI
# 独立的 UniRoute 网关配置示意
# 切换前请先核实目标 MODEL_ID 及当前 Key 的激活路由支持所选接口路径
uniroute_client = OpenAI(
api_key=os.environ["UNIROUTE_API_KEY"],
base_url="https://api.uniroute.app/v1",
max_retries=0,
)
MODEL_ID = os.environ["MODEL_ID"] # 请设置为在 /zh/models 中核实支持的模型 ID
# 根据目标模型与 UniRoute 路由支持情况,调用 uniroute_client.chat.completions.create(...)
# 或 uniroute_client.responses.create(...)
3. 多轮状态管理、previous_response_id 计费规则与数据存储(store)
不少开发者误以为切换到 /v1/responses 或传入 previous_response_id 就能省去历史上下文的 token 计费。在实际工程与成本预算中,必须把“网络传输层少传数组”与“模型计费层的输入 token 结算”以及“网关状态边界”严格区分开。
OpenAI 官方 previous_response_id 的工作方式与计费真相
在 OpenAI 官方 Responses 规范中,传入 previous_response_id 可以基于服务端已保存的上一轮响应继续对话,而无需在客户端请求体里重复上传完整历史数组。但请特别注意两条官方规则:
- 历史链条中的输入 token 仍按输入 token 计费: OpenAI 官方文档明确说明,使用
previous_response_id串联多轮对话时,响应链中此前所有的输入 tokens 在新一轮请求中仍会作为有效的输入 tokens 计费。换言之,改用/v1/responses或传入previous_response_id不会改变模型的每百万 tokens 单价,也不会免除历史上下文的输入费用;重复前缀的折扣依然取决于提示词缓存(Prompt Caching)命中情况。关于普通未缓存输入、缓存读取、缓存写入与推理输出 token 的完整核算方式,请参阅 OpenAI API 价格指南:UniRoute 上的 GPT Token 费用与用量核对。 - 上一轮顶层
instructions不会自动继承: 根据 OpenAI 官方文档,通过顶层instructions传入的系统或开发者指令仅对当次响应生效。如果在使用previous_response_id时仍需保留相同的系统指令,必须在后续每一轮请求中显式重新传入instructions。
store: true、store: false 与零数据保留(ZDR)边界
在 OpenAI 官方第一方环境中:
- 默认存储行为: Responses API 默认开启服务端存储(
store: true),而 Chat Completions 对新注册的 OpenAI 账户同样默认开启存储。 - 关闭存储(
store: false): 两个接口均支持传入store: false以关闭服务端响应留存。在 OpenAI 官方 ZDR(零数据保留)或store: false模式下调用推理模型时,官方支持请求include: ["reasoning.encrypted_content"],由客户端在下一轮手动回传encrypted_content以延续推理状态。 - 多渠道网关状态边界:
previous_response_id、Conversations API、GET /v1/responses/{response_id}、DELETE /v1/responses/{response_id}、store、encrypted_content以及后台异步模式(background: true)均属于 OpenAI 官方第一方平台规范。通过 UniRoute 等多模型路由网关调用时,不应默认所有上游渠道都支持跨请求服务端状态存储——除非您已针对特定模型与路由完成实测,否则建议优先采用手动维护input[]或messages[]历史数组的无状态方式。
4. 函数调用、结构化输出与流式 SSE 事件的迁移差异
如果您的应用涉及工具调用(Tool Calling)、强制 JSON Schema 输出或流式增量渲染,在 /v1/chat/completions 与 /v1/responses 之间切换时,必须同步改造请求序列化与流式消费逻辑。
函数调用格式与 Strict 模式默认值差异
在 Chat Completions 中,函数定义采用外部包装(Externally tagged)结构(嵌套在 function 字段内),且默认关闭严格模式(需显式声明 "strict": true)。而在 Responses API 中,函数定义采用内部标记(Internally tagged)的扁平结构,且默认尝试启用 strict 模式:
# 1. Chat Completions 工具定义(外部包装在 function 对象内;默认非 strict)
chat_tools = [
{
"type": "function",
"function": {
"name": "get_route_status",
"description": "查询指定模型路由的延迟状态",
"strict": True,
"parameters": {
"type": "object",
"properties": {"model_id": {"type": "string"}},
"required": ["model_id"],
"additionalProperties": False,
},
},
}
]
# 2. Responses API 工具定义(顶层扁平内部标记;默认尝试开启 strict 模式)
responses_tools = [
{
"type": "function",
"name": "get_route_status",
"description": "查询指定模型路由的延迟状态",
"parameters": {
"type": "object",
"properties": {"model_id": {"type": "string"}},
"required": ["model_id"],
"additionalProperties": False,
},
}
]
在 Responses API 中处理函数调用循环时:
- 模型触发工具调用会在
output[]数组中返回一个"type": "function_call"条目,内含"name"、"arguments"与"call_id"。 - 您的业务代码执行本地函数后,需在下一轮
input[]数组中附上"type": "function_call_output"条目并传入相同的"call_id"(同时保留上一轮response.output中的推理与调用条目)。 - 新模型推理强度与工具调用的兼容性: 根据 OpenAI 官方迁移文档,自 GPT-5.4 起,当
reasoning_effort设置为none以外的值时,Chat Completions 不再支持工具调用。因此,需要同时启用深度推理与函数调用的工作流应使用/v1/responses。 - 区分自定义函数、内置工具类型与远程 MCP 连接: 除开发者自定义的
functionSchema 外,Responses API 规范还定义了多种内置工具类型(如web_search、file_search、code_interpreter、image_generation以及由客户端环境执行具体操作动作的computer_use)和外部远程 MCP 服务器连接。这些能力的可用性与计费规则取决于具体的工具、模型与路由——启用内置工具可能会根据 OpenAI 官方定价规则产生额外的工具专项费用,且不应默认任意网关路由均支持所有内置工具或远程 MCP 连接。
结构化输出(response_format 迁移至 text.format)
若您的服务使用 Structured Outputs 强制约束 JSON 输出格式,迁移到 /v1/responses 时需将原本位于 response_format 的 Schema 配置移入 text.format:
# Chat Completions 结构化输出配置
chat_response_format = {
"type": "json_schema",
"json_schema": {
"name": "route_check",
"strict": True,
"schema": {
"type": "object",
"properties": {"endpoint": {"type": "string"}, "ready": {"type": "boolean"}},
"required": ["endpoint", "ready"],
"additionalProperties": False,
},
},
}
# Responses API 结构化输出配置
responses_text_config = {
"format": {
"type": "json_schema",
"name": "route_check",
"strict": True,
"schema": {
"type": "object",
"properties": {"endpoint": {"type": "string"}, "ready": {"type": "boolean"}},
"required": ["endpoint", "ready"],
"additionalProperties": False,
},
}
}
流式 SSE 消费逻辑(choices[].delta vs. 语义化生命周期事件)
两个接口虽都通过 stream: true 建立 HTTP Server-Sent Events(SSE)流,但根据 OpenAI 流式响应指南,二者的事件协议完全不兼容:
- Chat Completions 推送增量 chunk,文本位于
chunk.choices[0].delta.content,工具参数碎片位于chunk.choices[0].delta.tool_calls。 - Responses API 推送带有明确
event.type标识的语义化生命周期事件:response.created与response.in_progressresponse.output_item.added与response.content_part.addedresponse.output_text.delta(增量文本位于event.delta)与response.output_text.doneresponse.function_call_arguments.delta与response.function_call_arguments.done- 终止事件:
response.completed、response.incomplete、response.failed与error
# Responses API 流式 SSE 消费示意(不可直接复用 choices[].delta 解析器)。
# 显式校验 response.completed 终止状态,且对未完成的流不执行自动重试。
stream = client.responses.create(
model=MODEL_ID,
input="列出切换 API 接口路径前需要核对的三项检查。",
stream=True,
)
completed = False
for event in stream:
if event.type == "response.output_text.delta":
print(event.delta, end="", flush=True)
elif event.type == "response.completed":
completed = True
print("\n流式响应已完成:", event.response.id)
elif event.type in ("response.incomplete", "response.failed", "error"):
raise RuntimeError(f"流式传输未完整结束: {event.type}")
if not completed:
raise RuntimeError("流在收到 response.completed 前提前中断;请先核对用量再决定是否重试。")
在生产环境中,必须收到 response.completed 才能将流式请求视为正常完成,并对 response.incomplete、response.failed、error 以及未收到 response.completed 就提前结束的 EOF 显式报错。收到前几个 response.output_text.delta 仅代表部分增量片段已到达,并不代表整轮生成已完整结束或定义最终账单结算状态。
5. Codex 为何要求 /v1/responses(wire_api)及 UniRoute 路由验证与回滚
理解 /v1/responses 与 /v1/chat/completions 的协议边界,也能帮您快速定位各类 AI 编码客户端的接入要求。
为什么官方 Codex CLI 与插件必须走 /v1/responses
根据 OpenAI Codex 官方配置参考文档,~/.codex/config.toml 中的自定义模型提供方通过 model_providers.<id>.wire_api 指定通信协议。在当前官方规范中:
wire_api仅支持"responses"(省略该字段时默认值同样为"responses")。由于 Codex 原生发送强类型的 Responses 条目而非messages[],接入 Codex 的上游服务必须提供 HTTP/v1/responses接口。supports_websockets(true/false)是model_providers.<id>下的独立布尔配置项,用于声明是否支持 OpenAI 的 Responses WebSocket 传输模式。支持 HTTP/SSE 的/v1/responses并不代表某个网关或渠道自动支持 WebSocket 模式。
如需查看完整的 ~/.codex/config.toml 配置模板、环境变量隔离与回滚方法,请参阅 用 UniRoute API Key 接入 Codex:配置与用量核对教程。
在 UniRoute 上验证接口兼容性与安全回滚清单
UniRoute 公开的 OpenAI 兼容网关地址(API 根路径 https://api.uniroute.app,SDK base_url 为 https://api.uniroute.app/v1)包含 POST /v1/chat/completions、POST /v1/responses 与 GET /v1/models。由于多模型网关会将请求路由至不同的上游模型与渠道,接入时请严格区分以下三个层面:
- OpenAI 官方第一方协议规范: 定义在
developers.openai.com上的标准字段与官方第一方特性。 - UniRoute 公开网关路径、模型目录与充值页面: 浏览 UniRoute 模型目录可查看各模型的参考价与平台公开价格(调用
GET /v1/models仅代表模型可被发现),而前往 UniRoute USD 充值方案页面可为测试账户准备余额。 - 您当前 API Key 命中路由的实际能力: 无论是网关提供
/v1/responses路径,还是模型出现在/v1/models列表中,都不代表所有模型或所有路由均支持全部 Responses 参数、服务端状态存储(previous_response_id、store)、内置工具或 WebSocket。请结合 路由选择与渠道配置指南进行验证。
在 UniRoute 上切换 /v1/responses 或回滚至 /v1/chat/completions 时,建议遵循以下四步检查清单:
- 创建独立的测试用 API Key: 参考 创建 UniRoute API Key 指南或前往控制台的 密钥管理,为待测服务创建并命名一个独立的测试 Key(控制台支持创建、重命名、启用/停用与删除密钥)。建议保持小额测试预算进行验证,并将密钥保存在本地环境变量(
UNIROUTE_API_KEY)中。 - 关闭自动重试并发送单次非敏感测试请求: 将
MODEL_ID设为目标模型字符串,在关闭客户端自动重试的前提下对目标路径(/v1/responses或/v1/chat/completions)发起一次简短测试。若因参数不支持或结构不匹配报错,请立即停止并修正代码,切勿让客户端自动重试或 Agent 循环产生多笔额外计费调用。 - 回滚时同步切换路径、请求结构与流解析器: 若需将某项服务从
/v1/responses回滚至/v1/chat/completions(或反向升级),必须将接口路径、请求体结构(input+instructions+text.format↔messages+response_format)、工具 Schema(内部扁平标记 ↔ 外部function包装)以及 SSE 流式解析器作为整体一并切换。 - 在控制台核对本人用量记录与账单状态: 打开 本人 UniRoute 用量记录,点击测试请求打开详情抽屉,核对请求时间、模型 ID、显示的渠道分类信息(如 Official、Cloud vendor 或 Unknown,以及界面显示的路由组)、请求状态、token 明细(输入、输出、缓存)与记录的实际费用。
- 区分单条用量记录与钱包最终结算: 用量详情抽屉或诊断摘要展示的是单次请求的记录元数据,不等于钱包总结算对账单;同时,失败或中途中断的请求并不自动代表零费用。在结算状态未最终确认前,请将其视为未知,并通过本人登录后的账户记录或私有支持渠道核实。
- 安全使用诊断摘要: 如需就某笔调用联系支持,可在详情抽屉中点击复制诊断摘要(Copy diagnostic summary)。发送前请先审阅内容——尽管摘要不包含提示词正文、API Key、Cookie 和账户余额,但仍包含请求时间、模型 ID、请求 ID、状态码与记录费用等私人元数据,请仅通过私有支持渠道发送,切勿发往公开群组或论坛。

