首页使用帮助Responses Compaction
HELP / RESPONSES COMPACTION

OpenAI Responses Compaction 怎么用?

长会话不要等到超出上下文窗口才处理。Responses API 可以在正常生成中用 context_management 自动压缩,也可以调用独立 /responses/compact 显式生成下一轮的规范输入窗口;两种模式的续接方式不同,不能混用 response ID 与 compact output。

主关键词:OpenAI Responses Compaction 怎么用compact_threshold/responses/compact更新:2026-10-30
先给结论

想让 Responses 在正常生成时自动压缩,用服务端 compaction;想由应用明确控制压缩时机,用独立 compact 接口。服务端模式仍沿用原来的 input-array 或 previous_response_id 链;独立接口返回的是新的 compacted input window,不是可继续传的 response ID。无论哪种模式,都要把加密 compaction item 当作不可解析的状态载体。

官方资料(2026-10-30 核对):Compaction guide · Compact response API · Conversation state · WebSocket mode

先判断:Compaction 和哪些功能不是一回事?

机制解决的问题下一轮怎样继续不要误解为
服务端 Compaction正常 Responses 生成中自动压缩增长的上下文继续 input-array,或传最新 previous_response_id独立后台任务
独立 /responses/compact应用显式把完整窗口压缩成新的规范窗口把 compact output 原样作为新 input,开启新链返回新的 previous_response_id
previous_response_id让服务端关联上一条 Response 状态传新输入与最新 response ID自动减少历史计费或自动压缩
Background Mode单个长任务脱离原 HTTP 连接继续执行retrieve、Webhook 或恢复流上下文压缩
Streaming / WebSocket逐步接收事件或复用持久连接按各自事件与状态规则继续替代上下文管理

如果问题是“任务运行时间太长”,先看 Background Mode;如果问题是“每轮上下文越来越大”,才进入 Compaction。端点和状态基础可先读 Responses 与 Chat Completions 区别。

方案一:在 Responses create 中启用服务端 Compaction

在正常 responses.create 请求里加入 context_management。当渲染后的 Token 数跨过所设阈值,服务端在同一次生成流程中触发压缩,并在输出中带回加密 compaction item;不需要额外调用 /responses/compact。

import OpenAI from "openai";
import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";

const client = new OpenAI();
let input = [{
  type: "message",
  role: "user",
  content: "开始一个长期代码审查任务。"
}];

async function runTurn() {
  const response = await client.responses.create({
    model: "YOUR_MODEL",
    input,
    store: false,
    context_management: [{
      type: "compaction",
      compact_threshold: YOUR_EVALUATED_THRESHOLD
    }]
  });

  // 输出中的 compaction item 也必须保留
  input.push(...toResponseInputItems(response.output));
  return response;
}

compact_threshold 不是“越接近模型上限越好”的固定常数。请求里还可能包含工具定义、系统指令、本轮输入和模型输出预留;阈值要来自所用模型的真实上下文预算和应用评测。官方示例数值只是示例,不能直接当作所有模型或业务的推荐值。

服务端模式有两种续接方式,不要混成第三种

方式 A:无状态 input-array 链

应用自己持有 Items,每轮把上一轮输出转换为下一轮输入。服务端 compaction 触发后,最新 compaction item 会出现在输出里。官方说明,在已经把输出追加到历史数组后,可以删除“最新 compaction item 之前”的 Items,以减少请求体积和长尾延迟;最新 compaction item 及其后的 Items 必须保留。

input.push(...toResponseInputItems(response.output));

const latest = findLatestCompactionIndex(input);
if (latest >= 0) {
  input = input.slice(latest);
}

input.push({
  type: "message",
  role: "user",
  content: "继续下一步并运行测试。"
});

删除动作只能发生在你明确找到最新 compaction item 后。不要靠字符数、消息条数或猜测位置删除,因为工具调用、reasoning item 与工具结果之间可能存在关联。

方式 B:previous_response_id 链

如果使用服务端状态链接,每轮只提交新的用户或工具 Items,并传最新 previous_response_id。官方明确提醒:这种模式不要再手动裁剪服务端链路。

const first = await client.responses.create({
  model: "YOUR_MODEL",
  input: "开始长期任务。",
  store: true,
  context_management: [{
    type: "compaction",
    compact_threshold: YOUR_EVALUATED_THRESHOLD
  }]
});

const next = await client.responses.create({
  model: "YOUR_MODEL",
  previous_response_id: first.id,
  input: "继续下一步。",
  context_management: [{
    type: "compaction",
    compact_threshold: YOUR_EVALUATED_THRESHOLD
  }]
});

是否使用 store:true、能保存多久以及数据控制,应按 Project 和最新官方政策核对。本页只说明状态续接形状,不把存储设置当作合规结论。

方案二:显式调用 /responses/compact

独立 compact 接口适合应用自己持有完整上下文、需要在明确检查点压缩的场景。发送的输入窗口本身仍必须能放进所选模型的上下文窗口;已经超出窗口之后再调用并不能补救。

import OpenAI from "openai";
import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";

const client = new OpenAI();

const compacted = await client.responses.compact({
  model: "YOUR_MODEL",
  input: longInputItems
});

// compacted.output 是下一轮规范输入窗口
const nextInput = toResponseInputItems(compacted.output);
nextInput.push({
  type: "message",
  role: "user",
  content: "基于已压缩状态继续任务。"
});

const response = await client.responses.create({
  model: "YOUR_MODEL",
  input: nextInput,
  store: false
});
三个不能做的动作

不要把 compacted response 的 id 当作 previous_response_id;不要只保留加密 compaction item 而丢弃接口返回的其他 Items;不要对 compacted.output 再自行裁剪。官方把整个返回窗口定义为下一轮的规范输入,应原样延续。

与 Responses WebSocket 一起使用时怎样继续?

服务端 compaction 和独立 compact 的 WebSocket 续接方式不同:

  1. 服务端模式:在 WebSocket 的 response.create 中配置 context_management 后,仍在同一 lane 传最新 previous_response_id 与本轮新 Items。
  2. 独立 compact:先通过 HTTP 调用 /responses/compact;然后在 WebSocket 发送新的 response.create,把 compact output 加最新用户/工具 Items 作为 input。
  3. 开启新链:独立 compact 后省略 previous_response_id 或设为 null,因为 compact endpoint 返回的是输入窗口,不是上一条 Response。

完整的连接、lane、并发和断线边界见 Responses WebSocket 教程。Compaction 不能让已断开的连接自动恢复,也不能替代应用对工具副作用的幂等控制。

compact_threshold 怎样设计才不会过早或过晚?

  1. 先算硬预算:获取所用模型的当前上下文上限,再预留系统指令、工具 Schema、本轮输入和最大输出空间。
  2. 按真实渲染 Token 评测:不要只看字符数。图片、工具定义、reasoning、缓存和多语言文本都会影响实际 Token。
  3. 设置安全余量:阈值应低于可能触发 context overflow 的点,但过低会增加不必要的压缩频率。
  4. 保留任务检查点:长代码任务或 Agent 应把关键文件版本、工具结果 ID 和业务状态存进自己的数据库;不要把唯一事实只交给模型上下文。
  5. 分任务类型测试:长对话、代码修改、检索、工具链的最佳阈值可能不同,不要共用一个未经验证的全局常数。

如果需要在请求前更精确估算输入,可结合官方 token counting 能力;上线后再用 API Usage 对账真实输入输出,而不是凭页面字符长度推断费用。

质量、成本和延迟应该怎样验证?

Compaction 的目标是控制不断增长的上下文,但“压缩后一定更省钱、更快、质量不变”都不是可直接承诺的结论。建议用同一批长任务做 A/B:

指标记录内容失败信号
上下文每轮 input/output Token、压缩触发轮次、请求体积触发前已接近溢出,或压缩过于频繁
质量任务成功率、事实保持、工具参数、测试通过率忘记约束、重复工具、遗漏关键状态
延迟首事件、总时长、P50/P95、压缩轮次长尾P95 上升或用户等待显著增加
成本总输入、输出、缓存与压缩相关实际账单Token 降低但重试或错误成本上升
可靠性4xx/5xx、链路恢复、幂等冲突错误后丢上下文或重复副作用

工具调用、Reasoning 和业务状态要特别注意什么?

  • 工具调用闭环:工具请求、call_id 和 function_call_output 必须保持关联;不要在自定义裁剪时拆开。工具实现见 Function Calling 教程。
  • 不要解密或摘要 compaction item:它是服务端生成的加密状态对象,不是用户可见摘要,也不应进入日志分析正文。
  • 业务事实外置:订单状态、文件版本、权限、已执行副作用等必须保存在应用数据库,Compaction 不是事务日志。
  • 失败后不要盲目重放:先区分请求是否已被处理,再按幂等键和 5xx/超时规则重试。
  • 可观测性脱敏:记录 response ID、Request ID、触发轮次、Token 和错误码;不要记录 API Key 或敏感原文。

ZDR、store=false 与安全边界

OpenAI 当前资料说明,独立 /responses/compact 是无状态且 ZDR-friendly;服务端 compaction 在 Responses 请求设置 store:false 时也可用于 ZDR 场景。加密 compaction item 仍要按敏感状态对象保护:只在受信任服务端传输和保存,限制访问,设置应用自己的保留周期,并在日志中脱敏。

“ZDR-friendly”不等于任何组织、模型、工具和外部数据源自动满足你的监管义务。启用前核对最新官方数据控制、Project 设置、合同和第三方工具的数据流。

常见错误与排查

现象常见原因处理
仍然出现 context overflow阈值过高、工具 Schema 或本轮输出预留不足重新计算完整预算,并在压缩前预留安全余量
独立 compact 后 previous_response_not_found把 compacted response ID 当作 previous_response_id改用 compacted.output 作为新 input,并开启新链
压缩后工具状态缺失自行删掉了返回窗口中的保留 Items独立 compact output 原样传递;检查工具状态是否另有持久化
服务端链路重复历史previous_response_id 模式又手动重放旧 Items只传新一轮 Items 与最新 response ID
费用没有明显下降压缩太频繁、任务太短或重试增加查看真实 Usage,按任务类型调整而非承诺固定比例
4xx/5xx 后链路不确定重试逻辑没有区分已处理与未处理记录 Request ID、response ID 与幂等键,有限重试并保留检查点

上线前检查清单

  • 确认问题确实是上下文增长,而不是 Background、Streaming 或 WebSocket 连接问题。
  • 选择服务端自动压缩或独立 compact,并只实现对应的续接模式。
  • 阈值来自当前模型上下文预算与真实任务评测,不复制示例常数。
  • input-array、previous_response_id 与 standalone 新链的代码路径分别测试。
  • 独立 compact output 原样保存和传递,不提取、解析或裁剪 compaction item。
  • 工具副作用、权限、文件版本和关键业务事实已经外置持久化。
  • 记录触发轮次、Token、P50/P95、质量、重试、错误率和实际成本。
  • 模拟 context overflow、4xx、5xx、断线、重复请求和工具超时。
  • ZDR、store=false、日志与数据保留经过安全和合规评审。

常见问题

OpenAI Responses Compaction 解决什么问题?

它用于长时间、多回合的 Responses API 工作流,在上下文逐渐变大时压缩旧状态,并把后续推理需要的关键信息放进加密 compaction item。它解决上下文增长问题,不是连接续传、后台执行或批处理机制。

Server-side compaction 和 /responses/compact 怎么选?

希望在正常 Responses 请求中自动触发时,用 context_management 和 compact_threshold;需要由应用决定压缩时机、显式持有完整输入窗口时,用独立 /responses/compact。前者随正常生成发生,后者返回一个新的规范输入窗口。

compact_threshold 应该设置多少?

官方没有给所有应用通用的唯一数值。阈值必须结合所用模型的上下文窗口、工具定义、输出预留、延迟和质量评测决定。先在测试流量记录压缩触发点、输入 Token、P95 延迟、任务成功率和成本,再逐步调整。

可以解析或修改 compaction item 吗?

不应该。官方把加密 compaction item 定义为不面向人类解释的状态载体。独立 compact 接口的 output 还是下一轮的规范窗口,通常还包含保留的旧 Items;应原样传给下一次 Responses 请求,不要只摘出 compaction item。

使用 previous_response_id 时还要手动删除旧 Items 吗?

启用服务端 compaction 并使用 previous_response_id 链接时,只发送新一轮输入并继续传最新 response ID,不要手动裁剪服务端链路。若改用独立 /responses/compact,则它返回的不是 response ID,需要把返回窗口作为新 input 并开启新链。

Compaction 一定会降低费用和延迟吗?

不能保证。压缩可减少后续携带的上下文,但压缩本身也会产生处理开销,质量、成本与延迟取决于模型、阈值、历史长度和工具链。上线前要用相同任务集比较总 Token、P50/P95 延迟、正确率和失败率。

Compaction 是否适合 Zero Data Retention?

OpenAI 当前说明,独立 /responses/compact 是无状态且 ZDR-friendly;服务端 compaction 在 Responses 请求设置 store=false 时也可用于 ZDR 场景。实际项目仍应核对组织控制、所用模型与最新数据政策,不能仅凭一个参数替代合规评审。

先在长任务测试集上验证压缩策略

把阈值、续接模式和业务检查点一起测试;只有质量、成本、延迟和恢复路径都通过,才扩大生产流量。