首页使用帮助API Streaming
HELP / API 流式输出

OpenAI API Streaming 怎么用?

设置 stream: true 后,应用可以边接收边显示模型输出。Responses API 使用带类型的 SSE 事件,Chat Completions 读取 choices[].delta;可靠上线还要处理完成状态、工具参数、最终 usage、断线和内容审核。

主关键词:OpenAI API Streaming 怎么用SSEdelta更新:2026-10-31
先给结论

Streaming 改善的是“多久看到第一个结果”,不是自动缩短完整生成时间。Responses 新项目应按 event.type 消费语义化 SSE 事件;前端不能只拼接 delta,还必须等到 response.completed 才标记成功。流中断、failed、incomplete 或 error 都不能假装成完整答案。

官方资料(2026-10-30 核对):Streaming API responses · Responses streaming events · Chat Completions create · Function calling

Streaming 到底解决什么问题?

非流式请求会等模型完成整段输出后一次返回。流式请求通过 Server-Sent Events 持续发送增量,让页面先显示开头、进度或工具名称。它适合聊天、长报告、代码生成和需要“正在响应”反馈的界面。

维度非流式流式
首屏体验等待完整结果收到 delta 后即可逐步展示
完整结果判断一次响应成功后读取必须等待 completed/结束标志
错误处理通常在响应前失败可能已经显示部分内容后再失败
内容审核可先检查完整输出再展示部分文本可能先被用户看到
实现复杂度较低需要事件状态机、缓冲、取消和断线处理

Streaming 不会自动降低 Token、费用或 429 概率。限流、模型耗时和总输出长度仍需按 速率限制、Usage 与正式模型规则核对。

Responses API:按事件类型消费 SSE

Responses 使用 typed events。文本流至少关注 response.created、response.output_text.delta、response.completed 和 error;生产代码还应处理 response.failed、response.incomplete、拒答和连接提前结束。

import OpenAI from "openai";
const client = new OpenAI();

const stream = await client.responses.create({
  model: "YOUR_MODEL",
  input: "用三点解释提示词缓存。",
  stream: true
});

let text = "";
let completed = false;

for await (const event of stream) {
  switch (event.type) {
    case "response.output_text.delta":
      text += event.delta;
      process.stdout.write(event.delta);
      break;
    case "response.completed":
      completed = true;
      console.log("\n完成,usage:", event.response.usage);
      break;
    case "response.failed":
    case "response.incomplete":
    case "error":
      console.error("流式请求未完整完成", event);
      break;
  }
}

if (!completed) {
  throw new Error("stream ended before response.completed");
}

response.output_text.delta 可以出现多次;事件中还带有 item_id、output_index、content_index 和顺序信息。简单单文本界面可直接追加 delta;存在多个 output Item、工具或并发内容时,应按这些索引分别聚合,不能把所有字符串盲目拼到一个缓冲区。

Responses 流式事件生命周期

事件发生时机应用动作
response.created响应对象创建记录 response ID,初始化状态
response.output_item.added消息、工具等输出 Item 出现按 output_index/item_id 建立缓冲区
response.output_text.delta新增文本片段追加文本并节流渲染
response.output_text.done某个文本部分完成保存该文本部分,不等于整个 Response 已完成
response.completed整个响应成功完成确认最终状态,读取完整 response 与 usage
response.failed / response.incomplete生成失败或未完成保留已显示内容但标记不完整,禁止当成成功结果
error流内错误记录 code、message、response/request ID,按错误类型处理

不要只因为连接自然关闭就判定成功。你的状态机需要一个明确的终态:只有收到完成事件才写入“已完成”;否则记录为中断、失败或不完整,并向用户显示可理解的提示。

Chat Completions:读取 delta 与最终 usage

Chat Completions 同样设置 stream: true,但每个 chunk 主要从 choices[0].delta 读取内容。它不会使用 Responses 的 typed event 名称。

const stream = await client.chat.completions.create({
  model: "YOUR_MODEL",
  messages: [{ role: "user", content: "解释提示词缓存。" }],
  stream: true,
  stream_options: { include_usage: true }
});

for await (const chunk of stream) {
  process.stdout.write(
    chunk.choices[0]?.delta?.content ?? ""
  );
  if (chunk.usage) {
    console.log("\n最终 usage:", chunk.usage);
  }
}

开启 stream_options.include_usage 后,官方参考说明会在 data: [DONE] 前发送一个额外 usage chunk,其中 choices 为空;其他 chunk 的 usage 通常为 null。如果流提前中断,最终 usage chunk 可能不会到达,因此不能把“没有 usage”误判成“没有消耗”。

如果要比较两套端点的 input、output、状态和迁移步骤,请看 Responses API 与 Chat Completions 区别;本页只解决流式消费者的正确实现。

流式 Function Calling:参数完成前不要执行

工具调用的 arguments 也是分片到达的 JSON 字符串。Responses 会发送 response.function_call_arguments.delta,并在参数完成时发送 response.function_call_arguments.done。要按 item_id 或 output_index 聚合不同调用,不能把多个工具的参数混在一起。

const argBuffers = new Map();

for await (const event of stream) {
  if (event.type === "response.function_call_arguments.delta") {
    const current = argBuffers.get(event.item_id) ?? "";
    argBuffers.set(event.item_id, current + event.delta);
  }

  if (event.type === "response.function_call_arguments.done") {
    const args = JSON.parse(event.arguments);
    validateAndAuthorize(args);
    // 只有 done 后才执行工具
  }
}

不要对半截 JSON 反复 JSON.parse,更不要根据尚未完成的参数提前执行支付、删除或发信。等 done 后再解析,随后执行 Schema、业务和权限校验;完整工具循环、call_id 与幂等控制见 OpenAI Function Calling 教程。

浏览器、服务端和 OpenAI 应如何连接?

  1. 浏览器:发送用户请求到你自己的后端,使用 Fetch stream、ReadableStream 或前端框架读取增量;不保存 OpenAI API Key。
  2. 应用服务器:完成登录、额度、内容策略和参数校验,持有服务端 Key,再调用 OpenAI。
  3. 流式转发:只向当前用户转发需要的事件或文本,设置正确的流式响应头,避免代理缓存整段响应。
  4. 客户端断开:停止继续渲染,并尽可能取消上游工作;服务端仍要记录本次请求是否已经产生用量或副作用。
  5. 最终落库:只有收到完成事件后才把回答标记为完整;中断内容要带状态,不与成功答案混淆。

前端渲染 Markdown 时也要防止 XSS,不要把 delta 直接写入 innerHTML。高频 delta 应合并到短时间缓冲后再刷新 UI,避免每个 Token 都触发一次昂贵重绘。

连接中断、超时和重试怎么处理?

  1. 区分两类失败:HTTP 建连前错误与流已经开始后的错误,用户界面提示和日志字段不同。
  2. 记录终态:保存是否见到 completed、最后 sequence/index、已显示字符数、response/request ID 和耗时。
  3. 不要假设可续传:普通 SSE 中断后不能靠最后一个文本位置保证无缝继续;需要根据业务重新请求、回到上一条完整消息,或让用户主动重试。
  4. 副作用不自动重试:工具、支付、写数据库必须先确认幂等状态,避免中断后重复执行。
  5. 有限退避:429、5xx 与连接错误按错误类别处理,避免 SDK 重试、代理重试和业务重试三层叠加。

详细的 500/503、超时、Request ID 和 SDK 重试边界见 OpenAI API 5xx 与超时排查。

流式内容审核为什么更难?

用户可能在完整答案出来前看到部分文本。OpenAI 官方指南明确提醒,部分 completion 更难评估;如果生成请求附带审核结果,分数是在完整输出后可用,不会随着每个 delta 同步返回。

  • 低风险聊天可流式展示,但仍要处理 refusal、error 和最终状态。
  • 中高风险场景可先缓冲一段、延迟展示,或使用非流式生成后整体审核。
  • 工具参数和输出还需要单独的权限与策略检查;不要把文本审核等同于工具授权。
  • 日志保留事件类型、状态和脱敏摘要,不记录 API Key 或敏感完整内容。

上线前检查清单

  • API Key 只在服务端,浏览器网络请求中看不到。
  • Responses 按 event.type 分支,不把 Chat Completions delta 代码直接复用。
  • 只有 completed 才标记成功;failed、incomplete、error 和断线有明确 UI。
  • 多 output Item 与多工具按 item_id/output_index 分开聚合。
  • 工具参数等 done 后再解析、授权和执行。
  • 最终 usage 缺失时不推断为零,能与服务端日志和 Usage Dashboard 对账。
  • Markdown/HTML 安全、渲染节流、取消和代理缓存均经过真实网络测试。
  • 429、5xx、客户端断线和重复提交都有评测用例。
SSE 与 Webhook 解决的问题不同

SSE 用于同一次请求的增量展示;Webhook 用于异步事件通知。需要终态回调时,请按 OpenAI Webhooks 验签与去重指南实现,不能把 SSE 重连逻辑直接复制到 Webhook。

流式输出的审核结果不会逐 delta 到达

高风险场景应先确定缓冲或完整输出策略,并按 OpenAI Moderation API 指南读取 flagged、类别和分数。

常见问题

OpenAI API Streaming 会降低总生成时间吗?

Streaming 主要降低用户看到第一个 Token 的等待时间,让界面可以逐步显示内容;它不会自动缩短生成完整答案所需的总时间,也不会减少输出 Token。

Responses API 流式输出应该监听哪些事件?

文本场景至少处理 response.created、response.output_text.delta、response.completed 和 error,并为 response.failed、response.incomplete、refusal 与连接中断保留失败路径。只有完成事件出现后,才能把本次输出标记为完整。

Chat Completions 的 delta 能直接替换 Responses 事件吗?

不能。Chat Completions 从 choices 中读取 delta;Responses 使用带 type 的语义化事件。迁移时要改事件分发、完成判断、工具参数、错误与 usage 读取逻辑。

流式 Function Calling 的参数可以边到边执行吗?

通常不应。参数 delta 是尚未完成的 JSON 片段,应按 item_id 或 output_index 聚合,等 response.function_call_arguments.done 后再解析、校验权限和执行工具。

stream_options.include_usage 为什么有时拿不到总用量?

Chat Completions 开启 include_usage 后,会在 data: [DONE] 前发送一个额外 usage chunk;如果流在此前中断,官方说明这个最终用量块可能不会到达。因此应用还要保留服务端日志和 Usage Dashboard 对账。

浏览器可以直接连接 OpenAI Streaming API 吗?

生产站点不应把 API Key 放进浏览器。通常由自己的服务端持有 Key、调用 OpenAI,并把经过鉴权和过滤的流转发给前端,同时处理断线、限流和审计日志。

流式内容为什么更难做审核?

因为用户会在完整答案生成前看到部分文本。官方说明流式部分输出更难审核,而且生成请求附带的审核结果会在完整输出后到达,不会随每个 delta 一起返回。高风险场景应增加缓冲、策略检查或非流式审核。

先把成功、失败和中断三条路径跑通

不要只测试理想的文本 delta。真实上线前至少模拟连接中断、429、5xx、工具参数分片与最终 usage 缺失。

Streaming 不是实时语音会话

SSE 适合逐步显示文字;需要 WebRTC、VAD、语音打断和双向音频时,请查看 OpenAI Realtime API 教程。

音频流有专用事件

完整文件的 transcript delta/done 与麦克风 Realtime transcription 是两条不同路径;选型和完成判断见 OpenAI Audio API 教程。

图片流式事件不是文本 delta

Image API 与 Responses 可返回 partial image,但局部图有额外输出 Token,也不能当最终资产;事件与成本见 OpenAI Images API 教程。