ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

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

上下文装不下以后:Pi Compaction 怎样压缩历史,又会丢掉什么 上下文装不下以后Pi Compaction 怎样压缩历史又会丢掉什么一个 Coding Agent 已经连续工作两小时读过几十个文件尝试过三条修复路线跑了多轮测试还记着用户最早说的“不能改公开 API”。此时上下文接近上限系统自动生成摘要然后继续工作。API 没有再报溢出Agent 却把“不能改公开 API”压成了“保持兼容”把失败方案的原因只记成“测试未通过”又把计划中的迁移写进了 Done。压缩在传输层成功了任务状态却已经发生漂移。这正是 Compaction 最容易被误解的地方它解决的是“下一次模型调用装不下”不是“如何无损保存长期记忆”。Piv0.82.1的实现很适合拆解这条边界因为它同时保留完整 Session、结构化摘要和近期原文也明确暴露 Cut Point、Split Turn、文件轨迹与 Extension Hook。本文只有一条主线Compaction 是有损的上下文投影不可丢的执行状态必须脱离自然语言摘要进入可验证的数据层。一、先把三种状态分开长会话至少包含三个不同对象完整 Session JSONL原始 Entry 与分支仍在磁盘 当前 Context本轮真正发给模型的消息集合 外部执行状态文件、Git、进程、数据库、审批与远端任务Pi 的 Compaction 不会缩小 JSONL也不会回滚外部环境。它在当前分支追加一个compactionEntry后续构建 Context 时先放入 Summary再接上保留的近期消息。因此历史仍存在 ≠ 模型仍逐字看见历史 摘要提到文件 ≠ 模型仍知道文件内容 摘要写成 Done ≠ 工具与环境已经验证完成PI-07 讨论 Session Tree 怎样选择活动路径本篇进一步讨论这条路径过长以后哪些内容被摘要哪些原文继续留下以及损失怎样被发现。二、触发条件其实在分配两种预算固定版本文档给出的自动触发条件是contextTokens contextWindow - reserveTokens默认reserveTokens为 16384keepRecentTokens为 20000。两个参数不能混为一谈reserveTokens给下一次模型输出留空间keepRecentTokens决定压缩后尽量保留多少近期输入原文。系统既可以在估算值接近上限时主动压缩也可以在 Provider 已返回 Context Overflow 后压缩并重试。前者减少失败请求后者处理本地估算与 Provider 真实计数不一致。这种不一致并不罕见。Tool Schema、System Prompt、图片、Provider 包装、Reasoning 字段和缓存计数都可能影响真实占用。把本地 Token 估算当绝对事实会让系统在不同 Provider 上表现不稳定。三、Cut Point 不是“删掉最旧的 80%”Pi 会从最新消息向前累计估算 Token寻找能满足近期预算的合法切点。关键规则是不在 Tool Result 上切开。一个正常 Turn 可能是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默认流程可以还原为六步从当前活动路径构建压缩前 Context并估算占用若已有上一次 Compaction读取其 Summary 与firstKeptEntryId从后向前寻找本轮合法 Cut Point将旧消息转换并序列化为待总结文本生成结构化 Summary追加新的 Compaction Entry用 Summary、从firstKeptEntryId开始的近期消息和压缩后新增消息重建 Context。固定版本的结果核心字段包括interfaceCompactionResult{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并分别处理完整旧 Turn → History Summary 当前超长 Turn 的前缀 → Turn Prefix Summary 切点后的消息 → Recent Raw TailTurn 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中累计已读、已改文件。这有助于跨多轮压缩保留代码范围也能提示接手者从哪里重新核对。但文件轨迹只是索引readFiles → 应优先重新读取的范围 modifiedFiles → 应优先检查 Diff 与版本的范围它既不是内容缓存也不是工作区快照。可靠系统应同时记录文件版本或内容 SHA、Git 基线、测试证据与环境检查点避免把“曾经修改”当成“当前仍正确”。九、文档与默认源码在 retainedTail 上并不完全一致固定 Tag 的session-format.md描述了较新的 Harness-generated CompactionEntry 可以携带retainedTail成为自包含 Checkpoint不再向前读取旧 Entry。但同一 Tag 的默认CompactionEntry类型、compact()返回值和buildContextEntries()主路径仍以firstKeptEntryId为核心源码中没有确认默认创建流程已写入retainedTail。所以本篇采用保守口径firstKeptEntryId是v0.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 AccuracyDone、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。面向长周期工程任务建议拆成三层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 历史也不等于外部环境状态。因此可靠的结论不是“换一个更强模型做摘要”而是让摘要负责解释让结构化状态负责恢复让原始事件负责审计。参考资料Pi v0.82.1 Compaction 文档Pi v0.82.1 Compaction 源码Pi v0.82.1 Shared Summary UtilitiesPi v0.82.1 Session FormatPi v0.82.1 Session Manager
返回列表