Pi 中压缩的工作原理
摘要
本文解释了 Pi 编码代理中压缩的工作原理,即在上下文窗口接近限制时对旧对话历史进行总结,并详细介绍了 Pi 的具体实现和触发条件。
暂无内容
查看缓存全文
缓存时间: 2026/08/13 21:22
# Pi 中压缩的工作原理 | EARENDIL
来源:https://earendil.com/posts/compaction-in-pi/
如果你曾在像 [Pi](https://pi.dev/)、Claude Code 或 Codex 这样的编码代理中进行过一次长时间的编码会话,你一定会触发压缩(compaction)。在这篇文章中,我们将解释压缩的工作原理,以及 Pi 何时需要压缩。
## LLM 对话
大型语言模型(LLM)的[上下文窗口](https://en.wikipedia.org/wiki/Context_window)是有限的。上下文窗口就是模型在生成响应时能够“看到”的内容。LLM 所使用的 [Transformer 架构](https://en.wikipedia.org/wiki/Transformer_(deep_learning)) 限制了它们能处理的输入量。编码代理会话的输入包括所有先前的消息和工具调用,而这些内容会随着你的工作不断增多。一旦超出上下文窗口,LLM 就会拒绝请求。
当与像 Pi 这样的编码代理进行交互式协作时,代理会向 LLM 发送请求并接收响应。每个请求都包含系统提示、加载的文件(如 [AGENTS.md](https://agents.md/))、工具定义以及对话历史。
编码代理的第一次 LLM 请求包含这个初始上下文,以及第一条用户消息。
```
request 1:
[system][tools][user]
```
这会开启一个回合(turn)。LLM 可能首先返回包含工具调用的助手消息。代理程序执行这些调用,并向 LLM 发送一个新的请求,其中包含完整的对话,现在还包括工具结果。我们会得到另一条助手消息。当助手完成生成输出后,这个回合才算结束。
```
request 1 之后:
[system][tools][user][assistant: tool call][tool result][assistant]
<-------------------> ^ <--------->
由 LLM 返回 | 由 LLM 返回
|
由代理生成
```
我们继续工作,再发送一条消息。
```
request 2:
[system][tools][user][assistant: tool call][tool result][assistant][user]
^
新的用户消息
```
每个回合都会扩展对话。最终,历史记录会超过上下文限制。下一个请求会返回类似 `Request exceeds the maximum size` 的错误。
```
[system][tools][user][assistant][....][tool result][user]
^
超出上下文窗口
```
## 处理上下文溢出
当我们无法按原样继续现有对话时,有两个选择。
1. 我们可以开始一个全新的空对话,不带任何累积的上下文。这会丢弃历史记录,包括先前做出的决定和未完成的工作。这仍然可能是一个好主意,因为 LLM 输出的性能会随着上下文规模的增长而下降(https://www.trychroma.com/research/context-rot)。
2. 我们可以创建对话上下文的更精简表示,因为我们想让这段对话继续进行。这就是压缩(compaction)的作用。
## 压缩
理论上,实现压缩有很多种方法。例如,我们可以编写一个确定性函数,保留对话中的部分内容并丢弃其余部分。不过在实践中,压缩的实现通常使用一个 LLM 请求来总结对话历史。
压缩会用一种经过压缩的表示来替换部分历史记录,从而为额外的消息和工具调用腾出空间。
```
[system][tools][compaction result][user]
^
新的消息
```
## Pi 的实现
让我们更仔细地看看 Pi 具体是如何实现压缩(compaction)的(https://pi.dev/docs/latest/compaction#summary-format)。
当对话变得过长时,Pi 会使用压缩来总结较早的内容,同时保留近期的工作。当上下文限制接近上下文窗口的总大小时,就会触发自动压缩。你也可以使用 `/compact` 命令手动触发压缩。
Pi 会在一个回合结束后检查是否需要进行自动压缩。在此之前,每个请求都会扩展现有的提示(prompt),并且可以复用其缓存前缀。如果 Pi 遇到上下文溢出错误,它也可能会在回合中途进行压缩。
压缩时,Pi 会保留若干条最近的消息不变。
```
压缩前:
[system + tools][older turns][recent retained messages]
```
保留的消息数量并不固定,因为 Pi 使用可配置的 token 预算(https://pi.dev/docs/latest/compaction#when-it-triggers)。Pi 当前默认的 2 万个 token 大约相当于 5 到 20 个回合。在这个截断点之前的所有消息都会被提取并序列化,然后进行总结。
## Pi 的压缩提示(Compaction Prompt)
对于编码代理来说,一个好的总结的理想效果,就像是交接班时的简报。Pi 的压缩提示关注这样一个事实:现有上下文中有很多内容已经不再相关。我们应该只保留对下一次 LLM 请求仍然重要的上下文。
因此,Pi 用于压缩的请求与常规对话的请求不同。
1. 独立的压缩请求所使用的系统提示是不同的。我们不会告诉 LLM“你是一个专业的编码助手”,而是告诉它“你是一个上下文总结助手”。(https://github.com/earendil-works/pi/blob/47610217098d9ba8f22d223fa7c1413f9f5fd759/packages/coding-agent/src/core/compaction/utils.ts#L152-L158)
2. 压缩请求中的用户消息也不同。它要求“为之后返回时提供上下文,对这个对话分支进行结构化总结”。(https://github.com/earendil-works/pi/blob/47610217098d9ba8f22d223fa7c1413f9f5fd759/packages/coding-agent/src/core/compaction/compaction.ts#L463-L498)提示中指定了目标、进度和关键决策等部分。
3. 这是一个独立的请求,不使用任何现有对话历史,这意味着它可以采用不同的 LLM 模型,而不会产生不必要的成本。
压缩的结果会作为一条压缩记录追加到 Pi 会话中,会话现在就可以继续了。压缩请求完成后,上下文已被压缩。
```
压缩后:
[system][tools][summary][recent turns][new user message]
```
现在对话上下文中有了更多空间,可以容纳更多消息。
Pi 将压缩总结以纯文本形式存储在会话中。这使得压缩后的上下文可读且可移植(https://earendil.com/posts/session-portability),因为我们可以在 Pi 中切换模型并继续使用该总结。
## 压缩与提示缓存(Prompt Caching)
提示缓存(https://earendil.com/posts/prompt-caching)被 LLM 提供商用来降低同一对话中重复请求的成本。在活跃的编码会话中,对于模型已经生成过的上下文,我们支付的费用更低。这种缓存要求前缀完全匹配,因此压缩会话会破坏提示缓存。
```
压缩前缓存:
[system][tools][older history][recent retained turns]
<-------------------- 缓存前缀 -------------------->
压缩后的第一个请求:
[system][tools][summary][recent retained turns][new user message]
<-- 可复用 -->^
|
第一个改变的 token
|
+-- 此之后的所有内容都必须重新计算
相似文章
@geekbb: 为 Pi coding agent 提供纯算法化的会话压缩,无需 LLM 调用
pi-vcc 是一个开源工具,为 Pi coding agent 提供纯算法化的会话压缩,无需 LLM 调用即可实现 35-99% 的令牌缩减,并通过 vcc_recall 支持无损历史搜索。
@injaneity: pi-computer-use v0.4.3 现已发布!此次更新使我们与 Codex 达到同等水平(不得不承认,他们在最近一次更新中大幅提升了表现……)
pi-computer-use v0.4.3 已发布,实现了与 Codex 的功能对等,新增了幽灵光标、子代理并行任务以及改进的批处理,使得延迟降低约 50%,并能更好地处理如 Microsoft 应用等复杂场景。
上下文压缩应该保留什么?我观察了六种智能体的处理方式[D]
分析六种AI编程智能体(Claude Code、Codex CLI、OpenCode、Cline、Cursor、Amp)如何趋同于分层渐进式压缩以处理长上下文,它们在保护内容(用户消息、有状态工具输出)以及是否告知模型压缩方面存在差异,并在成本与准确性之间进行权衡。
@MaximeRivest: Pi 编码代理在其价格上通常是最优的。Pi 的系统提示非常简短,只有4个工具。我的 Pi 系统...
Maxime Rivest 分享了使用自定义系统提示优化 Pi 编码代理使用的技巧,Matei Zaharia 讨论了在 Databricks 对编码代理进行基准测试时发现的令人惊讶的结果。
@wquguru: https://x.com/wquguru/status/2056235143623495975
A comprehensive guide to the Pi Coding Agent, comparing its features to Claude Code and highlighting its support for the /goal command.