Pi 如何智能压缩对话上下文
How Compaction Works in Pi

在使用 Pi、Claude Code 或 Codex 等编程助手进行长时间编码时,对话历史会不断膨胀,最终触发 LLM 的上下文窗口限制。为了解决这个问题,Pi 采用了一种巧妙的压缩机制:当上下文即将溢出时,它不会直接丢弃历史,而是调用 LLM 生成一份结构化的摘要,涵盖目标、进度和关键决策,同时保留最近的对话轮次。这种机制既保留了关键信息,又为新的交互腾出了空间。虽然压缩会打破现有的 Prompt 缓存,但它确保了会话的连续性,并且生成的纯文本摘要支持在不同模型间无缝切换。
理想的代码助手摘要效果,就像是从一个班次向下一个班次进行的交接简报。
HN 评论区
90- errantmind
根据我的经验,最好的压缩策略是根本不要走到需要压缩的那一步,通常将上下文窗口利用率保持在 30% 以下。即使是漫长的智能体工作流,也能维持相当长的一段时间,远比大多数人想象的久。
这是我针对每个会话的做法:
1. 对于旁支话题、离题工作或会话中已完成的重复性工作,向后分支(使用 /tree)并进行总结。
2. 如果超过 30% 或触及“价格翻倍”的多层级定价,就进行修剪(使用我的自定义扩展)。
3. 如果已经修剪过但依然接近 30%,就执行“全部修剪”(更彻底的修剪)。
定义:
'/prune':在新会话(此前未修剪过)中移除约 50% 的上下文
- 保留:用户消息、正常的助手文本、命令/状态标记、扩展收据、模型设置,以及每次工具调用的纯文本收据。
- 移除:思考过程、签名、实际的工具调用/结果、工具输出、图片、压缩摘要以及其他扩展的状态。
'/prune-extended':在新会话中移除约 80% 的上下文
- 保留:用户消息、正常的助手文本及结论、命令/状态标记、扩展收据和模型设置。
- 移除:思考过程、签名、所有工具调用/结果及输出、图片、压缩摘要、其他扩展的状态,以及由 /prune 创建的任何工具活动收据。
两者都会在成功切换后创建新会话并删除旧会话。
使用这些方法,我可以保持 […]
- kierangill
除了压缩,有人见过成功的修剪(pruning)实现吗?也就是说,智能体查看对话历史并移除任何低价值的消息。
例如,有时上下文会被旁支话题、工具调用输出或低价值的代码库探索所占用。
很多时候,我倾向于保留对话历史而不是对其进行总结。我发现总结后的对话会导致未来聊天更加令人沮丧,因为 LLM 会丢失意图或上下文。(或者,大段大段的 LLM 输出会让下一个 token 预测器变得更笨?我不确定。)
- skeledrew
我认为提示词缓存(prompt caching)的工作机制实际上非常不利于更创造性的压缩技术。比如,某种启发式的渐进式压缩,用指针替换使用后的工具结果和思考轨迹,可能会让模型在更长时间内保持“聪明”,但这意味着每轮甚至每轮之内都要打破缓存,从而严重推高成本。
- novaRom
如果你只运行一个本地 LLM,压缩会很痛苦,避免它的最佳方法是将上下文保持得尽可能小。
我发现的一个有用技巧是:让一个模型同时运行两个 KV 缓存。当第一个缓存生成 token 时,第二个缓存立即在输入 token 生成期间(工具运行时间)对它们进行总结,然后 harness 切换到第二个 KV 缓存,该缓存接收新生成的输入 token,同时第一个缓存中的 KV 被替换为压缩后的摘要 token。这是一种乒乓机制,所以我们用更多的空间换取更少的时间。目前仍在实验,但看起来可行,而且一个不错的额外收益是提高了 GPU 利用率。顺便说一句,我有自己的 harness 和模型服务代码,但这可以轻松地在任何其他的 harness 和模型服务器中实现。
- navs
Ampcode 曾使用过一段时间的手递手(handoff)功能,我发现它确实很有用 [1],后来他们把它移除了。据个人经验,我觉得它比压缩效果更好。