- 教程
- 文档
【免费下载链接】how-pi-agent-works
Pi Agent 原理与实现
本文围绕 Pi Agent 上下文压缩(compaction)展开,基于教程项目 how-pi-agent-works,拆解真实 Pi 压缩系统中三个教学版没有展开的复杂边界:reserveTokens输出预算、turn boundary 切分规则与 branch summary 分支摘要。读完你会明白:压缩不是“删旧消息”,而是在 token 预算、对话协议和会话树分支之间做工程权衡。
📌 如果你还没看过基础版压缩(摘要旧消息 + 保留最近消息),建议先读 Demo 4:上下文压缩,本文是它的进阶篇。
1. reserveTokens:压缩触发看的不是消息条数
很多第一版实现用“消息数量”或“字符串长度”判断是否压缩。真实 Pi 的做法不同:它从模型返回的 usage 里读取真实 token,加上新消息的估算值,得到contextTokens,再与一条预算线比较:
contextTokens > contextWindow - reserveTokens| 参数 | 默认值 | 解决的问题 |
|---|---|---|
reserveTokens | 16384 | 给模型回复、工具参数、后续事件预留输出空间 |
keepRecentTokens | 20000 | 控制最近多少 token 的原文必须保留 |
关键点在于:Agent 不是“输入塞得下”就行。如果压缩后上下文贴着窗口上限,模型刚开始输出就可能撞墙。reserveTokens就是提前给“输出”留出的安全垫。
💡 对比教学版:sessionStore.ts 中的
compactIfNeeded()用近似字符数模拟触发点,参数是maxApproxTokens和keepRecentMessages,刻意保持可预测、方便观察 JSONL 文件。
2. firstKeptEntryId:摘要为什么必须带“恢复指针”
只存一个summary字段的压缩,恢复上下文时会立刻卡住:摘要后面到底从哪条原文接上?
Pi 的CompactionEntry不止有摘要:
| 字段 | 作用 |
|---|---|
summary | 旧上下文摘要,给模型读 |
firstKeptEntryId | 后续原文从这个 entry 开始保留 |
tokensBefore | 压缩前的 token 规模,用于 UI 和日志解释 |
details | 结构化细节(如读过/改过哪些文件),给程序读 |
于是压缩后模型看到的上下文变成三段式:
system prompt compaction summary messages from firstKeptEntryId to current leaf注意 JSONL 文件里的旧消息一条都没删,firstKeptEntryId只是告诉运行时“下次喂模型时从哪里接回原文”。完整链路说明见 会话格式、分支与压缩链路。
3. turn boundary:为什么压缩不能随便切
工具调用让切分变复杂了。一次完整的工具交互至少包含:assistant 发出toolCall→ tool 执行生成toolResult→ assistant 读取结果继续回答。
如果 cut point 恰好落在toolResult前后,模型会看到两种“孤儿”:
- 没有来源的工具结果(调用被摘要掉了)
- 没有结果的工具调用(结果被划进旧上下文)
两者都会破坏对话协议。官方 cut point 规则因此限定:切点可以落在用户消息、assistant 稳定输出点、branch summary 等位置,但不会切在 toolResult 上。这就是 turn boundary 的意义——在“一轮对话”的语义边界上切,而不是在任意消息边界上切。
🔧 教学版练习方向:给compactIfNeeded()加一条规则——选firstKeptEntryId时,若保留段第一条是toolResult,就把它前面的 assistant toolCall 一起保留。
4. split turn:一个 turn 自己就超过保留预算
理想情况是压缩切在 turn 边界:旧 turn 摘要掉,新 turn 保留原文。但代码 Agent 经常遇到超长 turn——一次“修复失败测试”可能串起读文件、跑测试、改代码、看 diff 好几轮工具输出,单 turn 就超过了keepRecentTokens。
这时 Pi 会把 cut point 放进 turn 内部,形成split turn:
超长 turn ├─ 前半段(turnPrefixMessages)→ 单独摘要 └─ 后半段 → 原文保留这样模型既知道这个巨大 turn 前面做了什么,又不会把整段工具输出塞进下一轮请求。split turn 保护的是“连续工作现场”,而不是机械地整段保留或整段丢弃。
5. 重复压缩:摘要也会成为历史
长会话不会只压缩一次。第二次压缩时,Pi 不会简单地从上一个 compaction entry 后面开始算,而是从上一次firstKeptEntryId的保留边界附近继续。
原因很实在:上次被“保留原文”的消息,这次可能已经变旧了,也应该有机会进入新的 summary。否则最近上下文会越滚越大,压缩效果越来越差——这也是 上下文、技能与压缩 里强调的两个风险的工程解法。
6. branch summary:它不是压缩,是“换路带经验”
branch_summary和compaction都用摘要,但触发场景完全不同:
| 维度 | compaction | branch summary |
|---|---|---|
| 触发 | 上下文超阈值,或用户运行/compact | 用户在/tree中切换分支 |
| 摘要对象 | 当前路径上的旧上下文 | 正在离开的分支(旧 leaf 到共同祖先) |
| 目标 | 减少 token 占用 | 把离开分支的重要发现带到新位置 |
| 写入 entry | type: "compaction" | type: "branch_summary" |
一个常见误区:切分支时直接把旧分支全丢掉。你可能在 A 分支里读过关键文件、验证过失败假设,切到 B 分支后这些经验就没了。branch summary 的价值,就是把“走过的弯路”变成可携带经验。
🌳 分支与/tree导航的背景见 会话、树与分支,教学版把 branch summary 作为扩展方向,因为它需要会话树 UI 支撑,适合二阶段练习。
7. 对照真实源码与教学版
真实实现集中在官方仓库的packages/coding-agent/src/core/compaction/(触发条件、cut point、branch summary、文件操作追踪)。本仓库把主线整理在 进阶:真实 Pi 为什么压缩更复杂,源码阅读路线见 源码阅读地图。
| 真实 Pi 能力 | 教学版处理 | 为什么 |
|---|---|---|
| 真实 token usage 触发 | 字符长度近似 | 先理解触发点,不被 provider 细节打断 |
reserveTokens/keepRecentTokens | 固定阈值与保留条数 | 保持 Demo 可预测,方便观察 JSONL |
| turn boundary / split turn | 不做复杂切分 | 工具调用链路已在 loop 章节单独学 |
| branch summary | 扩展方向 | 需要会话树 UI 支撑 |
参考最小实现:04-compaction.ts 中的compactMessages(),运行npm run demo:04即可看到tokensBefore、summary 和“模型下一轮看到什么”。
8. 小练习:给教学版补一个真实边界
- 给 compactIfNeeded() 增加
reserveApproxChars参数,模拟“输出空间预留”。 - 选
firstKeptEntryId时不按条数,而是从最新消息向前累加近似字符数,直到达到keepRecentApproxChars。 - 遇到
toolResult时保证它前面的 toolCall 一起保留,避免出现孤儿结果。 - 在 compaction event 里展示
tokensBefore、firstKeptEntryId和keptMessageCount。
做完你会发现:压缩不是字符串裁剪,而是一个同时保护协议边界、上下文预算和工程恢复能力的独立模块——这正是真实 Pi 把它拆成compaction/单独目录的原因。
- 教程
- 文档
【免费下载链接】how-pi-agent-works
Pi Agent 原理与实现
相关推荐
how-pi-agent-works:一文讲清Pi Agent三层架构 pi-ai、pi-agent-core 与 pi-coding-agent
how pi agent works:一文讲清Pi Agent三层架构 pi ai、pi agent core 与 pi coding agent how pi
教程文档如何配置 pi 的自动压缩 reserveTokens 与 keepRecentTokens?
如何配置 pi 的自动压缩 reserveTokens 与 keepRecentTokens? pi 的 coding agent 在对话变长时会触发自动压缩(
人工智能大模型AI Agent代码智能体AI 应用工具调用Vue-Croppa性能优化:10个提升图片处理效率的方法
Vue Croppa性能优化:10个提升图片处理效率的方法 Vue Croppa是一个简单直接的、可定制的、移动端友好的Vue 2.0图片裁剪组件。在前端开发中
教程文档
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考