← 所有文章

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 接口路径,避免将早期补全接口与对话接口混为一谈:

  1. Legacy Completions(POST /v1/completions): OpenAI 早期的单字符串文本补全接口(传入 prompt 字符串,返回纯文本续写),请勿将其与 Chat Completions 混淆。
  2. Chat Completions(POST /v1/chat/completions): 广泛采用的 messages[] 消息数组接口(包含 system、developer、user、assistant 与 tool 角色),返回 choices[].message,可作为跨 SDK 与网关的常见兼容基线(接入时请逐一核实目标提供方支持情况)。
  3. Responses API(POST /v1/responses): OpenAI 面向 Agent 工作流设计的基于条目(Item-based)原语接口,接收字符串或强类型 input 条目数组(配合顶层 instructions),并返回由 reasoning、message、function_call 等多态条目组成的 output[] 数组。

30 秒接口选型速查表

业务场景或客户端类型推荐接口路径选型依据
已稳定运行、使用 messages[] 与常规 JSON Schema 的现有生产服务POST /v1/chat/completionsOpenAI 官方与 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/responsesCodex 配置项 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 数组)+ 可选顶层 instructionsmessages[] 角色消息对象数组单一 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.contentchoices[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 可以基于服务端已保存的上一轮响应继续对话,而无需在客户端请求体里重复上传完整历史数组。但请特别注意两条官方规则:

  1. 历史链条中的输入 token 仍按输入 token 计费: OpenAI 官方文档明确说明,使用 previous_response_id 串联多轮对话时,响应链中此前所有的输入 tokens 在新一轮请求中仍会作为有效的输入 tokens 计费。换言之,改用 /v1/responses 或传入 previous_response_id 不会改变模型的每百万 tokens 单价,也不会免除历史上下文的输入费用;重复前缀的折扣依然取决于提示词缓存(Prompt Caching)命中情况。关于普通未缓存输入、缓存读取、缓存写入与推理输出 token 的完整核算方式,请参阅 OpenAI API 价格指南:UniRoute 上的 GPT Token 费用与用量核对。
  2. 上一轮顶层 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 连接: 除开发者自定义的 function Schema 外,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_progress
    • response.output_item.added 与 response.content_part.added
    • response.output_text.delta(增量文本位于 event.delta)与 response.output_text.done
    • response.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。由于多模型网关会将请求路由至不同的上游模型与渠道,接入时请严格区分以下三个层面:

  1. OpenAI 官方第一方协议规范: 定义在 developers.openai.com 上的标准字段与官方第一方特性。
  2. UniRoute 公开网关路径、模型目录与充值页面: 浏览 UniRoute 模型目录可查看各模型的参考价与平台公开价格(调用 GET /v1/models 仅代表模型可被发现),而前往 UniRoute USD 充值方案页面可为测试账户准备余额。
  3. 您当前 API Key 命中路由的实际能力: 无论是网关提供 /v1/responses 路径,还是模型出现在 /v1/models 列表中,都不代表所有模型或所有路由均支持全部 Responses 参数、服务端状态存储(previous_response_id、store)、内置工具或 WebSocket。请结合 路由选择与渠道配置指南进行验证。

在 UniRoute 上切换 /v1/responses 或回滚至 /v1/chat/completions 时,建议遵循以下四步检查清单:

  1. 创建独立的测试用 API Key: 参考 创建 UniRoute API Key 指南或前往控制台的 密钥管理,为待测服务创建并命名一个独立的测试 Key(控制台支持创建、重命名、启用/停用与删除密钥)。建议保持小额测试预算进行验证,并将密钥保存在本地环境变量(UNIROUTE_API_KEY)中。
  2. 关闭自动重试并发送单次非敏感测试请求: 将 MODEL_ID 设为目标模型字符串,在关闭客户端自动重试的前提下对目标路径(/v1/responses 或 /v1/chat/completions)发起一次简短测试。若因参数不支持或结构不匹配报错,请立即停止并修正代码,切勿让客户端自动重试或 Agent 循环产生多笔额外计费调用。
  3. 回滚时同步切换路径、请求结构与流解析器: 若需将某项服务从 /v1/responses 回滚至 /v1/chat/completions(或反向升级),必须将接口路径、请求体结构(input + instructions + text.format ↔ messages + response_format)、工具 Schema(内部扁平标记 ↔ 外部 function 包装)以及 SSE 流式解析器作为整体一并切换。
  4. 在控制台核对本人用量记录与账单状态: 打开 本人 UniRoute 用量记录,点击测试请求打开详情抽屉,核对请求时间、模型 ID、显示的渠道分类信息(如 Official、Cloud vendor 或 Unknown,以及界面显示的路由组)、请求状态、token 明细(输入、输出、缓存)与记录的实际费用。
    • 区分单条用量记录与钱包最终结算: 用量详情抽屉或诊断摘要展示的是单次请求的记录元数据,不等于钱包总结算对账单;同时,失败或中途中断的请求并不自动代表零费用。在结算状态未最终确认前,请将其视为未知,并通过本人登录后的账户记录或私有支持渠道核实。
    • 安全使用诊断摘要: 如需就某笔调用联系支持,可在详情抽屉中点击复制诊断摘要(Copy diagnostic summary)。发送前请先审阅内容——尽管摘要不包含提示词正文、API Key、Cookie 和账户余额,但仍包含请求时间、模型 ID、请求 ID、状态码与记录费用等私人元数据,请仅通过私有支持渠道发送,切勿发往公开群组或论坛。