LangGraph Checkpoint 详解
LangGraph Checkpoint 详解
本文是面试向的回忆笔记: LangGraph 的短期记忆底层 —— checkpoint。从”是什么”到”怎么实现”再到”能干嘛”, 按面试答题结构组织。
一句话定位
LangGraph 不是普通 API 调用, 是 Pregel 风格状态机。每次 invoke 是图上跑一轮 superstep (节点执行)。checkpoint = 某个 superstep 结束后, 对整个图 state 做的一次快照, 存进 checkpointer。图跑多少步, 就留多少个快照 —— 类似 git, 每次 commit 一个状态。
何时写、存什么
每次节点执行完 (一个 superstep 完成), 自动写一个 checkpoint。存三样:
| 字段 | 内容 |
|---|---|
checkpoint | 所有 channel 的值 (即完整 state, 含 messages 列表) + 各 channel 版本号 |
metadata | created_at、step、source (input/loop/update)、writes (这步写了啥)、parents (父线程引用) |
key | thread_id + checkpoint_id |
channel 版本号很关键: 并发写时靠它做冲突检测。checkpoint_id 是时间序 UUID (v7), 保证排序可靠。
核心接口 BaseCheckpointSaver
4 个方法, 能背这个就是加分:
class BaseCheckpointSaver:
def get_tuple(config) -> CheckpointTuple: ... # 读某 checkpoint
def list(config, *, limit, before) -> iterator: ... # 枚举某线程历史
def put(config, checkpoint, metadata, new_versions): ... # 写快照
def put_writes(config, writes, task_id, task_path): ... # 写 pending writes
put_writes 是精髓 —— 预写日志 (WAL)。节点输出先落盘 writes, 再写 checkpoint。好处:
- 崩溃恢复: 进程挂了, checkpoint 在但 writes 未刷? 从 WAL 重放节点输出, 不丢半步。
- 不需要重跑已完成节点, 直接接着跑。这就是 LangGraph 的耐久执行 (durable execution)。
thread_id vs checkpoint_id
面试最容易考这个区分:
-
thread_id= 会话维度。同一次对话共享。换 id = 新对话。定位”哪个人”。 -
checkpoint_id= 步骤维度。线程内每次快照一个。像 git 的 commit hash。定位”哪一步”。
thread_id: "1" ── checkpoint_id: aaa (step 0)
── checkpoint_id: bbb (step 1, 含工具调用)
── checkpoint_id: ccc (step 2, 最终回答)
线程”当前状态” = 最新 checkpoint_id 那份。所以记忆 = 每次 invoke 从最新快照恢复 state, 再往里塞新输入。
一次 invoke 完整流程
agent.invoke({messages:[Q2]}, config)
1. 查 checkpointer: thread "1" 最新 checkpoint → 取回 [Q1, A1]
2. state = 旧state + [Q2]
3. 图上跑: model 节点 → 可能 tool 节点 → 每步写新 checkpoint
4. 返回最终 state
所以第二问能看到 Q1+A1 不是魔法, 是 state 恢复 + 全量重发。checkpointer=None 时第 1 步查不到任何东西 → 裸调用, 无记忆。
短记忆 vs 长记忆 (关键辨析)
- checkpoint = short-term memory: 按 thread 记对话内状态。
InMemorySaver存内存, 进程重启全没 → 纯短期。换SqliteSaver/PostgresSaver(durable store) → 跨重启, 但仍是”会话内”。 - 长期记忆 =
StoreAPI (BaseStore), 不是 checkpointer。跨线程、经语义检索、专门挑出的长期事实。两者别混, 面试常见坑。
checkpoint 解锁的高级能力
a) Time travel (时间旅行)
state_history = agent.get_state_history(config) # 该线程所有快照
past = state_history[2] # 回退到任意一步
agent.update_state(config, values, as_node="...") # 改某个中间状态
拿到任意 checkpoint_id, 就能从历史任一步 fork 出新分支 —— 调试、回溯、回滚都靠这个。
b) Interrupt / Human-in-the-loop
from langgraph.types import interrupt
value = interrupt({"question": "approve?"}) # 暂停, 已存 checkpoint
# 之后:
agent.invoke(Command(resume="yes"), config) # 同 thread 恢复, 不用重跑
中断时 checkpoint 已落盘 → 暂停多久都行, 恢复时从断点继续。这是 HITL 的底层机制。
c) 失败重试
checkpoint 让”跑了一半挂了”变得廉价, 从最近快照续跑。
面试加分总结句
“LangGraph 的 checkpoint 是每步 state 快照 + WAL 的耐久执行机制。thread_id 定位会话、checkpoint_id 定位步骤; 靠它实现记忆、时间旅行、中断恢复。短记忆是会话级 checkpoint, 长记忆是 Store。”
结合实践
课程 notebook 里的写法:
from langgraph.checkpoint.memory import InMemorySaver
agent = create_agent(
"anthropic:deepseek-v4-flash",
checkpointer=InMemorySaver(), # 开启记忆
)
config = {"configurable": {"thread_id": "1"}}
# 第一问
response = agent.invoke({"messages": [question]}, config)
# 第二问: 模型能"记得"第一问, 因为 state 从 thread "1" 恢复
create_agent(...) + checkpointer=InMemorySaver() + 传 config 带 thread_id —— 就是开了短记忆。内存存, 重启即失。
Enjoy Reading This Article?
Here are some more articles you might like to read next:
- Google Gemini updates: Flash 1.5, Gemma 2 and Project Astra
- Displaying External Posts on Your al-folio Blog
- Agent 评测体系与评测集构建——美团《评测漫谈》+《评测白皮书 01》笔记
- 多模态 LLM 用户智能体做推荐系统离线 A/B 测试
- 自我改进 Agent 统一拆解:θ / Σ 双路线
- CS146S 学习笔记(Week 4-8):从智能体管理者到多栈 AI 构建
- CS146S 学习笔记:从 Prompt 技术全景到 AI IDE 设计文档规范
- 二分查找双模板 + searchInsert 逐行拆解:从模板到边界
- Agent Memory 全景:30 个记忆技术的模块化拆解
- LightRAG 深度解析:简单快速的图增强 RAG