OpenAI 后台模式

2026-11-06 18:37 更新

Codex和深度研究等智能体说明,推理模型可能需要数分钟处理复杂问题。后台模式允许GPT-5.2、GPT-5.2 Pro等模型异步执行长任务,减少长连接超时或断开对结果获取的影响。

设置background=true启动后台生成,随后轮询响应对象查看状态。

零数据保留(ZDR)项目的后台请求使用store=false,但仍会将响应数据临时写入磁盘约10分钟,支持异步执行和轮询。这不是完全不落盘的保证。

对使用修改后的滥用监控(MAM)及增强MAM的项目:前台请求在省略store或设为true时按标准保留;后台响应只有显式store=true才会在轮询期后继续保留。后台请求省略store或设为false,响应约10分钟后删除。

来源示例 1(bash):

## [中文] 异步生成关于太空水獭的长篇小说,background=true,先取得响应状态。
curl https://api.openai.com/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
  "model": "gpt-6-astra",
  "input": "Write a very long novel about otters in space.",
  "background": true
}'

来源示例 2(javascript):

// [中文] 异步生成关于太空水獭的长篇小说,background=true,先取得响应状态。
import OpenAI from "openai";
const client = new OpenAI();

const resp = await client.responses.create({
  model: "gpt-6-astra",
  input: "Write a very long novel about otters in space.",
  background: true,
});

console.log(resp.status);

来源示例 3(python):

## [中文] 异步生成关于太空水獭的长篇小说,background=true,先取得响应状态。
from openai import OpenAI

client = OpenAI()

resp = client.responses.create(
    model="gpt-6-astra",
    input="Write a very long novel about otters in space.",
    background=True,
)

print(resp.status)

来源示例 4(go):

// [中文] 异步生成关于太空水獭的长篇小说,background=true,先取得响应状态。
package main

import (
    "context"
    "fmt"

    "github.com/openai/openai-go/v3"
    "github.com/openai/openai-go/v3/responses"
)

func main() {
    client := openai.NewClient()

    response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
        Model:      "gpt-6-astra",
        Background: openai.Bool(true),
        Input: responses.ResponseNewParamsInputUnion{
            OfString: openai.String("Write a very long novel about otters in space."),
        },
    })
    if err != nil {
        panic(err)
    }

    fmt.Println(response.Status)
}

来源示例 5(java):

// [中文] 异步生成详细市场分析,background=true,先取得响应状态。
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.responses.ResponseCreateParams;

ResponseCreateParams params =
    ResponseCreateParams.builder()
        .model("gpt-6-astra")
        .input("Write a detailed market analysis.")
        .background(true)
        .build();

var response = client.responses().create(params);
System.out.println(response.status().orElseThrow());

来源示例 6(csharp):

// [中文] 异步生成关于太空水獭的长篇小说,background=true,先取得响应状态。
using OpenAI.Responses;
#pragma warning disable OPENAI001

string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
ResponsesClient client = new(key);

CreateResponseOptions options = new()
{
    Model = "gpt-6-astra",
    BackgroundModeEnabled = true,
};
options.InputItems.Add(
    ResponseItem.CreateUserMessageItem("Write a very long novel about otters in space.")
);

ResponseResult response = await client.CreateResponseAsync(options);
Console.WriteLine(response.Status);

来源示例 7(ruby):

## [中文] 异步生成详细市场分析,background=true,先取得响应状态。
require "openai"

client = OpenAI::Client.new
response = client.responses.create(
  model: "gpt-6-astra",
  input: "Write a detailed market analysis.",
  background: true
)

puts(response.status)

轮询后台响应

使用Responses的GET端点读取状态。处于queued或in_progress时继续轮询;离开这些状态后已进入终态,仍应查看是成功、失败还是其他终态。

来源示例 8(bash):

## [中文] 轮询queued或in_progress状态,离开等待态后还需检查最终状态。
curl https://api.openai.com/v1/responses/resp_123 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY"

来源示例 9(javascript):

// [中文] 轮询queued或in_progress状态,离开等待态后还需检查最终状态。
import OpenAI from "openai";
const client = new OpenAI();

let resp = await client.responses.create({
  model: "gpt-6-astra",
  input: "Write a very long novel about otters in space.",
  background: true,
});

while (resp.status === "queued" || resp.status === "in_progress") {
  console.log("Current status: " + resp.status);
  await new Promise((resolve) => setTimeout(resolve, 2000)); // wait 2 seconds
  resp = await client.responses.retrieve(resp.id);
}

console.log("Final status: " + resp.status + "\nOutput:\n" + resp.output_text);

来源示例 10(python):

## [中文] 轮询queued或in_progress状态,离开等待态后还需检查最终状态。
from openai import OpenAI
from time import sleep

client = OpenAI()

resp = client.responses.create(
    model="gpt-6-astra",
    input="Write a very long novel about otters in space.",
    background=True,
)

while resp.status in {"queued", "in_progress"}:
    print(f"Current status: {resp.status}")
    sleep(2)
    resp = client.responses.retrieve(resp.id)

print(f"Final status: {resp.status}\nOutput:\n{resp.output_text}")

来源示例 11(go):

// [中文] 轮询queued或in_progress状态,离开等待态后还需检查最终状态。
package main

import (
    "context"
    "fmt"
    "time"

    "github.com/openai/openai-go/v3"
    "github.com/openai/openai-go/v3/responses"
)

func main() {
    client := openai.NewClient()

    response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
        Model:      "gpt-6-astra",
        Background: openai.Bool(true),
        Input: responses.ResponseNewParamsInputUnion{
            OfString: openai.String("Write a very long novel about otters in space."),
        },
    })
    if err != nil {
        panic(err)
    }

    for response.Status == "queued" || response.Status == "in_progress" {
        fmt.Println("Current status:", response.Status)
        time.Sleep(2 * time.Second)
        response, err = client.Responses.Get(context.Background(), response.ID, responses.ResponseGetParams{})
        if err != nil {
            panic(err)
        }
    }

    fmt.Printf("Final status: %s\nOutput:\n%s\n", response.Status, response.OutputText())
}

来源示例 12(java):

// [中文] 轮询queued或in_progress状态,离开等待态后还需检查最终状态。
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseStatus;

ResponseCreateParams params =
    ResponseCreateParams.builder()
        .model("gpt-6-astra")
        .input("Write a very long novel about otters in space.")
        .background(true)
        .build();

var response = client.responses().create(params);
while (response.status().filter(ResponseStatus.QUEUED::equals).isPresent()
    || response.status().filter(ResponseStatus.IN_PROGRESS::equals).isPresent()) {
  System.out.println("Current status: " + response.status().orElseThrow());
  Thread.sleep(1000);
  response = client.responses().retrieve(response.id());
}
System.out.println("Final status: " + response.status().orElseThrow());
response.output().stream()
    .flatMap(item -> item.message().stream())
    .flatMap(message -> message.content().stream())
    .flatMap(content -> content.outputText().stream())
    .forEach(text -> System.out.println(text.text()));

来源示例 13(csharp):

// [中文] 轮询queued或in_progress状态,离开等待态后还需检查最终状态。
using OpenAI.Responses;
#pragma warning disable OPENAI001

string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
ResponsesClient client = new(key);

CreateResponseOptions options = new()
{
    Model = "gpt-6-astra",
    BackgroundModeEnabled = true,
};
options.InputItems.Add(
    ResponseItem.CreateUserMessageItem("Write a very long novel about otters in space.")
);

ResponseResult response = await client.CreateResponseAsync(options);
while (response.Status is ResponseStatus.Queued or ResponseStatus.InProgress)
{
    await Task.Delay(TimeSpan.FromSeconds(1));
    response = await client.GetResponseAsync(response.Id);
}
if (response.Status != ResponseStatus.Completed)
{
    throw new InvalidOperationException($"Background response ended with status: {response.Status}");
}
Console.WriteLine($"Status: {response.Status}");
Console.WriteLine(response.GetOutputText());

来源示例 14(ruby):

## [中文] 轮询queued或in_progress状态,离开等待态后还需检查最终状态。
require "openai"

client = OpenAI::Client.new
response = client.responses.create(
  model: "gpt-6-astra",
  input: "Write a very long novel about otters in space.",
  background: true
)

while [:queued, :in_progress].include?(response.status)
  puts("Current status: #{response.status}")
  sleep(2)
  response = client.responses.retrieve(response.id)
end

puts("Final status: #{response.status}")
puts("Output:")
puts(response.output_text)

取消后台响应

可取消正在执行的响应:

来源示例 15(bash):

## [中文] 按已有响应ID取消后台任务;重复取消幂等。
curl -X POST https://api.openai.com/v1/responses/resp_123/cancel \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY"

来源示例 16(javascript):

// [中文] 按已有响应ID取消后台任务;重复取消幂等。
import OpenAI from "openai";
const client = new OpenAI();

const resp = await client.responses.cancel("resp_123");

console.log(resp.status);

来源示例 17(python):

## [中文] 按已有响应ID取消后台任务;重复取消幂等。
import os

from openai import OpenAI

response_id = os.environ["OPENAI_RESPONSE_ID"]
client = OpenAI()

resp = client.responses.cancel(response_id)

print(resp.status)

来源示例 18(go):

// [中文] 按已有响应ID取消后台任务;重复取消幂等。
package main

import (
    "context"
    "fmt"

    "github.com/openai/openai-go/v3"
)

func main() {
    client := openai.NewClient()

    canceled, err := client.Responses.Cancel(context.Background(), "resp_123")
    if err != nil {
        panic(err)
    }

    fmt.Println(canceled.Status)
}

来源示例 19(java):

// [中文] 按已有响应ID取消后台任务;重复取消幂等。
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;

String responseId = "resp_123";

var response = client.responses().cancel(responseId);

System.out.println(response.status());

来源示例 20(csharp):

// [中文] 按已有响应ID取消后台任务;重复取消幂等。
using OpenAI.Responses;
#pragma warning disable OPENAI001

string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
ResponsesClient client = new(key);

// Replace this illustrative ID with the background response to cancel.
string responseId = "resp_123";

ResponseResult response = await client.CancelResponseAsync(responseId);
Console.WriteLine(response.Status);

来源示例 21(ruby):

## [中文] 按已有响应ID取消后台任务;重复取消幂等。
require "openai"

client = OpenAI::Client.new
response = client.responses.cancel("resp_123")
puts(response.status)

重复取消具有幂等性,后续调用返回最终Response对象。

流式读取后台响应

同时设置background=true和stream=true,可以立即读取事件,并在客户端断开后尝试续流。保存与事件sequence_number对应的游标。

当前来源说明后台请求的首词元延迟高于同步请求,并计划缩小差距,不应把这一计划当成已经实现的延迟保证。

来源示例 22(bash):

## [中文] 同时开启background与stream,读取事件并记录续流游标;示例任务为太空水獭长篇小说。 Python现也记录响应ID并过滤keepalive;Java示例设置请求超时并从已保存游标恢复一次,Ruby确保关闭流并保留续流提示。各语言恢复路径仍须分别验证。
curl https://api.openai.com/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
  "model": "gpt-6-astra",
  "input": "Write a very long novel about otters in space.",
  "background": true,
  "stream": true
}'

// To resume:
curl "https://api.openai.com/v1/responses/resp_123?stream=true&starting_after=42" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY"

来源示例 23(javascript):

// [中文] 同时开启background与stream,读取事件并记录续流游标;示例任务为太空水獭长篇小说。 当前JavaScript版排除keepalive游标,并从事件取得responseId,用retrieve续流。
import OpenAI from "openai";
const client = new OpenAI();

const stream = await client.responses.create({
  model: "gpt-6-astra",
  input: "Write a very long novel about otters in space.",
  background: true,
  stream: true,
});

let cursor = null;
let responseId = null;
for await (const event of stream) {
  console.log(event);
  // Keepalives use connection counters, not stored-event resume positions.
  if (String(event.type) !== "keepalive") cursor = event.sequence_number;
  if ("response" in event && event.response?.id) responseId = event.response.id;
}

// If the connection drops, resume streaming from the last stored-event cursor:
// const resumedStream = await client.responses.retrieve(responseId, {
//   stream: true,
//   starting_after: cursor,
// });
// for await (const event of resumedStream) { ... }

来源示例 24(python):

## [中文] 同时开启background与stream,读取事件并记录续流游标;示例任务为太空水獭长篇小说。 各语言的keepalive处理和恢复路径按当前示例分别说明。
from openai import OpenAI

client = OpenAI()

## Fire off an async response but also start streaming immediately
stream = client.responses.create(
    model="gpt-6-astra",
    input="Write a very long novel about otters in space.",
    background=True,
    stream=True,
)

cursor = None
response_id = None
for event in stream:
    print(event)
    if event.type == "response.created":
        response_id = event.response.id
    # Keepalives use connection counters, not stored-event resume positions.
    if event.type != "keepalive":
        cursor = event.sequence_number

    # If your connection drops, the response continues running and you can reconnect:
    # with client.responses.stream(response_id=response_id, starting_after=cursor) as resumed:
    #     for event in resumed:
    #         print(event)
    if event.type == "response.created":
        response_id = event.response.id

来源示例 25(go):

// [中文] 同时开启background与stream,读取事件并记录续流游标;示例任务为太空水獭长篇小说。 Python现也记录响应ID并过滤keepalive;Java示例设置请求超时并从已保存游标恢复一次,Ruby确保关闭流并保留续流提示。各语言恢复路径仍须分别验证。
package main

import (
    "context"
    "fmt"

    "github.com/openai/openai-go/v3"
    "github.com/openai/openai-go/v3/responses"
)

func main() {
    client := openai.NewClient()

    stream := client.Responses.NewStreaming(context.Background(), responses.ResponseNewParams{
        Model:      "gpt-6-astra",
        Background: openai.Bool(true),
        Input: responses.ResponseNewParamsInputUnion{
            OfString: openai.String("Write a very long novel about otters in space."),
        },
    })
    defer stream.Close()
    var cursor int64
    var responseID string
    for stream.Next() {
        event := stream.Current()
        fmt.Println(event.Type)
        // Keepalives use connection counters, not stored-event resume positions.
        if event.Type != "keepalive" {
            cursor = event.SequenceNumber
        }
        if event.Response.ID != "" {
            responseID = event.Response.ID
        }
    }
    if err := stream.Err(); err != nil {
        panic(err)
    }
    fmt.Printf("response %s last cursor %d\n", responseID, cursor)

    // If the connection drops, resume streaming from the last cursor:
    // resumed := client.Responses.GetStreaming(
    //  context.Background(),
    //  responseID,
    //  responses.ResponseGetParams{StartingAfter: openai.Int(cursor)},
    // )
    // for resumed.Next() {
    //  fmt.Println(resumed.Current().Type)
    // }
}

来源示例 26(java):

// [中文] 同时开启background与stream,读取事件并记录续流游标;示例任务为太空水獭长篇小说。 Python现也记录响应ID并过滤keepalive;Java示例设置请求超时并从已保存游标恢复一次,Ruby确保关闭流并保留续流提示。各语言恢复路径仍须分别验证。
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.RequestOptions;
import com.openai.core.http.StreamResponse;
import com.openai.errors.OpenAIIoException;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseRetrieveParams;
import com.openai.models.responses.ResponseStreamEvent;
import java.time.Duration;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;

ResponseCreateParams params =
    ResponseCreateParams.builder()
        .model("gpt-6-astra")
        .input("Write a very long novel about otters in space.")
        .background(true)
        .build();

AtomicLong lastSequenceNumber = new AtomicLong(-1);
AtomicReference<String> responseId = new AtomicReference<>("");
AtomicBoolean streamCompleted = new AtomicBoolean(false);
JsonMapper json = new JsonMapper();
// This long-running response can exceed the SDK's default request deadline.
RequestOptions streamOptions = RequestOptions.builder().timeout(Duration.ofMinutes(30)).build();
try (StreamResponse<ResponseStreamEvent> stream =
    client.responses().createStreaming(params, streamOptions)) {
  stream.stream()
      .forEach(
          event -> {
            if (event.failed().isPresent()
                || event.incomplete().isPresent()
                || event.error().isPresent()) {
              throw new IllegalStateException("Background response did not complete");
            }
            var data = json.valueToTree(event);
            // Keepalives count connection traffic, not stored response events.
            if (data.path("type").asText().startsWith("response.")
                && data.path("sequence_number").isIntegralNumber()) {
              lastSequenceNumber.set(data.path("sequence_number").asLong());
            }
            event
                .created()
                .ifPresent(
                    created -> {
                      responseId.set(created.response().id());
                      System.out.println("response.created");
                    });
            event
                .outputTextDelta()
                .ifPresent(
                    delta -> {
                      System.out.println("response.output_text.delta");
                    });
            event
                .completed()
                .ifPresent(
                    completed -> {
                      streamCompleted.set(true);
                      System.out.println("response.completed");
                    });
          });
} catch (OpenAIIoException error) {
  // Resume an interrupted stream once, from its stored-event checkpoint.
  if (Thread.currentThread().isInterrupted()
      || streamCompleted.get()
      || responseId.get().isBlank()
      || lastSequenceNumber.get() < 0) {
    throw error;
  }
}
System.out.println(
    "Response " + responseId.get() + "; last sequence number " + lastSequenceNumber.get());
if (!streamCompleted.get()) {
  if (Thread.currentThread().isInterrupted()
      || responseId.get().isBlank()
      || lastSequenceNumber.get() < 0) {
    throw new IllegalStateException("Stream ended without a resumable checkpoint");
  }
  try (StreamResponse<ResponseStreamEvent> resumed =
      client
          .responses()
          .retrieveStreaming(
              ResponseRetrieveParams.builder()
                  .responseId(responseId.get())
                  .startingAfter(lastSequenceNumber.get())
                  .build(),
              streamOptions)) {
    resumed.stream()
        .forEach(
            event -> {
              if (event.failed().isPresent()
                  || event.incomplete().isPresent()
                  || event.error().isPresent()) {
                throw new IllegalStateException("Resumed response did not complete");
              }
              event.outputTextDelta().ifPresent(delta -> System.out.println(delta.delta()));
              event.completed().ifPresent(completed -> streamCompleted.set(true));
            });
  }
  if (!streamCompleted.get()) {
    throw new IllegalStateException("Resumed response did not complete");
  }
}

来源示例 27(csharp):

// [中文] 同时开启background与stream,读取事件并记录续流游标;示例任务为太空水獭长篇小说。 Python现也记录响应ID并过滤keepalive;Java示例设置请求超时并从已保存游标恢复一次,Ruby确保关闭流并保留续流提示。各语言恢复路径仍须分别验证。
using OpenAI.Responses;
#pragma warning disable OPENAI001

string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
ResponsesClient client = new(key);

CreateResponseOptions options = new()
{
    Model = "gpt-6-astra",
    BackgroundModeEnabled = true,
    StreamingEnabled = true,
};
options.InputItems.Add(
    ResponseItem.CreateUserMessageItem("Write a very long novel about otters in space.")
);

string? responseId = null;
int lastSequenceNumber = -1;
bool completed = false;

void HandleUpdate(StreamingResponseUpdate update)
{
    lastSequenceNumber = update.SequenceNumber;
    switch (update)
    {
        case StreamingResponseCreatedUpdate created:
            responseId = created.Response.Id;
            break;
        case StreamingResponseOutputTextDeltaUpdate text:
            Console.Write(text.Delta);
            break;
        case StreamingResponseCompletedUpdate:
            completed = true;
            break;
        case StreamingResponseFailedUpdate:
            throw new InvalidOperationException("The background response failed.");
        case StreamingResponseIncompleteUpdate:
            throw new InvalidOperationException("The background response was incomplete.");
        case StreamingResponseErrorUpdate error:
            throw new InvalidOperationException($"The response stream failed: {error.Message}");
    }
}

try
{
    await foreach (
        StreamingResponseUpdate update in client.CreateResponseStreamingAsync(options)
    )
    {
        HandleUpdate(update);
    }
}
catch (Exception error)
    when (error is HttpRequestException or IOException && responseId is not null)
{
    // The background response continues after its streaming connection is interrupted.
}

if (!completed)
{
    if (responseId is null)
    {
        throw new InvalidOperationException("The response stream ended before providing its ID.");
    }

    GetResponseOptions resumeOptions = new(responseId)
    {
        StartingAfter = lastSequenceNumber,
        StreamingEnabled = true,
    };
    await foreach (StreamingResponseUpdate update in client.GetResponseStreamingAsync(resumeOptions))
    {
        HandleUpdate(update);
    }

    if (!completed)
    {
        throw new InvalidOperationException(
            "The resumed response stream ended before the background response completed."
        );
    }
}

来源示例 28(ruby):

## [中文] 同时开启background与stream,读取事件并记录续流游标;示例任务为太空水獭长篇小说。 各语言的keepalive处理和恢复路径按当前示例分别说明。
require "openai"

## An uncapped background novel can run beyond the SDK's default ten minutes.
client = OpenAI::Client.new(timeout: 30 * 60)
stream = client.responses.stream(
  model: "gpt-6-astra",
  input: "Write a very long novel about otters in space.",
  background: true
)

last_sequence_number = -1
response_id = ""
begin
  stream.each do |event|
    puts(event.type)
    # The SDK filters transport keepalives before yielding stored events.
    last_sequence_number = event.sequence_number || last_sequence_number
    if event.is_a?(OpenAI::Models::Responses::ResponseCreatedEvent)
      response_id = event.response.id
    end
  end
ensure
  stream.close
end

puts("response #{response_id} last cursor #{last_sequence_number}")

## If the connection drops, resume from the last sequence number:
## client.responses.stream(response_id: response_id, starting_after: last_sequence_number).each do |event|
##   puts(event.type)
## end

2026-10-27的JavaScript示例已更新续流处理:keepalive使用连接计数,不是持久化事件的恢复位置,因此不据其更新游标;从携带响应的事件保存响应ID,之后用responses.retrieve配合stream:true与starting_after续流。

限制

  1. 后台请求可用store=false,但仍会临时保存响应以支持异步执行和轮询。
  2. 取消同步响应应终止连接。
  3. 只有创建时设置stream=true的后台响应,才能再启动新的读取流。
以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号