跳到主要内容

上下文压缩

上下文压缩用更短的内容替换旧对话,让接近窗口上限的任务能继续执行。本文先比较常见压缩方案,再说明该保留哪些信息、何时触发压缩,以及怎样验证恢复后的任务。摘要会舍弃细节,所以需要逐字核对的信息应另行归档。

1. 面试核心​

先记住这几条,再读正文
  • 压缩方式。 滑动窗口保留近期原文,摘要保留旧历史要点。前者会丢失较早的约束,后者可能遗漏细节,需要按任务组合使用。卡 · 压缩方案
  • 摘要内容。 压缩后的摘要应保留任务目标、用户约束、关键决定、产物位置、未决错误和下一步。卡 · 保留字段
  • 触发阈值。 压缩阈值应为下一轮输入、工具结果和输出预留空间。卡 · 触发时机与合并
  • 工具结果管理。 旧工具结果可缩为结论和引用,原始结果留在外部存储。卡 · 压缩方案
  • 消息配对。 工具调用与结果按调用 ID 保持有效配对。压缩时还要保留已执行状态,避免消息失配或重复执行有副作用的操作。卡 · 工具消息配对与重放

2. 压缩方案​

选择压缩方案时,要看下一步还需要哪些历史信息。下表比较常见做法,长任务可以组合使用。

方案做法代价
截断删除早期消息早期约束会随消息消失。
滑动窗口保留最近若干轮远期事实需要另行保存。
摘要用短文本表达旧历史增加调用成本,也有遗漏风险。
窗口加摘要近期留原文,远期留摘要需要处理新旧事实冲突。
工具结果清理旧结果缩为结论和原文引用再次读取会增加调用。
外部存储加检索归档原文,按需取回依赖引用有效性和检索质量。

截断和滑动窗口都无需额外调用模型,实现也简单。滑动窗口保留最近 N 轮原文,所以近期细节完整、长度容易控制。代价是窗口外的信息会被移出;早期目标和约束需要另行保存。

摘要通过一次额外的模型调用,把旧历史改写成较短的文本。它能保留远期要点,但改写时会遗漏细节或改变含义。窗口加摘要兼顾近期细节和远期要点,因此要设计固定字段,并约定新旧事实冲突时如何更新。

在反复读取文件、查询日志的任务中,工具结果会迅速占满窗口。优先清理已经使用过的旧结果,可以释放较多空间,同时保留对话主线。外部存储则保留完整历史,需要时再检索,代价是增加读取延迟。原文仍在,也要确保模型能找到正确的那一段。

压缩要围绕后续任务所需的信息进行。比如,删除重复结果可以减少长度,同时保留所需事实。摘要会舍弃原文细节,两者的损失方式不同。用户说“禁止修改公共接口”,摘要应保留这条原话。如果改成“尽量减小改动”,禁止修改接口就变成了改动大小的偏好,后续步骤便容易越界。

3. 保留字段​

摘要要让下一轮能接着工作,所以应围绕任务状态组织。压缩前可以把历史分成必须保留、可以摘要和可以移出窗口三类。

必须保留的信息用固定字段记录,比自由叙述更容易逐项核对:

  • 目标与验收:保留最终目标和完成条件。
  • 约束与授权:保留用户明确提出的约束和偏好,以及操作范围和已确认事项。
  • 决定与原因:保留仍影响后续工作的选择,以及做出选择的原因。
  • 产物与状态:记录文件路径、版本和实际修改结果。
  • 错误与下一步:保留未决问题、错误原文和失败尝试,说明接下来要做什么。
  • 原文引用:保存归档位置,便于按需恢复细节。

探索时读过的代码和文档,可以只留结论与位置。被否定的方案要留下否定原因,避免恢复后重复尝试。已经被后续结果替代的中间输出、重复工具结果和寒暄,可以移出窗口。

下面用订单分页任务示范如何记录目标、约束与执行状态:

## 目标
修复订单分页最后一页的重复数据。
## 约束
禁止修改响应字段。
## 已完成
修改 src/order/repo.ts 的 offset 计算。
order.repo.test.ts 在当前提交通过。
## 未解决
orders.e2e 超时,原因未确认。
## 下一步
检查测试数据库,再重跑集成测试。

这个摘要把单测通过与集成测试超时分开记录,恢复后就能找到尚未完成的验证。完整记录还应说明修改原因。比如,/api/orders 的分页错误来自 OrderRepository.page() 使用了 page,而非 page-1。原先的修改位置是 src/order/repo.ts:41,摘要可以保留该位置,方便重新定位。约束也应保留原因:前端已经上线,所以响应字段必须保持不变。下一步则可写明启动本地测试数据库后重跑 e2e。

文件路径用于重新读取产物,测试结果还应附带所测版本。恢复时,要重新核对文件、测试和外部系统的实际状态。摘要里的“已完成”只是历史记录,验收仍以当前检查结果为准。

目标和进度还可以写进上下文之外的进度文件,稳定的项目约束可以写进仓库指令。这样,恢复时能重新读取原始记录,减少反复摘要造成的遗漏。持久化状态机制见Agent 状态与持久化执行。

4. 触发时机与合并​

压缩要在窗口耗尽前发生,否则下一轮的工具结果就可能放不下。常见的四种触发方式适用于不同任务:

  • Token 阈值:当已用 Token 达到窗口的某个比例时触发。阈值要为下一轮输入、工具结果和模型输出预留空间。
  • 轮次:每 N 轮压缩最早的一段,让历史定期缩短。同样的轮数可以包含不同长度的消息,所以还要限制每轮长度。
  • 任务边界:子任务完成后,把探索过程压缩为结论。它适合计划明确、可以分阶段推进的长任务。
  • 手动触发:用户在切换话题前主动要求压缩,并指定需要保留的重点。

编码 Agent 可以把预算检查接入自动压缩,也可以提供手动入口。具体触发比例和轮数属于应用配置,应根据任务测试确定。

多次压缩后,还要决定怎样处理旧摘要。每次将旧摘要与新增历史合并成一份,能控制总长度,适合预算紧张的任务。不过,每次改写都可能遗漏或改变早期内容,失真会随次数累积。

分段保留摘要可以减少对早期内容的改写,适合需要保留阶段细节的任务。代价是摘要数量和总长度继续增长。因此,可以让近期摘要分段保留,远期摘要再合并。最初的目标和仍有效的约束固定保存,避免参与反复改写。

4.1 工具消息配对与重放​

压缩除了要保留任务信息,还要让消息序列符合 API 的会话规则。工具结果通过调用 ID 关联发起它的请求。只删除调用而保留结果,就会留下找不到来源的工具消息,导致接口报错。

因此,裁剪时应按完整交互处理调用与对应结果。尚未返回的调用要保留到交互完成。即使使用 LangChain 等框架裁剪历史,程序也应在生成摘要前检查配对是否有效。

需要旧工具结果时,应优先读取归档。重新查询读取的是当前状态,因此结果可能与当时的快照不同。支付或发送邮件等工具还会改变外部系统,盲目重跑会造成重复操作。这类操作恢复前应查询执行状态,必要时使用幂等标识。幂等标识用于识别同一次操作,让重复请求复用已有结果。

5. 常见问题​

5.1 怎样验证压缩没有破坏任务?​

验证压缩是否有效,要看任务能否继续正确完成。可以建立固定回归用例:在长对话早期或中途加入约束,再触发压缩,检查后续是否仍然遵守。

对同一批任务,分别运行保留原文和启用压缩的版本,比较三项指标:

  • 约束遵守率:早期禁止事项和验收条件是否仍然有效。
  • 任务成功率:压缩后能否继续完成原定目标。
  • 恢复成本:重新读取文件和调用工具增加了多少耗时与费用。

出现失败时,对照压缩前后的字段,检查目标、约束或未决错误是否被遗漏或改写。这样才能判断失败是否来自压缩。

5.2 摘要能还原成原文吗?​

6 · 面试题卡片​

本页题目与参考回答

6.1 对话超过上下文窗口时,有哪些处理方案?滑动窗口和动态摘要各有什么优缺点?​

考察重点:说明不同方案怎样保留信息,并比较调用成本与实现复杂度。

相关内容:压缩方案。

参考回答

超过窗口时,可以组合使用截断、滑动窗口、摘要、工具结果清理和外部检索。

滑动窗口保留最近 N 轮原文,无需额外调用模型,实现简单且近期细节完整。窗口外的目标和约束会随旧消息移出,因此需要另行保存。动态摘要能留下远期要点,但多一次模型调用,也有遗漏或改写细节的风险。

组合方案可以固定保留系统规则、目标和约束,再用摘要记录旧过程,近期消息继续保留原文。大工具结果只放结论和归档位置。后续需要细节时,按引用读取原始历史。

6.2 压缩和摘要怎样尽量保留任务信息?​

考察重点:说明哪些信息需要保留、摘要或移出窗口,以及怎样验证恢复后的任务。

相关内容:保留字段、怎样验证压缩没有破坏任务?。

参考回答

用固定字段保留关键任务状态,并保存原文引用,可以减少压缩造成的信息损失。

目标、验收条件和用户约束决定后续工作的方向,应原样保留。授权范围、关键决定及其原因也应明确记录。产物位置、失败尝试和未决错误则告诉下一轮从哪里继续。探索过程可缩为结论与依据位置,被替代的中间结果可以移出窗口。

关键信息另存进度文件或状态库,摘要中区分已完成、已验证和计划执行。这样,恢复时可以读取实际产物,核对摘要记录。再用带远期约束的回归任务比较压缩前后表现,检查是否仍能遵守约束并完成目标。

6.3 常见的压缩触发机制有哪些?旧摘要和新摘要应该合并还是分别保留?​

考察重点:解释触发时机怎样影响剩余预算,以及合并和分段保留各适合什么场景。

相关内容:触发时机与合并。

参考回答

压缩可按 Token 阈值、轮次、任务边界或用户要求触发,摘要合并方式取决于预算和细节保留需求。

Token 阈值要给下一轮输入、工具结果和输出留出空间。按轮次触发便于定期整理,但还需限制每轮长度。子任务完成时适合压缩其探索过程;手动触发则让用户指定保留重点。

合并摘要便于控制长度,适合预算紧张时使用。反复重写会改变早期内容,所以存在累计失真的风险。分段保留适合需要阶段细节的任务,但总长度会继续增长。可以固定目标和约束,近期分段保留,远期再合并。

6.4 Tool Result 如何淘汰或压缩?​

考察重点:说明怎样控制工具结果的长度,并在清理后保留有效调用记录、避免重复操作。

相关内容:压缩方案、按需加载与渐进式披露。

参考回答

工具结果可以在返回时限制长度,再把历史中已经使用过的旧结果压缩为结论和引用。

大结果可以截断、分页或写入归档,上下文中保留摘要、总行数和路径。日志应先由程序按错误级别和请求 ID 过滤,让模型看到与任务相关的部分。

近期结果和未决错误保留原文。旧结果保留工具名、参数、调用 ID 和必要结论,便于追溯。清理后仍需满足调用与结果的配对规则。后续优先读取归档,避免重复执行支付、发邮件等有副作用的工具。

6.5 压缩后为何出现工具消息错误或重复操作?​

考察重点:解释裁剪怎样破坏消息配对,以及重新执行工具为何会改变结果或造成重复操作。

相关内容:工具消息配对与重放。

参考回答

工具消息错误来自调用与结果失配,重复操作则会出现在旧结果被删除后盲目重跑工具的场景中。

工具结果依赖调用 ID 找到原请求,所以压缩应按完整交互处理,并保留未完成调用。旧结果优先从归档恢复;重新查询会读到当前状态,写操作还会再次改变外部系统。因此,恢复写操作前应查询执行状态,并用幂等标识识别重复请求。

7. 参考资料​