首页使用帮助Conversation State
HELP / CONVERSATION STATE

OpenAI Conversation State 怎么用?

Responses API 有三种多轮状态方案:应用自己回传历史 Items、用 previous_response_id 串联上一条 Response,或用 Conversations API 创建可跨会话、设备和任务复用的持久对象。正确选择的关键不是“哪种最先进”,而是状态由谁持有、要保留多久,以及你是否需要独立的读取和删除能力。

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

短链路或一次工作流优先手动 Items;只想少传历史请求体可用 previous_response_id;需要一个跨设备、后台任务或多次登录都能复用的会话 ID,再用 Conversations API。不要把 conversation 和 previous_response_id 放进同一次请求;后者不会继承上一轮顶层 instructions,也不会免除历史输入 Token 计费。

官方资料(2026-10-30 核对):Conversation state · Responses migration · Conversations API · Data controls

三种方案先放在一张表里判断

方案状态由谁持有适合场景主要代价与边界
手动回传 Items你的应用和数据库需要审计、裁剪、迁移,或严格控制发送内容要保存完整消息、reasoning、工具调用与输出之间的关系
previous_response_idOpenAI Response 链单线程多轮问答、工具链,想少传历史请求体顶层 instructions 每轮重发;历史输入仍计费;Response 默认保留规则需核对
Conversations API持久 conversation 对象跨会话、设备、作业或 Worker 继续同一状态保留到删除,不符合当前 ZDR;应用必须做归属、权限和删除

这三种方式解决的是“下一轮从哪里取得上下文”。如果问题是上下文越来越大,应另看 Responses Compaction;如果问题是单个请求运行太久,则看 Background Mode。

方案一:应用手动管理历史 Items

手动模式最透明:每次把上一轮 response.output 转为下一轮可接受的 input Items,再加入本轮用户输入。应用可以在发送前审计、过滤或压缩上下文,也能把供应商状态迁移到自己的数据库。

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

const client = new OpenAI();
let input = [{
  type: "message",
  role: "user",
  content: "分析这个故障并给出第一步。"
}];

const first = await client.responses.create({
  model: "YOUR_MODEL",
  instructions: "你是生产故障分析助手。",
  input,
  store: false
});

input.push(...toResponseInputItems(first.output));
input.push({
  type: "message",
  role: "user",
  content: "继续第二步,并保留已确认的证据。"
});

const second = await client.responses.create({
  model: "YOUR_MODEL",
  instructions: "你是生产故障分析助手。",
  input,
  store: false
});

不要只保存最终文本。Responses 输出可能包含 message、reasoning、function_call 和其他 typed Items;工具调用还要保持 call_id 与 function_call_output 配对。完整工具循环见 Function Calling 教程。

手动模式什么时候更合适?

  • 你需要在数据库中保留可审计的规范上下文,而不是只保存一个远端 ID。
  • 你要根据租户、任务或敏感级别决定哪些 Items 可以进入下一轮。
  • 你需要显式压缩、迁移提供商,或在离线测试中重放完全相同的输入。
  • 你的数据策略不能接受 Conversation 对象“保留到删除”的服务端持久化。

代价是应用要正确处理 Items 的顺序和依赖。不要按“最近 N 条可见消息”粗暴裁剪,因为一条工具结果、reasoning item 或调用 ID 可能依赖更早的 Item。

方案二:用 previous_response_id 串联 Response

previous_response_id 让下一次请求引用上一条 Response,适合单条链路或从某个 Response 分叉。应用仍要保存最新 response ID,但不必在每个请求里重传全部历史 Items。

const first = await client.responses.create({
  model: "YOUR_MODEL",
  instructions: "只依据已确认信息回答。",
  input: "列出第一步。",
  store: true
});

const next = await client.responses.create({
  model: "YOUR_MODEL",
  instructions: "只依据已确认信息回答。", // 每轮重发
  previous_response_id: first.id,
  input: "继续第二步。",
  store: true
});
两个常见误区

第一,上一条 Response 的顶层 instructions 不会自动继承,因此稳定指令要每轮重发。第二,官方当前说明链中的既往输入 Token 仍按输入 Token 计费;少传请求体不等于历史上下文免费。

Response 对象默认会保存 30 天,创建时可用 store:false 关闭这一默认行为,但实际可用性还受组织数据控制、工具和所选功能约束。需要跨很长时间继续时,不要假设任意旧 response ID 永久可取;要么在应用保存规范 Items,要么评估 Conversations API。

如何处理分支与失败?

从同一个旧 response ID 发起不同后续请求会形成分支。应用数据库应记录 user_id、内部 thread_id、当前 response_id 和父 ID,避免两个并发请求同时覆盖“最新 ID”。发生 5xx 或超时时先核对请求是否已成功处理,再决定重试;具体证据和退避见 API 500/503 与超时排查。

方案三:用 Conversations API 建立持久会话

Conversation 是拥有独立 durable ID 的持久对象,可以跨浏览器会话、设备、Worker 或后台任务继续。它保存的 Items 不只有消息,也可包含工具调用、工具输出等状态。

const conversation = await client.conversations.create({
  metadata: {
    app_user_id: "user_123",
    purpose: "support_case"
  }
});

const first = await client.responses.create({
  model: "YOUR_MODEL",
  conversation: conversation.id,
  instructions: "回答前先检查已有会话状态。",
  input: "记录订单故障的第一条证据。"
});

const next = await client.responses.create({
  model: "YOUR_MODEL",
  conversation: conversation.id,
  instructions: "回答前先检查已有会话状态。",
  input: "现在继续排查。"
});

Responses create 中的 conversation 会把该会话已有 Items 放在本轮 input 之前,并把本轮输入与生成结果加入会话。API Reference 明确说明,conversation 与 previous_response_id 不能同时使用;迁移时应选一个主状态键,而不是叠加两套链路。

应用数据库仍然不可省略

持久 Conversation 不替代你的用户、权限和业务数据库。至少保存:

  • 内部用户或租户 ID 与 conversation ID 的映射;
  • 创建人、可访问角色、用途、创建与最后活动时间;
  • 业务对象 ID,例如工单、项目或任务;
  • 删除、导出和审计状态;
  • 当前模型、关键 instructions 版本与应用发布版本。

每次读取、列出 Items、追加输入或删除前,都要在服务端验证该 conversation 属于当前用户或租户。API Key 只放在服务端环境变量,不把 Conversation API 直接暴露给浏览器。

Conversation 的读取、分页与删除怎么做?

Conversations API 提供创建、读取、更新和删除对象的操作,也提供 Items 的创建、读取、列出和删除。列表接口支持分页和顺序参数;不要假设一次响应包含无限历史。

// 列出一页 Items
const page = await client.conversations.items.list(conversation.id, {
  limit: 20,
  order: "asc"
});

// 删除单个 Item
await client.conversations.items.delete(
  conversation.id,
  "ITEM_ID"
);

// 用户要求删除整个会话
await client.conversations.delete(conversation.id);

删除某个历史 Item 不会改变已经生成并交付给用户的旧答案;它主要影响后续可用状态与保留记录。删除整个 Conversation 后,应用也要同步清除本地映射、缓存和搜索索引,并把失败重试设计为幂等操作。

数据保留、ZDR 与隐私边界

对象或方式官方当前保留说明应用责任
Response 对象默认保存 30 天;可在适用场景设置 store:false核对组织控制、工具与功能例外,不把默认值写成合同承诺
Conversation 与 Items不受 Response 30 天 TTL 限制,保留到删除实现归属、权限、用户删除和保留周期任务
手动 Items由你发送并按所用 API 的数据控制处理控制自有数据库、日志、备份和传输内容

OpenAI 当前数据控制表把 /v1/conversations 和 conversation Items 标为保留到删除,并且不符合 Zero Data Retention。若项目有严格 ZDR 要求,不要先创建持久 Conversation 再试图用 store:false 抵消;应选择符合政策的无状态路径并让安全、法务或合规负责人复核最新文档。

Conversation State 与 Compaction 怎样配合?

状态持久化和上下文窗口管理是两层问题。Conversation 可以不断累积 Items,但模型每次仍受上下文窗口限制;previous_response_id 也不会自动让无限历史免费或无限可见。

  1. 先确定状态所有权:手动 Items、Response 链或 Conversation ID。
  2. 再控制窗口增长:按任务评测是否启用服务端 compaction、独立 compact,或应用自定义摘要与检查点。
  3. 业务事实外置:订单、权限、文件版本和已执行副作用保存在业务数据库,不能只依赖模型上下文。
  4. 监测真实用量:记录每轮 input/output Token、延迟、错误和质量,并用 API Usage 对账。

Compaction 的两种模式、阈值和续接规则见 Responses Compaction 教程。

生产架构建议:状态键、权限和并发

风险错误做法建议
越权读取拿到 conversation ID 就允许访问服务端按租户和用户归属校验,每次操作都授权
并发覆盖两个请求同时写同一“最新 Response”用版本号、队列或乐观锁记录父 ID 和当前状态
指令漂移以为 previous_response_id 自动带上 instructions保存指令版本并在每轮显式发送
无限增长只持久化,不设置窗口或保留策略同时设计 Compaction、删除期限和业务检查点
不可审计只存最终文本,不存 ID 和工具状态记录 response/conversation/item ID、Request ID、工具调用与应用版本
重复副作用超时后直接重放工具请求工具使用幂等键,重试前检查结果和调用状态

常见错误与排查

  • 400:conversation 与 previous_response_id 同时出现:保留一个主状态方案,移除另一个字段。
  • 下一轮行为像“忘了系统指令”:检查是否只传了 previous_response_id 而没有重发顶层 instructions。
  • Conversation 读不到:核对 Project、API Key 权限、ID、环境,以及对象是否已删除;不要跨项目猜测 ID。
  • 历史越来越贵:previous_response_id 不免历史输入计费;检查真实 Usage,并单独设计窗口与 Compaction。
  • 列表缺少早期 Items:检查分页游标、limit 和 order,不要把一页结果当完整历史。
  • 用户删除后仍在本地出现:清理应用数据库映射、缓存、向量索引和备份流程,不只调用远端 delete。

上线前检查清单

  • 明确一个主状态方案,并记录为什么不用另外两种。
  • previous_response_id 与 conversation 不会同时发送。
  • 顶层 instructions 在需要时每轮显式传递,并有版本记录。
  • 工具调用、reasoning 与工具输出 Items 的关联不会在裁剪时被拆开。
  • Conversation ID 只由服务端读取,且每次操作都验证用户和租户归属。
  • 实现 Items 分页、会话删除、缓存清理和失败幂等。
  • 验证 Response 默认 30 天与 Conversation 保留到删除的差异。
  • 严格 ZDR 项目没有使用当前不符合 ZDR 的 Conversations API。
  • 监控 Token、P50/P95、错误率、任务成功率和重复副作用。
  • 对并发写、旧 ID、超时、5xx、权限错误和删除后的请求做回归测试。
对话状态不要只保存 file_id

还要记录文件所有者、purpose、到期和删除状态;完整生命周期见 OpenAI Files API 指南。

会话状态与知识库状态要分开

Conversation 保存对话 Items,Vector Store 保存可检索文件索引;后者流程见 OpenAI File Search 指南。

常见问题

OpenAI Conversation State 有哪三种管理方式?

可以手动把历史 Items 放回下一次 input,也可以用 previous_response_id 让 OpenAI 串联上一条 Response,或用 Conversations API 创建可跨会话、设备与任务复用的持久 conversation。选择依据是状态由谁持有、是否需要长期标识,以及数据保留要求。

previous_response_id 和 Conversations API 应该怎么选?

只需沿单条 Response 链继续时,previous_response_id 更轻量;需要一个能跨会话、设备或后台任务复用,并可单独读取、更新或删除的持久对象时,用 Conversations API。两者不能在同一次 Responses create 请求中同时使用。

使用 previous_response_id 后还要重复发送 instructions 吗?

要。OpenAI 当前文档明确说明,上一条 Response 的顶层 instructions 不会自动带到下一条,因此稳定的系统或开发者指令应在每次请求中重新发送。

previous_response_id 会减少历史 Token 计费吗?

不会自动免除。OpenAI 当前说明,即使用 previous_response_id 串联响应,链中既往输入 Token 仍作为输入 Token 计费。它简化状态传递,不等于免费上下文或自动压缩。

Conversation 对象会在 30 天后自动删除吗?

不会按 Response 对象默认的 30 天规则自动过期。官方当前说明,Conversation 对象及其中 Items 会一直保留到删除;因此应用必须提供权限校验、删除路径和自己的数据保留策略。

Conversations API 适合 Zero Data Retention 项目吗?

按 OpenAI 当前数据控制表,/v1/conversations 及其 Items 会保留到删除,且不符合 Zero Data Retention。严格 ZDR 场景应改用符合组织控制的无状态方案,并由安全或合规负责人核对最新政策。

Conversation State 和 Compaction 是一回事吗?

不是。Conversation State 决定多轮上下文怎样保存和续接;Compaction 处理上下文不断增长、接近窗口上限的问题。长会话通常既要选状态方案,也要单独设计压缩、截断或业务检查点。

先画清状态所有权,再写多轮代码

明确状态由应用、Response 链还是 Conversation 对象持有,并把权限、删除、成本和窗口增长一起纳入上线验收。

Realtime 有独立会话状态

Session、Conversation 与 Response 事件不同于 Responses 的 previous_response_id;60 分钟上限、语音截断与重连见 Realtime API 教程。