登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  科技周边 >  人工智能

OpenAI Responses API 怎样让长任务异步运行

来源:17golang原创

时间:2026-10-26 22:03:29 327浏览 收藏

我在接入长耗时 Responses 请求时,最先遇到的不是模型参数,而是连接应该一直等着,还是先把任务交出去。对于可能运行数分钟的任务,Responses API 提供了 background=true:请求先返回一个 Response 对象,客户端保存 response_id,之后再查询状态和结果。这样,业务接口不必把一次 HTTP 连接维持到模型完成。

官方文档:https://developers.openai.com/api/docs/guides/background

核心判断是:长任务用 background 模式异步提交;拿到 response ID 后轮询,只有离开 queued 或 in_progress 等处理中状态,才按终态读取结果。

先判断是否真的需要后台响应

普通的短请求仍然适合同步调用。background 模式更适合耗时不可预测、调用方可能超时,或者需要让前端显示“处理中”的任务。它解决的是连接生命周期,不会自动替你设计任务表、重试策略或业务幂等键。

我通常把它和业务记录绑定起来:提交成功后立刻保存 response_id,同时记录自己的任务状态。这样即使 Web 请求结束,后台 worker 或定时任务仍能根据这个 ID 查询进度。

提交 background 请求并保存 response_id

创建请求时把 background 设为 true。下面用 Python SDK 展示最小骨架;密钥只从环境变量读取,示例不把密钥写进代码。

import os
from openai import OpenAI

# 只从环境变量读取密钥,避免把凭据写入源码或日志。
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])

# background=True 让长任务异步运行,调用先得到 response 对象。
response = client.responses.create(
    model="gpt-6-astra",
    input="整理这份长文档的章节要点,并给出结构化摘要。",
    background=True,
)

# response.id 是后续查询、取消和业务任务关联所需的标识。
print({"response_id": response.id, "status": response.status})

生产代码应把 response.id 和业务任务一起持久化,而不是只打印后丢弃。第一次返回的状态可能已经变化,也可能仍处于排队或处理中,不能依据一次响应就假设任务完成。

客户端、Responses API、background 标识与响应状态之间的静态关系图
图1:静态结构图展示客户端请求、background 模式、Response ID、状态字段和终态结果之间的关系,不是运行截图。

轮询时只把处理中状态当作等待

官方示例把 queued 和 in_progress 视为仍在运行的状态。客户端可以使用 SDK 的 retrieve 方法查询同一个响应;离开这两个状态后,再根据最终状态决定读取、重试或提示失败。

import time

def wait_for_response(client, response_id, interval=2, max_polls=60):
    """轮询后台响应;超出次数时交给上层处理,避免无限等待。"""
    for _ in range(max_polls):
        # retrieve 查询同一个 response_id,不重新创建模型请求。
        current = client.responses.retrieve(response_id)
        if current.status not in {"queued", "in_progress"}:
            return current

        # 轮询间隔应可配置,避免高频查询放大请求量。
        time.sleep(interval)

    raise TimeoutError("后台响应在轮询窗口内没有进入终态")


final_response = wait_for_response(client, response.id)
if final_response.status == "completed":
    # 只有 completed 才把 output_text 当成业务结果保存。
    print(final_response.output_text)
else:
    # 其它终态交给业务层记录,不能伪装成成功结果。
    print("response ended with status:", final_response.status)

这个骨架故意设置了最大轮询次数。到达上限不代表模型失败,只代表当前 worker 的等待窗口结束;业务层可以把任务留在“待继续查询”状态,稍后再恢复。

完成、失败和取消要分开处理

当响应进入 completed,才读取并保存输出内容。若进入其它终态,应该记录原始状态和响应 ID,便于后续排查。取消是另一种主动终止方式,不能用普通 retrieve 查询代替。

# 用已经保存的响应 ID 取消一个仍在运行的后台任务。
# 这里的 ID 应来自业务数据库或安全的任务上下文,而不是用户任意输入。
curl -X POST "https://api.openai.com/v1/responses/resp_123/cancel" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY"

取消动作适合用户主动停止、任务超过业务截止时间,或上游输入已经失效的场景。取消后仍应以 API 返回的最终状态为准,并把业务任务从“运行中”迁移到可解释的终止状态。

background、stream 和同步连接怎么选

这三种方式解决的问题不同。同步调用适合结果很快就能返回的交互;background 适合先提交、后查询;background 加 stream=true 则适合希望边运行边接收事件,同时保留断线后恢复机会的场景。

方式适合场景需要保存的东西主要代价
同步短请求、调用方能持续等待请求上下文连接超时会影响体验
background长任务、异步任务中心response_id、业务状态需要轮询与终态处理
background + stream需要事件流、允许断线恢复response_id、sequence_number要管理游标和重连逻辑
长任务的 background、轮询、stream 恢复和取消关系静态图
图2:静态关系图比较 background、轮询、stream 恢复和取消接口的职责,不表达真实执行顺序。

断线恢复与数据保留要提前设计

如果创建 background 响应时同时启用 stream,客户端可以记录事件中的 sequence_number,连接断开后按游标继续获取事件。这个设计适合事件本身就是业务进度的情况;如果业务只关心最终答案,简单轮询通常更容易维护。

还要注意 store 的取舍。官方文档说明,background 请求需要暂时保存响应数据以支持异步轮询;是否长期保留则与 store 和项目的数据控制策略有关。对敏感数据,不要把“能轮询”误解成“可以永久取回”,应把保留周期、业务副本和删除策略一起设计。

我会采用的最小落地清单

  • 提交成功后马上保存 response_id,并写入业务任务表。
  • 只把 queued、in_progress 当作处理中,其他状态统一进入终态分支。
  • 轮询间隔和最大次数配置化,避免 worker 无限占用。
  • 用户取消走 cancel 接口,超时不等于自动重发。
  • 需要断线续接才启用 stream,并持久化 sequence_number。
  • 按数据敏感度选择 store,同时维护业务侧的结果生命周期。

常见问题

background=true 会让模型更快吗?

它主要改变调用方式和连接生命周期,不是性能加速开关。任务仍然要等待模型完成,只是客户端可以先结束当前连接。

轮询拿到 queued 时要重新创建请求吗?

不要重新创建。继续使用原来的 response_id 查询,否则可能产生重复任务。

什么时候值得使用 stream?

当中间事件本身有展示或编排价值,并且团队愿意维护游标、断线和重复事件处理时再使用;只取最终结果时,轮询更直观。

小结

让 OpenAI Responses API 长任务异步运行的关键不是把同步代码包一层线程,而是使用 background=true 建立可查询的响应任务:保存 response_id,轮询处理中状态,按终态读取或结束,再根据是否需要事件流选择 stream。把取消、恢复和数据保留一起纳入设计,后台任务才不会从“连接超时”变成“状态丢失”。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>