当前位置: 首页 > news >正文

langGraph从入门到精通(四)——基于LangGraph的State状态模式设计 - 指南

1 导语

在构建AI Agent时,状态(State)是连接各个节点的灵魂。LangGraph 采用消息传递机制来驱动程序的运行,而 State 则是信息的载体。本文将深入探讨 LangGraph 中最基础也最核心的部分——State的定义模式设计。通过学习本文,你将掌握如何利用字典和 TypedDict 构建可靠的图状态,理解节点间数据流动的底层逻辑,为开发复杂多代理系统打下坚实基础。

2 技术栈清单

3 项目核心原理

LangGraph 的核心在于状态管理。State 本质上是一个共享的数据结构,它在图中从左向右流动。每个节点执行完毕后,会将更新的部分“广播”给状态。默认情况下,状态更新采用覆盖机制(Overwriting),但通过 Reducer 函数(如 operator.add),我们可以实现更复杂的逻辑,例如消息的自动追加
AI Agent应用程序的设计中,场景的复杂性直接决定了构建图的复杂度。例如,最简单的场景可能仅涉及一个大模型的问答流程,形式为:START -> Node -> END(其中大模型的交互逻辑被封装在Node中)。而更复杂的场景则可能涉及多个AI Agent的协同工作,包括多个分支和循环的构成。无论是简单还是复杂的图,LangGraph的价值永远不在于如何去定义节点,如何去定义边,而是在于如何有效管理各个节点的输入和输出,以保持图的持续运行状态LangGraph底层图算法采用消息传递机制来定义和执行这些图中的交互流程,其中状态(State)组件扮演着关键的载体角色,负责在图的各个节点之间传递信息。这也就意味着,LangGraph框架的核心在于State的有效使用和掌握。在复杂的应用中,State组件需要存储和管理的信息量会显著增加。核心功能如工具使用、记忆能力和人机交互等,都依赖State来实现和维护。所以,接下来我们对LangGragh框架的探索,都将紧密围绕State的实现和应用机制展开,这包括LangGraph内置封装好的工具/方法的使用,以及我们自定义构建功能时的实现方法。


LangGraph构建的图中的每个节点都具备访问、读取和写入状态的权限。当某一个节点去修改状态时,它会将此信息广播到图中的所有其他节点。这种广播机制允许其他节点响应状态的变化并相应地调整其行为。如上图所示,从初始状态(Initial State)开始,其中包含了一条消息 { “x”: “10” },随着消息在节点间通过边传递,每个节点根据其逻辑对状态进行更新。Node 1 和 Node 2 分别对状态进行了处理和变更,结果是在图的末端,我们得到了一个包含三条消息的最终状态 { “x”: “10” }, { “x”: “11” }, { “y”: “9” }。**从开发的角度来看,State实际上是一个共享的数据结构。如上图所示,状态表现为一个简单的字典。通过对这个字典进行读写操作,可以实现自左而右的数据流动,从而构建一个可运行的图结构。那么根据前面学习的内容,我们可以利用这个流程来复现并理解图中的动态数据交换,整体的设计如下:

4 实战步骤

4.1 环境准备

在开始代码实现前,确保安装了核心依赖:

pip install langgraph==1.0.5 typing-extensions==4.15.0

4.2 代码实现

我们通过两个示例对比“字典模式”与“TypedDict模式”。代码保存在 02-state-schema.py

import operator
from typing import Annotated
from langgraph.graph import StateGraph, START, END
from typing_extensions import TypedDict
# 1. 使用字典类型定义状态 (灵活但缺乏约束)
def test_dict_state():
# 初始化一个以字典为状态模式的图
builder = StateGraph(dict)
def addition(state):
# 节点仅返回需要更新的部分,LangGraph 内部会自动合并
return {"x": state["x"] + 1}
def subtraction(state):
# 新增一个键 y
return {"y": state["x"] - 2}
builder.add_node("addition", addition)
builder.add_node("subtraction", subtraction)
builder.add_edge(START, "addition")
builder.add_edge("addition", "subtraction")
builder.add_edge("subtraction", END)
graph = builder.compile()
result = graph.invoke({"x": 10})
print(f"字典状态执行结果: {result}")
# 2. 使用 TypedDict 定义状态 (推荐:强类型约束)
class State(TypedDict):
x: int
y: int
def test_typeddict_state():
builder = StateGraph(State)
def addition(state: State):
# 关键逻辑:读取当前状态 x 并加 1
return {"x": state["x"] + 1}
def subtraction(state: State):
# 关键逻辑:基于更新后的 x 计算 y
return {"y": state["x"] - 2}
builder.add_node("addition", addition)
builder.add_node("subtraction", subtraction)
builder.add_edge(START, "addition")
builder.add_edge("addition", "subtraction")
builder.add_edge("subtraction", END)
graph = builder.compile()
result = graph.invoke({"x": 10})
print(f"TypedDict状态执行结果: {result}")
# 3. 使用 Reducer 实现列表追加 (进阶:解决状态覆盖问题)
class ReducerState(TypedDict):
# 使用 Annotated 标注该字段的更新方式为 operator.add (追加而非覆盖)
messages: Annotated[list[str], operator.add]
def test_reducer_state():
builder = StateGraph(ReducerState)
def node_1(state: ReducerState):
# 节点 1 返回第一条消息
return {"messages": ["这是来自节点1的消息"]}
def node_2(state: ReducerState):
# 节点 2 返回第二条消息
return {"messages": ["这是来自节点2的消息"]}
builder.add_node("node_1", node_1)
builder.add_node("node_2", node_2)
builder.add_edge(START, "node_1")
builder.add_edge("node_1", "node_2")
builder.add_edge("node_2", END)
graph = builder.compile()
# 初始状态带有一条消息
result = graph.invoke({"messages": ["初始消息"]})
print(f"Reducer(追加模式)执行结果: {result}")
if __name__ == "__main__":
test_dict_state()
test_typeddict_state()
test_reducer_state()

4.3 功能测试

运行脚本,观察两种模式下状态是如何在节点间传递并完成计算的。

5 核心代码解析

5.1 StateGraph(dict) 灵活模式

builder = StateGraph(dict)
  • 核心作用:定义了一个没有任何模式约束的图。
  • 关联逻辑:这种方式下,节点可以自由增加或修改任何键值。虽然灵活性极高,但在大型项目中容易导致键名冲突或类型错误。

5.2 TypedDict 强约束模式

划重点:这是工业级开发的标准选择。

class State(TypedDict):
x: int
y: int
  • 核心作用:通过 Python 的类型提示(Type Hinting)显式声明状态结构。
  • 为何这样实现StateGraph(State) 允许 LangGraph 在编译阶段(Compile Time)进行初步校验。解析重点在于它规定了节点返回的字典必须符合声明的 Key 和 Value 类型,有效防止了动态运行时因为访问不存在的键而导致的中断。

5.3 Annotated 与 Reducer 机制

划重点:这是实现对话记忆(Memory)的底层技术。

messages: Annotated[list[str], operator.add]
  • 核心作用:告诉 LangGraph,当多个节点向 messages 写入数据时,不要覆盖,而是将结果 add(追加)到一起。
  • 关联逻辑:这使得我们可以轻松追踪对话历史。每个节点只需要返回当前产生的消息,LangGraph 会自动维护一个完整的消息链条。

6 效果验证

通过 graph.invoke() 传递初始状态后,系统会顺序执行各节点,并返回合并后的最终状态字典。

【图片占位符:核心功能运行效果截图 - 终端显示 x 与 y 的最终合并结果】

7 踩坑记录

7.1 KeyDoesNotExist 错误

  • 错误现象KeyError: 'x'
  • 根因分析:在节点函数中尝试访问 state["x"],但初始输入或前置节点未提供该键。
  • 解决方案:确保在 invoke 时传入完整的必要字段,或在 TypedDict 中通过 total=False 设置可选键。

7.2 节点返回值类型不匹配

7.3 状态覆盖问题

  • 错误现象:后一个节点的返回覆盖了前一个节点的同名键。
  • 根因分析:LangGraph 默认使用“覆盖”机制。
  • 解决方案:若需保留历史记录(如对话历史),必须使用 Annotated 配合 operator.addReducer 函数。

8 总结与扩展

掌握 State 的定义模式 是开启 LangGraph 高阶开发的大门。通过 TypedDict 我们建立了一套可预测的数据契约。划重点:状态在任何给定时间只包含来自一个节点的更新信息,但 LangGraph 内部的合并机制让它看起来像一个全局共享池。下一步,我们将研究如何通过 Annotatedadd_messages 实现对话历史的自动追溯。

欢迎评论区留言讨论核心主题相关的问题~

http://www.jsqmd.com/news/382590/

相关文章:

  • 关于凸性的 things(wqs + slope trick + 闵可夫斯基和)
  • 【Docker进阶篇】拒绝重复构建镜像!.env文件+Profile实现多环境无缝切换
  • 华为OD机考双机位C卷 - 测试用例执行计划 (Java Python JS GO C++ C)
  • 手摸手在扣子平台搭建周报智能体[特殊字符]
  • 华为OD机考双机位C卷 - 相对开音节 (Java Python JS GO C++ C)
  • 为什么通用寄存器RAX,EAX,AX后面都有一个‘X’? - i686
  • 【MATLAB】多子阵合成孔径声纳(SAS)成像仿真——基于时域反向投影(BP)算法 - 详解
  • 【KnowledgeLITE | 知识速递 第一期】为什么通用寄存器RAX,EAX,AX后面都有一个‘X’? - i686
  • Hadoop 在大数据领域的开源生态优势
  • 多智能体协作在复杂推理任务中的应用
  • 1、、、
  • 安全防护:AI多轮对话系统中的敏感信息识别与过滤机制
  • proteus_snake_pswd小记
  • 大数据领域Kafka与其他消息队列的对比分析
  • Debian 13 VMware Fusion 字号太小?一招解决!
  • 语言模型在复杂决策树生成中的能力研究
  • 11:【Windows Git】换行符警告 CRLF/LF core.autocrlf设置
  • 12:【GitHub PAT】Personal Access Token过期/2FA后HTTPS推送失败(2026仍高频)
  • 深入解析:推荐使用的C++ IDE
  • 2026年诚信的危化品防爆箱厂家品牌实力推荐榜 - 品牌鉴赏师
  • 2026年评价高的易燃易爆品防爆柜,实验室防爆柜厂家选型推荐指南 - 品牌鉴赏师
  • 数据合成中的通用模型蒸馏、领域模型蒸馏和模型自我提升 - 详解
  • openFuyao 社区 2025 年度报告,致谢所有同行者!
  • 全套恒压供水(3 托 3)系统:高效与稳定的完美结合
  • Selenium SafariDriver 深度解析
  • 大数据领域Storm的集群搭建指南
  • Selenide深度解析
  • 题解:AT_ttpc2015_o 数列色ぬり -数形结合法
  • 详细介绍:opencv基础(读取图片与视频)
  • 第11届新加坡国际亚新艺术节圆满落幕 700余选手共赴艺术盛宴