> ## Documentation Index
> Fetch the complete documentation index at: https://nvd-54.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 持久执行

**持久执行**是一种技术，其中进程或工作流在关键点保存其进度，允许它暂停并在稍后从中断处精确恢复。这在需要[人机协作](/oss/javascript/langgraph/interrupts)的场景中特别有用，用户可以在继续之前检查、验证或修改流程，以及在可能遇到中断或错误的长时间运行任务中（例如，调用 LLM 超时）。通过保存已完成的工作，持久执行使进程能够在不重新处理之前步骤的情况下恢复——即使在相当长的延迟之后（例如，一周后）。

LangGraph 内置的[持久化](/oss/javascript/langgraph/persistence)层为工作流提供持久执行，确保每个执行步骤的状态都保存到持久存储中。此功能保证如果工作流被中断——无论是系统故障还是[人机协作](/oss/javascript/langgraph/interrupts)交互——都可以从最后记录的状态恢复。

<Tip>
  如果你正在使用带有检查点的 LangGraph，你已经启用了持久执行。你可以在任何时候暂停和恢复工作流，即使在中断或故障之后。
  为了充分利用持久执行，请确保你的工作流被设计为[确定性的](#determinism-and-consistent-replay)和[幂等的](#determinism-and-consistent-replay)，并将任何副作用或非确定性操作包装在[任务](/oss/javascript/langgraph/functional-api#task)中。你可以在 [StateGraph（图 API）](/oss/javascript/langgraph/graph-api)和[函数式 API](/oss/javascript/langgraph/functional-api)中使用[任务](/oss/javascript/langgraph/functional-api#task)。
</Tip>

## 要求

要在 LangGraph 中利用持久执行，你需要：

1. 通过指定将保存工作流进度的[检查点](/oss/javascript/langgraph/persistence#checkpointer-libraries)来在工作流中启用[持久化](/oss/javascript/langgraph/persistence)。

2. 在执行工作流时指定[线程标识符](/oss/javascript/langgraph/persistence#threads)。这将跟踪工作流特定实例的执行历史。

3. 将任何非确定性操作（例如，随机数生成）或具有副作用的操作（例如，文件写入、API 调用）包装在[任务](https://reference.langchain.com/javascript/langchain-langgraph/index/task)中，以确保当工作流恢复时，这些操作不会针对特定运行重复执行，而是从持久化层检索其结果。更多信息请参阅[确定性和一致重放](#determinism-and-consistent-replay)。

## 确定性和一致重放

当你恢复工作流运行时，代码**不会**从执行停止的**同一行代码**恢复；相反，它会确定一个合适的[起始点](#starting-points-for-resuming-workflows)来接续之前中断的地方。这意味着工作流将从[起始点](#starting-points-for-resuming-workflows)重放所有步骤，直到到达停止的位置。

因此，当你编写用于持久执行的工作流时，必须将任何非确定性操作（例如，随机数生成）和任何具有副作用的操作（例如，文件写入、API 调用）包装在[任务](/oss/javascript/langgraph/functional-api#task)或[节点](/oss/javascript/langgraph/graph-api#nodes)中。

为了确保你的工作流是确定性的并且可以一致重放，请遵循以下准则：

* **避免重复工作**：如果一个[节点](/oss/javascript/langgraph/graph-api#nodes)包含多个具有副作用的操作（例如，日志记录、文件写入或网络调用），请将每个操作包装在单独的**任务**中。这确保当工作流恢复时，操作不会重复执行，其结果将从持久化层检索。
* **封装非确定性操作**：将任何可能产生非确定性结果的代码（例如，随机数生成）包装在**任务**或**节点**中。这确保在恢复时，工作流以相同的结果遵循精确记录的步骤序列。
* **使用幂等操作**：尽可能确保副作用（例如，API 调用、文件写入）是幂等的。这意味着如果在工作流失败后重试操作，它将与第一次执行时产生相同的效果。这对于导致数据写入的操作尤其重要。如果**任务**开始但未能成功完成，工作流的恢复将重新运行该**任务**，依赖记录的结果来维持一致性。使用幂等性键或验证现有结果以避免意外重复，确保工作流执行顺畅且可预测。

有关应避免的陷阱示例，请参阅函数式 API 中的[常见陷阱](/oss/javascript/langgraph/functional-api#common-pitfalls)部分，该部分展示了如何使用**任务**来构建代码以避免这些问题。同样的原则适用于 [StateGraph（图 API）](https://reference.langchain.com/javascript/langchain-langgraph/index/StateGraph)。

## 持久性模式

LangGraph 支持三种持久性模式，允许你根据应用需求平衡性能和数据一致性。更高的持久性模式会为工作流执行增加更多开销。你可以在调用任何图执行方法时指定持久性模式：

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
await graph.stream(
  { input: "test" },
  { durability: "sync" }
)
```

持久性模式从最低到最高持久性依次为：

* `"exit"`：LangGraph 仅在图执行成功退出、出错或由于人机协作中断退出时持久化更改。这为长时间运行的图提供了最佳性能，但意味着中间状态不会被保存，因此你无法从执行过程中发生的系统故障（如进程崩溃）中恢复。
* `"async"`：LangGraph 在下一步执行时异步持久化更改。这提供了良好的性能和持久性，但如果进程在执行过程中崩溃，存在 LangGraph 未写入检查点的小风险。
* `"sync"`：LangGraph 在下一步开始前同步持久化更改。这确保 LangGraph 在继续执行前写入每个检查点，以一些性能开销为代价提供高持久性。

## 在节点中使用任务

如果一个[节点](/oss/javascript/langgraph/graph-api#nodes)包含多个操作，你可能会发现将每个操作转换为**任务**比将操作重构为单独的节点更容易。

<Tabs>
  <Tab title="原始版本">
    ```typescript theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
    import { StateGraph, StateSchema, GraphNode, START, END, MemorySaver } from "@langchain/langgraph";
    import { v7 as uuid7 } from "uuid";
    import * as z from "zod";

    // 定义 StateSchema 来表示状态
    const State = new StateSchema({
      url: z.string(),
      result: z.string().optional(),
    });

    const callApi: GraphNode<typeof State> = async (state) => {
      const response = await fetch(state.url);  // [!code highlight]
      const text = await response.text();
      const result = text.slice(0, 100); // 副作用
      return {
        result,
      };
    };

    // 创建 StateGraph 构建器并为 callApi 函数添加节点
    const builder = new StateGraph(State)
      .addNode("callApi", callApi)
      .addEdge(START, "callApi")
      .addEdge("callApi", END);

    // 指定检查点
    const checkpointer = new MemorySaver();

    // 使用检查点编译图
    const graph = builder.compile({ checkpointer });

    // 定义带有线程 ID 的配置
    const threadId = uuid7();
    const config = { configurable: { thread_id: threadId } };

    // 调用图
    await graph.invoke({ url: "https://www.example.com" }, config);
    ```
  </Tab>

  <Tab title="使用任务">
    ```typescript theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
    import { StateGraph, StateSchema, GraphNode, START, END, MemorySaver, task } from "@langchain/langgraph";
    import { v7 as uuid7 } from "uuid";
    import * as z from "zod";

    // 定义 StateSchema 来表示状态
    const State = new StateSchema({
      urls: z.array(z.string()),
      results: z.array(z.string()).optional(),
    });

    const makeRequest = task("makeRequest", async (url: string) => {
      const response = await fetch(url);  // [!code highlight]
      const text = await response.text();
      return text.slice(0, 100);
    });

    const callApi: GraphNode<typeof State> = async (state) => {
      const requests = state.urls.map((url) => makeRequest(url));  // [!code highlight]
      const results = await Promise.all(requests);
      return {
        results,
      };
    };

    // 创建 StateGraph 构建器并为 callApi 函数添加节点
    const builder = new StateGraph(State)
      .addNode("callApi", callApi)
      .addEdge(START, "callApi")
      .addEdge("callApi", END);

    // 指定检查点
    const checkpointer = new MemorySaver();

    // 使用检查点编译图
    const graph = builder.compile({ checkpointer });

    // 定义带有线程 ID 的配置
    const threadId = uuid7();
    const config = { configurable: { thread_id: threadId } };

    // 调用图
    await graph.invoke({ urls: ["https://www.example.com"] }, config);
    ```
  </Tab>
</Tabs>

## 恢复工作流

一旦你在工作流中启用了持久执行，你可以在以下场景中恢复执行：

* **暂停和恢复工作流**：使用 [interrupt](https://reference.langchain.com/javascript/langchain-langgraph/index/interrupt) 函数在特定点暂停工作流，使用 [`Command`](https://reference.langchain.com/javascript/langchain-langgraph/index/Command) 原语以更新后的状态恢复它。更多详情请参阅[**中断**](/oss/javascript/langgraph/interrupts)。
* **从故障中恢复**：在异常（例如，LLM 提供商中断）后从最后一个成功的检查点自动恢复工作流。这涉及通过提供 `null` 作为输入值，使用相同的线程标识符执行工作流（参见函数式 API 中的[此示例](/oss/javascript/langgraph/use-functional-api#resuming-after-an-error)）。

## 恢复工作流的起始点

* 如果你使用的是 [StateGraph（图 API）](/oss/javascript/langgraph/graph-api)，起始点是执行停止处的[**节点**](/oss/javascript/langgraph/graph-api#nodes)的开始。
* 如果你在节点内进行子图调用，起始点将是调用被停止子图的**父**节点。
  在子图内部，起始点将是执行停止处的特定[**节点**](/oss/javascript/langgraph/graph-api#nodes)。
* 如果你使用的是函数式 API，起始点是执行停止处的[**入口点**](/oss/javascript/langgraph/functional-api#entrypoint)的开始。

## 优雅关闭

***

<div className="source-links">
  <Callout icon="terminal-2">
    [将这些文档连接](/use-these-docs)到 Claude、VSCode 等工具，通过 MCP 获取实时答案。
  </Callout>

  <Callout icon="edit">
    [在 GitHub 上编辑此页面](https://github.com/langchain-ai/docs/edit/main/src/oss/langgraph/durable-execution.mdx) 或 [提交问题](https://github.com/langchain-ai/docs/issues/new/choose)。
  </Callout>
</div>
