设置
安装langgraph:
定义和更新状态
这里我们将展示如何在 LangGraph 中定义和更新状态。我们将演示:定义状态
LangGraph 中的状态使用StateSchema 类定义。它提供了一个统一的 API,可以接受字段的标准架构(如 Zod),以及特殊值类型如 ReducedValue、MessagesValue 和 UntrackedValue。
默认情况下,图将具有相同的输入和输出架构,而状态决定了该架构。有关如何定义不同的输入和输出架构,请参阅定义输入和输出架构。
让我们考虑一个使用消息的简单例子。这代表了许多 LLM 应用程序中一种通用的状态表示方式。更多详情请参阅我们的概念页面。
更新状态
让我们构建一个包含单个节点的示例图。我们的节点只是一个 TypeScript 函数,它读取图的状态并对其进行更新。此函数的第一个参数始终是状态:StateGraph 来定义一个在此状态上操作的图。然后使用 addNode 来填充我们的图。
- 我们通过更新状态的单个键来启动调用。
- 我们在调用结果中接收整个状态。
使用归约器处理状态更新
状态中的每个键都可以拥有自己独立的归约器函数,该函数控制来自节点的更新如何被应用。如果没有显式指定归约器函数,则假定对该键的所有更新都应覆盖它。 在前面的例子中,我们使用了MessagesValue,它已经内置了一个归约器。对于自定义字段,你可以使用 ReducedValue 来定义如何应用更新。
在前面的例子中,我们的节点通过向 "messages" 键追加一条消息来更新状态。MessagesValue 归约器会自动处理:
MessagesValue
在实践中,更新消息列表还有其他注意事项: LangGraph 包含内置的MessagesValue 来处理这些考虑:
MessagesValue,因此我们可以这样写:
定义输入和输出架构
默认情况下,StateGraph 使用单一架构操作,并且所有节点都预期使用该架构进行通信。然而,也可以为图定义不同的输入和输出架构。
当指定了不同的架构时,内部仍会使用一个架构在节点之间通信。输入架构确保提供的输入符合预期的结构,而输出架构则过滤内部数据,仅根据定义的输出架构返回相关信息。
下面,我们将看到如何定义不同的输入和输出架构。
invoke 的输出只包含输出架构。
在节点之间传递私有状态
在某些情况下,你可能希望节点交换对中间逻辑至关重要但不需要成为图主架构一部分的信息。这些私有数据与图的总体输入/输出无关,并且只应在特定节点之间共享。 下面,我们将创建一个由三个节点(node_1、node_2 和 node_3)组成的顺序图示例,其中私有数据在前两个步骤(node_1 和 node_2)之间传递,而第三步(node_3)只能访问公共的整体状态。替代状态定义
虽然StateSchema 是定义状态的推荐方法,但 LangGraph 也支持其他几种方法。本节涵盖所有可用选项。
通道 API
通道 API 提供了对状态管理的底层控制。LangGraph 提供了几种内置通道类型:
使用对象简写:
当你传递一个包含
reducer 和 default 的对象时,它会创建一个 BinaryOperatorAggregate 通道。传递 null 会创建一个 LastValue 通道:
Annotation.Root
Annotation.Root 提供了一种声明式的方式来定义带有归约器的状态。它类似于 StateSchema,但使用不同的语法:
使用 Zod v3 的 Zod 对象
当使用 Zod v3 时,你可以使用普通的z.object() 架构来定义状态。LangGraph 通过一个 .langgraph 插件扩展了 Zod v3,该插件提供了 .reducer() 和 .metadata() 方法:
使用 Zod v4 的 Zod 对象
Zod v4 使用基于注册表的方法。使用 LangGraph 注册表来向架构字段附加元数据:比较表
添加运行时配置
有时你希望在调用图时能够对其进行配置。例如,你可能希望能够在运行时指定使用哪个 LLM 或系统提示符,而不会用这些参数污染图状态。 要添加运行时配置:- 为你的配置指定一个架构
- 将配置添加到节点或条件边的函数签名中
- 将配置传递给图。
扩展示例:在运行时指定 LLM
扩展示例:在运行时指定 LLM
下面我们演示一个实际示例,我们在运行时配置要使用的 LLM。我们将使用 OpenAI 和 Anthropic 的模型。
扩展示例:在运行时指定模型和系统消息
扩展示例:在运行时指定模型和系统消息
下面我们演示一个实际示例,我们配置两个参数:运行时要使用的 LLM 和系统消息。
添加重试策略
在许多用例中,你可能希望你的节点具有自定义的重试策略,例如,如果你正在调用 API、查询数据库或调用 LLM 等。LangGraph 允许你为节点添加重试策略。 要配置重试策略,请将retryPolicy 参数传递给 addNode。retryPolicy 参数接受一个 RetryPolicy 对象。下面我们将使用默认参数实例化一个 RetryPolicy 对象,并将其与一个节点关联:
TypeErrorSyntaxErrorReferenceError
扩展示例:自定义重试策略
扩展示例:自定义重试策略
考虑一个从 SQL 数据库读取的示例。下面我们向节点传递两个不同的重试策略:
在节点内部访问执行信息
你可以通过runtime.executionInfo 访问执行标识和重试信息。这会显示线程、运行和检查点标识符以及重试状态,而无需直接从 config 读取。
访问线程和运行 ID
使用executionInfo 在节点内部访问线程 ID、运行 ID 和其他标识字段:
根据重试状态调整行为
当节点具有重试策略时,使用executionInfo 检查当前尝试次数,并在第一次尝试失败后切换到回退方案:
executionInfo 也可在 Runtime 对象上使用——nodeAttempt 默认为 1,nodeFirstAttemptTime 设置为节点开始执行的时间。
在节点内部访问服务器信息
当你的图在 LangGraph Server 上运行时,你可以通过runtime.serverInfo 访问服务器特定的元数据。
serverInfo 为 null。
需要
deepagents>=1.9.0(或 @langchain/langgraph>=1.2.8)才能使用 runtime.executionInfo 和 runtime.serverInfo。创建步骤序列
前提条件
本指南假设你熟悉上面关于状态的部分。
- 如何构建一个顺序图
- 构建类似图的内置简写方式。
.addNode 和 .addEdge 方法:
为什么使用 LangGraph 将应用程序步骤拆分为序列?
为什么使用 LangGraph 将应用程序步骤拆分为序列?
LangGraph 可以轻松地为你的应用程序添加底层持久化层。
这允许在节点执行之间对状态进行检查点,因此你的 LangGraph 节点控制着:它们还决定执行步骤如何被流式传输,以及你的应用程序如何使用 Studio 进行可视化和调试。让我们演示一个端到端的示例。我们将创建一个三个步骤的序列:我们的节点只是读取图的状态并对其进行更新的 TypeScript 函数。该函数的第一个参数始终是状态:最后,我们定义图。我们使用 StateGraph 来定义一个操作此状态的图。然后我们将使用 addNode 和 addEdge 来填充我们的图并定义其控制流。请注意:让我们进行一次简单的调用:请注意:
- 在状态的某个键中填入一个值
- 更新同一个值
- 填入一个不同的值
请注意,在向状态发出更新时,每个节点只需指定它希望更新的键的值。默认情况下,这会覆盖相应键的值。你也可以使用 Reducer 来控制更新的处理方式——例如,你可以将连续的更新追加到某个键后面。更多详情请参见使用 Reducer 处理状态更新。
.addEdge接受节点的名称,对于函数,默认为node.name。- 我们必须指定图的入口点。为此,我们添加一条边连接到 START 节点。
- 当没有更多节点可执行时,图会停止。
- 我们通过为单个状态键提供一个值来启动调用。我们必须始终为至少一个键提供一个值。
- 我们传入的值被第一个节点覆盖了。
- 第二个节点更新了该值。
- 第三个节点填入了一个不同的值。
创建分支
节点的并行执行对于加速整体图运行至关重要。LangGraph 原生支持节点的并行执行,这可以显著提高基于图的工作流的性能。这种并行化是通过扇出和扇入机制实现的,利用标准边和 conditional_edges。下面是一些示例,展示了如何添加适合你的创建分支数据流。并行运行图节点
在此示例中,我们从Node A 扇出到 B 和 C,然后扇入到 D。对于我们的状态,我们指定了 reducer add 操作。这将为状态中的特定键组合或累积值,而不是简单地覆盖现有值。对于列表,这意味着将新列表与现有列表连接起来。有关使用 Reducer 更新状态的更多详情,请参见上面关于状态 Reducer 的部分。
在上面的示例中,节点
"b" 和 "c" 在同一个超步中并发执行。因为它们在同一个步骤中,节点 "d" 在 "b" 和 "c" 都完成后才执行。重要的是,并行超步的更新可能不会一致排序。如果你需要来自并行超步的更新具有一致、预定的顺序,你应该将输出与用于排序的值一起写入状态的单独字段中。异常处理?
异常处理?
LangGraph 在超步内执行节点,这意味着虽然并行分支是并行执行的,但整个超步是事务性的。如果这些分支中的任何一个引发异常,则不会将任何更新应用到状态(整个超步入错)。重要的是,当使用检查点器时,超步内成功节点的结果会被保存,并且在恢复时不会重复执行。如果你有容易出错的节点(也许想处理不稳定的 API 调用),LangGraph 提供两种方式来解决:
- 你可以在节点内编写常规的 Python 代码来捕获和处理异常。
- 你可以设置一个 retry_policy 来指示图重试引发特定类型异常的节点。只有失败的分支会被重试,因此你不必担心执行冗余工作。
条件分支
如果你的扇出应该在运行时根据状态变化,你可以使用addConditionalEdges 来使用图状态选择一个或多个路径。参见下面的示例,其中节点 a 生成一个状态更新,决定后续节点。
Map-Reduce 和 Send API
LangGraph 使用 Send API 支持 Map-Reduce 和其他高级分支模式。以下是如何使用它的一个示例:创建和控制循环
创建带有循环的图时,我们需要一种机制来终止执行。最常见的方式是添加一个条件边,一旦我们达到某个终止条件,就路由到 END 节点。 你也可以在调用或流式传输图时设置图的递归限制。递归限制设置了图在引发错误之前允许执行的超步数量。阅读更多关于递归限制概念的信息。 让我们考虑一个带有循环的简单图,以更好地理解这些机制的工作原理。 创建循环时,您可以包含一个指定终止条件的条件边:"recursionLimit"。这将引发 GraphRecursionError,您可以捕获并处理它:
"a" 是一个工具调用模型,节点 "b" 代表工具。
在我们的 route 条件边中,我们指定当状态中的 "aggregate" 列表长度超过阈值后应终止。
调用图时,我们可以看到节点 "a" 和 "b" 交替执行,直到满足终止条件。
施加递归限制
在某些应用中,我们可能无法保证会达到给定的终止条件。在这些情况下,我们可以设置图的 递归限制。这会在给定数量的 超级步骤 后引发GraphRecursionError。然后我们可以捕获并处理此异常:
使用 Command 组合控制流和状态更新
将控制流(边)和状态更新(节点)组合起来可能很有用。例如,您可能希望在同一个节点中同时执行状态更新并决定下一步要跳转到哪个节点。LangGraph 提供了一种方法,通过从节点函数返回一个 Command 对象来实现:
StateGraph。请注意,该图没有用于路由的条件边!这是因为控制流是在 nodeA 内部使用 Command 定义的。
导航到父图中的节点
如果您正在使用子图,您可能希望从子图中的一个节点导航到另一个子图(即父图中的不同节点)。为此,您可以在Command 中指定 graph=Command.PARENT:
nodeA 改成一个单节点图,并将其作为子图添加到我们的父图中来实现。
在工具内部使用
一个常见的用例是从工具内部更新图状态。例如,在一个客户支持应用中,您可能希望在对话开始时根据客户的账号或 ID 查询客户信息。要从工具更新图状态,您可以从工具返回Command(update={"my_custom_key": "foo", "messages": [...]}):
Command 更新状态的工具,我们建议使用预构建的 ToolNode,它可以自动处理返回 Command 对象的工具并将其传播到图状态。如果您正在编写一个调用工具的自定义节点,则需要手动将工具返回的 Command 对象作为该节点的更新进行传播。
可视化您的图
这里我们演示如何可视化您创建的图。 您可以可视化任意 Graph,包括 StateGraph。 让我们创建一个简单的示例图来演示可视化。Mermaid
我们也可以将图类转换为 Mermaid 语法。PNG
如果愿意,我们可以将 Graph 渲染成.png。这里使用 Mermaid.ink API 来生成图表。
Connect these docs to Claude, VSCode, and more via MCP for real-time answers.

