开始之前
你需要一个 OpenAI 平台账号和一个 API 密钥,密钥在控制台的 API keys 页面创建。每个官方 SDK 都会从环境变量 OPENAI_API_KEY 读取密钥,所以代码里不用出现它。macOS 或 Linux 上运行 export OPENAI_API_KEY="your_api_key_here",PowerShell 里运行 setx OPENAI_API_KEY "your_api_key_here"。
你为自己创建的密钥,带的是你本人的权限。部署好的应用、定时任务或 CI,API 密钥指南建议改用项目服务账号。服务账号是一个非人类身份,自己持有密钥,这样工作负载就不会因为某位开发者离开团队而失效。服务账号的密钥只在创建那一刻完整显示一次,所以要直接存进密钥管理器。
密钥上的权限范围可以收窄它能做的事,但永远不会给出它的主人本来没有的权限。轮换密钥有固定的顺序:先签发新密钥,更新工作负载,确认能用,再吊销旧密钥。密钥换了,服务账号的身份不变。不同的项目可以把不同应用或环境的资源、成员和用量隔离开。如果工作负载运行在 OpenAI 支持的身份提供方上,可以用工作负载身份联合,完全不必保存长期有效的密钥。
Python SDK 需要 Python 3.10 或更高版本。JavaScript SDK 支持 Node.js 22 和 24 LTS,也支持 Deno、Bun 和 Cloudflare Workers。Node.js 20 已在 2026 年 4 月底结束生命周期,不再受支持。浏览器默认被禁止,打开 dangerouslyAllowBrowser 选项才能用,而那样一来,任何打开页面的人都能读到你的密钥。
发出第一次调用,再看看返回了什么
快速入门里的第一个请求只有三步:创建客户端,用模型和输入调用 responses.create,打印 output_text。下面是开发者快速入门里的 Python 版本。JavaScript 版本的调用写法是 await client.responses.create({ model, input }),文件存成 example.mjs,最后用 console.log(response.output_text) 输出。
返回的是一个带自己 id 的 response 对象,不是字符串。它的 output 属性是一组输出项。文本生成指南针对这个提示词给出的示例里,列表只有一项:id 以 msg_ 开头,类型是 message,角色是 assistant。里面有一个 content 列表,装着一个 output_text 部分,也就是那个独角兽故事,旁边是一个空的 annotations 列表,工具提供引用时,引用就放在这里。
迁移指南打印了同一个请求在 gpt-5.5 上的结果,那里的列表以一个 id 以 rs_ 开头的 reasoning 项开头,消息排在第二。output_text 是 SDK 提供的辅助属性,把所有文本部分拼成一个字符串,正好把这个差别藏了起来。写个小脚本时它很方便。代码一旦加了工具或要保存历史,就该逐项遍历这个列表,因为文本生成指南明确提醒,回复不一定在 output[0].content[0].text。
from openai import OpenAI
client = OpenAI()
response = client.responses.create(
model="gpt-6-astra",
input="Write a one-sentence bedtime story about a unicorn.",
)
print(response.output_text)- 在要运行代码的终端里导出密钥。
- 安装 SDK:Python 用
pip install openai,JavaScript 用npm install openai。 - 把代码存成
example.py,JavaScript 版本存成example.mjs。 - 运行
python example.py或node example.mjs,调用返回后会打印出一个短故事。 - 把打印
output_text换成打印response.output,看看那个字符串背后有哪些输出项类型。
| 输出项类型 | 什么时候出现 | 你的代码要做什么 |
|---|---|---|
message | 模型给用户写了文字 | 读取其中的文本部分,或者直接用 output_text |
reasoning | 推理模型在回答前先做了推理 | 保留它,自己回放历史时要原样传回 |
function_call | 模型想运行你的某个函数 | 运行函数,再回一个带相同 call_id 的 function_call_output |
web_search_call 或 file_search_call | 内置工具已在 OpenAI 那边运行过 | 不用运行任何东西,读消息里的引用即可 |
用 instructions 引导模型,再把回复做成流式
instructions 是顶层参数,用来规定模型怎样表现,比如语气、目标、好回答的例子。它的优先级高于 input 里的提示词。传入它,大致相当于在输入列表最前面放一条 developer 角色的消息。developer 消息承载应用的规则,排在 user 消息之前,user 消息则是用户打出来的内容。模型自己的回合用 assistant 角色。
文本生成指南拿代码来比喻这两种角色。developer 消息像函数定义,装着规则和业务逻辑。user 消息像传给这个函数的参数。
它只对当前这一次请求生效。用 previous_response_id 串起来的回合,看不到你之前发过的 instructions,所以串联调用的代码每次都要重新发送。提示词本身应该写在代码里,这样它就有类型化的输入、代码审查和测试。OpenAI 正在淘汰一些旧教程存在平台上的可复用提示词对象,下面的时间线列出了日期。
默认情况下,API 要把整段回答写完,才通过一个 HTTP 响应发回来,回答一长,用户看到的就是这段等待。流式输出只多一个开关就解决了等待。把 stream 设为 true,SDK 交给你的就是带类型的服务器推送事件,也就是服务器单向持续写入的 HTTP 流。下面的示例把文本生成指南里的 instructions 示例和流式输出指南里的事件循环拼在了一起。
文档的示例还设置了 reasoning: { effort: "low" }。推理强度告诉推理模型回答前要想多少,强度越低,速度越快,token 越少。可用的取值因模型而异,推理指南写明 GPT-6.1 Sol 和 GPT-6 Luna 的默认值是 medium。Python 里传 stream=True,再用 for event in stream 遍历,检查的 event.type 名称完全相同。
import OpenAI from "openai";
const client = new OpenAI();
const stream = await client.responses.create({
model: "gpt-6-astra",
reasoning: { effort: "low" },
instructions: "Talk like a pirate.",
input: "Are semicolons optional in JavaScript?",
stream: true,
});
for await (const event of stream) {
if (event.type === "response.output_text.delta") {
process.stdout.write(event.delta);
} else if (event.type === "response.completed") {
console.log("\nResponse completed.");
} else if (event.type === "error") {
console.error(event.message);
}
}response.created只出现一次,在回复开始时。response.output_text.delta会出现很多次,每次的delta里是下一段文字。response.completed只出现一次,在生成结束时。error可能在流的中途出现,所以循环里要给它单独一个分支。
Assistants API 停用
它已经无法使用,迁移指南把它的用户引向 Responses API。
来源:OpenAI Docs: Migrate to the Responses API (2026年11月5日 查阅)
一旦开始读取流,Python SDK 就不会再自动重试,因为重放可能把应用已经显示过的文字再输出一遍。流式输出也让内容审核更难,因为不完整的回答比完整的更难判断。如果你要求返回审核分数,它们要等完整输出生成后才会到达。
让对话跨回合延续
先问“tell me a joke”,再在第二个请求里问“explain why this is funny”,第二个请求对第一个一无所知。每次调用都是独立的。要让模型拿到上下文,你有三种办法。
手动回放最直白。在应用里维护一个输出项列表,每次回复后把模型的 output 追加进去,再加上下一条用户消息,把整个列表作为 input 发出去。没有任何东西替你保存,也没有任何东西瞒着你。
最轻的是 previous_response_id:传入上一次响应的 id,只带新的用户输入,前面的回合由 OpenAI 补上。这能成立,是因为响应默认会被存储,存储的响应对象保留 30 天。下面的代码就是对话状态指南里的示例。
串联省掉的是重复发送文字,省不掉费用:链上所有先前的输入 token,在下一个回合仍按输入计费。如果你学过 Claude API 课程,这里的变化很大,因为 Anthropic 的 Messages API 是无状态的,历史总要由你的代码重新发送。
如果一段对话要跨会话保留,或者在不同设备之间接续,就用 client.conversations.create() 创建一个 conversation,并在每次请求里把它的 id 作为 conversation 传入。conversation 用自己的持久 id,把消息、工具调用和工具输出都存成输出项。
三种办法都会撞上同一个上限。上下文窗口是单次请求能用的最多 token 数,输入、输出和推理 token 都算在里面。长对话一个回合一个回合地逼近它,超出上限的输出可能被截断。对这种情况,指南指向压缩功能,在 /responses 上通过 context_management 和 compact_threshold 设置。发送之前,还可以用它提供的分词工具数一数一段文字有多少 token。
from openai import OpenAI
client = OpenAI()
response = client.responses.create(
model="gpt-6-astra",
input="tell me a joke",
)
print(response.output_text)
second_response = client.responses.create(
model="gpt-6-astra",
previous_response_id=response.id,
input=[{"role": "user", "content": "explain why this is funny."}],
)
print(second_response.output_text)| 方式 | 历史存在哪里 | 每个回合发送什么 | 保留多久 |
|---|---|---|---|
| 手动回放 | 你的应用 | 之前的所有输出项,加上新消息 | 你保留多久就多久,store 可以设为 false |
previous_response_id | OpenAI,按响应逐个保存 | 上一次响应的 id 和新输入 | 响应对象默认保留 30 天 |
| Conversations API | 一个有自己 id 的 conversation 对象 | conversation id 和新输入 | 其中的输出项不受 30 天期限限制 |
在 store 设为 false 的情况下手动回放?要保留 output 里的每一项,包括加密的推理项。Python 里就是在下一条用户消息之前执行 history += response.output。
Responses 和 Chat Completions 是什么关系
Chat Completions 是更早的接口,路径是 /v1/chat/completions,现在仍受支持。迁移指南建议所有新项目都用 Responses,而有些模型直接替你做了选择:GPT-6 Astra 和 GPT-6.1 Sol 只能通过 Responses 调用工具。从 GPT-5.4 起,只要推理强度不是 none,Chat Completions 也不再支持工具调用。
指南把迁移看成三处改动:请求发到 /v1/responses,从带类型的 output 列表读取输出,再决定应用怎样在回合之间保存状态。只有文本的消息列表可以原样迁移,同一个数组在一个接口里叫 messages,在另一个接口里叫 input。
其余部分的结构都变了,下表就是对照图。Chat Completions 把文本、工具调用和元数据黏在一个消息对象里,Responses 则把它们拆成各自独立的输出项。迁移指南给下表每一行都配了左右对照的示例。
存储方式也不同。Responses 默认会被存储,Chat Completions 只对新账号默认存储,两个接口都可以用 store: false 关闭存储。迁移旧代码时,有两个缺口最容易绊人。Responses 没有 n 参数,想要多个候选回答,就多请求几次。Assistants API 已经停用,还在调用它的代码只能在 Responses 上重写。
| Chat Completions | Responses API |
|---|---|
messages 数组 | input,一个字符串或一组输出项 |
| system 或 developer 消息 | 顶层的 instructions |
choices[0].message.content | output_text,或者 output 里的 message 项 |
| 工具调用放在助手消息里 | 独立的 function_call 项,靠 call_id 配对 |
用 response_format 指定 JSON schema | text.format |
带 delta 字段的流式片段 | 带类型的事件,比如 response.output_text.delta |
用 n 一次生成多个结果 | 不支持,需要分开请求 |
| 函数默认是非严格模式 | 省略 strict 时会先尝试严格模式 |
Atty Eleti 和 OpenAI Developers 谈 Responses API
Atty Eleti 在 OpenAI 工作,是这个接口的设计者之一。2025-03-11 Responses API 发布当天,他在 X 上介绍了它,称它是 OpenAI API 新的基础原语,凝结了两年的经验,也是构建智能体的基础。这条帖子是一串讲设计经过的帖子的开头。你第一次调用拿回的那个带类型的 item 列表,就是这个原语在工作,所以加工具之前,先认熟这些类型。
OpenAI Developers 在 2025-08-26 发帖说,Assistants API 的 beta 会在一年后停用,并附上迁移到 Responses 的指南。同一条帖子还说,Responses API 的 token 用量已经超过了 Chat Completions。时间线里的停用日期就是这一次。还在调用 Assistants 的代码现在得重写,而 Chat Completions 的代码可以一个流程一个流程地迁。
它是我们推荐的 OpenAI API 接入方式,现在如此,将来也是。

X 官方嵌入卡片的截图,拍摄于 2026-11-05,时间为 UTC。点击截图可到 X 上打开原帖。X 用 Show more 截断了 OpenAI Developers 的帖子。
常见错误
- 出于习惯,从 Responses 对象里读取
choices[0].message.content。 - 把
output[0]当成回答,而它前面其实还有一个推理项。 - 手动回放历史时,丢掉了推理项或工具项。
- 串联的回合没带上 instructions,然后纳闷语气为什么变了。
- 既传了
previous_response_id,又回放了完整对话,结果模型把同样的回合读了两遍。 - 以为
previous_response_id能让先前的回合免费,其实它们每次都按输入计费。 - 把带类型的 Responses 事件交给旧的流处理代码,而它还在等
delta片段。 - 用
dangerouslyAllowBrowser把密钥放进公开网页。
自己试一试
- 问一个普通问题,打印
response.output里每一项的类型。gpt-6-astra返回了哪些类型? - 把 instructions 改成放在
input最前面的一条developer消息,对比两次回复。 - 用
previous_response_id串起三个回合,第三个回合不带instructions。语气还保持得住吗? - 用
store=False发一次调用,再试着从它的 id 串联第二个回合。会发生什么? - 同一个问题,先把
reasoning强度设为low,再设为high,记下第一个流式词出现要等多久。 - 照着上面的对照表,迁移你自己代码里的一个 Chat Completions 调用,再把两边的输出并排比较。
接下来
第 2 课会给模型加上工具,包括你用 JSON Schema 描述的函数,以及由 OpenAI 替你运行的网页搜索和文件搜索。它就从第一张表里的 function_call 项讲起,还有把它和你的结果配对起来的 call_id。
本课里的每一个限额和每一笔费用都按 token 计算。文字在送到模型之前,会先被切分成 token,弄清这一点,串联的对话开始超出预算时,你就知道钱花在了哪里。
自测一下
你用 previous_response_id 串起第二个回合,第一个回合发过的 instructions 会怎样?
查看答案
B. 它们不在上下文里,所以要重新发送 instructions 只对当前请求生效,所以串联的回合要重新发送。
请求里有推理或工具时,哪种读取回复的方式靠得住?
查看答案
A. 遍历 response.output,逐项检查类型 输出列表可能以推理项或工具调用开头,所以代码要按每一项的类型分别处理。
哪个流式事件带着下一段文字?
查看答案
D. response.output_text.delta 每个 response.output_text.delta 事件的 delta 字段里,都是下一段文字。
你把一个使用 JSON schema 的 Chat Completions 请求迁到 Responses,schema 该放在哪里?
查看答案
C. text.format 在 Responses API 里,结构化输出从 response_format 移到了 text.format。
常见问题
OpenAI API 免费吗?
只有第一次测试是免费的。快速入门把你的第一个请求称为免费测试,之后会把你带到账单页面去充值额度,供正式使用。从那以后,用量按 token 计量,记在你的组织账上。价格经常变动,所以这一课不写具体数字。
刚开始该用哪个 OpenAI 模型?
2026 年 11 月 5 日的模型页面建议:复杂推理和编程用 GPT-6 Astra,兼顾能力和成本用 GPT-6.1 Sol,大批量任务用 GPT-6 Luna。三者标注的上下文窗口都是 1,050,000 个 token,最多输出 128,000 个 token。上线生产时,文本生成指南要求固定一个带日期的快照,比如 gpt-5.5-2026-04-23,这样不同版本发布之间行为不会变。
SDK 会自己重试哪些错误?
连接错误,以及 408、409、429 和 500 以上的状态码,默认各重试两次,采用较短的指数退避。请求超时时间是 10 分钟。Python 用 max_retries,JavaScript 用 maxRetries 来调整,失败的调用要记录 _request_id,这是 Python SDK README 给的建议。
现在就得重写我的 Chat Completions 代码吗?
不必一次全改。指南建议一次迁移一个用户流程,先从纯文本生成开始,比较延迟、token 用量和错误之后,再把更多流量切过去。需要在最新模型上调用函数的流程,要最先迁移。
资料来源
- OpenAI Docs: Developer quickstart https://developers.openai.com/api/docs/quickstart
- OpenAI Docs: Text generation https://developers.openai.com/api/docs/guides/text
- OpenAI Docs: Streaming API responses https://developers.openai.com/api/docs/guides/streaming-responses
- OpenAI Docs: Conversation state https://developers.openai.com/api/docs/guides/conversation-state
- OpenAI Docs: Migrate to the Responses API https://developers.openai.com/api/docs/guides/migrate-to-responses
- OpenAI Docs: Reasoning models https://developers.openai.com/api/docs/guides/reasoning
- OpenAI Docs: SDKs and CLI https://developers.openai.com/api/docs/libraries
- OpenAI Docs: API keys and service accounts https://developers.openai.com/api/docs/guides/api-keys
- OpenAI Docs: Models https://developers.openai.com/api/docs/models
- OpenAI Docs: GPT-6 Astra https://developers.openai.com/api/docs/models/gpt-6-astra
- openai/openai-python on GitHub https://github.com/openai/openai-python
- openai/openai-node on GitHub https://github.com/openai/openai-node
- X: Atty Eleti introduces the Responses API https://x.com/athyuttamre/status/1899541471532867821
- X: OpenAI Developers on winding down the Assistants API beta https://x.com/OpenAIDevs/status/1960409187122602172
- YouTube (OpenAI): Build Hour: Responses API https://www.youtube.com/watch?v=hNr5EebepYs


