hello 我是逆境不可逃
用 Agent 处理一个任务,往往要经历多轮讨论和工具调用。有时做到一半需要退出,有时发现方案不合适,想回到前面换个方向。会话管理要解决的,就是这些记录如何保存,以及继续任务时应该取出哪些内容。
Pi 把会话组织成带有父子关系的记录。这种结构既能保留不同尝试,也能从中提取当前分支的上下文。
回到前面继续,对话会形成分支
假设一段对话已经发展到 D:
text
A:提出需求
→ B:明确约束
→ C:讨论方案一
→ D:完善方案一
现在想回到 B,尝试方案二。删除 C、D 会丢失之前的讨论;直接在 D 后面续写,又会把方案一的内容继续带给模型。
Pi 可以把当前续写位置移回 B,让新记录接在 B 后面:
text
A:提出需求
└─ B:明确约束
├─ C:讨论方案一
│ └─ D:完善方案一
└─ E:要求尝试方案二
└─ F:讨论方案二 ← 当前续写位置
每条记录有自己的编号,也记录父节点,也就是它接在哪条记录后面。C 和 E 的父节点都是 B,于是它们形成两个不同方向。
切换分支本身不会删除旧记录。C、D 不再属于当前路径,但仍然可以用于查看和比较。
保存顺序与对话顺序可以不同
Pi 用 JSONL 文件保存会话。可以把它理解为每行一条记录,行内保存该记录的类型、内容和关联信息。
从 B 分支后新增 E,文件中的顺序可能是:
text
保存顺序:A、B、C、D、E
E 的父节点:B
当前对话路径:A → B → E
文件中排在 E 前面的是 D,但 E 并不接着 D。承接关系由父节点决定,不能靠行号猜测。
普通的消息追加会把新记录接到当前续写位置,再把当前位置推进到新记录。会话文件建立后,新增记录通常追加到末尾,不必每次重写全部历史。新会话的首次落盘还存在延迟写入逻辑,因此不能把"内存里已有记录"理解成"此刻一定已写入文件"。
这种组织方式把两个需求分开了:文件按产生顺序保存记录,对话按父子关系形成分支。
保存的全部历史,不等于模型看到的上下文
继续看前面的会话树。当前在 F,暂不考虑压缩或分支摘要,模型需要的路径是:
text
A → B → E → F
Pi 从当前记录往前查找父节点,再调整为从早到晚的顺序,构造这一条路径。C、D 留在会话历史中,但不会因为保存在同一个文件里,就自动混进当前分支。
这样可以避免模型把方案一与方案二的决定混在一起。
Pi 也支持分支摘要:把离开分支中的有用信息整理成摘要,再接入新分支。例如方案一已经确认某种依赖不可用,这条结论可能值得带到方案二。带入的是明确的摘要记录,而不是把其他分支的全部消息拼进来。
会话中还可以记录模型切换、压缩等信息。它们用于恢复设置或构造上下文,并不全都作为普通聊天文本发送给模型。
恢复会话,恢复的是什么
重新打开会话时,Pi 读取已经保存的记录,重建索引和续写位置,再按所选路径构造上下文。恢复的依据是文件中的历史,而不是模型自己记住了上次的对话。
对 Agent 来说,只保存用户和模型的文字还不够。工具请求及其结果也关系到后续判断:
text
用户:读取配置文件
模型:请求读取工具
工具:返回文件内容
模型:根据内容解释配置
丢掉工具结果,就会失去"当时实际读到了什么"的依据。恢复这些消息后,模型才能利用先前观察继续处理任务。
不过,加载历史中的工具请求,并不会自动重新执行它。否则,历史里每一次追加配置、创建工单,都可能在恢复时再发生一遍。记录过去的动作,与调度新的动作,是两个不同步骤。
历史记录与当前文件状态要分开看
假设昨天工具成功修改了配置,今天另一个程序又修改了同一文件。会话里保存的"修改成功"仍然描述昨天的操作,却不能保证文件今天还是那个样子。
因此,用旧记录回答"昨天为什么这样改"是有依据的;回答"文件现在是什么内容",通常需要重新读取。
同样,回到旧对话节点不会自动把项目文件恢复到当时的版本。需要恢复文件时,还要依靠 Git、备份或其他文件版本机制。
还有一种更难处理的情况:会话里有工具请求,却没有对应结果。下面是一个可能的故障场景:
text
工具已经追加配置
→ 程序意外退出
→ 成功结果尚未写入会话
缺少结果只能说明当前证据不完整,不能直接判定操作没有发生。恢复任务时,应先检查目标文件或外部系统,再决定是否重试。尤其是追加、创建等有副作用的操作,盲目重试可能造成重复。
会话保存和业务文件修改没有天然组成一个事务。这个边界决定了恢复流程不能只看聊天记录,还要在必要时重新确认外部状态。
用测试核对分支与恢复
本地运行了仓库已有的两组会话测试,共 47 个用例通过。测试使用构造的消息与临时会话文件,不请求真实模型。
其中几项直接对应前面的讨论:
- 从旧节点分支后,新记录的父节点指向分支起点,原来的子节点仍然保留。
- 同一份记录包含两条路径时,构造上下文只取指定路径。
- 带有工具结果、压缩摘要和分支摘要的会话写入文件后,可以重新打开并保留测试断言中的记录及用量信息。
这些测试验证了记录结构和正常文件重载。它们不代表工具执行与会话落盘具备原子性,也不代表恢复会话会还原项目文件。
会话树保存了不同尝试,父节点关系决定当前讨论沿哪条路径继续。真正恢复任务时,还要结合工具结果和当前外部状态,判断哪些已经完成、哪些需要重新确认。
