上下文压缩与会话分支
在长会话中,LLM 的上下文窗口有限。Pi 通过 上下文压缩(compaction) 将历史消息摘要化,从而释放 token 空间。同时,Pi 支持会话分支(fork),每个分支可以独立演化,分支摘要则帮助用户理解被放弃的路径。本文基于 Pi v0.79.10。
什么是上下文压缩?
当会话越来越长时,Pi 会把较早的消息交给一个" summarizer 模型",生成一段摘要,然后用摘要替换掉原始消息。这样:
- 保留关键上下文
- 释放大量 token
- 让长会话能继续推进
压缩并不是把所有历史都丢掉,而是保留一个后缀(suffix):最近的几轮对话保持完整,只有更早的部分被摘要替换。
压缩触发时机
有三种情况会触发压缩:
v0.79.10 在 compaction 相关事件中新增了 reason 和 willRetry 字段,扩展可以通过这两个字段区分不同场景。
核心数据流
prepareCompaction:找到切割点
文件:packages/coding-agent/src/core/compaction/compaction.ts
CompactionPreparation 字段
compact:生成摘要
文件:packages/agent/src/harness/compaction/compaction.ts
generateSummary() 会把 messagesToSummarize 序列化成文本,然后调用 summarizer 模型生成摘要。
AgentSession 中的压缩事件
文件:packages/coding-agent/src/core/agent-session.ts
手动压缩
自动压缩
事件字段
扩展钩子:session_before_compact / session_compact
扩展可以监听压缩事件,提供自定义摘要或执行额外逻辑。
session_before_compact
session_compact
v0.79.10 新增 reason 和 willRetry 后,扩展可以:
- 对
overflow做更激进的摘要策略 - 对
manual展示不同的 UI 反馈 - 在
willRetry = true时保存临时状态
会话分支与分支摘要
Pi 的会话是树形结构,每次用户回复都会形成新的节点。/fork 可以从历史任意消息创建新分支。
分支结构
分支摘要
当一个分支被放弃(例如 fork 出去但不再访问),Pi 可以为其生成摘要,帮助用户理解这条分支上发生了什么。
文件:packages/agent/src/harness/compaction/branch-summarization.ts
分支摘要的结果会包含:
summary:分支内容的文字摘要readFiles:分支中读取过的文件modifiedFiles:分支中修改过的文件
会话格式:JSONL
文件:packages/coding-agent/src/core/session-manager.ts
Pi 的会话是每行一条 JSON 的格式(JSONL):
用 JSONL 的好处:
- 流式写入:不需要等会话结束才写文件
- 崩溃恢复:即使进程崩溃,已写入的行仍然有效
- 增量读取:可以继续附加,不需要重写整个文件
- 大文件友好:不需要一次性加载到内存
设计要点
- 压缩不是删除历史:原始消息仍保存在 session 文件中,只是从 LLM 上下文中移除。
- 保留后缀:最近的几轮对话保持完整,避免丢失当前工作上下文。
- overflow 自动重试:遇到上下文溢出时,Pi 会移除错误消息、压缩、然后自动继续。
- threshold 不自动重试:仅提示用户上下文已压缩,由用户决定是否继续。
- 扩展可自定义摘要:通过
session_before_compact提供自己的摘要逻辑。
下一步
- 核心架构与设计哲学 — 回到高层设计模式
- pi-ai:Models 运行时与 Provider 架构 — 压缩调用的 summarizer 模型如何被调用

