news 2026/10/5 5:33:01

OpenAI API演进:从Completions到Responses的迁移实践与开源兼容

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
OpenAI API演进:从Completions到Responses的迁移实践与开源兼容

Completions、Chat Completions、Responses,OpenAI 的接口规范在短短几年里经历了三轮大版本演进。每次版本更迭,社区里都会出现两种声音:一种说"官方又在制造迁移成本",另一种说"这是为了长期体验而必须付出的代价"。我自己的项目从 2023 年接入 Completions,到后来全面转向 Chat Completions,再到最近开始评估 Responses,中间踩过不少坑,也逐渐看清楚了这次演进背后的技术逻辑,以及开源社区在接口兼容层上的真实处境。这篇就把我从 API 使用者角度观察到的演进路径、迁移细节、开源兼容真相,一次说清楚。

1. Completions 时代:一个只懂"接龙"的接口,为什么能火?

1.1 本质就是文本接龙

很多人第一次接触 OpenAI 接口,用的其实是后来居上的 Chat Completions,对最早的 Completions 接口反而很陌生。这个接口的设计思路非常朴素:你给它一段prompt,它帮你把后面的文本补全。模型内部做的事情,本质上就是在大规模预训练阶段学会的"文本接龙"。

一个标准的 Completions 请求长这样:

curl https://api.openai.com/v1/completions \ -H "Authorization: Bearer $OPENAI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "text-davinci-003", "prompt": "给我写一封请假邮件,主题是感冒需要休息", "max_tokens": 200 }'

返回结果也很直白:一个choices数组,里面带着补全出来的text字段。没有角色概念,没有对话历史结构,就是纯粹的"上文接下文"。在那个 GPT-3 还占据主流的年代,这种设计是够用的,因为大家的玩法本来就很简单:写邮件、做翻译、生成文案,一次请求就是一次完整的生成任务。

1.2 为什么它最终被官方冷落

用久了你会发现 Completions 有几个硬伤,放到现在的智能体应用场景里几乎没法忍受。

第一,多轮对话要自己拼上下文。你想做客服机器人,就必须把用户前几轮的问题和 AI 的回答拼成一个超长字符串塞进prompt,顺序错了、分隔符混淆了,模型的表现就会明显变差。第二,没有系统提示词和用户角色的区分。系统指令只能靠字符串拼接硬塞进 prompt 的开头,稍微复杂一点的业务逻辑,提示词就变成了一锅粥。第三,函数调用的支持非常丑陋。在 Completions 时代,你想让模型结构化输出,只能靠"在 prompt 里用自然语言描述函数签名"这种 hack 方式,解析结果更是全凭正则拼运气。

我记得 2022 年底在做一个简历解析项目时,为了让模型返回 JSON 格式的候选人信息,费尽心思在 prompt 里规定输出模板,结果模型偶尔还是会多输出一句解释性文字,导致 JSON 解析直接失败。这类问题不是调参能解决的,而是接口设计层面缺少"约束机制"。

1.3 这段历史的技术遗产

不过 Completions 时代并不是毫无意义。它验证了一个重要假设:大规模语言模型确实能靠"补全"完成大量实际任务,而且 API 化调用是产品化的正确路径。没有这段积累,Chat Completions 发布时,社区不会那么快接受 OpenAI 的接口规范。换句话说,Completions 是这个生态的第一个锚点,后来所有接口设计,都是在它身上打补丁、做演进。

2. Chat Completions 的统治算法:messages 结构如何赢得所有人的心

2.1 消息结构是一次正确的抽象

2023 年 3 月,OpenAI 推出 Chat Completions 接口(/v1/chat/completions),最大变化是把"一段文本"换成了"一个消息数组"。每条消息带有role字段,分成system、user、assistant三类。这个设计看似简单,实际上精准解决了 Completions 时代的三大痛点:系统指令有专门的位置了,多轮对话有自然的结构了,助手的历史输出也有独立记录了。

用代码看更直观:

from openai import OpenAI client = OpenAI(api_key="sk-...") response = client.chat.completions.create( model="gpt-4o", messages=[ {"role": "system", "content": "你是简历解析助手,只输出 JSON"}, {"role": "user", "content": "请解析这段简历:张三,5年Python经验"}, {"role": "assistant", "content": "{"name": "张三", "years": 5}"}, {"role": "user", "content": "再补充一栏技能标签"}, ] )

你不用再自己拼历史、记分隔符了,接口把"对话状态"显式化了。这也让 OpenAI 后续的微调、指令跟随能力的优化有了统一的发力方向。可以说,Chat Completions 的成功不只是模型的成功,更是交互原语设计上的成功。

2.2 函数调用终于规范化了

Chat Completions 真正让我觉得"接口开始懂开发者"的,是tools参数和函数调用的标准化。模型可以根据系统提示和用户问题,自己决定调用哪个函数,并输出结构化的调用参数,然后你执行函数、把结果塞回对话,模型再基于结果生成最终回答。

也许你会觉得这套机制在 Completions 时代也能靠 prompt 硬凑出来,但规范化之后完全不一样了:

tools = [ { "type": "function", "function": { "name": "get_weather", "description": "查询指定城市天气", "parameters": { "type": "object", "properties": { "city": {"type": "string"} }, "required": ["city"] } } } ]

模型返回的tool_calls有标准 ID、函数名、参数 JSON,你再也不需要猜测模型的输出格式了。当时我做的第一个函数调用版本,解析成功率从 80% 左右直接跳到了 99% 以上,因为失败的原因从"模型输出格式飘忽不定"变成了"模型选错了参数"——后者简单得多。

2.3 统治期留下的判断惯性

从 2023 年到 2025 年,Chat Completions 成为事实上的行业标准接口。国内外的模型厂商、开源推理框架、中间层网关,几乎都选择兼容/v1/chat/completions。这也导致很多开发者的心智被深深固化了:一提到"调用大模型 API",脑子里浮现出的就是messages数组,就是max_tokens,就是choices[0].message.content。

这种固化带来的问题在于,当 OpenAI 推出 Responses API 时,很多人第一反应是抗拒——"好好的 Chat Completions 不用,为什么要换?"事实上,如果你的产品只是做聊天机器人、内容生成,Chat Completions 完全够用,并不需要主动迁移。但如果你想做更复杂的智能体应用,或者想省掉自己封装工具、上下文管理的代码,Responses 提供的东西是 Chat Completions 再怎么打补丁也补不出来的。

3. Responses API 到底改了什么:从 messages 到 input 的底层逻辑

3.1 定位不再是"聊天补全",而是"任务执行"

Responses API(/v1/responses)的定位和 Chat Completions 有本质区别。Chat Completions 的核心抽象是"对话",而 Responses 的核心抽象是"一次任务的完整执行"。它不再要求你把每一条消息都自己传一遍,而是允许你从零开始构建一个响应,也可以基于上一次响应的 ID 继续对话,还能在请求里直接声明要使用哪些内置工具。

拿一个最简单的例子对比一下。Chat Completions 的请求是:

response = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "介绍一下 Vue 3"}] )

Responses 的请求变成:

response = client.responses.create( model="gpt-4o", input="介绍一下 Vue 3" )

messages变成了input,连数组都可以不传,直接传字符串。看起来改动不大,但在这个简化背后,隐藏着一整套新的执行模型。

3.2 内置工具改变了集成方式

Chat Completions 时代,你要给模型接入网络搜索、代码执行、文件分析能力,得自己去找第三方服务、自己封装工具调用流程。Responses API 把这部分能力变成了声明式的:

{ "model": "gpt-4o", "input": "帮我搜索一下今天开源社区的新闻,并总结要点", "tools": [ { "type": "web_search" } ] }

你不需要自己实现搜索函数、不需要解析搜索结果、不需要把结果再塞回对话里。Responses API 会在内部完成工具调用闭环:搜索 → 拿到结果 → 让模型基于结果生成回答。这一类内置工具还包括file_search、code_interpreter,以及对开发者来说很有价值的computer_use。对于做智能体的团队来说,这套机制省掉的不是一星半点的代码量。

我不否认,这种"内置工具"策略带有明显的厂商锁定意味,但对多数开发者来说,快速交付价值远比纠结锁不锁定更重要。等业务真正跑起来了,再去评估是否迁移到开源模型也不迟。

3.3 状态、事件与令牌开销的重新设计

Responses API 还引入了显式的响应状态机制。一个响应对象会经历in_progress、completed、failed、rejected等状态。其中rejected表示请求被安全策略拦截,failed表示执行环节出现异常。对稳定性要求高的生产系统来说,这个状态机比从前"只靠 HTTP 状态码猜错误"要直观得多。

流式输出也做了重新设计。Chat Completions 的流式返回是choices[].delta,每个 chunk 只是一个增量片段,你还要自己拼装。Responses 的流式输出改用事件模型,不同类型的事件区分了响应生命周期中不同阶段:

stream = client.responses.create( model="gpt-4o", input="说一个关于程序员的笑话", stream=True ) for event in stream: if event.type == "response.output_text.delta": print(event.delta, end="")

不同 SDK 版本里事件对象的属性名可能略有差异,但事件类型本身是稳定的。你可以按response.created、response.output_text.delta、response.completed这套流程精确控制自己的 UI 展示逻辑。

还有一个容易被忽略的改进:支持传入previous_response_id来延续对话上下文。之前每次多轮对话都要全量把历史消息重新传一遍,token 开销和时延都上去了。现在如果对话是基于上一次响应的延续,只需要带上响应 ID 即可。官方在发布时提过一个数字:在典型的连续多轮会话场景下,相较传统方案可以节省约 25% 的 token 消耗。我实测下来,短会话场景改善不明显,但长会话场景确实能省出不少成本。

4. 动手迁移:从 chat.completions 到 responses 的代码改造实录

4.1 环境准备与版本确认

迁移前先确认 SDK 版本。不管是 Python 的openai包还是 Node 的openainpm 包,老版本不一定支持 Responses 接口。建议直接升级到最新稳定版:

pip install --upgrade openai
npm install openai@latest

升级之后,先跑一个最小请求验证 API Key 和网络连通性:

import openai client = openai.OpenAI(api_key="your-key") resp = client.responses.create(model="gpt-4o", input="ping") print(resp.output_text)

能输出pong之类的回复,环境就算没问题了。

4.2 参数映射:哪些变了,哪些没变

我整理了日常开发中最常用的参数映射关系:

维度Chat CompletionsResponses
HTTP 端点/v1/chat/completions/v1/responses
消息入口messages[]input[]
系统提示messages 中 role=systeminput 中 role=system 或字符串开头
模型参数modelmodel
采样参数temperature, top_ptemperature, top_p
流式输出stream=True + choices[].deltastream=True + 事件类型
工具调用tools + tool_calls + role=tool 消息tools + function_call + function_call_output 消息
历史延续手动传全部历史消息传 previous_response_id

从表格能看出来,改动不是天翻地覆的,model、temperature、tools这些核心参数仍然保留,真正需要动手改的是消息结构和工具结果的回传方式。这样迁移的阻力其实比想象中小。

4.3 工具调用链路改造

工具调用是迁移时最大的工作量来源。Chat Completions 的工具调用流程是:模型返回tool_calls,你执行函数,再把结果作为新的role=tool消息追加进 messages 数组,然后再次发起请求。

Responses 的流程变成了这样:

# 第一步:发起请求,带上工具定义 resp = client.responses.create( model="gpt-4o", input="北京今天天气怎么样?", tools=[ { "type": "function", "name": "get_weather", "parameters": { "type": "object", "properties": { "city": {"type": "string"} }, "required": ["city"] } } ] ) # 第二步:从响应中提取函数调用 fc = resp.output[0] if fc.type == "function_call": # 自己实现 get_weather 并拿到结果 result = run_weather_function(fc.arguments) # 第三步:把函数执行结果回传 resp2 = client.responses.create( model="gpt-4o", input=[ { "type": "function_call_output", "call_id": fc.call_id, "output": result } ] )

注意这里有两个明显的不同:第一,工具执行结果不再是一条普通消息,而是有明确类型的function_call_output;第二,回传时必须携带call_id,把结果和之前的函数调用对应起来。这套设计让工具调用链路的追踪清晰了不少,调试多工具协作场景时尤其有用。

4.4 流式与结构化输出的迁移技巧

如果你需要流式输出,迁移时的改动主要是把"解析 delta 文本"改成"遍历事件"。Chat Completions 的代码是:

stream = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "写一段长篇故事"}], stream=True ) for chunk in stream: delta = chunk.choices[0].delta if delta and delta.content: print(delta.content, end="")

Responses 事件流风格不同,但逻辑同样简洁。如果暂时不想大改代码,官方也提供了带include参数的机制来过滤事件,比如只关心response.output_text.delta。

结构化输出方面,text参数的format字段仍然可以使用json_schema方式约束输出格式,这一点和 Chat Completions 的response_format很接近,迁移成本几乎为零。

5. 开源兼容的真相:大家都在"仿 OpenAI",但仿到什么程度?

5.1 兼容是从哪里来的

只要接触过开源大模型生态,你就一定见过"OpenAI 兼容 API"这个说法。vLLM、llama.cpp、Ollama、LocalAI,以及国内大量开源推理框架,几乎无一例外提供/v1/chat/completions端点。背后的原因很简单:OpenAI 通过 Chat Completions 定义了一套事实标准,开发者已经在用这套接口写业务了,如果开源框架不能兼容它,推广成本就非常高。

本质上,这是一种聪明的"追随策略":模型能力可以在开源世界自由竞争,但交互层必须先对齐主流生态,用户才有迁移的动力。所以开源兼容不是口头上的致敬,而是生态准入的门票。

5.2 兼容的层次分析

开源兼容要分三个层次看。

第一层是 HTTP 协议和路径兼容。你向http://localhost:8000/v1/chat/completions发请求,返回的 JSON 形状和 OpenAI 官方基本一致。这是最常见、也最容易做到的兼容。

第二层是 SDK 层兼容。开发者使用openaiPython 包,把base_url改成自定义地址,代码尽量不用改或只改很少几行就能接入。这一层比 HTTP 层更考验框架作者对字段细节的把握,因为 SDK 会自动做类型解析、错误处理、流式解析,任何字段命名偏差都会立刻暴露。

第三层是行为兼容,属于最难的层面。模型能不能理解同一个messages结构?会不会正确输出tool_calls?JSON 格式的输出是否稳定?流式事件是不是按预期顺序到达?这些不是靠"返回 200 状态码"就能糊弄过去的,需要大量测试和调优。很多标榜兼容的框架,到第三层就开始露馅,尤其是工具调用,往往是半天调不通一个函数。

5.3 开源兼容的边界:Responses 的推进明显滞后

当 OpenAI 把主推方向从 Chat Completions 转向 Responses 时,开源社区陷入了某种"追赶式兼容"的尴尬。大多数框架至今仍集中火力做好/v1/chat/completions的成熟度,对/v1/responses的支持要么完全没有,要么只是草草实现了最基本的功能。原因也不难理解:开源社区资源有限,你不可能要求每个项目都把 OpenAI 每次接口演进的边边角角都无缝跟上。

这就带来一个很现实的问题:如果你的业务迁移到了 Responses API,你就失去了大部分开源框架的即时兼容性。想从 OpenAI 切换到某个开源模型推理服务,原来的responses.create调用很可能直接报 404 或者 501,因为对方根本没有实现这个端点。这就是"开源兼容"真正的边界所在——兼容的是历史事实标准,而不是正在变动中的未来标准。

5.4 兼容是动态博弈

我在实际项目中体会到,开源兼容更像一场动态博弈。OpenAI 负责制定新规则,开源社区负责追平时差。Chat Completions 用了几年时间成为业界公认的通用语言,Responses API 要走到同样地位,可能需要更长时间,也可能因为智能体生态的爆发而加速。

对于创业团队,我的建议是:如果你依赖开源模型做私有化部署,现阶段不要轻易把全链路迁到 Responses,保持 Chat Completions 作为主要接口;如果你做的是在线产品,并且需要智能体能力快速落地,那可以考虑在 Responses 上做增量开发,集中精力吃透新接口的红利。

6. 实操踩坑记录:Codex 安装、API Key 与 Windows 可选依赖

6.1 Codex 安装时的 optional dependency 报错

Contrary to expectation(但这就是实际开发中的常态),我在一次环境准备中遇到了一个跟接口演进没有直接关系、却非常典型的安装报错:

missing optional dependency @openai/codex-win32-x64. reinstall codex: npm i

这个报错出现在 npm 安装 Codex CLI 工具时。原因是 Codex 在不同平台上有各自的原生二进制可选包,比如 Windows 对应@openai/codex-win32-x64。npm 在处理 optional dependency 时,如果网络原因或镜像源问题导致某一个平台包没装上,就会抛出这条提示。

我的处理方式是先执行清理再重新安装:

npm uninstall -g codex npm cache clean --force npm install -g codex

如果还报同样的错,说明 npm 源和该平台包的同步有问题。这种情况我建议换个镜像源再试一次。顺带一提,拿到 Codex 后你还需要一个可用的 OpenAI API Key,CLI 启动时会引导你配置,也可以在环境变量里直接设置好。

6.2 API Key 的获取与轮换经验

很多新手在申请 API Key 时会被官网页面的节奏绕晕。简单说,登录 OpenAI 平台之后进入 API Keys 页面,创建一个新的 key,创建后立刻复制保存,因为 key 只在生成时刻完整展示一次,关掉页面就再也看不到了。

我自己通常会给不同环境创建不同 Key,比如开发环境、生产环境各用一个,并在项目里通过环境变量注入而不是硬编码。这样做的好处是,一旦某个 Key 疑似泄露,只需在后台删除它再重新生成,其他环境不受影响。另外,生产环境建议开启用量限制,防止异常流量导致费用飙升——这个教训我吃过一次亏。

6.3 Responses API 在各个开源生态中的支持现状

回到 Responses 接口,我目前观察到的开源支持现状是:主流推理框架多半还没把 Responses 列为一等公民。在 GitHub 上搜/v1/responses的支持情况,大多数项目还处于 open issue 状态,或者只有最基本的路径转发,没有实现事件流和内置工具语义。

这意味着,当你选择 Responses API 时,你的代码和 OpenAI 官方平台的耦合度是显著提高的。如果你在意后续模型可替换性,建议在业务代码之上再包一层抽象,比如自己定义一个轻量级 client 接口,把 Responses 的调用封装在里面,将来切换模型或接入其他兼容层,只需要替换这一层即可。这个习惯我一直建议身边的朋友保持,它不会增加多少代码量,但能极大降低未来被接口锁定带来的痛苦。

6.4 回归测试是迁移的底线

最后特别提醒一点:从 Completions 到 Chat Completions 再到 Responses,每次接口迁移最容忽视的环节是回归测试。不要只验证一条最简单的 prompt 能返回内容就觉得没问题了,工具调用、流式输出、超长上下文、并发访问、安全策略拦截这五类场景必须全部覆盖。

我自己的做法是准备一组固定的测试用例,包括"正常问答""多轮追问""函数调用""流式输出""违禁内容拦截"五类,在每次迁移后跑一遍,用脚本对比响应中的关键字段是否正常。有了这套基线,迁移的恐慌感会小很多,因为你知道哪些行为变了,哪些行为没变,心里有数。

7. 我从这轮接口演进中提炼出的几点判断

先说结论:OpenAI 一定会继续演进接口规范,Chat Completions 不会立刻消失,但新特性会越来越集中在 Responses 生态里。站在开发者的角度,最理性的策略不是"马上大规模迁移",也不是"永远不迁移",而是把迁移当作一次能力升级的机会。

我的建议是,新项目直接用 Responses API。既然官方已经明确把新工具、新模型能力优先集成到 Responses 生态,新项目再抱着 Chat Completions 不放,等于主动放弃了免费的前进动力。旧项目则不要急着推倒重来,只有当确实需要内置工具、需要减少长对话 token 消耗、需要更流畅的事件流时,才考虑迁移。

我在实际项目里的体会是,接口演进本身不可怕,可怕的是把接口当成本质的"心智怠惰"。Completions 教会我们补全,Chat Completions 教会我们对话,Responses 教会我们把模型放进更完整的任务闭环里。每轮演进其实都在削减开发者的重复劳动,让你把精力从"怎么把模型回调格式整理干净"逐渐挪到"怎么用模型能力解决业务问题"上。

最后分享一个小技巧:如果你暂时不想大改代码,可以在自己的工具函数层做一层响应解析适配,把 Responses 的输出转成旧的 Chat Completions 消息格式,这样既能尝到新接口的甜头,又能沿用旧的业务逻辑。我在一个原型项目里就是这么干的,新旧代码混跑了两周,最后才平滑地完全切过去。整个过程没有一次"服务不可用",也没有一次"输出格式崩溃"。这就是我认为对待接口演进最健康的方式:跟上变化,但带着护栏去跟。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/5 5:32:46

工业级Agent意图识别分层漏斗设计与落地实践

1. 什么是工业级Agent意图识别分层漏斗?它到底在解决什么问题?“工业级Agent意图识别分层漏斗”——这名字听着像技术黑话,但拆开来看,它其实是在回答一个非常朴素、每天都在真实业务中反复出现的问题:当用户一句“帮我…

作者头像 李华
网站建设 2026/10/5 5:31:57

Agent可观测性:分布式追踪与Token成本精细化诊断

1. 为什么“Agent可观测性”不是锦上添花,而是生死线最近帮一家做智能客服Agent的团队做性能复盘,他们上线两周后突然出现大量用户投诉:“响应慢、卡顿、有时直接不回复”。运维日志里只有一堆200状态码,监控大盘上CPU和内存曲线平…

作者头像 李华
网站建设 2026/10/5 5:30:51

近场动力学模拟疲劳裂纹扩展:二维程序实现与关键细节

两个月前,我准备把一个二维斜裂纹板的循环拉伸算例迁到自编程序里跑,结果被网格重划分折磨得够呛:每扩展一个增量步就要重新生成网格,裂尖附近还要层层加密,算出来的扩展路径又对网格取向特别敏感。后来我干脆把目光转…

作者头像 李华
网站建设 2026/10/5 5:30:04

Arduino PWM控制直流风扇调速实战:从占空比到续流二极管的避坑指南

Arduino玩PWM控制风扇这事儿,看起来是入门级操作,但真正调起来门道不少。很多人拿到板子第一步就是接个电机、写个analogWrite(9, 128),然后发现风扇嗡嗡响、转速不受控、甚至板子直接掉线——这些问题我都踩过。这篇文章就把我做直流电机风扇…

作者头像 李华
网站建设 2026/10/5 5:29:43

端侧小模型量化解密:从 FP16 到 4-bit 量化对 WebGPU 显存与速度的影响

端侧小模型量化解密:从 FP16 到 4-bit 量化对 WebGPU 显存与速度的影响在尝试将 1B 到 3B 级别的前沿大模型塞进浏览器端侧运行时,前端工程师最先遭遇的绝不是算力不足,而是两道冷冰冰的“物理墙”:带宽下载墙与显存物理墙。 以开…

作者头像 李华
网站建设 2026/10/5 5:29:04

AI编程智能体实战指南:从核心原理到私有化部署

大概半年前,我还在用“AI补全代码”这种小儿科玩法,每天对着IDE里的灰色提示一行行Tab。当时打死我也没想到,就这一年光景,AI编程智能体已经能把一个功能模块从需求分析到测试用例全流程跑通,甚至能主动重构我写的一坨…

作者头像 李华