跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
编程语言Agent RuntimeCheckpointResumeRollbackDurable Execution

《Agent Runtime 工程化》如何实现 Agent Checkpoint?

如何实现 Agent Checkpoint? 长任务一定会中断。 浏览器刷新。进程崩溃。网络断开。模型请求失败。用户临时离开。工具超时。机器重启。 这些都不稀奇。 真正危险的是:Agent 中断后从头再来。 从头再来听起来只是浪费时间。实际

陈堂会发布于 —2 浏览
《Agent Runtime 工程化》如何实现 Agent Checkpoint?

如何实现 Agent Checkpoint?

长任务一定会中断。

浏览器刷新。进程崩溃。网络断开。模型请求失败。用户临时离开。工具超时。机器重启。

这些都不稀奇。

真正危险的是:Agent 中断后从头再来。

从头再来听起来只是浪费时间。实际更麻烦:

  • 已经写过的文件又写一次。
  • 已经发出的请求又发一次。
  • 用户已经拒绝的权限又问一次。
  • 上次测试失败的证据丢了。
  • 用户在中断后手动改了文件,Agent 恢复时覆盖掉。

所以 Agent Runtime 需要 checkpoint。

但 checkpoint 不是保存聊天记录。

Checkpoint 保存的是一致性。

聊天记录不是 checkpoint

很多系统第一次做 resume,会保存 message history。

这只能解决一小部分问题。

聊天记录能告诉模型'刚才说了什么',但不能告诉 runtime:

哪些工具已经开始执行?
哪些工具已经成功?
哪些工具状态不确定?
哪些文件被 Agent 改过?
用户批准了哪个高风险动作?
哪个工具不能重放?
当前 trace 写到哪里?
预算还剩多少?

没有这些信息,恢复就只能靠模型猜。

让模型猜恢复状态,是很糟糕的设计。

一个 checkpoint 至少包含什么

一个可用 checkpoint 至少要有:

type Checkpoint = {
  id: string;
  runId: string;
  stepId: string;
  createdAt: string;
  messagesRef: string;
  runState: RunStateSnapshot;
  toolLedger: ToolLedgerEntry[];
  fileSnapshot: FileSnapshot;
  approvalsRef: string;
  budget: BudgetState;
  traceRef: string;
};

这几个字段不是为了好看。

runState 说明任务到哪里了。

toolLedger 说明工具执行到哪里了。

fileSnapshot 说明工作区发生了什么变化。

approvalsRef 说明用户批准或拒绝过什么。

budget 说明还能不能继续。

traceRef 说明后续复盘能从哪里接上。

Checkpoint 的价值,是让这些状态彼此对得上。

保存时机比格式更重要

很多人纠结 checkpoint 格式:JSON、SQLite、git commit、event log。

格式当然重要,但更容易出事的是保存时机。

建议至少在这些点保存:

run 开始
每个 step 请求模型前
工具计划生成后
高风险工具审批后
工具执行开始时
工具执行完成后
文件写入后
run 结束

最容易漏的是'工具执行开始时'。

如果只在工具完成后保存,进程在等待外部 API 响应时崩溃,checkpoint 里就像什么都没发生。恢复时 Agent 可能再次调用同一个工具。

对读文件来说问题不大。

对发邮件、创建 issue、扣款、提交订单来说,这就是事故。

Tool Ledger 是 checkpoint 的账本

工具账本应该在工具执行前后都写:

type ToolLedgerEntry = {
  callId: string;
  stepId: string;
  toolName: string;
  inputHash: string;
  status:
    | "planned"
    | "approved"
    | "started"
    | "succeeded"
    | "failed"
    | "uncertain";
  idempotency: "idempotent" | "conditional" | "non_idempotent";
  replayPolicy: "auto" | "ask" | "never";
  sideEffects: string[];
  startedAt?: string;
  finishedAt?: string;
  resultRef?: string;
};

uncertain 很关键。

工具请求已经发出,但响应没回来。这个状态不能写成普通失败,也不能写成没发生。

恢复时看到 uncertain:

  • 幂等工具可以重放。
  • 条件幂等工具要检查状态。
  • 非幂等工具禁止自动重放。

没有 ledger,checkpoint 就只是半截聊天记录。

文件系统要单独保存

对 coding agent 来说,文件系统是一等状态。

最轻量的方案是 patch-based checkpoint:

type FilePatchEntry = {
  path: string;
  beforeHash: string;
  afterHash: string;
  patchRef: string;
  toolCallId: string;
  createdAt: string;
};

写文件前记录 beforeHash。写文件后记录 afterHash 和 diff。

恢复时:

当前 hash = afterHash:说明 patch 已应用,不要重复写。
当前 hash = beforeHash:可以重新应用 patch。
当前 hash 两者都不是:用户或其他工具改过,进入冲突处理。

这个判断比'直接覆盖'安全得多。

保护用户改动是底线。

Git 可以帮忙,但别污染用户历史

代码项目里,git 很适合做 checkpoint 辅助。

可以读取 HEAD、dirty 状态、保存 patch、生成临时 worktree。

但不要一上来就自动 commit 到用户仓库。

更稳的做法:

检测是否是 git 仓库
读取当前 HEAD 和 dirty 状态
checkpoint 保存 patch 文件和 metadata
不自动创建用户可见 commit
用户要求提交时再 commit
回滚前检查当前 dirty changes

aider 这类 coding agent 有 /undo,本质上也是在处理'如何撤销上一次 AI 变更'。Git 自带 revert/restore/reset/stash 等能力,但 Agent Runtime 不能粗暴调用 destructive 命令。它要知道哪些 diff 是 Agent 写的,哪些是用户原本就有的。

不要用'回滚 Agent 改动'误伤用户正在写的代码。

Resume 流程要保守

恢复流程建议这样:

1. 找到最新完整 checkpoint。
2. 校验 checkpoint 文件完整性。
3. 校验 workspace 状态。
4. 恢复 message history 和 run state。
5. 检查最后一个 tool call 是否完成。
6. 禁止自动重放不可重复工具。
7. 给模型注入恢复说明。
8. 从下一个安全 step 继续。

恢复说明不要写成'继续之前的任务'。

应该具体:

系统从 checkpoint 恢复。
Checkpoint: ckpt_004
上一次已完成 step_8。
工具 write_file(call_13) 已成功写入 src/runtime.ts。
工具 run_command(call_15) 执行 npm test,失败,错误摘要如下……
不要重复执行 write_file(call_13)。
请根据已有观察规划下一步。

模型需要知道自己不是重新开始。

它是在继续一个有证据的 run。

Rollback 不是 undo 按钮

用户说'回滚',可能有三种意思:

回滚文件
恢复会话状态
补偿外部副作用

这三件事不能混。

type RecoveryAction =
  | { type: "rollback_files"; checkpointId: string }
  | { type: "restore_session"; checkpointId: string }
  | { type: "compensate_external_action"; ledgerEntryId: string };

文件 patch 可以回滚。

会话状态可以恢复。

外部副作用通常只能补偿。创建了 issue,可以关闭;发出的邮件不能撤回;数据库 migration 可能需要 down migration。

不要把所有东西都叫 undo。

模糊的词,会让用户以为系统能做它其实做不到的事。

本书 demo 的最小实现

本书配套 demo 里有一个 FileCheckpointStore。

它保存两类东西:

run-state-latest.json
snapshots/

run-state-latest.json 用来恢复 Runtime 状态。

snapshots/ 保存写文件前的副本,rollback 时根据 tool ledger 反向恢复。

代码方向大概是:

class FileCheckpointStore {
  async save(state: RunState, label: string): Promise<string> {
    // 写 run-state-latest.json
    // 写 checkpoints/<step>-<label>.json
  }

  async loadLatest(): Promise<RunState> {
    // 读取 run-state-latest.json
  }

  async captureBeforeWrite(path: string): Promise<SnapshotRecord> {
    // 写入前复制旧文件到 snapshots/
  }

  async rollback(state: RunState): Promise<string[]> {
    // 根据 toolLedger 反向恢复写入副作用
  }
}

这不是完整生产方案。

但它很适合作为第一版:先让 run 能保存、能恢复、能撤销 Agent 写入。

和 LangGraph、Temporal 的关系

LangGraph 文档里有 persistence 和 checkpointer,核心是让 graph state 能跨步骤持久化,支持恢复和 human-in-the-loop。

Temporal 讲 durable execution,会把 workflow 的事件历史持久化,让长时间运行的流程在 worker 崩溃后继续。

这些系统都在解决类似问题:长任务不能只靠内存。

Agent Runtime 可以借鉴它们,但 Agent 多了几个麻烦点:

  • 模型输出不稳定。
  • 工具可能有副作用。
  • 文件系统可能被用户手动修改。
  • 上下文压缩会影响后续决策。
  • 需要把 checkpoint 信息写回给模型。

所以 Agent checkpoint 不能只保存状态机位置。它还要保存工具证据、上下文证据和文件证据。

第一版实现清单

如果你已经有了前面文章里的 loop、maxSteps、budget、retry、idempotency,可以这样加 checkpoint:

1. 为每个 run 创建 runDir。
2. 保存 run-state-latest.json。
3. 每个 step 后保存 checkpoints/<step>.json。
4. 工具执行前写 ledger started。
5. 工具执行后写 ledger succeeded/failed/uncertain。
6. 写文件前保存 snapshot 或 beforeHash。
7. 写文件后保存 afterHash 和 patchRef。
8. resume 时加载最新 checkpoint。
9. resume 时禁止重放 non_idempotent 工具。
10. rollback_files 只撤销 Agent 自己的 patch。

先别一上来做分布式存储。

先把一致性语义写清楚。

最后

Checkpoint 不是'保存一下当前聊天'。

它保存的是:

这个 Agent run 执行到这里,
哪些事情已经发生,
哪些事情可能发生,
哪些事情不能重复发生,
从哪里可以安全继续。

这句话听起来啰嗦,但就是 checkpoint 的价值。

Agent 一旦能写文件、执行命令、调用外部系统,就必须有这层。

否则中断后的'重新来一次',迟早会变成事故。

参考资料

  • LangGraph Docs: Persistence
  • LangGraph Docs: Durable execution
  • Temporal Docs: Durable execution
  • Git Docs: git restore
  • aider Docs: Undoing changes

推荐阅读

  • 从 Agent Loop 重构成 Agent Runtime
  • LangGraph 到底是不是 Agent Runtime?
  • Agent Framework 会被模型原生 Tool Use 淘汰吗?

目录

  1. 如何实现 Agent Checkpoint?
  2. 聊天记录不是 checkpoint
  3. 一个 checkpoint 至少包含什么
  4. 保存时机比格式更重要
  5. Tool Ledger 是 checkpoint 的账本
  6. 文件系统要单独保存
  7. Git 可以帮忙,但别污染用户历史
  8. Resume 流程要保守
  9. Rollback 不是 undo 按钮
  10. 本书 demo 的最小实现
  11. 和 LangGraph、Temporal 的关系
  12. 第一版实现清单
  13. 最后
  14. 参考资料
  15. 推荐阅读
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Python 核心语法详解:测试脚本开发基础
  • 在 Linux 桌面里跑 Windows 应用:Winboat 实战笔记
  • AI 编程工具深度对比:Trae、Cursor、Copilot 与 Windsurf
  • 论文阅读--Agent AI 探索多模态交互的前沿领域(一)
  • OpenCode 开源 AI 编程助手使用教程
  • Linux diff 与 patch 命令实战指南
  • 网络安全工程师职业定义、核心技能与认证体系详解
  • Python 为何如此流行?深度解析其核心优势与应用场景
  • 大疆无人机如何导出日志并解析
  • 前端 WebSocket 通信实战与最佳实践
  • OpenClaw 进阶教程:记忆系统、定时任务、多模型与子代理解析
  • Python 爬虫实战指南:从基础请求到分布式框架
  • Kubernetes Python 客户端实战教程
  • Java IO 核心:BufferedReader、BufferedWriter、PrintStream 与 PrintWriter 详解
  • AI 辅助编程工具:GitHub Copilot 安装与使用指南
  • 基于 Rokid AR 眼镜的聚会游戏助手开发实践
  • 百瑞互联 BR8654A02 蓝牙 6.0 SOC 芯片规格介绍
  • Windows 7 安装 Python 3.9+ 配置指南
  • 前端加密:常用方式与使用示例
  • GitHub Copilot 学生认证教程(2026 版)

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online