OpenAI API 流式输出怎么开启?
简答:OpenAI API 流式输出的核心是:在请求体中设置 <code>stream=true</code>,然后循环读取服务端返回的增量事件或数据块,而不是等待完整 JSON。Responses API 通常读取 <code>response.output_text.delta</code>,Chat Completions 则读取 <code>choices[0].delta.content</code>。如果后端能收到增量但前端不实时显示,应继续检查响应类型、代理缓冲和浏览器端读取方式。
定义:OpenAI API 流式输出是通过 HTTP SSE 持续返回模型生成过程中的增量内容,让客户端边接收边展示,而不是等完整回答生成后一次性返回。
先看结论:开启流式只改一个参数,但读取方式也要改
本文是中立的 OpenAI API 接入指南;站点并非 OpenAI 官方站。以 2026-11-03 检索到的官方文档为准,HTTP 流式请求使用 stream=true,服务端通过 Server-Sent Events(SSE)逐步发送事件或数据块。
| 接口类型 | 请求中的关键参数 | 客户端读取字段 | 完成判断 |
|---|---|---|---|
| Responses API | stream: true | event.type === "response.output_text.delta" 时读取 event.delta | response.completed |
| Chat Completions | stream: true | chunk.choices[0].delta.content | 检查结束数据块或 finish_reason |
| 兼容 OpenAI 的接口 | 通常也是 stream: true,但需服务端确认 | 可能是 SSE、JSON Lines 或其他兼容格式 | 以当前接口返回格式为准 |
官方流式指南同时说明,Responses API 和 Chat Completions 都可以通过 stream=true返回增量结果;但兼容接口不一定完整支持相同事件、字段或结束标记,不能只凭配置项推断能力。参考:OpenAI Streaming API responses。
最短步骤:先确认模型、接口路径和密钥,再开启 stream
- 确认接口类型:决定使用
/v1/responses还是/v1/chat/completions。如果使用兼容 OpenAI 的 Base URL,应以服务商当前文档确认路径和协议。 - 确认模型 ID:从当前控制台或模型列表获取可调用的模型名称。模型列表能显示某个模型,不等于当前项目一定有权调用,仍要用最小请求验证。
- 使用环境变量保存 Key:例如设置
OPENAI_API_KEY,不要把密钥写进网页源码、公开仓库、日志或截图。 - 在请求体加入参数:Responses API 和 Chat Completions 都使用布尔值
stream: true;Python 字典中写作True。 - 按增量字段拼接:每收到一个文本片段就追加到缓冲区,同时把片段输出到终端或服务端响应。
- 检查结束状态:Responses API 监听
response.completed;Chat Completions 读取结束块或finish_reason,不能仅以“连接关闭”判断完整成功。
如果 Base URL、模型名或接口路径来自中转服务,以上示例只是通用模板,必须把占位内容替换为当前可核验的配置;无法从公开一手资料确认的字段应标记为“需核实”。
Responses API:Python、Node.js 与 curl 的最小模板
Responses API 的流式事件带有明确的 type 字段。官方文档列出的常见事件包括 response.created、response.output_text.delta、response.completed 和 error。参考:Responses streaming events。
Python 读取增量文本
下面是通用模板,MODEL_ID 需要替换为当前账号可调用的模型;示例没有声称该占位模型真实存在。
from openai import OpenAI
client = OpenAI()
stream = client.responses.create(model="MODEL_ID", input="用一句话解释流式输出", stream=True)
for event in stream:
if event.type == "response.output_text.delta":
print(event.delta, end="", flush=True)
elif event.type == "response.completed":
print("\n完成")
elif event.type == "error":
print(f"\n错误:{event.message}")
Node.js 使用 for await...of
Node.js SDK 的基本模式是创建流,然后使用 for await...of顺序处理事件。官方 SDK 文档还提醒,干净 EOF 不一定代表完整完成,应检查最终响应状态并处理异常。参考:openai-node streaming 文档。
import OpenAI from "openai";
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const stream = await client.responses.create({ model: "MODEL_ID", input: "用一句话解释流式输出", stream: true });
let text = "";
for await (const event of stream) {
if (event.type === "response.output_text.delta") {
text += event.delta;
process.stdout.write(event.delta);
} else if (event.type === "response.completed") {
console.log("\n完成");
} else if (event.type === "error") {
console.error(event.message);
}
}
curl 原始 HTTP 模板
curl 适合先确认 HTTP 层是否真的返回流。下面的地址和模型仅适用于 OpenAI 原生接口模板;使用其他 Base URL 时,必须按其文档替换并核对路径。
curl -N https://api.openai.com/v1/responses \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"MODEL_ID","input":"用一句话解释流式输出","stream":true}'
成功时,HTTP 状态码首先应为成功响应,随后持续收到事件数据;具体模型、响应事件和权限仍以本次请求返回为准。若直接返回完整 JSON、HTML 错误页或 JSON 错误对象,不要把它当成流式成功。
Chat Completions:读取 delta.content 并拼接完整答案
Chat Completions 的流式响应通常以多个 chat.completion.chunk数据块返回,文本增量位于 choices[0].delta.content。官方参考文档说明,最后一个块在启用 stream_options: {"include_usage": true}时可能没有普通 choices,而是携带用量信息,因此读取代码不能假设每个块都有文本。参考:Chat Completions streaming events。
Python 模板
from openai import OpenAI
client = OpenAI()
stream = client.chat.completions.create(
model="MODEL_ID",
messages=[{"role": "user", "content": "用一句话解释流式输出"}],
stream=True,
stream_options={"include_usage": True},
)
full_text = ""
for chunk in stream:
if chunk.choices:
piece = chunk.choices[0].delta.content
if piece:
full_text += piece
print(piece, end="", flush=True)
print()
Node.js 模板
const stream = await client.chat.completions.create({
model: "MODEL_ID",
messages: [{ role: "user", content: "用一句话解释流式输出" }],
stream: true,
stream_options: { include_usage: true }
});
let fullText = "";
for await (const chunk of stream) {
const piece = chunk.choices?.[0]?.delta?.content;
if (piece) {
fullText += piece;
process.stdout.write(piece);
}
}
stream_options.include_usage不是“开启流式”的必要条件,它只用于请求兼容接口在结束附近返回用量信息。某些兼容实现可能忽略该字段或不支持它,因此应以响应中的 usage 字段和接口文档核验,不能仅凭请求成功推断用量一定可得。
前端收不到实时内容:按 HTTP、代理和解析方式分流
| 现象 | 优先检查 | 处理动作 |
|---|---|---|
| HTTP 401 或 403 | Key、项目权限、Base URL 和认证头 | 先用非流式最小请求验证认证,再检查模型调用权限;不要先改前端代码。 |
| HTTP 404 | 路径是否把 Responses 和 Chat Completions 混用 | 核对完整 Base URL 与资源路径,确认中转接口是否真的提供该端点。 |
| HTTP 400 | 请求体字段、模型名、stream 类型 | 删除可选字段,只保留模型、输入和 stream=true,再逐项加回。 |
| 终端有增量,浏览器一次性显示 | 服务端响应头、代理缓冲、前端读取逻辑 | 服务端应透传适合的流式 Content-Type,避免中间层缓存或缓冲;浏览器端要按 SSE 或实际返回格式逐段解析。 |
| 中途停止且没有完成标记 | 网络超时、客户端取消、代理断开、上游错误 | 记录已收到的事件、HTTP 状态和错误内容;不要把部分文本保存为完整成功结果。 |
服务端转发时,API Key 应只放在服务端环境变量中,浏览器只调用你自己的后端接口。Cloudflare 的官方示例也采用服务端 SDK 和 TransformStream处理流式数据,说明转发链路需要显式处理可读流与写入流。参考:Cloudflare Workers:Stream OpenAI API Responses。
如果接口返回的是 SSE,通常需要保留事件边界并解析每个 data:数据段;如果返回的是 JSON Lines,则应按换行分隔解析。不要把所有流式响应都强制当作一个完整 JSON 文档读取,否则前端往往会等到连接结束才显示。
成功标准与安全边界
一次可判定的流式成功至少应满足以下条件:HTTP 请求通过认证;响应没有立即返回错误对象;客户端收到多个增量片段;文本片段能够按顺序拼接;最后收到明确的完成事件、结束原因或完整响应状态;若请求了用量信息,还能在响应允许的字段中读取 usage。
- 不要把模型列表当成调用授权:列表可见只说明目录返回了名称,不能替代一次实际调用验证。
- 不要把流式当作更低成本:它改变的是传输和展示方式,不自动改变模型价格、输入输出 token 计算或账户限额。
- 注意内容审核时机:官方文档提醒,流式输出的部分片段更难在生成过程中完整评估;生产应用应设计中断、过滤、人工审核或延迟展示策略。参考:OpenAI 流式响应指南。
- 兼容接口逐项核验:Base URL、模型 ID、认证头、Responses 或 Chat Completions 路径、SSE 格式、结束标记和 usage 支持,都应以当前服务端文档或本机返回结果为准。
- 保留错误上下文:记录请求时间、HTTP 状态、响应头、事件类型和脱敏后的错误体;不要记录完整 API Key 或用户敏感输入。
常见问题
只加 stream=true 就能让网页实时显示吗?
不一定。它只要求上游接口返回流式数据;你的后端还要持续读取并转发,前端也要按 SSE、JSON Lines 或接口实际格式解析。如果代理层缓冲响应,用户仍可能在最后一次性看到内容。建议先用 curl 或服务端日志确认是否已经收到多个增量片段。
Responses API 和 Chat Completions 应该选哪一个?
先看你的工具或兼容接口支持哪一种。Responses API 使用事件类型和 event.delta读取文本,Chat Completions 使用 chunk 和 delta.content读取文本。不要只替换路径而不修改请求体和解析器;两者的事件结构不同,应分别按官方参考文档实现。
为什么最后一个 Chat Completions 数据块没有 content?
流式结束块可能只包含结束原因,或者在请求 stream_options.include_usage时只携带 usage 信息。代码应先判断 choices是否为空,再读取 delta.content,不能直接假设 choices[0]始终存在。
使用 Base URL 或中转接口时,stream 参数仍然有效吗?
不能直接假设。许多兼容接口沿用 stream=true,但可能只兼容 Chat Completions,或使用不同的结束标记、事件格式和 usage 字段。最稳妥的做法是查当前接口文档,再用已确认的模型发送最小请求,检查 HTTP 状态、Content-Type、第一段数据和结束数据。
流式输出中断后可以直接重试吗?
先区分请求是否已经产生副作用、是否已经消耗额度,以及客户端是否收到了部分文本。记录 response ID、已接收事件和错误类型后,再按接口支持的恢复机制处理;不要无条件重复提交可能产生重复结果的请求。Node.js SDK 文档也建议检查最终响应状态,并用 try/catch 处理网络、请求和中止错误。
常见问题
OpenAI API 流式输出怎么开启?
在请求体中加入布尔参数 <code>stream=true</code>;Python 使用 <code>stream=True</code>。随后循环读取增量事件,而不是调用一次后等待完整响应。
Responses API 流式文本应该读取哪个字段?
当事件类型为 <code>response.output_text.delta</code>时读取 <code>event.delta</code>,收到 <code>response.completed</code>后再将结果视为正常完成。
Chat Completions 流式文本应该读取哪个字段?
通常读取 <code>chunk.choices[0].delta.content</code>。读取前先判断 <code>choices</code>是否为空,因为结束块或 usage 块可能没有文本内容。
为什么开启 stream 后前端仍然不实时显示?
先确认服务端是否收到多个增量片段,再检查响应 Content-Type、代理缓冲、后端转发方式和浏览器端解析器。上游有流、下游无流时,问题通常在转发链路。
中转接口是否一定支持 OpenAI API 流式输出?
不一定。需要分别核验 Base URL、路径、模型 ID、认证方式、SSE 或 JSON Lines 格式、结束事件和 usage 支持;仅看到 OpenAI 兼容字样不足以证明全部能力一致。