外观
LangGraph 持久化恢复与人工介入
目录
1. 面试结论
30 秒专业短答| 持久化把线程状态按步骤保存,Interrupt 在确定位置暂停并把控制权交给人,Resume 以同一线程继续执行。主链路是“按 thread_id 读取 checkpoint → 节点执行到风险点触发 interrupt → 人工检查并提交恢复值 → 运行时从已保存状态继续”。适合长任务、审批和可恢复执行;不可重放副作用仍需业务幂等与对账,项目中必须用 Trace、失败样本和成本指标验证。
面试官为什么问: 看你能否把框架名词拆成控制流、数据契约、失败边界与选型依据,而不是只会调用 API。
2. 概念、原理与边界
小白先这样理解:手术做到关键步骤先封存病历,等待家属签字后从原步骤继续
手术做到关键步骤先封存病历,等待家属签字后从原步骤继续;病历对应 Checkpoint,签字对应 Interrupt 与 Resume。技术上仍要由确定性代码处理权限、状态提交和终止;生活类比没有覆盖并发、版本与分布式失败。
核心机制
- 按 thread_id 读取 checkpoint:把输入和约束变成可校验契约。
- 节点执行到风险点触发 interrupt:执行主题的核心计算或控制决策。
- 人工检查并提交恢复值:提交结果,并保留版本和证据。
- 运行时从已保存状态继续:成功收口;失败按类别重试、降级或人工处理。
边界: 适合长任务、审批和可恢复执行;不可重放副作用仍需业务幂等与对账。概念本身与框架无关,框架只是实现路径。
Checkpoint 需要持久化“记忆”吗
Checkpoint 需要持久化,但持久化的是“能让工作流精确恢复的执行状态”,不是再建一套长期 Memory。如果消息本来就在 Graph State 中,Checkpointer 会随状态快照保存它们,但这仍属于线程级恢复数据,不等于跨线程长期记忆。
如果“会话级”指一段连续对话或任务上下文,它与 LangGraph thread_id 基本是同一层。差别只在于“会话”容易与浏览器登录 Session 或单次 API 请求混淆:登录 Session 内可以打开多个 Thread;一个 Thread 可跨多次 Run 继续对话或恢复;一次 Run 又会在多个 Super-step 后产生多个 Checkpoint。因此严格说是“按 Thread 组织、按 Super-step 快照”,不是 Workflow Run 级只保存一份状态。
落到 Chat 产品中,最直接的映射是:用户每新建一个 Chat,后端生成一个新 thread_id;该 Chat 内每次连续追问都沿用这个 thread_id,通常每次提问触发一次新 Run,Run 内各个 Super-step 产生 Checkpoint。用户再新建另一个 Chat 时,必须分配新 thread_id,避免两段对话的状态相互污染。
Thread 可以跨进程重启,也可能因为人工审批持续数天;因此 Redis 是合适的共享后端,但不能把 Checkpoint 当成可随意淘汰的 Session Cache。
Checkpoint 应保存当前节点、Graph State、恢复必需的输入输出、pending writes、未完成 Tool Call、Interrupt/审批数据,以及 thread_id、checkpoint_id、版本号和外部事实引用。大段消息历史、RAG 文档、向量、业务主数据、实时价格库存和超大 Tool Result 应留在各自的权威存储,Checkpoint 中优先保存 ID、版本、摘要和校验信息。恢复时再依引用重读,并校验数据是否过期或已变更。
持久化不代表永久保留。运行中、等待人工审批和需要恢复的任务必须保留;已完成任务按审计、隐私、故障重放和成本需求设置保留期,到期删除或只归档最小证据。
3. 技术栈与横向选型
| 技术点 ID | 技术点/环节 | 类型 | 采用方案 | 链路职责 | 版本/证据边界 |
|---|---|---|---|---|---|
| TP-LP-CORE | LangGraph 持久化恢复与人工介入核心链路 | 机制与参考实现 | Checkpointer、thread_id 与 interrupt | 完成“按 thread_id 读取 checkpoint → 节点执行到风险点触发 interrupt → 人工检查并提交恢复值 → 运行时从已保存状态继续” | 设计参考;动态能力以 2026-07-14 官方资料和项目基准为准 |
| TP-LP-STORE | Checkpoint 持久化后端 | 存储/中间件 | Redis Saver、MongoDB Saver、SQL 或自定义 BaseCheckpointSaver | 按 (thread_id, checkpoint_ns, checkpoint_id) 保存快照、父版本和节点 pending writes,支持恢复、列表、删除与时间旅行 | 以 2026-08-25 LangGraph Checkpointer 契约、Redis 与 MongoDB 项目资料为准;候选后端不等于当前项目已接入 |
| 技术点 ID | 候选方案 | 优点 | 缺点/代价 | 适用场景 | 不适用场景 | 选择结论与依据 |
|---|---|---|---|---|---|---|
| TP-LP-CORE | 持久化图运行时 | 能力完整,便于标准化 | 抽象、依赖或运维成本更高 | 约束与生态匹配的生产项目 | 只验证最小机制 | 当前参考方案;须用同数据、同预算基准验证 |
| TP-LP-CORE | 任务重头重跑 | 路径直接,边界透明 | 需要自行补齐工程能力 | 小规模、强定制或机制验证 | 复杂协作和快速交付 | 需求简单时优先;复杂度超过维护能力再切换 |
| TP-LP-STORE | Redis AsyncRedisSaver | 多实例共享、低延迟、支持完整历史或 Shallow 模式、TTL 清理 | 需 RedisJSON 与 RediSearch;持久化、逐出策略和容灾配置不当会丢失恢复点 | 已有 Redis 能力、高频恢复、多 Agent 实例 | 只有普通 Redis 且不能增加模块,或必须依赖数据库级长期审计 | 已使用 Redis 的 Agent 项目优先候选;建议使用独立实例或至少独立命名空间和容量预算 |
| TP-LP-STORE | MySQL 自定义 BaseCheckpointSaver | 复用现有 MySQL、ACID、备份和审计链统一 | 不是“换连接串”;要自行实现快照、pending writes、父版本、序列化、并发和删除契约 | 严格控制中间件数量、团队能维护 Saver 且 Checkpoint 写入量可控 | 想用未验证的第三方包直接承担生产恢复 | 只在通过 LangGraph conformance suite、重启、并发、HITL 和故障注入后采用 |
| TP-LP-STORE | MongoDB MongoDBSaver | 成熟的 LangGraph 合作伙伴集成,文档模型自然,支持共享持久化 | 新增一套集群、权限、备份和监控负担 | 组织已有 MongoDB 平台或需文档型运行状态 | 项目已有 MySQL + Redis 且没有 MongoDB 运维能力 | 只在现有平台能抵消新中间件成本时选择 |
| TP-LP-STORE | InMemorySaver | 零外部依赖、测试快 | 进程重启即丢失,不能故障恢复 | 单元测试、一次性 Demo | 任何需要持久化的生产 Agent | 只作测试基线,不是 SQLite 的生产替代 |
不使用 SQLite 时怎么选
Checkpoint 按
thread_id组织执行状态,并在 Super-step 边界生成快照;其读写频繁、需要多实例共享且通常可按任务生命周期清理,因此已有 Redis 且不保留 PostgreSQL 的 Agent 项目可优先验证独立 Redis Checkpointer。但 Redis 必须按“恢复数据”而不是“可丢缓存”治理;如果更重视统一备份、长期审计和不增加中间件,再评估 MySQL 自定义 Saver。
Redis 方案必须另行验证 AOF/RDB、副本与故障转移、maxmemory-policy、TTL、大 Checkpoint 内存放大和租户隔离。MySQL 方案必须实现并验证 put/put_writes/get_tuple/list/delete_thread 及对应异步方法,不能只保存最终 State。Milvus、Kafka、对象存储和普通消息队列都不适合单独承担 Checkpointer:它们可以保存投影、事件或冷备,但不直接满足按 checkpoint ID 读取、pending writes 和父版本恢复契约。
4. 架构与调用流程
图:架构|LangGraph 持久化恢复与人工介入组件边界
替代文本: 输入经过按 thread_id 读取 checkpoint、节点执行到风险点触发 interrupt、人工检查并提交恢复值和运行时从已保存状态继续形成结果,策略与观测横跨链路提供约束和证据。
图表加载中…
读图结论: 核心机制位于中间两步,策略控制执行边界,观测层负责证明结果和定位失败。
架构图说明静态职责,不代表所有步骤都必须拆成独立服务;是否拆分取决于隔离、扩缩容和故障域。
图:技术调用流程|LangGraph 持久化恢复与人工介入成功与失败路径
替代文本: 调用方提交请求,控制层执行前置校验后调用核心组件;有效结果被验证并返回,异常结果进入止损、降级或人工处理。
图表加载中…
读图结论: 失败不能统一重试;先区分未执行、可重试和结果未知,再决定恢复动作。
调用流程把模型或框架能力放在受控运行时内部,授权、验证和最终完成判定不交给概率模型。
5. 最小实现与证据
python
def run(request, policy, engine, verifier):
checked = policy.validate(request)
result = engine.execute(checked)
verifier.assert_valid(result)
return result这段伪代码刻意只保留四个边界:输入校验、核心执行、结果断言和返回。生产实现还需超时、取消、幂等、版本与审计。
最小证据集: 一个正常样本、一个边界样本、一个失败注入;记录输入、输出、版本、Trace、延迟和成本。没有这些证据时,只能说“完成设计”,不能声称已上线或提升。
6. 项目落地与面试追问
示例项目: 在内部 AI 助手中用 TP-LP-CORE 承担核心链路。上线前以固定任务集比较 持久化图运行时 与 任务重头重跑,验收任务成功率、关键错误率、P95、单位任务成本和人工接管率。
面试追问:
- LangGraph 持久化恢复与人工介入解决什么问题,又不解决什么?
- 四步链路中哪一步必须由确定性代码控制?
- 为什么当前选择 持久化图运行时,何时改用 任务重头重跑?
- 如何证明不是 Demo 恰好成功?
- 发生“恢复后重复执行外部副作用”时先查什么?
7. 生产风险与排障
生产风险演练
| 现象 | 影响 | 定位证据 | 根因 | 临时止损 | 长期修复 | 回归验证 | 监控与防复发 |
|---|---|---|---|---|---|---|---|
| 审批一次却发送两次或扣费两次 | 恢复后重复执行外部副作用,影响正确性、稳定性或成本 | checkpoint_id、call_id、外部业务流水 | 把 checkpoint 恢复误当成事务 exactly-once | 暂停恢复并按业务键查询外部真实状态 | 副作用前后记录意图与结果,使用幂等键和补偿 | 注入响应丢失与进程重启,核对外部动作唯一 | 按租户、任务和版本监控失败率、尾延迟、成本与降级率 |
排障顺序固定为:先止损并固定版本,再找首次异常证据,最后修复、重放和灰度;不要先换模型或扩大重试。
8. 参考资料
- LangGraph 持久化,访问日期:2026-08-25。
- LangGraph 自定义 Checkpointer 契约,访问日期:2026-08-25。
- Redis LangGraph Checkpointer,访问日期:2026-08-25。
- MongoDB LangGraph Checkpointer,访问日期:2026-08-25。
- 本文项目与指标均为设计或故障演练证据,不代表仓库已有线上实测。
9. 总结
一句话记忆: 持久化把线程状态按步骤保存,Interrupt 在确定位置暂停并把控制权交给人,Resume 以同一线程继续执行。
- 核心链路:按 thread_id 读取 checkpoint → 节点执行到风险点触发 interrupt → 人工检查并提交恢复值 → 运行时从已保存状态继续。
- 记忆边界:Checkpoint 持久化恢复所需的线程状态;长期 Memory、业务事实和检索投影仍归各自权威存储。
- 存储选型:已有 Redis 的多实例 Agent 优先验证 Redis Saver;想复用 MySQL 则必须实现完整 Checkpointer 契约并通过一致性测试。
- 边界:适合长任务、审批和可恢复执行;不可重放副作用仍需业务幂等与对账。
- 排障:固定版本,沿 Trace 找首次异常,再重放验证。