首页使用帮助API Streaming
HELP / RESPONSES BACKGROUND

OpenAI Background Mode 怎么用?

在 Responses API 请求中设置 background: true,长任务会脱离当前客户端连接继续执行。应用必须保存 response ID,轮询 queued / in_progress,或通过 Webhook 接收终态;需要边看边恢复时,再同时开启 stream: true 并保存事件游标。

主关键词:OpenAI Background Mode 怎么用background true轮询与取消更新:2026-10-30
先给结论

Background Mode 解决的是“任务很长,但 HTTP 请求、浏览器标签或 Serverless Function 不应一直占着连接”。创建后立即持久化 response ID;运行中只识别 queued 与 in_progress,离开这两个状态就停止轮询,再分别处理 completed、failed、cancelled 和 incomplete。它不会自动让模型更便宜、更快,也不能替代 Batch、SSE 或 WebSocket。

官方资料(2026-10-30 核对):Background mode · Retrieve response · Webhooks · Cancel response

Background Mode、同步、SSE、WebSocket 与 Batch 怎么选?

方案核心问题结果获取适合场景
同步 Responses一次请求内完成连接结束时拿完整对象短任务、后端可稳定等待
普通 SSE降低首 Token 等待同一 HTTP 连接接收事件聊天 UI、长文本逐步展示
Background Mode长任务脱离原连接继续按 response ID 轮询、Webhook 或恢复流深度推理、复杂长任务、易超时环境
Responses WebSocket多回合 Agent 复用持久连接重复 response.create 与 stream_id lane工具调用多、并发会话、低回合开销
Batch API大量离线请求集中处理批次状态与结果文件评测、分类、嵌入、批量摘要

如果只想显示实时增量,先看 API Streaming 教程;多工具长链路需要持久连接,参见 Responses WebSocket;成千上万条不要求即时返回的任务,参见 Batch API。

第一步:创建后台 Response 并立即保存 ID

在服务端调用 Responses create,设置 background: true。模型名用账户当前可用模型替换,不能把示例模型当成所有 Project 永久可用。

import OpenAI from "openai";

const client = new OpenAI();

const response = await client.responses.create({
  model: "YOUR_MODEL",
  input: "生成一份需要较长推理时间的风险分析。",
  background: true
});

// 立即持久化,不能只放在浏览器内存
await db.jobs.insert({
  userId,
  responseId: response.id,
  status: response.status,
  createdAt: new Date()
});

return {
  jobId: response.id,
  status: response.status
};

标准 API Key 只放在受信任服务端。前端可以拿你自己的 job ID 或经过授权的 response ID 查询应用后端,但不应直接获得 OpenAI Key。生产服务还要将 response ID 与当前用户、Project、请求摘要、取消权限和创建时间绑定,避免越权读取其他人的结果。

第二步:只在 queued 或 in_progress 时继续轮询

Responses retrieve 使用 GET /v1/responses/{response_id}。官方要求在 queued 或 in_progress 时继续查询;状态离开这两个值后就是终态,应停止轮询。

const RUNNING = new Set(["queued", "in_progress"]);

let current = await client.responses.retrieve(responseId);

while (RUNNING.has(current.status)) {
  await sleep(nextDelay()); // 应用自己的退避与最大等待时间
  current = await client.responses.retrieve(responseId);
}

switch (current.status) {
  case "completed":
    await saveCompleted(current.output_text, current.usage);
    break;
  case "failed":
  case "cancelled":
  case "incomplete":
    await saveTerminalFailure(current);
    break;
  default:
    await saveUnknownTerminalState(current);
}

API Reference 当前列出的状态包括 completed、failed、in_progress、cancelled、queued 和 incomplete。不要写成“不是 in_progress 就成功”,也不要在多个 Vercel 实例中同时高频轮询同一个 response ID。

轮询间隔、超时和幂等怎样设计?

  1. 立即保存 ID:创建成功后先落库,再向浏览器返回;否则客户端刷新就可能丢失任务。
  2. 退避而非固定轰炸:官方示例的短间隔用于演示,不是生产 SLA。加入随机抖动、最大间隔和最大等待窗口。
  3. 单任务单调状态:用数据库锁、租约或队列避免多个实例重复查询与重复写结果。
  4. 终态幂等:以 response ID 为唯一键,completed Webhook 与轮询同时到达也只能完成一次。
  5. 区分 API 超时与任务失败:一次 retrieve 网络错误不等于后台任务失败;按 500/503 与连接错误规则有限重试。
  6. 保留审计字段:记录状态时间线、Request ID、用户、Project 和脱敏错误,不保存 API Key。

第三步:允许用户取消后台响应

后台任务仍在运行时,可调用 POST /v1/responses/{response_id}/cancel:

const cancelled = await client.responses.cancel(responseId);

await db.jobs.update(responseId, {
  status: cancelled.status,
  cancelledAt: new Date()
});

官方说明只有用 background: true 创建的 Response 才能调用该取消接口;重复取消是幂等的,会返回最终 Response 对象。应用仍需先验证当前用户是否拥有该任务,避免任意 response ID 被他人取消。取消请求返回后,也应按返回的真实终态更新 UI,不能仅凭“按钮点击成功”假设模型已经停止。

不想轮询:用 Webhook 接收终态

可在 OpenAI Dashboard 配置 Webhook,订阅 response.completed、response.failed、response.cancelled 和 response.incomplete。Webhook 的 data 只给出 response ID 时,再由受信任后端 retrieve 详情。

  1. 读取原始请求体并验证 Webhook 签名,不信任未验签 JSON。
  2. 用 webhook-id 去重;官方提醒少数情况下可能重复投递。
  3. 迅速返回 2xx,把 retrieve、数据库更新和通知放到后台队列。
  4. 不要依赖 3xx 跳转;官方不会跟随 Webhook 3xx。
  5. 处理轮询和 Webhook 竞态,以 response ID + 终态做幂等更新。

官方当前说明,未能及时返回成功 2xx 时会用指数退避重试,最长可持续 72 小时。因此“Webhook 收到两次”并不等于任务执行两次,但你的业务写入必须去重。

Background + Streaming:断线后从游标恢复

创建时同时设置 background: true 与 stream: true,既能立即消费事件,又允许原连接中断后重新拉取。保存 Response ID,并记录每个非 keepalive 存储事件的 sequence_number:

const stream = await client.responses.create({
  model: "YOUR_MODEL",
  input: "生成一份长报告。",
  background: true,
  stream: true
});

let responseId = null;
let cursor = null;

for await (const event of stream) {
  if (event.type !== "keepalive") {
    cursor = event.sequence_number;
  }
  if ("response" in event && event.response?.id) {
    responseId = event.response.id;
  }
  await persistCursor({ responseId, cursor });
}

// 连接中断后,从最后一个已持久化事件之后恢复
const resumed = await client.responses.retrieve(responseId, {
  stream: true,
  starting_after: cursor
});

for await (const event of resumed) {
  // 继续按 event.type 消费,并更新 cursor
}

官方限制是:只有创建时已经设置 stream: true 的后台响应,才能启动新的恢复流。starting_after 使用的是已存储事件的 sequence number;keepalive 的连接计数不是恢复游标。官方还提示 Background Streaming 当前首 Token 时间可能高于同步流,因此它的主要目标是可恢复性,不应宣传成首屏加速。

数据保留与 ZDR:必须单独做合规评审

OpenAI 当前文档说明,ZDR Project 的后台请求以 store=false 运行,但为了异步执行和轮询,响应数据仍会临时存储到磁盘约 10 分钟。对 Modified Abuse Monitoring Project,只有显式 store=true 才会在轮询窗口后保留后台响应;省略 store 或设置 false,文档说明约 10 分钟后删除。

不要把“store=false”简单写成“绝不落盘”

Background Mode 的异步执行存在官方说明的短暂磁盘存储例外。金融、医疗、法律或企业敏感数据应用,应让数据治理负责人核对合同、Project 控制和最新文档后再启用。

Background Mode 与 Batch API 的查重边界

问题Background ModeBatch API
任务单位单个 ResponseJSONL 中的大量请求
开始方式Responses create + background:true上传文件并创建 Batch
完成通知轮询或 response.* Webhook批次状态、Webhook 或结果文件
取消按 response ID cancel按 batch ID 取消
适合交互可做用户发起的长任务更偏离线批处理
成本/限额不要假设 background 自动折扣按 Batch 官方价格与独立限额核对

常见错误与排查

现象常见原因处理
前端刷新后任务丢失response ID 只保存在组件状态创建后服务端落库,并关联用户与 Project
轮询永不停止只判断 completed,忽略 failed/cancelled/incompletequeued/in_progress 才继续,其他状态进入终态分支
大量 429多实例固定高频轮询加退避、抖动、租约与集中队列
恢复流重复文本未持久化 sequence_number 或把 keepalive 当游标按非 keepalive 存储事件更新 cursor,从 starting_after 续接
取消接口报错原响应不是 background:true 或权限不匹配确认创建参数、response ID 与 Project/用户所有权
Webhook 重复写数据库重复投递或轮询竞态webhook-id 去重,response ID 终态幂等更新

上线前检查清单

  • 确认任务确实需要脱离请求连接,不把普通短回答全部改成 Background。
  • 创建成功后先持久化 response ID、用户、Project 和初始状态。
  • 只在 queued/in_progress 时轮询,所有终态都有独立 UI 与日志。
  • 轮询具有退避、抖动、最大等待时间和多实例去重。
  • 取消操作先鉴权,重复取消与重复终态写入均幂等。
  • Webhook 验签、webhook-id 去重并快速返回 2xx。
  • Background Streaming 保存非 keepalive sequence_number,并测试断线恢复。
  • 合规团队已阅读 ZDR/store=false 的约 10 分钟临时磁盘存储说明。
  • 用 Usage 与成本记录验证实际消耗,不把 Background 宣传成自动降价。
把 Webhook 接收器作为独立可靠性边界

Background Mode 只负责让单个 Response 脱离原连接继续执行;端点配置、原始请求体验签、webhook-id 去重、快速 2xx 与重试处理请按 OpenAI Webhooks 验签与去重指南实现。

常见问题

OpenAI Background Mode 适合什么任务?

它适合单个 Responses API 请求可能持续较长时间、客户端连接容易超时或用户不必一直等待的任务。普通短回答继续使用同步请求;只需边生成边显示可用普通 SSE;大批量离线请求应单独评估 Batch API。

background true 后怎样知道任务完成?

保存创建请求返回的 response ID,使用 Responses retrieve 接口查询。只在状态为 queued 或 in_progress 时继续轮询;进入 completed、failed、cancelled 或 incomplete 等终态后停止,并按具体状态处理,不能把所有非运行状态都当成功。

Background Mode 可以取消吗?

可以通过 POST /v1/responses/{response_id}/cancel 或 SDK cancel 方法取消仍在执行的后台响应。官方说明只有使用 background:true 创建的响应才能调用取消;重复取消是幂等的,会返回最终 Response 对象。

Background Mode 能和 Streaming 一起用吗?

可以在创建时同时设置 background:true 与 stream:true。记录非 keepalive 事件的 sequence_number;连接中断后,用同一个 response ID、stream:true 和 starting_after 从已存储事件游标之后恢复。只有最初以 stream:true 创建的后台响应才能启动新的恢复流。

Background Mode 和 Batch API 有什么区别?

Background Mode 面向单个长时间 Responses 任务,按 response ID 轮询、取消或接收 Webhook;Batch API 面向大量离线请求,通过 JSONL 批次提交并在完成窗口内处理。两者的限额、成本和结果获取方式不同,不能互相替代。

Background Mode 是否兼容 Zero Data Retention?

官方当前说明,ZDR Project 的后台请求使用 store=false,但为了异步执行和轮询,响应数据仍会临时写入磁盘约 10 分钟。对数据驻留有严格要求的应用,应在启用前让合规和安全负责人核对这一例外。

应该一直每两秒轮询吗?

官方示例用短间隔演示,但生产系统不应把示例间隔当固定规则。应设置退避、最大等待时间和状态持久化,或使用 response.completed、failed、cancelled、incomplete Webhook;Webhook 也要验签、快速返回 2xx,并按 webhook-id 去重。

先把任务 ID、终态和恢复游标持久化

Background Mode 的可靠性来自状态管理,不是一个参数本身。上线前模拟浏览器刷新、网络断开、Webhook 重复和取消竞态。