Cookbook
OpenAI API 流式输出示例
OpenAI API 流式输出示例讲清 stream true、SSE、Responses、Chat Completions、Python、JavaScript、curl、前端展示和中断处理。
流式输出适合聊天界面、长文生成、命令行工具和实时写作场景。它的价值不是让 模型“算得更快”,而是让用户更早看到文本片段,页面不必等完整响应返回后才开 始展示。
本文示例基于 OpenAI-compatible API 写法。使用 OfApp.cn 时,Base URL 可配置
为 https://api.ofapp.cn/v1,真实模型名、速率限制、流式事件支持和费用请以
OfApp.cn 控制台或官方文档为准。
| 项目 | 内容 |
|---|---|
| 阅读时间 | 约 7 分钟 |
| 更新时间 | 2026-07-03 |
| 适合场景 | 聊天界面、AI 写作、命令行助手、长文生成、实时摘要、代码助手和前端实时展示 |
| 核心问题 | 如何把 stream: true 从“能输出片段”做成可取消、可保存、可排错的产品体验 |
| 你会完成 | curl 流式验证、JavaScript 与 Python 读取增量、Responses 事件处理、前端展示状态和中断处理清单 |
| 边界提醒 | OfApp.cn 官方文档展示了 OpenAI 兼容端点和 stream 相关写法;具体模型、价格、额度、套餐、流式事件和速率限制请以 OfApp.cn 控制台或官方文档为准 |
流式输出是什么
Section titled “流式输出是什么”普通请求会等模型生成完整结果后再返回。流式输出会把响应拆成多个事件或片段 逐步返回,应用可以边接收边展示。
| 对比项 | 非流式请求 | 流式请求 |
|---|---|---|
| 用户感受 | 等完整结果返回 | 更早看到首段内容 |
| 返回结构 | 一个完整 JSON | 多个事件或 chunk |
| 代码复杂度 | 低 | 需要处理空片段、结束事件和中断 |
| 适合场景 | 短答案、后台任务、批处理 | 聊天、长文、终端实时输出 |
| 保存方式 | 直接保存完整文本 | 展示片段,同时拼接完整 buffer |
OpenAI 文档说明,Chat Completions 开启 stream: true 后会返回数据流事件;
流式 chunk 中读取的是 delta,不是非流式响应里的完整 message。
选择 Responses 还是 Chat Completions
Section titled “选择 Responses 还是 Chat Completions”OpenAI 迁移文档说明,Responses API 是新的接口形态,Chat Completions 仍被支 持。放到 OpenAI 兼容服务里,还要看服务商当前是否支持对应端点和流式事件。
| 场景 | 优先路径 | 原因 |
|---|---|---|
| 新项目、代理式流程 | Responses API | 输入、输出和事件结构更统一 |
| 旧项目、现有客户端 | Chat Completions | 兼容 messages 和 choices 结构 |
| 只想验证流式展示 | 服务商明确支持的端点 | 先让 UI 跑通,再评估迁移 |
| 客户端只支持 OpenAI Chat 格式 | Chat Completions | 工具协议比接口偏好更重要 |
建议调试顺序:非流式 Chat 或 Responses 成功后,再打开 stream: true。如果
非流式都失败,流式错误只会增加排查噪声。
流式输出任务选择矩阵
Section titled “流式输出任务选择矩阵”不要因为界面看起来“实时”就默认所有任务都要流式。流式输出会提升等待体验,也会带来事件解析、中断恢复和前端状态管理成本。
| 任务 | 是否适合流式 | 先验证什么 | 主要风险 |
|---|---|---|---|
| 聊天界面 | 适合 | 非流式成功后,用 curl -N 验证增量返回 |
代理缓冲、空片段、用户取消 |
| 长文写作 | 适合 | 前端能边显示边拼接完整 fullText |
只显示片段,没有保存最终文本 |
| 命令行助手 | 适合 | 终端能逐段打印,错误能落到 stderr 或日志 | 中断后不知道已生成内容是否完整 |
| 批处理任务 | 通常不优先 | 非流式结果稳定、错误可重试 | 片段过多,日志和重试复杂 |
| 数据分类 | 通常不优先 | 输出格式稳定,能整体验证 JSON 或标签 | 流式中途失败导致半个结构 |
| 前端演示原型 | 适合小范围验证 | 停止按钮、超时提示和回退非流式 | 把真实 Key 放进浏览器 |
如果任务目标是生成一个必须完整解析的结构化结果,非流式往往更容易验收。如果目标是改善用户等待体验,流式才值得单独设计。
export OPENAI_BASE_URL="https://api.ofapp.cn/v1"export OPENAI_API_KEY="sk-xxxx"export OPENAI_MODEL="以 OfApp.cn 控制台可用模型为准"不要把真实 Key 写进前端代码、GitHub Actions 日志、README 截图或浏览器控制 台。前端页面应调用自己的服务端接口,由服务端再请求 OpenAI 兼容接口。
curl 流式验证
Section titled “curl 流式验证”curl -N 可以关闭缓冲,更容易观察服务端是否逐块返回。调试时先跑非流式,
再把 stream 改成 true。
curl -N "$OPENAI_BASE_URL/chat/completions" \ -H "Authorization: Bearer $OPENAI_API_KEY" \ -H "Content-Type: application/json" \ -d "{ \"model\": \"$OPENAI_MODEL\", \"messages\": [ {\"role\":\"user\",\"content\":\"用三句话解释流式输出。\"} ], \"stream\": true }"如果终端一次性吐出全部内容,可能是服务端不支持流式、代理发生缓冲、终端或 网络层没有按事件流展示。此时再看 SDK 代码意义不大,先排查请求链路。
JavaScript:Chat Completions 流式
Section titled “JavaScript:Chat Completions 流式”这段适合 Node.js 服务端、CLI 工具和后端接口。它读取
choices[0].delta.content,并把每个片段写到终端。
import OpenAI from "openai";
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY, baseURL: process.env.OPENAI_BASE_URL,});
const stream = await client.chat.completions.create({ model: process.env.OPENAI_MODEL, messages: [ { role: "user", content: "用三句话解释流式输出。" }, ], stream: true,});
let fullText = "";
for await (const chunk of stream) { const text = chunk.choices[0]?.delta?.content ?? ""; if (!text) continue; fullText += text; process.stdout.write(text);}
console.log("\n\n完整文本:", fullText);上线时不要只把片段写到屏幕。还要把完整文本拼成 fullText,用于保存、审计
和失败后的提示。
Python:Chat Completions 流式
Section titled “Python:Chat Completions 流式”Python 适合脚本、后台任务、数据整理和命令行助手。
import osfrom openai import OpenAI
client = OpenAI( api_key=os.environ["OPENAI_API_KEY"], base_url=os.environ["OPENAI_BASE_URL"],)
stream = client.chat.completions.create( model=os.environ["OPENAI_MODEL"], messages=[ {"role": "user", "content": "用三句话解释流式输出。"}, ], stream=True,)
full_text = ""
for chunk in stream: text = chunk.choices[0].delta.content if text is None: continue full_text += text print(text, end="", flush=True)
print("\n\n完整文本:", full_text)生产脚本还应加入超时、有限重试和日志脱敏。不要把完整用户材料、真实 Key 或 未脱敏响应写进日志。
JavaScript:Responses 流式
Section titled “JavaScript:Responses 流式”Responses API 的流式返回是事件流。OpenAI 文档列出的常见文本事件包括
response.created、response.output_text.delta、response.completed 和
error。兼容服务可能只实现其中一部分,接入前要用真实账号测试。
const stream = await client.responses.create({ model: process.env.OPENAI_MODEL, input: "用三句话解释流式输出。", stream: true,});
let fullText = "";
for await (const event of stream) { if (event.type === "response.output_text.delta") { fullText += event.delta; process.stdout.write(event.delta); }
if (event.type === "error") { throw new Error(event.message ?? "stream error"); }}如果 Responses 非流式可用,但流式事件缺失,可以先用 Chat Completions 流式 完成界面验证,再回到 Responses 做能力评估。
流式事件处理清单
Section titled “流式事件处理清单”流式输出的核心不是只监听一个文本字段,而是把生命周期事件、空片段和错误都纳入状态机。
| 处理点 | 应用应该做什么 | 没处理时会怎样 |
|---|---|---|
| 开始事件 | 标记 isStreaming = true,禁用重复提交 |
用户连续点击导致重复请求 |
| 文本增量 | 把片段追加到可见文本和完整 buffer | 页面能显示,但最终内容保存不完整 |
| 空片段 | 忽略或记录调试信息,不当作失败 | 错误提示乱跳,用户以为生成失败 |
| 完成事件 | 标记结束,保存完整文本,恢复输入框 | loading 一直存在,用户不知道是否完成 |
| 错误事件 | 展示可理解提示,保存已接收内容 | 一次网络抖动就丢失全部草稿 |
| 用户取消 | 关闭连接,说明内容可能不完整 | 后端仍在生成,前端状态失真 |
| 超时 | 主动结束请求,允许用户重试或切换非流式 | 页面一直等待,体验像卡死 |
OpenAI 文档中 Responses 常见文本流事件包括 response.created、response.output_text.delta、response.completed 和 error。Chat Completions 流式通常读取 choices[0].delta.content。放到兼容服务里,每个事件名和字段都要以服务商当前文档和真实账号测试为准。
前端展示怎么做
Section titled “前端展示怎么做”前端不要直接请求 OpenAI 兼容接口。推荐结构是:
| 层级 | 职责 | 注意 |
|---|---|---|
| 浏览器 | 展示增量文本、取消请求、提示重试 | 不保存 API Key |
| 服务端接口 | 持有 Key、转发流、记录脱敏日志 | 处理超时和取消 |
| 模型服务 | 返回 SSE 或 chunk | 能力以当前文档和实测为准 |
前端状态建议分开维护:
| 状态 | 用途 |
|---|---|
visibleText |
用户当前看到的增量内容 |
fullText |
最终保存或复制的完整文本 |
isStreaming |
控制 loading、停止按钮和输入框 |
streamError |
展示中断、超时或解析失败 |
不要在每个字符到来时都做重排很重的操作。可以按句子、段落或小批量刷新,避 免长文输出时页面卡顿。
中断和重试策略
Section titled “中断和重试策略”流式请求比非流式更容易暴露网络、代理和前端解析问题。上线前至少处理这些情 况:
| 现象 | 可能原因 | 处理方式 |
|---|---|---|
| 非流式成功,流式失败 | 代理缓冲、SSE 不通、端点不支持 | 用 curl -N 验证,检查网关设置 |
| 输出一半停止 | 超时、用户取消、网络中断 | 保存已接收文本,提示重新生成或继续补写 |
| 内容重复 | 自动重试了不可幂等请求 | 重试前让用户确认,或使用任务状态去重 |
| 页面乱码 | 把字节流当普通字符串拼接 | 使用正确的事件流解析和 UTF-8 处理 |
| 最终内容丢失 | 只更新 UI,没有保存 buffer | 展示和保存分开维护 |
| 线上失败,本地正常 | CDN、Serverless、反向代理差异 | 检查超时、缓冲和响应头 |
更多中断排查可以看 streaming interrupted。
上线前检查清单
Section titled “上线前检查清单”| 检查项 | 通过标准 |
|---|---|
| 非流式最小请求 | 同一 Key、Base URL、模型名能稳定返回 |
curl -N |
终端能逐块看到事件或 chunk |
| SDK 读取 | JavaScript 或 Python 能读取增量文本 |
| 前端代理 | API Key 只在服务端,不进入浏览器 |
| 状态管理 | UI 展示和完整保存各自有状态 |
| 取消操作 | 用户关闭页面或点击停止时能正确结束请求 |
| 中断提示 | 告知已生成内容是否完整,提供重试入口 |
| 日志脱敏 | 记录状态码、耗时、错误摘要,不记录完整 Key |
| 回退方案 | 流式失败时可切回非流式或提示稍后重试 |
流式输出会减少总生成时间吗?
Section titled “流式输出会减少总生成时间吗?”不一定。它主要减少首字等待时间,让用户更早看到部分输出。总耗时仍取决于模 型、输入长度、网络和服务状态。
Chat Completions 流式和 Responses 流式有什么区别?
Section titled “Chat Completions 流式和 Responses 流式有什么区别?”Chat Completions 通常读取 choices[0].delta.content。Responses 流式更像事
件流,需要按 event.type 处理,例如文本增量、完成事件和错误事件。
OfApp.cn 一定支持所有流式事件吗?
Section titled “OfApp.cn 一定支持所有流式事件吗?”本文不承诺具体事件覆盖。OfApp.cn 官方文档展示了多个 OpenAI 兼容端点;模型 能力、流式事件、速率限制和价格请以 OfApp.cn 控制台或官方文档为准。
流式中断后可以自动重试吗?
Section titled “流式中断后可以自动重试吗?”可以做有限重试,但不要无脑重提不可幂等任务。聊天生成可以让用户选择重新生 成;涉及写入、付款、发送消息或外部动作的任务必须先确认状态。
浏览器可以直接连 OpenAI 兼容接口吗?
Section titled “浏览器可以直接连 OpenAI 兼容接口吗?”不建议。浏览器会暴露 API Key。正确做法是浏览器连接你自己的服务端接口,由 服务端持有 Key 并转发流式响应。
为什么 delta.content 有时为空?
Section titled “为什么 delta.content 有时为空?”流式 chunk 可能只携带 role、结束标记或其他元数据。读取时要允许空片段,不 要把空片段当成错误。
把 OpenAI API 流式输出做稳定,关键不只是加上 stream: true。更可靠的接入
路径是:用非流式请求确认 Key、Base URL 和模型可用;再用 curl -N 验证真实
事件流;接着在 SDK 里拼接完整文本;上线前补齐取消、超时、错误提示和日志脱
敏。
如果希望用 OpenAI 兼容方式快速验证本文流程,可以参考 OfApp.cn API 直转文 档。真实模型、价格、额度、套餐和流式事件请以 OfApp.cn 控制台或官方文档为 准。
- OfApp.cn API 直转文档:用于核对 OfApp.cn 公开的 Base URL、Bearer 鉴权、OpenAI 兼容端点和
stream相关示例。 - OfApp.cn 首页:用于理解 OfApp.cn 作为统一 API 入口的品牌和产品入口。
- OfApp.cn 天才游乐场:用于确认普通用户从网页入口体验聊天、写作、读文件和生图的路径。
- OpenAI Streaming API responses:用于核对流式响应、Chat Completions chunk 和 Responses 事件说明。
- OpenAI 迁移到 Responses API 指南:用于理解 Responses 与 Chat Completions 的定位和迁移差异。
- 聊天补全 Chat Completions 示例:先跑通
messages和非流式请求。 - 响应接口 Responses API 示例:了解
input、output_text和事件流。 - JavaScript SDK 示例:在 Node.js 服务端接入兼容接口。
- Python SDK 示例:把流式输出放进脚本和后台任务。
- 错误重试示例:为 429、5xx、超时和网络中断设置有限重试。
- streaming interrupted:排查流式响应中断。
- curl 示例:用终端验证请求路径、请求头和事件流。