跳到主要内容
持久化执行是一种技术,其中一个进程或工作流会在关键点保存其进度,从而允许它暂停并在以后从中断的地方精确恢复。这在需要人工参与的场景中特别有用,用户可以在继续之前检查、验证或修改进程;以及在可能遇到中断或错误(例如,LLM 调用超时)的长时间运行任务中。通过保留已完成的工作,持久化执行可以使进程在不重新处理先前步骤的情况下恢复——即使在长时间延迟(例如,一周后)之后也是如此。 LangGraph 的内置持久性层为工作流提供持久化执行,确保每个执行步骤的状态都保存到持久存储中。此功能保证,如果工作流中断——无论是由于系统故障还是人工参与交互——它都可以从上次记录的状态恢复。
如果您将 LangGraph 与检查点器一起使用,您已经启用了持久化执行。您可以随时暂停和恢复工作流,即使在中断或失败之后也是如此。要充分利用持久化执行,请确保您的工作流设计为确定性幂等性,并将任何副作用或非确定性操作封装在任务中。您可以同时使用任务StateGraph (Graph API)函数式 API

要求

要利用 LangGraph 中的持久化执行,您需要
  1. 通过指定一个将保存工作流进度的检查点器,在工作流中启用持久性
  2. 在执行工作流时指定一个线程标识符。这将跟踪工作流特定实例的执行历史。
  3. 将任何非确定性操作(例如,随机数生成)或具有副作用的操作(例如,文件写入、API 调用)封装在任务中,以确保当工作流恢复时,这些操作不会针对特定运行重复,而是从持久性层检索其结果。有关更多信息,请参阅确定性和一致性重放

确定性和一致性重放

当您恢复工作流运行时,代码不会从执行停止的同一行代码恢复;相反,它将确定一个合适的起点,从该点继续。这意味着工作流将从起点重放所有步骤,直到到达停止点。 因此,当您编写用于持久化执行的工作流时,您必须将任何非确定性操作(例如,随机数生成)以及任何具有副作用的操作(例如,文件写入、API 调用)封装在任务节点中。 为确保您的工作流是确定性的并且可以一致地重放,请遵循以下指南:
  • 避免重复工作:如果一个节点包含多个具有副作用的操作(例如,日志记录、文件写入或网络调用),请将每个操作封装在一个单独的任务中。这确保了当工作流恢复时,这些操作不会重复,并且其结果从持久性层检索。
  • 封装非确定性操作: 将任何可能产生非确定性结果的代码(例如,随机数生成)封装在任务节点中。这确保了在恢复时,工作流以相同的输出遵循精确记录的步骤序列。
  • 使用幂等操作:如果可能,请确保副作用(例如,API 调用、文件写入)是幂等的。这意味着如果操作在工作流中失败后重试,它将与第一次执行时产生相同的效果。这对于导致数据写入的操作尤为重要。如果一个任务启动但未能成功完成,工作流的恢复将重新运行该任务,依靠记录的结果来保持一致性。使用幂等键或验证现有结果以避免意外重复,确保平稳和可预测的工作流执行。
有关要避免的一些陷阱示例,请参阅函数式 API 中的常见陷阱部分,该部分展示了如何使用任务来构造代码以避免这些问题。同样的原则也适用于StateGraph (Graph API)

持久性模式

LangGraph 支持三种持久性模式,允许您根据应用程序的要求平衡性能和数据一致性。持久性模式,从最低到最高持久性,如下所示 较高的持久性模式会增加工作流执行的开销。
v0.6.0 中新增 使用 durability 参数代替 checkpoint_during(v0.6.0 中已弃用)进行持久性策略管理
  • durability="async" 替换 checkpoint_during=True
  • durability="exit" 替换 checkpoint_during=False
用于持久性策略管理,具有以下映射
  • checkpoint_during=True -> durability="async"
  • checkpoint_during=False -> durability="exit"

“退出”

更改仅在图执行完成(成功或错误)时持久化。这为长时间运行的图提供了最佳性能,但意味着不会保存中间状态,因此您无法从执行中的故障中恢复或中断图执行。

“异步”

更改在下一步执行时异步持久化。这提供了良好的性能和持久性,但如果进程在执行过程中崩溃,检查点可能无法写入,存在很小的风险。

“同步”

更改在下一步开始之前同步持久化。这确保了每个检查点都在继续执行之前写入,以牺牲一些性能开销为代价提供高持久性。 您可以在调用任何图执行方法时指定持久性模式:

在节点中使用任务

如果一个节点包含多个操作,您可能会发现将每个操作转换为一个任务比将操作重构为单独的节点更容易。
  • 原始
  • 使用任务
import { StateGraph, START, END } from "@langchain/langgraph";
import { MemorySaver } from "@langchain/langgraph";
import { v4 as uuidv4 } from "uuid";
import * as z from "zod";

// Define a Zod schema to represent the state
const State = z.object({
  url: z.string(),
  result: z.string().optional(),
});

const callApi = async (state: z.infer<typeof State>) => {
  const response = await fetch(state.url);  
  const text = await response.text();
  const result = text.slice(0, 100); // Side-effect
  return {
    result,
  };
};

// Create a StateGraph builder and add a node for the callApi function
const builder = new StateGraph(State)
  .addNode("callApi", callApi)
  .addEdge(START, "callApi")
  .addEdge("callApi", END);

// Specify a checkpointer
const checkpointer = new MemorySaver();

// Compile the graph with the checkpointer
const graph = builder.compile({ checkpointer });

// Define a config with a thread ID.
const threadId = uuidv4();
const config = { configurable: { thread_id: threadId } };

// Invoke the graph
await graph.invoke({ url: "https://www.example.com" }, config);

恢复工作流

一旦您在工作流中启用了持久化执行,您就可以在以下场景中恢复执行
  • 暂停和恢复工作流: 使用中断函数在特定点暂停工作流,并使用Command原语以更新状态恢复它。有关更多详细信息,请参阅中断
  • 从故障中恢复: 在异常(例如,LLM 提供商中断)后,自动从上一个成功检查点恢复工作流。这涉及到使用相同的线程标识符执行工作流,并提供 null 作为输入值(请参阅此函数式 API 的示例)。

恢复工作流的起点

  • 如果您使用的是StateGraph (Graph API),则起点是执行停止的节点的开头。
  • 如果您在节点内进行子图调用,则起点将是调用被停止的子图的节点。在子图内部,起点将是执行停止的特定节点
  • 如果您使用的是函数式 API,则起点是执行停止的入口点的开头。

以编程方式连接这些文档到 Claude、VSCode 等,通过 MCP 获取实时答案。
© . This site is unofficial and not affiliated with LangChain, Inc.