LangGraph 具有内置的持久化层,可以将图状态保存为检查点。当您使用检查点记录器编译图时,系统会在执行的每一步保存图状态的快照,并按线程进行组织。这实现了人机交互 (human-in-the-loop) 工作流、对话记忆、时间旅行调试和容错执行。文档索引
在以下地址获取完整的文档索引:https://docs.langchain.org.cn/llms.txt
在进一步探索之前,请使用此文件发现所有可用页面。

Agent Server 自动处理检查点 使用 Agent Server 时,您无需手动实现或配置检查点记录器。服务器会在后台为您处理所有持久化基础设施。
为什么使用持久化
以下功能需要持久化支持- 人机交互 (Human-in-the-loop):检查点记录器允许人员检查、中断和批准图步骤,从而促进 人机交互工作流。这些工作流需要检查点记录器,因为人员必须能够随时查看图的状态,并且图必须能够在人员对状态进行任何更新后恢复执行。请参阅 中断 获取示例。
- 记忆 (Memory):检查点记录器允许在交互之间建立 “记忆”。在重复的人机交互(如对话)情况下,任何后续消息都可以发送到该线程,该线程将保留对之前消息的记忆。请参阅 添加记忆 了解如何使用检查点记录器添加和管理对话记忆。
- 时间旅行 (Time travel):检查点记录器允许 “时间旅行”,允许用户重放之前的图执行,以查看和/或调试特定的图步骤。此外,检查点记录器使得在任意检查点分叉图状态以探索替代路径成为可能。
- 容错性 (Fault-tolerance):检查点提供容错和错误恢复:如果一个或多个节点在给定的超级步骤中失败,您可以从上一个成功的步骤重启图。
- 待处理写入 (Pending writes):当图节点在给定的 超级步骤 执行中途失败时,LangGraph 会存储该超级步骤中成功完成的其他节点的待处理检查点写入。当您从该超级步骤恢复图执行时,无需重新运行已成功的节点。
核心概念
线程
线程 (Thread) 是分配给检查点记录器保存的每个检查点的唯一 ID 或线程标识符。它包含了一系列 运行 (runs) 的累积状态。当执行运行端时,辅助程序基础图的 状态 将持久化到该线程中。 在使用检查点记录器调用图时,您必须在配置的configurable 部分指定 thread_id:thread_id 作为存储和检索检查点的主键。没有它,检查点记录器就无法保存状态,也无法在 中断 后恢复执行,因为检查点记录器使用 thread_id 来加载保存的状态。检查点 (Checkpoints)
线程在特定时间点的状态称为检查点。检查点是每个 超级步骤 保存的图状态快照,由StateSnapshot 对象表示(有关完整的字段参考,请参阅 StateSnapshot 字段)。
超级步骤 (Super-steps)
LangGraph 在每个超级步骤边界处创建一个检查点。超级步骤是图的一次“刻度”,在该刻度中,为该步骤调度的所有节点都会执行(可能是并行执行)。对于像START -> A -> B -> END 这样的顺序图,输入、节点 A 和节点 B 都有各自独立的超级步骤——在每一个步骤之后都会生成一个检查点。理解超级步骤边界对于 时间旅行 非常重要,因为您只能从检查点(即超级步骤边界)恢复执行。 除了超级步骤检查点之外,LangGraph 还会持久化节点(任务)级别的写入。当超级步骤中的每个节点完成时,其输出将作为与正在进行的检查点关联的任务条目写入检查点记录器的 checkpoint_writes 表中。这些按任务的写入实现了 待处理写入 恢复:如果同一超级步骤中的另一个节点失败,已成功节点的写入已经持久化,恢复时不需要重新运行。一旦超级步骤完成,完整的状态快照就会被提交。 检查点是持久化的,以后可以用于恢复线程的状态。 让我们看看在如下调用一个简单的图时会保存哪些检查点:- 空检查点,下一个要执行的节点是
START - 带有用户输入
{'foo': '', 'bar': []}的检查点,下一个要执行的节点是nodeA - 带有
nodeA输出{'foo': 'a', 'bar': ['a']}的检查点,下一个要执行的节点是nodeB - 带有
nodeB输出{'foo': 'b', 'bar': ['a', 'b']}的检查点,没有下一个要执行的节点
bar 通道设置了 reducer,因此 bar 通道的值包含来自两个节点的输出。
检查点命名空间
每个检查点都有一个checkpoint_ns(检查点命名空间)字段,用于标识它属于哪个图或子图
""(空字符串):该检查点属于父(根)图。"node_name:uuid":该检查点属于作为给定节点调用的子图。对于嵌套子图,命名空间使用|分隔符连接(例如"outer_node:uuid|inner_node:uuid")。
获取并更新状态
获取状态
在与保存的图状态交互时,您必须指定一个 线程标识符。您可以通过调用graph.getState(config) 来查看图的最新状态。这将返回一个 StateSnapshot 对象,该对象对应于与配置中提供的线程 ID 关联的最新检查点,或者如果提供了检查点 ID,则对应于该线程的特定检查点。
getState 的输出如下所示
StateSnapshot 字段
| 字段 | 类型 | 描述 |
|---|---|---|
值 | 对象 | 此检查点处的状态通道值。 |
下一个 | 字符串[] | 下一步要执行的节点名称。空数组 [] 表示图已执行完成。 |
配置 | 对象 | 包含 thread_id、checkpoint_ns 和 checkpoint_id。 |
metadata | 对象 | 执行元数据。包含 source("input"、"loop" 或 "update")、writes(节点输出)和 step(超级步骤计数器)。 |
createdAt | 字符串 | 此检查点创建时的 ISO 8601 时间戳。 |
parentConfig | 对象 | null | 前一个检查点的配置。第一个检查点为 null。 |
tasks | PregelTask[] | 在此步骤要执行的任务。每个任务都有 id、name、error、interrupts,以及可选的 state(使用 subgraphs: true 时的子图快照)。 |
获取状态历史
您可以通过调用graph.getStateHistory(config) 获取给定线程的完整图执行历史记录。这将返回一个与配置中提供的线程 ID 关联的 StateSnapshot 对象列表。重要的是,检查点将按时间顺序排列,最近的检查点 / StateSnapshot 排在列表的首位。
getStateHistory 的输出如下所示

查找特定检查点
您可以过滤状态历史记录以查找符合特定条件的检查点重放
重放会重新执行来自先前检查点的步骤。使用先前的checkpoint_id 调用图,以重新运行该检查点之后的节点。检查点之前的节点将被跳过(它们的结果已经保存)。检查点之后的节点会重新执行,包括任何 LLM 调用、API 请求或 中断——这些在重放期间总是会再次触发。 有关重放过去执行的完整详细信息和代码示例,请参阅 时间旅行。 
更新状态
您可以使用graph.updateState() 编辑图状态。这将使用更新后的值创建一个新检查点——它不会修改原始检查点。更新的处理方式与节点更新相同:值在定义时通过 reducer 函数传递,因此带有 reducer 的通道会累加值而不是覆盖它们。 您可以选择指定 asNode 来控制将更新视为来自哪个节点,这会影响下一步执行哪个节点。有关详细信息,请参阅 时间旅行:asNode。 
内存存储

Store 接口的需求。作为演示,我们可以定义一个 InMemoryStore 来跨线程存储有关用户的信息。我们只需像以前一样使用检查点记录器编译图,并传入该存储即可。LangGraph API 自动处理存储 使用 LangGraph API 时,您无需手动实现或配置存储。API 会在后台为您处理所有存储基础设施。
InMemoryStore 适用于开发和测试。对于生产环境,请使用
PostgresStore、MongoDBStore 或 RedisStore 等持久化存储。所有实现都扩展了 BaseStore,这是在节点函数签名中使用的类型注释。基本用法
首先,让我们在不使用 LangGraph 的情况下单独展示这一点。tuple 进行命名空间划分,在此特定示例中为 (<user_id>, "memories")。命名空间可以是任何长度,并代表任何内容,不一定非要特定于用户。
store.put 方法将记忆保存到存储中的命名空间。执行此操作时,我们要指定如上定义的命名空间,以及记忆的键值对:键只是该记忆的唯一标识符 (memory_id),值(一个字典)是记忆本身。
store.search 方法读取命名空间中的记忆,该方法将以列表形式返回给定用户的所有记忆。最近的记忆位于列表的最后。
-
value:此记忆的值 -
key:此内存在此命名空间中的唯一键 -
namespace:字符串元组,此记忆类型的命名空间虽然类型是tuple,但在转换为 JSON 时可能会序列化为列表(例如['1', 'memories'])。 -
createdAt:此记忆创建时的时间戳 -
updatedAt:此记忆更新时的时间戳
语义搜索
除了简单的检索之外,存储还支持语义搜索,允许您根据含义而不是精确匹配来查找记忆。要启用此功能,请为存储配置嵌入模型 (embedding model)fields 参数或在存储记忆时指定 index 参数来控制记忆的哪些部分被嵌入
在 LangGraph 中使用
有了这些,我们在 LangGraph 中使用memoryStore。memoryStore 与检查点记录器协同工作:检查点记录器如上所述将状态保存到线程,而 memoryStore 允许我们存储任意信息以便跨线程访问。我们按如下方式同时使用检查点记录器和 memoryStore 编译图。
thread_id 调用图,就像以前一样,同时也使用 user_id,我们将使用它来将我们的记忆命名空间划分到如上所示的特定用户。
runtime 参数在任何节点中访问存储和 userId。以下是您如何使用它来保存记忆的方法
store.search 方法来获取记忆。回想一下,记忆以对象列表的形式返回,可以转换为字典。
user_id 相同,我们仍然可以访问相同的记忆。
langgraph.json 文件中配置索引设置。例如
优化检查点存储
检查点记录器 (Checkpointer) 库
在底层,检查点功能由符合BaseCheckpointSaver 接口的检查点记录器对象提供支持。LangGraph 提供了几种检查点记录器实现,全部通过独立的、可安装的库实现。
@langchain/langgraph-checkpoint:检查点记录器保存器的基础接口 (BaseCheckpointSaver) 和序列化/反序列化接口 (SerializerProtocol)。包含用于实验的内存中检查点记录器实现 (MemorySaver)。LangGraph 已经包含了@langchain/langgraph-checkpoint。@langchain/langgraph-checkpoint-sqlite:使用 SQLite 数据库的 LangGraph 检查点记录器实现 (SqliteSaver)。非常适合实验和本地工作流。需要单独安装。@langchain/langgraph-checkpoint-postgres:一种使用 Postgres 数据库的高级检查点记录器 (PostgresSaver),用于 LangSmith。非常适合在生产环境中使用。需要单独安装。@langchain/langgraph-checkpoint-mongodb:一种由 MongoDB 支持的高级检查点记录器 (MongoDBSaver) 和长期记忆存储 (MongoDBStore)。该存储支持跨线程持久化,并可选集成向量搜索。非常适合生产环境使用。需要单独安装。@langchain/langgraph-checkpoint-redis:一种使用 Redis 数据库的高级检查点记录器 (RedisSaver)。非常适合在生产环境中使用。需要单独安装。
检查点记录器接口
每个检查点记录器都符合BaseCheckpointSaver 接口,并实现了以下方法
.put- 存储包含其配置和元数据的检查点。.putWrites- 存储与检查点关联的中间写入(即 待处理写入)。.getTuple- 使用给定的配置(thread_id和checkpoint_id)获取检查点元组。这用于在graph.getState()中填充StateSnapshot。.list- 列出符合给定配置和过滤条件的检查点。这用于在graph.getStateHistory()中填充状态历史记录。

