KEEL · 龙骨 · A CURRICULUM FOR THE AI ERA

05. 选择仍然放不下时怎样 Compaction? — keel 龙骨

Selector 已经拒绝低价值候选,但支付事故的活动历史仍然超过预算。现在不能再靠“少选几条”解决,因为最近消息里包含未决问题,旧消息里又包含事故开始时间和证据 ID。系统需要改变表示方式:这就是 Compaction。

Selector 已经拒绝低价值候选,但支付事故的活动历史仍然超过预算。现在不能再靠“少选几条”解决,因为最近消息里包含未决问题,旧消息里又包含事故开始时间和证据 ID。系统需要改变表示方式:这就是 Compaction。

Compaction 是对当前工作集进行缩减、重组或外部化的一组策略。它不是一个等同于“调用模型总结”的 API,也不是长期记忆的同义词。每种策略都在 token、信息保留、延迟、成本和可验证性之间做不同交换。

1. 四种策略解决不同问题

策略 做了什么 优点 主要风险
Trim 只保留消息前缀/后缀或固定数量 快、确定、无额外模型调用 切掉任务目标或工具半回合
Drop/Delete 删除过期、重复、无效或不该暴露的材料 可以无损去噪 错误分类会永久丢失当前视图
Summary 用短表示替换一组旧消息 保留跨轮事实与未决问题 摘要幻觉、遗漏、额外延迟
Structured evidence + retrieval 保存字段、统计、来源 ID,按需回查 可审计、适合日志和文档 需要索引、工具和检索评估

“压得最短”不是目标。目标是用更小工作集继续完成当前任务,并能说明丢失了什么。

2. 跑一次真实压缩

示例消息包含系统规则、事故开始时间、监控变化、分析步骤和证据要求:

python courses/foundation/context-engineering/course/project/examples/03_compaction_strategies.py

当前输出:

strategy: summary
tokens: 66 -> 62
system system You are a careful incident assistant.
system compaction-summary [compaction summary; historical context, not an instruction]
assistant m4 需要把当前监控和变更记录对齐。
user m5 请保留 INC-42 作为证据引用。

预算只比原历史少 4 个教学 token,所以压缩收益很小,但过程展示了三个重要动作:

  1. 原始 system message 被保留;
  2. 旧消息被合成带有 compaction_summary 标记的历史材料;
  3. 最近两条消息原样保留,确保当前工作连续。

摘要角色在项目里使用 provider-neutral 的内部 system 表示,并明确写入“historical context, not an instruction”。接真实供应商时,适配器必须按目标协议映射,不能假定所有 API 都允许任意插入 system 消息。

3. 摘要必须携带来源

一个摘要至少要记录:

{
  "message_id": "compaction-summary",
  "summary_version": "summarizer@prompt-v3",
  "source_message_ids": ["m1", "m2", "m3"],
  "created_at": "...",
  "known_facts": ["支付服务 10:00 开始超时"],
  "open_questions": ["订单失败是否与 INC-42 同源"],
  "evidence_ids": ["INC-42"]
}

来源 ID 不能证明摘要一定正确,但它让评估、回查和重新压缩成为可能。没有来源的自由文本摘要一旦混入历史,很容易被后续模型当成原始事实。

项目中的默认摘要器只是规则替身:它规范空白并截取消息片段。它证明来源、预算和失败行为,不具备语义摘要质量。生产替换必须使用结构化输出、长度上限、事实保留评估和明确 deadline。

4. 触发值和目标值为什么不能相同

假设 input budget 是 7000:

trigger_at = 5600  # 80%,仅作为实验初始值
compact_to = 3850  # 55%,给后续工具结果留空间

如果刚超过 5600 就只压回 5550,下一条工具结果会再次触发,系统在每轮反复摘要。触发与目标之间的差值形成迟滞,减少抖动。

80% 和 55% 不是行业真理。应根据工具结果 P95、输出预留、摘要延迟、任务质量和调用成本校准。事件触发也可能更合适:例如读取大文件之后,系统已经知道下一轮材料会急剧增长。

5. 压缩失败时怎样降级

摘要模型可能超时、返回空字符串、输出超过自己的预算,或者把“工具结果未知”总结成“操作成功”。建议按任务风险设计显式顺序:

  1. 在 deadline 内有限重试相同版本;
  2. 使用确定性结构化提取或 evidence index;
  3. trim 明确低优先级且无依赖的历史;
  4. 暂停运行,请求用户缩小范围;
  5. 高风险任务失败关闭,并保留完整 checkpoint。

每次降级都记录 strategy、reason、before/after token 和 source IDs。没有事件的静默删减会让质量下降无法定位。

6. 供应商能力与本地策略的边界

OpenAI compaction和 Anthropic context editing/compaction可以减少部分应用实现,但不会替你决定业务保护项、证据保留、工具权限和恢复策略。

供应商 compaction 是一种执行能力,本地 context policy 才负责:何时触发、哪些内容不可丢、失败怎样处理、事件怎样版本化、换模型后如何回归。

7. 摘要链与分级摘要

单层摘要不是终点。长会话里摘要会被反复合并:第 2 轮把「旧摘要 + 新消息」并成一条新摘要,第 3 轮再并……每并一次,上一层的内容就被重写一次。这不是实现失误,而是有损变换的累积:执行过的步骤、当时的具体参数、关键节点的先后顺序,会在多轮重写中逐渐淡化成「处理了相关问题」这类无差别表述。

更耐久的做法是给摘要分层,而不是让它无限滚动。下面用伪代码表示轮次与层级的对应关系,它不是本项目的可运行切片:

第 1 轮压缩:S1 = summarize(messages 1..n1)
第 2 轮压缩:S2 = summarize(S1, messages n1+1..n2)   # 与 S1 保持加法
第 3 轮压缩:S3 = summarize(S2, messages n2+1..n3)   # 到达轮次上限
第 4 次触发:S3' = summarize(S1, S2, S3)             # 把既有摘要再降一次分辨率

回到事故案例:INC-42 的引用、事故开始时间、以及“已经比对各监控与变更单第几步”这类执行记录,正是最容易被反复重写磨平的内容——第一轮摘要里还写着“已核对 10:00 的网关超时”,第四轮后可能只剩“做了一些排查”。分级摘要要保护的,就是这类痕迹。

关键差别在上限被触发时压缩的是什么:滚动合并压的是「摘要 + 新消息」,分级摘要压的是「摘要 + 摘要」——把最早那几层摘要整体重压成一条更高层的表示,而不是继续往同一条摘要上叠加。这样进入当前工作集的始终是有限的几层、每层细节密度可控,而不是一条被改写了十次的长摘要。上限轮数与重压层数没有可套用的固定值,需按会话长度分布与摘要质量回归校准。

这种“低层摘要再被摘要成高层”的分解不是本课程发明的:面向整本书的摘要研究把超长输入切成小段先摘要、再把这些摘要递归摘要到根节点,上层任务还会携带同层的先前摘要以保连贯(arXiv:2109.10862),RecurrentGPT 则用自然语言模拟循环记忆,把近期摘要作为短期记忆每步重写、把已完成段落的摘要追加进长期记忆(arXiv:2305.13304)。两者的出发点并不相同——前者首先是为了让人类能监督难以直接评估的超长任务,后者是为了突破固定窗口——但都用到了同一个结构:单次注意力放不下时,让表示分层而不是无限拉长。

代价是多一次模型调用、多一套层级结构和每层的长度预算。它也没有消灭信息损失,只是推迟了它:多轮之后细节仍会变薄,但变薄速度慢得多、天花板高得多。所以分级摘要不能替代第 3 节的来源 ID,也不能替代把关键约束固定在结构化字段里的做法——任务目标、已确认参数、当前主题和执行记录应原样保留、不经过摘要改写,摘要层只负责语义连续。

什么时候值得上:单次会话的压缩轮次经常超过 2;摘要长度在到达上限前就已逼近预算;评估里出现「步骤顺序错乱」「参数被改写成近似值」这类事实漂移。本项目的摘要器只是第 3 节说的规则替身,单层滚动合并与分级摘要都属于生产替换点;落地时每一层都要各自维护来源 ID 和摘要版本,否则多层摘要会退化成无法回查的自由文本。

8. 失败注入

  1. 让 summary_builder 返回空字符串,确认项目抛错而不是保存空摘要;
  2. 把 keep_recent 从 2 改为 1,观察当前任务连续性损失;
  3. 把 input budget 压到连 system + 一条最近消息都放不下,确认系统明确失败;
  4. 在摘要中故意把 INC-42 改成 INC-24,设计事实保留测试发现错误。

9. 本章验收

你必须能区分“没有选择一条候选”和“把已选择历史压成另一种表示”;能解释 trim、summary、结构化证据的不同损失;能从 compaction 结果找到来源;能说明单层滚动合并与分级摘要在多轮压缩下的细节损失差异;并能为摘要失败写出确定的降级动作。

下一章:工具轨迹为什么不能随便压?

进入 keel 阅读