Pi Agent 101|06|Context Compaction
Pi 把 compaction 设计成 session tree 上的结构性 checkpoint,而不是简单删除旧消息。
先说人话:模型的“记忆窗口”有限,长任务迟早装不下。
最粗暴的办法是删掉旧消息。Pi 没这么做。它更像在长篇笔记里夹一张摘要卡:前面的细节还在档案里,但这一轮模型先看摘要和最近发生的事。
长任务一定会遇到上下文上限。最直接的做法是删旧消息,但这会破坏审计历史,也容易切断 tool call / tool result 结构。Pi 的 compaction 更像一次结构性 checkpoint:在 session tree 里追加一条 compaction entry,完整历史保留,当前模型上下文变短。

这张图要表达的是 checkpoint,而不是删除。上下文变长后,runtime 不能简单把旧消息裁掉;它要在安全位置生成摘要,保留关键事实,再让后续上下文从这个 checkpoint 继续。
安全位置很重要。不能留下 tool result 却切掉对应的 tool call,也不能丢掉当前文件工作集、失败测试、已经尝试过的方案和用户明确要求。压缩不是省 token 的小技巧,而是长任务的状态管理。
给基础读者的慢速版地图
模型的上下文窗口不是无限的。任务越长,历史越多,最后一定会放不下。压缩不是删除历史,而是把早期过程整理成一份能继续工作的摘要,再保留最近最重要的原文。它像把一大摞工作记录整理成“项目进展卡”。
下面不再把图集中堆在开头,而是把图放到真正需要的位置:概念边界、流程、状态结构、失败模式和产品判断。这样读者看到图时,正好能对应正在解释的问题。
读完这一篇,你应该能看懂什么
- 理解 compaction entry 如何改变当前模型视图
- 区分阈值压缩和 overflow 恢复
- 看清为什么压缩不能只按 token 截断
先把问题说清楚
读图说明:压缩不是优化小技巧,而是长任务继续运行的必要条件。
Pi 的 compaction 包含 summary、firstKeptEntryId、tokensBefore、details、fromHook 等信息。恢复上下文时,SessionManager 会把最新 compaction 转成一条 compactionSummary message,然后从 firstKeptEntryId 开始保留近期消息。
这意味着原始 session 文件没有被删除;只是当前 LLM context 不再包含完整旧历史。
和主流产品怎么对应
你用 Claude Code、Codex CLI 或 Cursor 做长任务时,都会遇到上下文压力:文件读多了,测试跑多了,工具输出堆多了,模型窗口迟早不够用。
产品通常不会把所有旧内容永远塞给模型。它们会保留一部分最近上下文,把更早的过程压成摘要。OpenClaw 这类长会话系统也一样:不同 channel 里持续对话,agent 又不断调用工具,最后一定需要 compaction 或类似机制。
放到修测试这个例子里
读图说明:摘要要保留可行动状态,而不是只写聊天大意。
修复失败测试跑久了,很容易把上下文撑满:读过的文件、失败日志、修改记录、重跑结果都在堆。模型下一轮真正需要的,不是从头到尾的每一行输出,而是“改过哪些文件、最近一次失败是什么、哪些假设已经排除”。
Compaction 要做的就是这件事。旧过程还留在 session 里,但给模型看的工作视图变短。尤其是测试命令和结果,不能把 tool call 留下、tool result 切掉;否则模型会看到一段断掉的现场记录。
压缩触发:预防与恢复
读图说明:压缩既可以提前预防,也可以在上下文溢出后恢复。
Pi 有两类自动压缩。第一类是阈值压缩:当上下文 token 接近窗口上限时,先压缩,避免下一轮失败。第二类是 overflow 恢复:provider 已经报上下文溢出,runtime 压缩后自动 retry,但要有保护,避免无限重试。
这很适合迁移:context overflow 不是普通异常,而是 agent runtime 的控制信号。
Cut point 不能随便选
读图说明:切点不能破坏工具调用与结果的配对关系。
压缩不能只按 token 砍一刀。tool result 必须跟在对应 tool call 后面;一个 turn 中间被切开时,要生成 turn prefix summary,避免保留的后半段失去上下文。
Compaction summary 通常不是纯规则拼接出来的。Pi 会准备一段待压缩历史,调用模型生成自然语言摘要,同时用规则方式跟踪读过和改过的文件,把 read-files 和 modified-files 一类结构化工作集放进 summary。也就是说,压缩本身也会消耗一次模型调用、token 和时间。
这也是为什么 compaction 不能太频繁。好的策略要在“继续塞原始历史的成本”和“额外做一次 summary 的成本”之间取平衡。对 coding agent 来说,自然语言摘要负责保留推理脉络,结构化文件工作集负责保留可执行状态,两者缺一都容易漂。
如果 summary 生成失败,也不能把 session 带崩。可恢复的策略通常是:保留原始历史不动,记录一次 compaction failure,降低本轮上下文或提示用户手动处理;如果是 overflow recovery,则最多 retry 一次,避免在“溢出 -> 压缩失败 -> 再溢出”的循环里空转。
压缩之后,模型上下文会少掉很多原始细节:旧的完整对话、长命令输出、已经不重要的中间推理、重复的工具结果。保留下来的,是摘要、最近消息、仍然相关的文件工作集,以及不能破坏协议结构的 tool call / tool result 配对。
这最后一点很关键。压缩不能在任意 token 位置切一刀。如果留下一个 tool result,却切掉了对应的 tool call,模型下一轮看到的上下文就是坏的。好的 compaction 要像整理施工记录:可以省略废话,但不能把“谁下的命令”和“命令结果”拆散。
可迁移的边界
如果自己做 harness,compaction 不应该等同于“删掉旧消息”。更好的方式是追加一个 checkpoint:记录摘要、保留哪些关键事实、从哪里继续,以及为什么压缩。这样既能控制上下文长度,也不会破坏审计历史。
压缩摘要应该保留什么
读图说明:好摘要像项目交接卡,能让模型下一轮继续工作。
对 coding agent 来说,好的摘要不是“前面聊了很多,我们继续”。它应该保留任务目标、当前判断、关键文件、已经执行过的命令、失败原因、用户约束、未完成事项,以及哪些路径已经尝试过。
如果摘要太短,模型下一轮会重复犯错;如果摘要太长,压缩失去意义;如果摘要只保留自然语言判断,不保留文件工作集和工具结果,后续修复会失去抓手。
为什么 compaction 需要可观测
用户通常看不到完整 prompt,但应该能知道系统什么时候压缩过、为什么压缩、压缩后是否继续成功。否则长任务中出现奇怪行为时,用户无法判断是模型变差、工具失败,还是上下文被压缩坏了。
这也是为什么 compaction 和 Observability 有关系。压缩动作本身应该成为 session 里的一个事件,而不是静默发生的内部优化。
这里的取舍
- 取舍:历史处理
- Pi 的倾向:append compaction entry
- 可迁移原则:不要删除审计历史
- 取舍:触发策略
- Pi 的倾向:threshold + overflow
- 可迁移原则:预防性和恢复性压缩分开
- 取舍:Cut point
- Pi 的倾向:避免破坏 tool 协议
- 可迁移原则:压缩要维护消息结构不变量
- 取舍:Summary
- Pi 的倾向:自然语言 + 文件工作集
- 可迁移原则:coding agent 摘要要保留结构化状态
- 取舍:扩展
- Pi 的倾向:session_before_compact hook
- 可迁移原则:领域压缩可由扩展接管
如果你在读 OpenClaw
如果你在读 OpenClaw,这一篇对应长会话的 token 压力和 transcript 压缩。OpenClaw 场景里,用户可能通过不同 channel 长时间对话,agent 还会调用工具。不能简单删历史,需要把旧过程压成仍然可用的摘要。
源码里真正能看到的压缩边界
Pi 的压缩不是把旧消息删掉,而是在当前分支上追加一条 checkpoint。这个 checkpoint 记录旧上下文摘要、压缩前 token 情况、从哪条记录开始保留原文,以及文件读写等关键细节。
后续构造模型上下文时,Pi 会先放入压缩摘要,再放入近期保留的原始消息。旧历史仍然在 session 里,但不再完整进入模型窗口。也就是说,压缩改变的是“模型这一轮看到什么”,不是删除历史。
切点也不能随便选。工具调用和工具结果有协议关系,不能留下 tool result 却切掉对应 tool call。Pi 会从当前路径尾部向前找合适位置,尽量保留近期内容,同时避免破坏消息结构。
压缩摘要不是普通总结
对 coding agent 来说,好的压缩摘要要保留状态,而不仅是聊天大意。它应该告诉模型:目标是什么,用户约束是什么,已经读过哪些文件,修改过哪些文件,测试失败在哪里,尝试过哪些方案,接下来应该从哪里继续。
如果摘要只写“我们正在修 bug”,模型会失去现场;如果摘要保留太多细节,又省不了上下文。Context Compaction 真正考验的是:如何把长任务压缩成下一轮仍然可行动的工作状态。
这也是它和 Session Tree 的关系:树保存完整历史,compaction 改变当前路径的模型视图。
阅读时可以用的三问
第一,压缩发生在任务前、中、后哪个位置。不同位置对应不同风险:任务前可以预防溢出,任务中要小心破坏 tool protocol,任务后要能继续恢复。
第二,摘要保留的是结论还是状态。coding agent 更需要状态:当前文件、失败测试、已尝试方案、未完成目标和用户约束。
第三,压缩动作是否可见。用户不一定要读完整摘要,但应该知道系统压缩过,以及压缩是否改变了后续运行。
如果只记住一句话
压缩不是删历史,而是给模型换一份更短的工作摘要。
小结
Pi 的 Context Compaction 不是“把旧对话总结一下”这么简单。它是 session tree 上的 checkpoint 机制:完整历史继续存在,模型视图被重建,结构化工作集被保留,overflow 可以被恢复。