压缩是「可选能力」,不属于agent loop主干——这意味着它可能根本没装(极简模式就没有)。装了之后,它的机制是这样的:
| 事件 | 载荷要点 | 作用 |
|---|---|---|
| compaction/start | { turn } | 拿日志锁。数字标识自动轮次,null标识手动 |
| compaction/summary | 摘要、被遮蔽范围与seq、估算token数、模型envelope | 记录摘要与它遮掉了哪一段 |
| compaction/end | { turn, error? } | 释放锁,error表示失败 |
关键设计:这三个事件都不进 surface
官方文档明确写:三者**仅写入日志**,绝不进入surface。也就是说模型看不到「我们刚刚压缩了」这件事。
真正改变模型看到的内容的,是另一步:摘要本身通过一条带 surfaceOp: { op: 'replace', start, end } 的 user/message 承载。这是摘要压缩唯一的surface变更。
这个设计解释了一个常见困惑:为什么压缩之后模型不觉得「自己被压缩过」,而是直接表现得像前面那段历史变了。因为它确实没收到任何「压缩」通知,只收到了一条替换消息。
锁的意义:崩溃可检测
三个事件构成一个锁:start拿锁 → 生成摘要 → 写summary → 写替换消息 → end释放锁。中途崩溃的表现是「有start没有end的遗留锁」——可被检测出来。
反过来,如果先写end再干活,崩溃就会表现成「压缩已完成」,而实际没有。这个细节说明设计者把「崩溃要说实话」当成硬要求。
对你的实际影响
- 压缩之后前面的细节可能只剩摘要:具体数字、文件路径、你纠过的错,未必都留在摘要里。
- 重要约束要重新说一遍,不要指望它跨越压缩还在。
- 需要保真的活分段做:一份长文档的处理,拆成多次短会话,比一次性长会话更可靠。