长对话变慢或超出窗口时,很多实现会“总结一下历史并继续”,同时把摘要叫作记忆、把 prompt cache 叫作状态保存。四个概念其实承担不同责任:上下文是本轮推理材料,compaction 是可续跑的有损快照,cache 是相同前缀的计算复用,memory 是应用决定长期保存的事实。混在一起会造成过期事实、隐私无法删除和恢复后行为漂移。

本文面向实现多轮对话、长任务或 Agent 的开发者。你需要熟悉 Responses item、持久化和检索。目标是用明确预算和晋升策略,让系统知道什么可以丢、什么只能压缩、什么能够复用、什么才有资格长期记住。

上下文、压缩、缓存和长期记忆四层拥有不同语义

图 1(1600 × 900):WEB/SUN 原创 SVG。四层之间不是自动同步;任何信息进入长期记忆,都要经过来源、策略、用户控制和过期检查。

先给上下文做预算表

模型窗口不是聊天记录容量,而是一次采样的总输入与输出空间。输入中同时竞争的有:developer instructions、工具定义、结构化输出 Schema、当前用户任务、必要历史、检索证据、工具结果、图像,以及推理和输出预留。只设置 max_output_tokens 不能解决上游挤占。

为任务类型定义预算而不是全局常量:

区域 保留原则 超预算动作
指令与安全策略 版本化、不可被摘要改写 减少重复措辞
工具 Schema 只加载当前阶段能力 延迟加载或缩小工具集
当前任务 保留原文与可信结构字段 拒绝过大附件或拆任务
证据 按支持性与覆盖选择 重排、去重、保留来源
历史 保留未决决定与必要 item 压缩已完成阶段
输出 提前保留硬空间 降低目标长度或分段

请求前计算渲染后的 token 估算并设置水位:预警、压缩、拒绝。工具返回也有上限,数据库查询先投影字段,文件搜索先重排,绝不能让一个意外大结果吃掉整个窗口。预算事件进入 trace,便于判断质量下降是否来自模型还是上下文被截断。

上下文:只放当前推理真正需要的材料

当前上下文应包含任务目标、可信约束、未决状态和能支持下一步的证据。已经提交的业务事实进入业务数据库;完成阶段的过程日志进入 trace;与当前任务无关的寒暄不必永远回放。把所有历史都塞进去会增加成本,也让旧指令、错误工具输出和不可信文本继续影响行为。

OpenAI 的Conversation state 指南提供手工回放、previous_response_id 和 Conversation 等策略。每个会话选一种主要状态所有者,避免本地历史与服务端链重复输入。文档还说明 Response 默认保存 30 天且可用 store: false 关闭;Conversation 中的 item 不受这一 30 天 TTL 约束。因此选择便利性时必须同时决定保留与删除政策。

历史裁剪不能只按“最旧先删”。最近一条闲聊可能不重要,较早但仍有效的用户确认可能决定权限或目标。按状态语义保留:当前目标、约束、已确认决定、未解决问题、最近工具结果和引用;其余进入阶段摘要或离开推理上下文。

Compaction:为了续跑,不是为了生成事实库

OpenAI 的Compaction 指南提供服务端自动压缩和显式 compact endpoint。服务端方式在渲染 token 超过阈值时产生 encrypted compaction item;该 item 是不透明的续跑状态,不用于人类阅读。手工 input-array 链要继续附带输出 item;用 previous_response_id 时只传新输入,不要再手动裁剪服务端链。

显式 compact endpoint 接收仍在窗口内的完整上下文,返回下一轮的 canonical compacted window。官方文档明确要求把返回窗口原样传入,不能只挑出 compaction item。压缩必须发生在溢出之前;已经超过模型窗口,再调用压缩也无法挽救请求。

应用还可以维护可读 checkpoint,但它与 opaque compaction 不同。checkpoint 使用结构化字段:目标、已完成步骤、未决问题、确认事实、artifact 引用、失败与下一步。每个字段带来源和 revision,生成后通过确定性 Schema 与必要人工确认。不要让一段自由摘要成为订单状态或授权事实。

压缩是有损的。测试时构造跨阶段约束、否定条件、数值、引用和待审批动作,在压缩前后运行相同 probe;若关键行为丢失,降低阈值、改用结构 checkpoint 或保留原始 item。官方 Cookbook 的Memory 与 compaction 示例也强调长任务需要在上下文增长与可恢复状态之间设计边界,而不是无限追加。

Prompt Cache:复用计算,不增加模型知道的内容

Prompt Caching 对满足条件的请求自动工作,命中要求精确前缀匹配。OpenAI 的Prompt caching 指南建议把稳定指令、示例和工具放前面,把用户特定内容放后面;工具与图像也必须保持相同才能复用对应前缀。

Cache 不会扩展上下文窗口,不会保存业务状态,也不会让下一轮“记住”上一轮。请求仍需包含逻辑所需输入;缓存只是避免重复处理相同前缀。把 cache hit 当作 memory,会在缓存未命中或过期时暴露行为错误。

结构可按以下顺序稳定:版本化 developer prompt → 稳定工具 Schema → 共享参考 → 用户与实时数据。任何会改变安全语义的版本都使用新前缀和 cache key。不要为了命中率把不同租户的私人内容放进共同前缀;缓存隔离和数据政策仍需按官方文档与组织要求核验。

记录 cached_tokens 以及当前文档提供的 cache read/write 用量字段,比较真实命中、写入与成本;不要声称缓存一定降低延迟或费用。发布 prompt 变化时观察冷、热两种路径。缓存策略是性能实验,不能改变评测预期。

Memory:只保存经确认、可撤销的长期事实

长期记忆需要应用数据模型,而不是聊天摘要表。候选记忆至少包含主体、事实、来源、作用域、置信状态、创建/核验时间、过期规则和删除权限:

type MemoryFact = {
  subjectId: string;
  key: string;
  value: unknown;
  source: { type: 'user-confirmed' | 'system-of-record'; id: string };
  scope: string;
  verifiedAt: string;
  expiresAt?: string;
  status: 'active' | 'superseded' | 'deleted';
};

模型推断、助手建议和外部网页不能直接晋升为事实。用户说“下周可能去东京”不等于永久偏好;工具返回的实时库存也不应长期记住。只有明确的用户确认或权威系统记录通过策略后写入,并提供查看、更正、删除和关闭记忆的入口。

读取记忆时按主体、租户、任务、时间和权限过滤,再像检索证据一样选择少量相关事实。每条事实标注来源,不允许旧偏好覆盖当前用户输入。冲突时以更新的权威来源为准,并保留 superseded 记录用于审计,而不把两条矛盾信息同时塞给模型。

Memory 与业务数据库也有界限。订单、余额、访问权限等实时事实始终查询 system of record;记忆最多保存检索线索或用户偏好,不能成为副作用授权。隐私敏感字段默认不记,确需保存时加密、最小保留并遵守用户同意。

四层如何协作

一次长任务开始时,从长期记忆检索经允许的偏好和稳定事实,连同当前任务与工具放入上下文;稳定前缀可能命中 cache;运行接近水位时生成 compaction item 与应用 checkpoint;完成后仅把通过策略的候选事实晋升 memory,其余 trace 按保留期清理。

每条迁移都是显式事件。context → compaction 表示为了续跑有损压缩;context → memory 表示事实经过确认;prompt → cache 表示计算可复用。不存在 cache → memorycompaction → authorization 的捷径。

失败模式与取舍

常见错误包括:按时间简单截断历史;压缩后删除待审批动作;把 opaque compaction 当可查询摘要;混用本地回放和 response chain;把 cache hit 当状态;为命中率缓存用户私人前缀;自动把模型推断写成记忆;记忆没有来源、过期与删除;用记忆中的旧权限执行工具。

保留更多上下文能减少压缩损失,却增加成本与干扰;更激进压缩降低输入量,却需要更强 checkpoint 和评测;长期记忆提高连续性,也带来隐私、陈旧和冲突治理。取舍由任务长度、失败成本和用户预期决定,必须用压缩前后 probe、cache 指标和 memory 审计验证。

结论

上下文工程不是把窗口塞满,而是给信息不同生命周期。Context 服务当前推理,compaction 服务同一任务续跑,cache 服务精确前缀计算复用,memory 保存应用认可且用户可控的长期事实。

当系统能回答“这条信息为何在本轮、压缩后是否仍有效、缓存未命中是否仍正确、谁允许它被长期保存”,长对话才不会用便利换来不可解释的状态。

Sources