Code Agent 崩溃后如何恢复:一篇技术文章拆解状态持久化机制

当 Code Agent 执行长任务时,一次崩溃可能让几十步探索全部丢失。一篇技术文章详细拆解了 Transcript、事件流恢复和 Session Memory 等机制。

AI 编程助手正在进入更真实的工程环境:它不再只是补全几行代码,而是在长对话中读取文件、调用工具、修改仓库,甚至连续执行数十步任务。此时,一次崩溃可能让前面所有探索全部清空。掘金上一篇关于 Code Agent 的技术文章,把这个问题拆开讲了:Agent 进程崩溃之后,如何把对话历史、工具调用状态和执行上下文重新恢复出来。

问题:内存里的上下文并不可靠

文章指出,Agent 运行时通常会把所有对话历史放在内存中的 HistoryManager 列表里。一旦遇到网络超时、OOM、用户手动中断等情况,进程退出后,这些内存状态就会丢失。用户重新启动会话,只能从头开始,之前几十步的探索结果都不再可见。

更复杂的是工具调用中断带来的问题。假设 Agent 正在执行 Edit 工具修改文件,进程在写入过程中崩溃,文件可能已经改了一半,也可能根本没有改动;进程日志里也未必留下足够信息。重启后,Agent 并不知道这次 Edit 是否真正生效,也就难以决定下一步动作。

针对这两类问题,文章介绍的方案是 Transcript:把运行过程中的关键事实持续写入一个 append-only 的 JSONL 文件。崩溃之后,Agent 不再依赖内存,而是从文件中重放事件,重建运行时状态。

为什么选择事件流,而不是快照

在持久化设计上,文章比较了两类常见方案:快照和事件流。快照方式需要保证写入的原子性,不能只写一半;重启后还要决定恢复哪一个快照。相比之下,事件流采用追加写入,每一行都是独立事件,天然更适合崩溃恢复场景。

在这套设计中,Transcript 文件路径形如 memory/transcripts/transcript-{session_id}.jsonl。文件中记录的事件包括用户消息、状态转移、工具生命周期、终止事件等。每条事件都带有 event_id、timestamp、session_id、run_id、step、event_type 和 payload 等字段,用于还原一次具体执行中的事实。

文章列出了五类关键事件:

  • message:记录对话消息本身,例如用户提出的重构需求。
  • state_transition:记录 Agent 状态变化,例如模型返回工具调用后进入工具执行阶段。
  • tool_lifecycle:记录工具调用的生命周期,例如 Read 工具从 requested 到 completed 的过程。
  • terminal:记录任务终止原因,例如 completed。
  • checkpoint:记录压缩检查点等可用于恢复的上下文节点。

这些事件并不是直接写入 Transcript 文件。RuntimeRunner 会先通过 _emit 发出事件,再由事件分发机制转发给不同的 sink。其中,Trace sink 用于生成调试日志,Transcript sink 则用于崩溃恢复。两者订阅同一个事件流,内容可能有重叠,但用途不同:Trace 更偏调试,Transcript 更偏事实记录。

恢复的关键:区分已完成、失败和不确定操作

当用户通过 agent.resume_transcript() 或 CLI 的 --resume 参数恢复会话时,系统会读取 Transcript 文件,重建历史消息、压缩检查点、终止事件和工具调用生命周期。

恢复并不是简单把所有动作重放一遍。文章强调,系统会根据工具调用状态进行分类:

  • completed:工具已经完成,无需重放。
  • failed:工具已经失败,也无需重放。
  • requested 但未进入 started:任务尚未真正执行,可以重新计划。
  • started 但没有 completed 或 failed:结果未知,属于中断状态。

其中最难处理的是第四类,也就是 uncertain actions。工具已经开始执行,但结果还没有写回,Agent 就崩溃了。此时,真实结果可能是成功、失败,或者某种中间状态。

文章给出的处理方式并非自动重放所有中断操作,而是根据工具是否具备幂等性进行区分。Read、Grep、Glob 这类只读工具通常可以安全重放;但 Edit、Bash、Task 这类工具可能产生副作用,不能盲目重复执行。恢复流程会把这些不确定操作展示出来,让用户确认哪些动作可能已经发生、哪些需要人工判断。

状态恢复完成后,系统会把重建结果注入 Agent 运行环境:重置上下文引擎,写入历史消息,恢复压缩检查点,并恢复 Read 工具的乐观锁缓存。文章称,恢复后的 Agent 可以重新拥有完整历史、压缩状态和文件读取缓存,仿佛没有经历过崩溃。

Transcript 之外,还需要 Session Memory

文章还提到,Transcript 保存的是完整事实流,但完整事实流并不适合直接喂给模型。一个会话可能积累几千行事件,如果全部放进模型上下文,会迅速超出 token 预算。因此,这套设计又引入了 Session Memory。

Session Memory 是从 Transcript 中派生出来的有界摘要。它会提取当前目标、已完成工作、关键决策、失败尝试、未完成事项和验证状态等高层信息,并以一条 system 消息的形式注入模型视图,放在系统提示词之后、历史消息之前。

也就是说,模型不需要读取全部事件,就能知道当前会话的大致背景:之前完成了什么、失败过什么、现在要继续做什么。Session Memory 采用增量维护方式:TranscriptRecorder 每写入一个事件,就会触发 SessionMemoryManager 更新摘要,而不是每次都全量重建。

在文件组织上,Transcript 和 Trace 也被分开存放。主 Agent 会话、子 Agent 会话分别拥有独立的 transcript 文件;调试用 trace 则放在单独目录中。这样的结构既保留了完整恢复能力,也保留了问题排查能力。

对 Code Agent 而言,崩溃恢复并不是一个附加功能,而是长任务执行能力的基础。随着 AI 编程工具开始承担更长时间、更多工具调用的复杂任务,状态持久化、工具副作用识别和可恢复执行,正在成为底层工程能力的一部分。

原创文章,作者:点点,如若转载,请注明出处:https://www.dian8dian.com/code-agent-beng-kui-hou-ru-he-hui-fu-yi-pian-ji-shu-wen

Like (0)
点点的头像点点
Previous 3小时前
Next 1小时前

相关推荐