AIFreeAPI Logo

Chat Completions 与 Responses API:差别不只是字段名

A
9 分钟阅读AI 开发

新项目通常应从 Responses API 开始;稳定运行的 Chat Completions 不必因为名称更新而仓促重写。真正需要评估的是输出解析、状态续接、工具回传和流式事件这四组合同。

Chat Completions 与 Responses API 的协议合同、工具调用往返和迁移验收总览

先给结论:新项目优先采用 Responses API;只做单轮文本、已经稳定运行的 Chat Completions 可以继续维护,再按功能收益分阶段迁移。 OpenAI 当前的官方迁移指南明确写着,Responses 是 Chat Completions 的演进,也是新项目的推荐接口;同一页也明确说明 Chat Completions 仍受支持。它不是“明天就不能用”的旧接口。

真正的区别也不是把 /v1/chat/completions 改成 /v1/responses。前者把一次生成组织成消息列表和候选答案,后者把模型消息、推理、工具调用和工具结果都建模为不同类型的 Item。只改 URL,最容易在输出解析、上下文、工具回传或流式 UI 上留下静默错误。

两套接口的最小心智模型

Chat Completions 的中心对象是 messages。应用把历史消息重新发送给模型,再从 choices[0].message 读取答案:

js
const completion = await client.chat.completions.create({ model: "gpt-5.6", messages: [ { role: "developer", content: "回答要简洁。" }, { role: "user", content: "给这个错误日志归类。" }, ], }); const text = completion.choices[0].message.content;

Responses 的中心对象是 input 和类型化的 output Item。纯文本场景可以使用 SDK 的 output_text 便捷属性,但工具调用、引用、状态或其他输出类型仍要遍历 output

js
const response = await client.responses.create({ model: "gpt-5.6", instructions: "回答要简洁。", input: "给这个错误日志归类。", }); const text = response.output_text; for (const item of response.output) { console.log(item.type, item.status); }

这一区别会产生几项直接后果:

合同Chat CompletionsResponses API迁移时要改什么
端点/v1/chat/completions/v1/responsesSDK 调用或 HTTP URL
输入messages字符串或 Item 列表 input,另有 instructions请求构造与类型定义
输出choices[].messageoutput[] 类型化 Item解析器、日志与错误分支
多个候选可用 n 返回多个 choice一次只产生一个 generation依赖多候选的业务逻辑
会话状态通常由应用重发消息可用 previous_response_id、Conversations 或手动重放 Item状态存储与恢复策略
结构化输出response_formattext.formatschema 配置位置
流式返回chunk 与 choices[].delta有类型的语义事件事件分发器和完成条件

因此,“能复用简单的 role/content 消息数组”只说明最小文本请求容易搬迁,不代表两套协议可以互换。

状态便利性和数据存储是两件事

Chat Completions 的多轮对话通常由应用维护:保存历史,把需要的消息重新放进下一次 messages。Responses 可以让下一轮带上 previous_response_id

js
const first = await client.responses.create({ model: "gpt-5.6", input: "把这份告警归纳成三类。", }); const next = await client.responses.create({ model: "gpt-5.6", previous_response_id: first.id, instructions: "现在只给出需要立即处理的一类。", input: "继续。", });

这能减少应用手动拼接上下文的工作,但有两个容易忽略的边界。

第一,Responses API reference说明,上一轮的 instructions 不会因为传了 previous_response_id 就自动沿用;需要持续生效的开发者指令,下一轮仍要明确提供。

第二,状态续接不等于数据不落盘。OpenAI 的数据控制说明对 Responses、store、Zero Data Retention、background mode、缓存和托管工具分别规定了边界。当前文档说明,Responses 在默认存储或 store: true 时可能保留至少 30 天的应用状态,但组织级设置和例外会改变行为。若你的业务有留存要求,不应只记住一个 store: false,而要根据组织配置和实际利用面重新核对。

工具调用为什么不能只改响应字段

Chat Completions 和 Responses API 的工具调用信封差异及类型化 streaming 事件对比
Chat Completions 和 Responses API 的工具调用信封差异及类型化 streaming 事件对比

两套接口都能调用自定义函数,但往返信封不同。

在 Chat Completions 中,模型的工具请求位于 assistant message 的 tool_calls;应用执行函数后,追加一个 role: "tool" 的消息,并用 tool_call_id 对应原调用。

在 Responses 中,模型返回独立的 function_call Item;应用回传 function_call_output Item,并用 call_id 建立对应关系:

js
const calls = response.output.filter( (item) => item.type === "function_call" ); const toolOutputs = calls.map((call) => ({ type: "function_call_output", call_id: call.call_id, output: JSON.stringify(runTool(call.name, call.arguments)), })); const final = await client.responses.create({ model: "gpt-5.6", previous_response_id: response.id, input: toolOutputs, });

这里必须遍历全部调用,而不是假设永远只有第一个。还要分别验证:参数 JSON 解析失败怎么办、工具超时如何回传、并行调用如何关联、工具结果之后是否还有下一轮工具调用。OpenAI 的函数调用指南给出了两套接口的完整往返示例。

如果你使用的是 web search、file search、code interpreter 或 remote MCP 等托管工具,Responses 的优势更明显:同一请求可以包含多个类型化的工具 Item。但具体模型是否支持某个工具,仍要看当前模型页;“接口支持”不能推出“任何模型都支持”。

流式 UI 要重写事件分发,而不是换一个取文本表达式

Chat Completions 流通常循环读取 chunk,从 chunk.choices[0].delta.content 追加文本。Responses 使用有明确类型的语义事件,例如文本增量、输出 Item 完成和整个 response 完成事件。官方流式响应指南建议按事件类型处理。

这会改变前端和可观测性代码:

  • 文本增量只更新正在显示的文本;
  • 工具调用参数增量进入工具状态,而不是聊天文本;
  • Item 完成用于收口单个输出;
  • response 的 completedfailedincomplete 决定整次请求最终状态;
  • 用户取消、网络断线和模型生成不完整必须拥有不同的 UI 与重试策略。

仅以 HTTP 200 或“收到过文本增量”作为成功条件并不够。Responses 对象本身拥有状态生命周期,迁移后的日志至少应记录 response ID、最终状态、输出 Item 类型、usage 和错误/不完整原因。

新项目与旧系统应采用不同决策

对于新项目,Responses 通常是更稳的默认选择,尤其是以下任一条件成立时:需要推理模型的连续上下文、托管工具、多步函数调用、原生多模态输入、长任务状态或未来扩展到代理工作流。

对于稳定的旧系统,继续使用 Chat Completions 也可能是正确决定,特别是业务只是单轮文本或简单结构化输出,现有解析、监控和供应商抽象都围绕 messages/choices,而 Responses 暂时没有带来能覆盖迁移风险的收益。支持仍在,不需要为了“接口更新”制造一次大爆炸式重写。

第三方标注“OpenAI compatible”时更要谨慎。兼容 Chat Completions 不自动等于兼容 Responses;即使端点存在,也要分别核对 Item 类型、流式事件、工具信封、状态续接和错误对象。OpenAI 官方文档只能证明 OpenAI 自身的合同,不能替第三方供应商背书。

用一次影子迁移把风险变成可验收结果

从输出解析到存储合规的六组迁移验收合同与常见静默错误
从输出解析到存储合规的六组迁移验收合同与常见静默错误

一个可控迁移可以按以下顺序推进:

  1. 先封装内部中间结果,不让业务代码直接读取 choices[0] 或任意 output[0]
  2. 用同一批代表性请求同时调用两条路径,对比最终文本、结构化字段、拒绝和截断行为,而不是只比字符串。
  3. 为多轮场景明确选择 previous_response_id、Conversation 或手动重放,验证进程重启后的恢复方式。
  4. 迁移全部工具往返,覆盖零次、一次、并行多次、失败与重试。
  5. 重写 streaming 事件分发和完成条件,验证取消、断线、incompletefailed
  6. 最后检查存储、日志脱敏、usage 计量和第三方兼容性,再逐步放量。

切换完成的标准不是“返回了一段正确文字”,而是旧接口承担的每一项可观察合同都有了新实现:状态能恢复、工具调用不丢、结构化输出能解析、流式 UI 能收口、失败能定位。做到这一步,迁移才从字段替换变成了受控的协议升级。