上下文装不下以后:Pi Compaction 怎样压缩历史,又会丢掉什么

上下文装不下以后:Pi Compaction 怎样压缩历史,又会丢掉什么

一个 Coding Agent 已经连续工作两小时:读过几十个文件,尝试过三条修复路线,跑了多轮测试,还记着用户最早说的"不能改公开 API"。此时上下文接近上限,系统自动生成摘要,然后继续工作。

API 没有再报溢出,Agent 却把"不能改公开 API"压成了"保持兼容",把失败方案的原因只记成"测试未通过",又把计划中的迁移写进了 Done。压缩在传输层成功了,任务状态却已经发生漂移。

这正是 Compaction 最容易被误解的地方:它解决的是"下一次模型调用装不下",不是"如何无损保存长期记忆"。Pi v0.82.1 的实现很适合拆解这条边界,因为它同时保留完整 Session、结构化摘要和近期原文,也明确暴露 Cut Point、Split Turn、文件轨迹与 Extension Hook。

本文只有一条主线:Compaction 是有损的上下文投影;不可丢的执行状态必须脱离自然语言摘要,进入可验证的数据层。

一、先把三种状态分开

长会话至少包含三个不同对象:

text 复制代码
完整 Session JSONL:原始 Entry 与分支仍在磁盘
当前 Context:本轮真正发给模型的消息集合
外部执行状态:文件、Git、进程、数据库、审批与远端任务

Pi 的 Compaction 不会缩小 JSONL,也不会回滚外部环境。它在当前分支追加一个 compaction Entry,后续构建 Context 时先放入 Summary,再接上保留的近期消息。

因此:

text 复制代码
历史仍存在 ≠ 模型仍逐字看见历史
摘要提到文件 ≠ 模型仍知道文件内容
摘要写成 Done ≠ 工具与环境已经验证完成

PI-07 讨论 Session Tree 怎样选择活动路径;本篇进一步讨论这条路径过长以后,哪些内容被摘要,哪些原文继续留下,以及损失怎样被发现。

二、触发条件其实在分配两种预算

固定版本文档给出的自动触发条件是:

text 复制代码
contextTokens > contextWindow - reserveTokens

默认 reserveTokens 为 16384,keepRecentTokens 为 20000。两个参数不能混为一谈:

  • reserveTokens 给下一次模型输出留空间;
  • keepRecentTokens 决定压缩后尽量保留多少近期输入原文。

系统既可以在估算值接近上限时主动压缩,也可以在 Provider 已返回 Context Overflow 后压缩并重试。前者减少失败请求,后者处理本地估算与 Provider 真实计数不一致。

这种不一致并不罕见。Tool Schema、System Prompt、图片、Provider 包装、Reasoning 字段和缓存计数都可能影响真实占用。把本地 Token 估算当绝对事实,会让系统在不同 Provider 上表现不稳定。

三、Cut Point 不是"删掉最旧的 80%"

Pi 会从最新消息向前累计估算 Token,寻找能满足近期预算的合法切点。关键规则是:不在 Tool Result 上切开。

一个正常 Turn 可能是:

text 复制代码
User
→ Assistant 发起 read
→ Tool Result
→ Assistant 发起 edit
→ Tool Result
→ Assistant 解释结果

如果保留 Tool Result 却丢掉对应 Tool Call,模型无法知道结果来自哪里;如果只保留 Tool Call,则会把已经完成的调用误认为没有结果。固定实现允许在用户消息或 Assistant 消息处切分,并让 Assistant 后续的 Tool Result 一起进入保留区。

这说明 Cut Point 的目标不是得到最精确的 Token 数,而是保护消息关系。自研 Harness 若只按数组长度或字符数截断,很容易制造孤立调用、失去来源的结果和错误的执行状态。

四、正常压缩怎样形成下一轮 Context

默认流程可以还原为六步:

  1. 从当前活动路径构建压缩前 Context,并估算占用;
  2. 若已有上一次 Compaction,读取其 Summary 与 firstKeptEntryId
  3. 从后向前寻找本轮合法 Cut Point;
  4. 将旧消息转换并序列化为待总结文本;
  5. 生成结构化 Summary,追加新的 Compaction Entry;
  6. 用 Summary、从 firstKeptEntryId 开始的近期消息和压缩后新增消息重建 Context。

固定版本的结果核心字段包括:

typescript 复制代码
interface CompactionResult {
  summary: string;
  firstKeptEntryId: string;
  tokensBefore: number;
  estimatedTokensAfter?: number;
  usage?: Usage;
  details?: unknown;
}

反复压缩时,新摘要会携带旧 Summary,并吸收这一轮新增的旧消息。这样不必每次重新处理 Session 最早部分,但也形成"摘要的摘要":第一次漏掉的约束,第二次往往没有原文可以补回。

五、一个 Turn 自己就超长时,必须处理 Split Turn

最难的场景不是有很多轮对话,而是单个 User Turn 里连续读取仓库、运行命令和处理巨量日志,直到近期预算也装不下。

此时 Cut Point 可能落在 Assistant 消息处。Pi 将其标为 Split Turn,并分别处理:

text 复制代码
完整旧 Turn → History Summary
当前超长 Turn 的前缀 → Turn Prefix Summary
切点后的消息 → Recent Raw Tail

Turn Prefix Summary 被要求保留 Original Request、Early Progress,以及理解后缀所需的 Context。否则,保留区可能只剩几段 Tool Result,却没有用户为什么发起任务、前面做过什么和当前结果对应哪一步。

这是一条很有工程价值的规则:保留近期 Token 不等于保留近期语义。只要切点进入一个尚未结束的 Turn,就必须为尾部补上可解释的前缀状态。

六、结构化 Summary 仍不是事实数据库

默认摘要包含 Goal、Constraints & Preferences、Progress、Key Decisions、Next Steps、Critical Context,以及 <read-files><modified-files>

结构化格式能降低遗漏率,也便于后续程序读取,但不会让模型输出自动变真。Summary 仍可能:

  • 把计划写成 Done;
  • 丢掉"不要""除非""仅限"等否定条件;
  • 合并来自用户、源码和模型推断的不同结论;
  • 记住文件路径,却忘记关键函数和精确错误;
  • 把 UNKNOWN 改写成已确认。

文件列表尤其容易制造安全感。知道曾读过 src/auth.ts,不等于仍知道其当前内容;知道修改过它,也不等于工作区仍处于当时版本。继续任务前,关键文件仍应重新读取,Git Diff 与测试状态仍应重新验证。

七、序列化阶段已经主动丢弃一部分内容

Pi 在摘要调用前先将 Agent Message 转成模型消息,再由 serializeConversation() 变成带标签的文本,例如 [User][Assistant thinking][Assistant tool calls][Tool result]。这样可把历史声明为待处理数据,而不是让总结模型直接续写原对话。

一个不能忽略的固定实现细节是:Tool Result 在序列化时最多保留 2000 个字符,超出部分被替换为截断提示。

因此,日志或大型文件的关键证据若位于 2000 字符之后,可能在 Summary 模型看到之前就已经消失。Prompt 边界也不能消除注入风险;旧文件和 Tool Result 中的恶意指令仍属于不可信输入。

生产实现至少应做到:

  • 对外部文本标记信任来源;
  • 由程序写入错误码、退出码、测试结论和产物 SHA;
  • 对摘要执行 Schema 与状态一致性检查;
  • 对关键约束做压缩前后回归,而不是只检查 Summary 非空。

八、文件轨迹与迭代摘要解决了什么,又没解决什么

默认 Compaction 和 Branch Summary 会从 Tool Call 以及上一轮 details 中累计已读、已改文件。这有助于跨多轮压缩保留代码范围,也能提示接手者从哪里重新核对。

但文件轨迹只是索引:

text 复制代码
readFiles → 应优先重新读取的范围
modifiedFiles → 应优先检查 Diff 与版本的范围

它既不是内容缓存,也不是工作区快照。可靠系统应同时记录文件版本或内容 SHA、Git 基线、测试证据与环境检查点,避免把"曾经修改"当成"当前仍正确"。

九、文档与默认源码在 retainedTail 上并不完全一致

固定 Tag 的 session-format.md 描述了较新的 Harness-generated Compaction:Entry 可以携带 retainedTail,成为自包含 Checkpoint,不再向前读取旧 Entry。

但同一 Tag 的默认 CompactionEntry 类型、compact() 返回值和 buildContextEntries() 主路径仍以 firstKeptEntryId 为核心,源码中没有确认默认创建流程已写入 retainedTail

所以本篇采用保守口径:

  • firstKeptEntryIdv0.82.1 默认源码可确认的机制;
  • retainedTail 是固定版本文档描述的更新或兼容方向;
  • 没有进一步 Commit 与调用链证据,不能把文档描述升级为该 Tag 默认 Runtime 已完整使用。

这不是文档挑错,而是源码研究的基本方法:文档、类型、创建路径、读取路径与测试必须形成同一条证据链。

十、Compaction 自己也有成本

Summary 不是免费的本地压缩。它会增加输入、输出、延迟、Provider 成本和失败重试。固定源码将摘要调用隔离到新的 Routing Session,并在支持时关闭 Prompt Cache Write,因为一次性历史通常难以复用。

摘要最大输出预算受 reserveTokens 与模型最大输出共同限制:普通 History Summary 约取 min(0.8 × reserveTokens, model.maxTokens),Split Turn Prefix 约取 min(0.5 × reserveTokens, model.maxTokens)

调大 reserveTokens 可能提高摘要表达空间,也会减少主 Context 可用区并影响成本。成熟配置应同时观察压缩频率、摘要费用、延迟、Continuation Success 和约束召回,而不是只追求"再也不 Overflow"。

十一、怎样验收一次压缩

只检查"成功追加 Compaction Entry"远远不够。至少需要五类指标:

指标 要回答的问题
Constraint Recall 用户限制、禁止项和输出合同保留了多少?
Decision Fidelity 关键决策、理由和反方是否仍准确?
Execution State Accuracy Done、In Progress、Blocked 是否与 Tool Event 一致?
Artifact Coverage 已读、已改、已创建产物及版本是否可定位?
Continuation Success 只看 Summary 与 Recent Tail,下一步能否做对?

最有价值的测试是同任务对照:一条路线保留原始长 Context,另一条只使用压缩 Context,再比较下一步 Tool Call、约束违反、重复读取、错误率和最终产物。

Batch 08 的 Fixture 只能证明给定 JSONL 按规则投影出 compaction + retained messages,状态为 PASS-SPEC-NOT-RUNTIME。它没有运行真实 Pi,也不能证明 Summary 质量、成本或继续执行成功。

十二、生产 Harness 应把摘要拆成三层

Pi Extension 可以在 session_before_compact 查看 Preparation、取消压缩或提供自定义结果。这为更强的状态系统留下了入口,但目标不应只是换一个更长的 Prompt。

面向长周期工程任务,建议拆成三层:

text 复制代码
Immutable Event Log
  原始消息、Tool Event、退出码、审批、外部副作用引用

Structured Working State
  goal、constraints、done、pending、blocked、artifacts、claims、versions

LLM Narrative Summary
  为模型解释背景、决策关系和近期路线

Context Builder 再将 Structured State、Narrative Summary 与 Recent Raw Messages 组合给模型。这样即使自然语言摘要漏掉细节,关键约束、产物 SHA、验证等级和审批状态仍可由程序恢复。

更重要的是,Structured State 不能完全由同一个总结模型自产自证。完成状态应来自 Tool Event,文件状态来自实际字节或 Git,远端任务来自 API,事实边界来自 Claim Ledger,用户授权来自独立 Gate。

结论

Pi Compaction 的价值不是把聊天"写短",而是在固定预算里构造下一次模型调用的工作集:它寻找合法 Cut Point,总结旧历史,在超长 Turn 中补充 Prefix Summary,保留近期原文,并把结果追加回完整 Session。

它的限制同样明确:Summary 有损,多代摘要会累积误差,Tool Result 可能在序列化前截断,文件列表不等于文件内容,Session 历史也不等于外部环境状态。

因此,可靠的结论不是"换一个更强模型做摘要",而是:让摘要负责解释,让结构化状态负责恢复,让原始事件负责审计。

参考资料

  1. Pi v0.82.1 Compaction 文档
  2. Pi v0.82.1 Compaction 源码
  3. Pi v0.82.1 Shared Summary Utilities
  4. Pi v0.82.1 Session Format
  5. Pi v0.82.1 Session Manager
相关推荐
科技风向标go2 小时前
2026户外太阳能监控怎么选不踩坑?户外(格行AOV+黑光)、工程(海康大华)、生态(小米萤石)——三大派系技术路线全解析
大数据·人工智能·智能家居·监控·户外安防
菜冻鱼2 小时前
Python-sklearn-特征工程
开发语言·人工智能·python·机器学习·numpy·matplotlib·sklearn
FlyWIHTSKY2 小时前
什么是ai智能体,智能体都有哪些部分组成,有那些实现框架
人工智能
环球科讯2 小时前
金融赋能焕新居——建行广东江门分行启动家装补贴季助力消费升温
大数据·人工智能·物联网
手写码匠2 小时前
华为云Flexus+DeepSeek征文|Agent 评测体系实战:用 DeepSeek-R1 当裁判,打造 Dify Agent 的自动化回归测试流水线
人工智能·深度学习·算法·aigc
用户298698530142 小时前
效率工具分享:3 款免费 Markdown 转 Word 在线转换器
人工智能·后端
河南博为智能科技有限公司2 小时前
配电站房智能辅控一体化监控方案——基于壁挂式边缘计算网关,实现无人值守!
人工智能·边缘计算
2601_962860152 小时前
智慧城市企业 2027 排期:LEAP East 香港站同时验证亚太与沙特需求
人工智能·智慧城市
2401_865261633 小时前
亦唐科技(YIKTANG):创新引领国产贴片机发展,稳居行业领军地位
大数据·人工智能·物联网