设置
安装langgraph:
定义和更新状态
这里我们展示如何在 LangGraph 中定义和更新状态。我们将演示:定义状态
LangGraph 中的状态使用StateSchema 类定义。这提供了一个统一的 API,它接受用于各个字段的标准模式(如 Zod),以及像 ReducedValue、MessagesValue 和 UntrackedValue 这样的特殊值类型。
默认情况下,图将具有相同的输入和输出模式,状态决定了该模式。有关如何定义不同的输入和输出模式,请参阅定义输入和输出模式。
让我们考虑一个使用消息的简单示例。这代表了许多 LLM 应用中一种通用的状态表述。更多详情请参阅我们的概念页面。
更新状态
让我们构建一个包含单个节点的示例图。我们的节点只是一个 TypeScript 函数,它读取图的状态并对其进行更新。此函数的第一个参数始终是状态:StateGraph 来定义一个在此状态上操作的图。然后我们使用 addNode 来填充我们的图。
- 我们通过更新状态的单个键来启动调用。
- 我们在调用结果中接收到整个状态。
使用归约器处理状态更新
状态中的每个键都可以有自己的独立归约器函数,该函数控制来自节点的更新如何被应用。如果没有明确指定归约器函数,则假定对该键的所有更新都应覆盖它。 在我们之前的示例中,我们使用了MessagesValue,它已经有一个内置的归约器。对于自定义字段,你可以使用 ReducedValue 来定义更新的应用方式。
在之前的示例中,我们的节点通过向状态中的 "messages" 键追加一条消息来更新它。MessagesValue 归约器会自动处理这一点:
MessagesValue
实际上,更新消息列表时还有额外的考虑因素: LangGraph 包含内置的MessagesValue,它处理了这些考虑因素:
MessagesValue 以方便使用,这样我们就可以:
定义输入和输出模式
默认情况下,StateGraph 使用单一模式操作,所有节点都期望使用该模式进行通信。但是,也可以为图定义不同的输入和输出模式。
当指定了不同的模式时,内部模式仍将用于节点之间的通信。输入模式确保提供的输入符合预期的结构,而输出模式根据定义的输出模式过滤内部数据,仅返回相关信息。
下面,我们将看到如何定义不同的输入和输出模式。
在节点之间传递私有状态
在某些情况下,你可能希望节点交换对中间逻辑至关重要但不需要成为图主要模式一部分的信息。这些私有数据与图的整体输入/输出无关,只应在特定节点之间共享。 下面,我们将创建一个由三个节点(node_1、node_2 和 node_3)组成的示例顺序图,其中私有数据在前两个步骤(node_1 和 node_2)之间传递,而第三个步骤(node_3)只能访问公共的整体状态。替代的状态定义方法
虽然StateSchema 是定义状态的推荐方法,但 LangGraph 支持其他几种方法。本节涵盖所有可用选项。
Channels API
Channels API 提供了对状态管理的底层控制。LangGraph 提供了几种内置的通道类型:
使用对象简写:
当你传递一个带有
reducer 和 default 的对象时,它会创建一个 BinaryOperatorAggregate 通道。传递 null 会创建一个 LastValue 通道:
Annotation.Root
Annotation.Root 提供了一种声明式的方式来定义带有归约器的状态。它类似于 StateSchema,但使用不同的语法:
使用 Zod v3 的 Zod 对象
使用 Zod v3 时,你可以使用普通的z.object() 模式定义状态。LangGraph 扩展了 Zod v3,添加了 .langgraph 插件,该插件提供了 .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 节点控制:我们的节点只是读取图的状态并对其进行更新的 TypeScript 函数。此函数的第一个参数始终是状态:最后,我们定义图。我们使用 StateGraph 来定义一个在此状态上操作的图。然后我们将使用 addNode 和 addEdge 来填充我们的图并定义其控制流。请注意:让我们进行一个简单的调用:请注意:
- 状态更新如何被检查点保存
- 在Human in the Loop工作流中如何恢复中断
- 我们如何使用 LangGraph 的时间旅行功能“回退”和分支执行
- 在状态的一个键中填充一个值
- 更新相同的值
- 填充一个不同的值
请注意,当向状态发出更新时,每个节点只需指定它希望更新的键的值。默认情况下,这将覆盖相应键的值。你也可以使用归约器来控制更新的处理方式——例如,你可以将连续的更新追加到一个键中。有关更多详细信息,请参阅使用归约器处理状态更新。
.addEdge接受节点的名称,对于函数,默认为node.name。- 我们必须指定图的入口点。为此,我们添加一条带有 START 节点的边。
- 当没有更多节点可执行时,图停止。
- 我们通过为单个状态键提供值来启动调用。我们必须始终至少为一个键提供值。
- 我们传入的值被第一个节点覆盖。
- 第二个节点更新了该值。
- 第三个节点填充了一个不同的值。
创建分支
节点的并行执行对于加速整体图操作至关重要。LangGraph 提供了对节点并行执行的原生支持,这可以显著提高基于图的工作流的性能。这种并行化是通过扇出和扇入机制实现的,利用标准边和 conditional_edges。以下是一些示例,展示如何添加创建适合你的分支数据流。并行运行图节点
在这个示例中,我们从Node A 扇出到 B 和 C,然后扇入到 D。对于我们的状态,我们指定了归约器添加操作。这将组合或累积状态中特定键的值,而不是简单地覆盖现有值。对于列表,这意味着将新列表与现有列表连接。有关使用归约器更新状态的更多详细信息,请参阅上面的状态归约器部分。
在上面的示例中,节点
"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
如果需要,我们可以将图渲染为.png。这使用 Mermaid.ink API 生成图表。
将这些文档连接到 Claude、VSCode 等,通过 MCP
获取实时答案。

