Skip to content

LangGraph:thread 不是一条只能覆盖的状态线

LangGraph 同一 thread 的 checkpoint 分支树

查看原尺寸 SVG(可缩放)

可编辑图源 · PNG 预览 · 图的文字版

关键代码走读:checkpoint 创建、读取与分支

核对官方仓库 langchain-ai/langgraph@bdb85b5aa87a21de68371d2e534b81aeed398f57 的 Python Pregel/checkpointer 路径。证据包括源码和仓库内已有测试用例;本文未运行测试或数据库后端。图只抽取几个关键快照,不表示真实执行只有这些 checkpoint。

一句话区分

LangGraph checkpointer 保存的是图执行状态的版本:每个快照有当前 values、下一步 next、可重新取用的 config 和父版本 parent_config。它不是类似 Letta 核心块那样默认进入模型提示的知识,也不是 Mem0 那样按语义检索用户事实的存储。StateSnapshot 字段

从一个旧快照分叉

  1. 图需要编译时提供 checkpointer;没有 checkpointer,get_statebulk_update_state 会报错。get_state 要求 · bulk_update_state 要求
  2. get_state_history({"configurable": {"thread_id": "T"}}) 委托 saver 的 list 并把每个 CheckpointTuple 准备成 StateSnapshot;其中 config 可再定位此版本。历史读取
  3. get_state(config) 委托 saver 的 get_tuple。在 InMemorySaver 示例实现中,config 有 checkpoint_id 就精确取该版本;没有就取同一 thread_id 和 namespace 的最新 ID。图接口 · 示例 saver 选择逻辑
  4. update_state(old_snapshot.config, values) 进入 bulk_update_state,先按传入 config 读旧 checkpoint,复制状态并应用节点写入,再 put 新 checkpoint;示例 saver 将传入的旧 checkpoint_id 记录为新版本的 parent。旧分支并未被同 ID 覆盖。更新入口 · 读取及复制旧状态 · 写新快照 · 父版本记录
  5. 仓库测试构造 node_a → node_b,找出 next == ("node_b",) 的旧快照,调用 update_stateinvoke(None, fork_config);另一个测试从同一旧快照做两次 fork,检查两条结果互不混入。这是测试代码的断言,不是本文已实测的运行结果。单次分叉用例 · 多分叉用例

为什么这比“有会话历史”具体

thread_id 定作用域,checkpoint_ns 进一步划分命名空间,checkpoint_id 选版本;parent_config 使新旧结果的祖先关系可见。它能支持回看和从旧状态继续执行,但后续节点会不会重新执行、写出怎样的状态,仍受图结构、reducers、pending writes 和中断状态影响。不能把“拿到旧 checkpoint”直接说成“所有副作用都回滚”。

持久性的边界

为了看清键结构,本篇引用 InMemorySaver:它按 thread → namespace → checkpoint ID 存储,并有父版本指针。官方类注释明确它用于调试或测试,不适合生产持久化;进程结束后数据不保留。生产 saver 的事务性、恢复语义和跨机器能力不由这张图证明。存储结构与官方限定

下一步应以一个可控两节点图分别使用 InMemorySaver 和生产 saver,记录每次 configparent_configvaluesnext 以及副作用是否重放;本文尚未做该实验。

图的文字说明 · langgraph-checkpoints

范围是 langchain-ai/langgraph@bdb85b5a 的 Python checkpointer 路径。返回章节

  1. 上支用 C₀ → C₁ → C₂ 示意一个 thread 的原始执行。C₁ 是 next 包含节点 B 的历史快照;C₂ 是原分支执行后的快照。
  2. 选取 C₁ 的 config 调用 update_state,会产生新版本 C₁′。以返回的 config 再 invoke(None, ...),产生新分支后继 C₂′。原 C₂ 仍是历史版本。
  3. thread_idcheckpoint_ns 定位作用域;加 checkpoint_id 可选具体快照。就图中引用的 InMemorySaver 而言,不给 checkpoint_id 时,get_state 取该作用域下最大 checkpoint ID;这不等于按分支语义选择某个“当前版本”。StateSnapshot.parent_config 用于追踪直接父版本。
  4. 图只绘制理解分叉所需的关键节点;真正执行可能写出更多 checkpoint。图没有描述 external tool 副作用回滚,也没有证明所有 saver 可跨进程持久化。

InMemorySaver 仅用于说明代码可见的键结构和父版本记录;官方注释限定它用于测试/调试。编辑 build.py 后运行 python3 figures/langgraph-checkpoints/build.py,再由 excalidraw-agent renderer 从 scene.excalidraw 导出 SVG 和 PNG。


在线预览稿:书稿仍在校稿,系统篇以文内固定源码版本为准;静态阅读不等于运行验收。