Pi Agent 101|05|Session Tree
Pi 的 session 不是聊天数组,而是带 parentId 的 append-only JSONL tree。
先说人话:Pi 的 session 更像 Git 历史,不像微信聊天记录。
聊天记录通常是一条线。但 agent 工作时,用户可能从中间回退、分叉、继续另一种修法,还要保留旧路径。线性记录很快会乱,tree 反而更自然。
很多 agent 系统一开始会把 session 存成线性消息数组。这样做简单,但很快会遇到问题:用户要从中间分叉、恢复旧分支、压缩上下文、导出会话、保留自定义事件、记录模型切换和 thinking level 变化。线性数组会越来越吃力。
Pi 的选择是 append-only JSONL tree。每条 entry 有 id、parentId、timestamp;当前会话上下文是从 leaf 沿 parentId 回溯得到的一条路径。

这张图的重点是:session 不是一条线,而是一棵可以恢复和分支的历史树。用户可能从某个中间点 fork 出另一条修复路线,也可能 clone 一个已有 session,在不同目录或不同模型下继续尝试。
如果 session 只是线性 messages 数组,这些操作要么覆盖历史,要么复制大量内容,要么让“当前路径”变得很难解释。Tree 的价值,是把共享前缀和不同后续自然表达出来。
给基础读者的慢速版地图
普通聊天像一条直线:从第一句到最后一句。Agent 的工作更像一棵树:你可以从中间回到某个点,换一种方法继续,旧尝试不会消失,新尝试形成新分支。Session Tree 就是在保存这种“可回退、可分叉、可复盘”的历史。
下面不再把图集中堆在开头,而是把图放到真正需要的位置:概念边界、流程、状态结构、失败模式和产品判断。这样读者看到图时,正好能对应正在解释的问题。
读完这一篇,你应该能看懂什么
- 理解 session tree 为什么比聊天数组更适合 coding agent
- 看清 buildSessionContext 如何把 session entry 变成当前模型上下文
- 学会把完整审计历史和当前模型视图分开
先把问题说清楚
读图说明:长任务会试错,树结构让旧路线和新路线共存。
Session 文件保存的是运行时事实,不只是 LLM messages。它可以包含 header、message、model change、thinking level change、compaction、branch summary、custom entry、custom message、label、session info 等。
这让 session 同时服务四件事:恢复对话、分支导航、上下文构造和导出审计。
Session tree 如何恢复上下文
读图说明:模型看到的是当前路径,不是整棵树的全部节点。
buildSessionContext() 的核心不是“读完整文件然后全部给模型”。它会从当前 leaf 开始沿 parentId 回溯到 root,得到 当前分支 路径。然后它根据路径上的 entry 恢复当前 messages、model、thinking level、compaction summary 和 branch summary。
所以 LLM 看到的不是整个 JSONL 文件,而是当前 leaf 的路径投影。这句话很重要:session 是事实库,context 是投影。
实际实现时,tree 变深后不应该每次都用线性扫描找 parent。通常会先把 entries 建成 id -> entry 的索引,再从 leaf 回溯;如果 session 很大,还可以缓存当前路径、分支元信息或最近 leaf 的构造结果。重点不是把所有历史一次性塞给模型,而是快速找到“当前这条分支”。
fork、clone 和 branch summary
读图说明:分支不是复制聊天,而是在历史结构上开出新的工作现场。
/fork 和 /clone 容易混。可以粗略理解为:fork 更像从当前历史点开出一个新分支,保留共同祖先;clone 更像复制当前 session 的工作现场,让你在另一个副本里继续尝试。二者都服务“不要覆盖旧路线”,只是产品语义不同。
Branch summary 是另一类辅助信息。它描述某条分支已经做过什么、为什么从这里分出去、当前路线的关键状态。它和 compaction summary 不一样:compaction summary 是为了缩短模型上下文;branch summary 更像给人和 runtime 的分支路标,帮助恢复、导航和导出时看懂这条路径。
放到修测试这个例子里
读图说明:不同修复方向共享前半段历史,后半段形成不同分支。
用户可能第一次让 Pi 修测试,模型走了一条路线;后来用户从某个中间点 /tree 回去,选择另一个修复方向。这两个方向共享前半段历史,但后半段不同。如果用线性数组,要么覆盖历史,要么复制大量消息。Tree 模型则自然表达为两个 leaf。
可迁移的边界
如果自己做 harness,session 不要只当作聊天数组。更稳的做法是把运行过程保存成 append-only 的事件/entry,再从某个 leaf 恢复当前路径。这样分支、恢复、导出和压缩都会自然很多。
为什么 session tree 是长任务底座
读图说明:树结构让 agent 的试错过程成为可复盘资产,也让用户能放心回退、比较和继续探索。
短对话可以 append 就结束。长任务不一样。Agent 可能尝试过错误方案,用户可能要求回到某个节点,模型可能因为上下文过长需要压缩,最后还要导出完整过程复盘。这些都要求 session 不只保存“最后答案”,还要保存路径、父子关系和关键状态变化。
在“修复失败测试”的例子里,第一条分支可能选择改测试,第二条分支可能选择改实现。两条分支共享最开始的错误日志,但后续文件修改和测试结果不同。好的 session tree 能让用户比较两条路径,而不是只能看到最后一次尝试。
读者应该关注的产品问题
一个 agent 产品如果没有 session tree,通常会在三个地方露出问题:恢复时只能回到最近状态,不能解释中间发生过什么;分支时要复制整段历史,成本高且容易不一致;导出时只能导出聊天文本,不能还原真正的工作轨迹。
Pi 的 Session Tree 文章要建立的就是这个直觉:session 是运行状态的结构化历史,不是聊天窗口的滚动记录。
这里的取舍
- 取舍:存储格式
- Pi 的倾向:JSONL append-only
- 可迁移原则:便于增量写入、审计和迁移
- 取舍:分支
- Pi 的倾向:parentId tree
- 可迁移原则:不覆盖历史,leaf 表示当前位置
- 取舍:模型上下文
- Pi 的倾向:从当前路径构造
- 可迁移原则:完整历史不等于模型输入
- 取舍:自定义 entry
- Pi 的倾向:支持 custom/custom_message
- 可迁移原则:扩展系统需要持久化自己的事实
和主流产品怎么对应
你用 Claude Code 做到一半想换条路线,或者用 Codex CLI 恢复昨天的 session 继续做,都会遇到同一个问题:历史不是一条线。
如果 session 只是聊天数组,这些能力很难自然表达。你要么覆盖旧历史,要么复制一大段消息,要么不知道 当前分支 到底从哪里来。Session Tree 的价值就在这里:完整历史保留,当前 leaf 表示你正在走的那条路径。
如果你在读 OpenClaw
如果你在读 OpenClaw,这一篇对应 transcript、session export 和复盘能力。OpenClaw 的运行记录不只是为了“继续聊天”,还要支持调试、审计、分享和恢复。Pi 的 Session Tree 提供的是底层存储模型。
源码里真正能看到的树结构
Pi 的 session 底层更像一份追加式运行日志。每一条记录都有自己的身份和父节点,当前用户所在的位置由 leaf 指向。新消息不是覆盖旧消息,而是挂在当前 leaf 后面;如果用户回到历史节点继续,就自然形成另一条分支。
这和普通聊天数组有本质差别。聊天数组只有“先后顺序”,而 session tree 还有“从哪条历史继续”的关系。用户可以从某个中间点重新尝试,旧路径仍然保留,新路径成为另一条分支。
Pi 还会在离开旧分支时生成 branch summary,把旧路径上重要内容总结后挂到新位置。这样模型在新分支继续时,不需要原样携带旧分支全部细节,也不会完全忘记刚刚离开的尝试。
为什么长任务需要树,不只是历史
在“修复失败测试”的任务里,agent 可能先尝试改实现,后来用户觉得方向不对,想回到跑测试后的节点,改另一处逻辑。如果 session 是线性数组,要么覆盖旧尝试,要么复制整段历史,要么让后续上下文难以解释。
树结构让这些动作变得自然:共享前半段,分叉后各自继续。导出、恢复、压缩和复盘也都可以围绕当前路径展开,而不是被一条全局数组绑死。
读者应该带走的判断是:session 不是聊天窗口里的滚动记录,而是 agent 工作现场的历史结构。
阅读时可以用的三问
第一,当前 session 的“当前位置”是什么。树结构里,用户不是只站在一条线的末尾,而是站在某个 leaf 上。
第二,分支之间共享了哪些历史。共享前缀应该被复用,而不是复制出多个互相漂移的历史副本。
第三,恢复时重建的是聊天文本,还是完整运行现场。真正的 session 恢复要带回 cwd、模型、工具、压缩摘要、分支说明和必要的上下文。
如果只记住一句话
完整历史是一棵树,模型看到的是当前分支上的一条路径。
小结
Pi 的 Session Tree 让一个 agent session 既能像聊天一样继续,又能像版本历史一样分支和恢复。对 coding agent 来说,这不是高级功能,而是长任务、回滚、压缩和分享的基础设施。