AIERROR故障诊断台
排障指南 / GUIDE

OpenAI Responses `store:false` 后上下文丢失:ZDR、加密 reasoning 与 compaction 排查

核验更新:2026-08-29证据状态:VERIFIED

直接答案

OpenAI Responses store:false 后上下文丢失:ZDR、加密 reasoning 与 compaction 排查

症状、差异与判断依据

先确认症状属于哪一层

不要把所有“忘记”都归类为上下文丢失。先保存每轮的请求 ID、response ID、使用的状态模式、输入 item 类型数量、输出 item 类型数量和 token 用量,但不记录密钥或加密载荷正文。 典型现象包括:模型重复询问已提供的条件;工具调用已完成,下一轮却认为尚未执行;第一轮遵守输出约束,第二轮恢复默认风格;或长会话到某个阈值后突然丢掉早期决策。

三种会话状态方式不要混用

Responses API 可以通过 previousresponseid 串联上一个 response,也可以把 response 放入 Conversation。官方 API 定义明确说明,previousresponseid 不能与 conversation 同时使用。第三种方式是客户端自己管理历史:每轮把需要的 input 和之前返回的 output items 重放给 API。 建立单一状态模式字段,例如 serverchain、conversation 或 clientreplay。在请求入口就拒绝混用,不要让不同 worker 根据局部条件各自选择。

`store: false` 改变了什么

store 控制生成的 response 是否供后续 API 检索。如果使用 store: false,应用不应假设服务端仍能长期恢复该 response。对于客户端管理的无状态流程,下一轮所需上下文必须由应用完整保存并重放。 排查时同时记录请求中的 store、组织数据保留策略以及是否使用 ZDR。不要用“开发环境可以 retrieve”推断生产环境也一定可以,两个环境可能使用不同 project 和保留策略。

无状态 reasoning 为什么会断链

对 reasoning 模型,上一轮 output 可能不只有最终 message。应用如果只提取 outputtext 并把它当成全部历史,就会丢掉其他 item。官方创建 Response 接口提供 include: ["reasoning.encryptedcontent"],用于无状态多轮或 ZDR 场景的加密 reasoning item。 加密内容是不透明的续接载荷,不是给应用解析的思维文本。应用只需完整保存 item 的类型、顺序和载荷,下一轮按 API 格式原样回传。不要尝试解密、拼接、摘要或对其字节做 JSON “精简”。

不要假设 `output[0]` 就是答案

官方 Response 对象说明,output 的长度和顺序取决于响应。有工具、reasoning 或其他 item 时,第一项不必然是 assistant message。界面展示可以使用 SDK 提供的 outputtext,但会话恢复不能只存这个便利字段。 反序列化后对 item 做白名单校验,未识别的新 item 应保留或安全失败,不要静默丢弃。这可避免 SDK 升级后新类型被旧代码吞掉。

instructions 不会自动继承的陷阱

创建 Response 的官方定义说明,与 previousresponseid 一起使用时,前一个 response 的 instructions 不会自动携带到下一个 response。因此,如果症状是“第二轮风格或约束失效”,不要先怀疑 reasoning item;检查应用是否每轮都发送当前 instructions。 把指令版本号和内容哈希写入调试元数据。只记录哈希,避免生产日志泄露完整系统指令。

工具调用必须保留关联关系

工具流程中,函数调用 item 和其输出通过 call ID 关联。手工裁剪历史时,只保留工具返回值、丢掉调用 item,或把两轮的输出拼错顺序,都会让续接状态无法重建。 建立不可变的会话事件流,保存 item 顺序、ID、call ID 和类型。并发分支不要同时覆盖同一个“最新状态”键;应使用版本号或乐观锁检测冲突。

排障步骤与验证

长会话应使用压缩而不是盲目删除

当会话接近上下文上限,从数组头部删掉固定数量的 item 可能破坏决策依赖和工具对。OpenAI 提供 POST /responses/compact 用于压缩对话,返回的 response.compaction 对象包含可续接的不透明 compaction item。 将压缩安排在明确里程碑后,而不是每轮执行。压缩前保存原会话版本和最后一个成功 response ID,压缩后用固定验证问题检查关键目标、约束和已完成工具是否仍然可用。

一个可复制的最小排查流程

用两轮纯文本对话建立基线,固定 model、instructions 和输入。 分别测试 previousresponseid、Conversation 和客户端 replay,一次只用一种模式。 对 replay 模式打印 item 类型、顺序和 ID,不打印敏感内容。 开启 store: false,对比是否仍错误依赖 retrieve 或仅回传 outputtext。 在无状态 reasoning 流中请求并保留 reasoning.encryptedcontent。 加入一个函数调用,验证 call item 和 output item 的关联没有断裂。 在长历史上运行 compaction,用同一组验收问题比较压缩前后。

日志中应保存什么

保存请求 ID、response ID、会话模式、store 布尔值、model、instructions 版本哈希、item 类型列表、item 数量、call ID 关联检查结果、是否包含 encrypted reasoning、是否经过 compaction 以及 token 用量。 不要保存 API key、Authorization 头、完整加密载荷、用户隐私原文或不必要的工具返回数据。加密 item 虽不是明文推理,仍应按敏感会话资产处理。

自动化回归测试

为每种状态模式建立至少一个三轮测试:第一轮给出随机会话标记,第二轮执行工具并返回结果,第三轮询问标记、工具状态和当前约束。无状态用例要断言所有必需 output items 都被回传,而不是只断言最终文本相似。 再加一个长会话测试,人工降低压缩阈值以稳定触发 compaction。断言压缩 item 未被应用解析或修改,且压缩后的第一轮仍能恢复预设事实。

修复后的验收标准

状态模式唯一,conversation 与 previousresponseid 不会同时出现。 store: false 流程不依赖后续 retrieve 恢复状态。 客户端 replay 保留完整 output item 序列,不只保存 outputtext。 无状态 reasoning 流包含并原样回传加密 reasoning item。 每轮 instructions 均由当前请求明确提供并记录版本。 工具 call ID 关联完整,并发更新不会静默覆盖。 compaction 后的固定验收集通过,无上下文突然断层。

总结

Responses API 的多轮上下文故障,核心不是“多发一遍用户文本”,而是统一状态模式并保存完整 item 图。服务端链接、Conversation 和客户端 replay 各有边界;store: false 或 ZDR 下,reasoning 续接还需正确处理加密 item。长会话应使用官方 compaction,不要盲目裁剪。只要把模式、item、instructions、工具关联和压缩验收纳入自动化测试,“偶发失忆”就能转化为可复现、可定位的工程问题。

常见问题

使用 `previous_response_id` 就不用重发 instructions 吗?

不是。官方接口说明,前一个 response 的 instructions 不会因 `previous_response_id` 自动携带到下一轮。

`store: false` 后只保存 `output_text` 可以吗?

不足以支持完整续接。`output_text` 适合显示,无状态多轮应保存所需的完整 output items。

可以解析 `reasoning.encrypted_content` 做日志吗?

不应这样做。它是不透明的续接载荷,应原样保存和回传,并按敏感资产保护。

会话很长时直接删最旧消息行不行?

风险很高。固定删除可能切断工具关联和关键决策,应优先使用 Responses compaction 并进行压缩后验收。

Conversation 和 `previous_response_id` 可以同时传吗?

不可以。官方 API 定义明确说明两者不能同时使用,应在应用层选定一种状态方案。

官方与规范资料

OpenAI API 错误处理OpenAI 官方文档

Responses API:Create a model responseOpenAI 官方文档