Agent App 在运行过程中由于一些预期或非预期的事件中断,中断后需要从原来断点恢复,执行原来未执行的 task 或 step,避免了需要重新执行带来的额外事件开支
Task/Step 中断恢复,主流Agent App 或 Agent 开源框架都内置有这一功能,如Claude Code/Codex,LangGraph,AutoGen 等
这一功能核心思想是,将 Agent 运行状态持久化,中断后去持久化磁盘或内存 查询最近的快照状态,记载到Agent 中,进行恢复

不同Agent 实现细节可能不太一样,但基本原理都类似: 借助 磁盘DB/ 内存Redis 持久化运行状态 + 实时异步保存/更新
类似于 git 文件管理,Agent 会话 session 中, 运行状态每一个步骤节点 update event 都会对应有一个snapshot 快照;系统中断发起恢复请求时,系统会查询当前会话最新快照记录,加载运行状态,继续运行待完成step 或 node
这里以 LangGraph 为例,介绍下agent 中断/resume 的实现机制,开始之前首先需要了解 LangGraph 内部一个概念 Superstep
在 LangGraph 中 Superstep定义为:"所有当前可以同时运行的节点或task,并发跑完一轮";task 可以理解为节点。理解为 Agent 将 节点 分为两类
顺序节点: 前后有依赖性,一个节点的输入必须等待另一个节输出 并发节点: 可以同时运行,彼此独立
LangGraph 将一组可以同时运行的并发节点, 称为 Superstep,每个 Superstep 执行完毕后都会save 一个 Checkpoint 到内存或磁盘 DB 里

Agent 中断分为两大类,
预期中断:包含用户输入 某个快捷键,强制中断或者在一些高危命令执行前,需要用户confirm 的指令 非预期中断:系统崩溃,程序强制退出,进程被外部强制杀死
对于预期中断,是用户主动或系统主动call 起的,只需要在输入指令后对agent 运动状态进行checkpoint 保存即可,等恢复时会自动加载最新状态
对于非预期中断,系统的恢复能力,就需要依托agent 后台写入逻辑,
非预期根据Superstep 节点完成情况,也分为两类
超步间崩溃:表示上个Supertep所有节点全部完成,准备执行下一个超步,发生了error 超步中崩溃:在运行 某个 Superstep 节点时发生了error

Superstep 间崩溃以及 Superstep中崩溃
LangGraph 主要依靠 两级写入保障,来确保 agent 的恢复能力,将Superstep 的持久化分为两个阶段,一个是节点级别,一个是SuperStep 级别
节点执行完成
↓
put_writes() ← 写入 writes 表(节点粒度,立即落盘)
↓
所有节点完成
↓
put() ← 写入 checkpoints 表(超步粒度,原子提交)
两个阶段写入的对象以及 db 表是不一样的,当节点完成后,用 put_writes写入 writes 表,主要存储节点运行状态,Superstep完成后( superstep 内所有节点完成)用 put 方法将将checkpoint 写入 checkpoints表中
两个表 ,checkpoints 与writes 相关联
SuperStep 可以理解为db 事务,put_writes表示事务中间redo log,记录每步操作,崩溃知道执行在哪里了;put 表示事务的 commit,详单与 事务所有step 都完成后,真正把状态持久化
这样的话,无论是Superstep 间还是Superstep中发生变化,都可以借助两张表来获取到最新运行状态,精确到note 级别,只需要运行未完成部分
节点执行中崩溃, 但状态没有持久化
还有一些特殊场景,是节点运行完毕后,但没有执行put_writes将状态持久化,此时如果发生中断再次 resume 的话,当前节点状态视为丢失,需要重跑,
但某个节点重跑意味着会重复执行,例如订单创建/发送邮件等;对于某些场景重复执行是致命问题,此时需要引入幂等性校验来进行限制,比如外部系统利用 固定唯一id ,多次执行是同样结果
数据持久化
Agent 中断/恢复能力,核心是依托于系统的持久化,考虑到持续化update 如果直接用硬盘db 会给系统带来不小的IO压力,所以大部分Agent App是优先内存来处理
但需要注意是,借助内存做持久化时要选用可以持久化磁盘的 中间件,例如Redis,Amazon MemoryDB,不可以用没有持久化能力的,如:Memcached,如果重启将会导致丢失
夜雨聆风