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,所以压缩收益很小,但过程展示了三个重要动作:
- 原始 system message 被保留;
- 旧消息被合成带有
compaction_summary标记的历史材料; - 最近两条消息原样保留,确保当前工作连续。
摘要角色在项目里使用 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. 压缩失败时怎样降级
摘要模型可能超时、返回空字符串、输出超过自己的预算,或者把“工具结果未知”总结成“操作成功”。建议按任务风险设计显式顺序:
- 在 deadline 内有限重试相同版本;
- 使用确定性结构化提取或 evidence index;
- trim 明确低优先级且无依赖的历史;
- 暂停运行,请求用户缩小范围;
- 高风险任务失败关闭,并保留完整 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. 失败注入
- 让
summary_builder返回空字符串,确认项目抛错而不是保存空摘要; - 把
keep_recent从 2 改为 1,观察当前任务连续性损失; - 把 input budget 压到连 system + 一条最近消息都放不下,确认系统明确失败;
- 在摘要中故意把
INC-42改成INC-24,设计事实保留测试发现错误。
9. 本章验收
你必须能区分“没有选择一条候选”和“把已选择历史压成另一种表示”;能解释 trim、summary、结构化证据的不同损失;能从 compaction 结果找到来源;能说明单层滚动合并与分级摘要在多轮压缩下的细节损失差异;并能为摘要失败写出确定的降级动作。