理解 LangGraph 的核心模型:State、Node、Edge 与 StateGraph

理解 LangGraph 的核心模型:State、Node、Edge 与 StateGraph 上一篇已经介绍了 LangGraph 为什么会引入 State、Node 和 Edge也写了一个最小的StateGraph示例。真正用 LangGraph 构建稍复杂一些的 Graph 时还需要理解这些问题Node 返回的数据去了哪里后面的 Node 为什么能读取前面产生的结果Edge 在其中负责什么定义完 Graph 以后为什么还需要compile()这些问题都指向同一件事State、Node 和 Edge 在一次 Graph 运行中怎样配合。本篇我们继续深入这些概念理解它们在实际运行时怎样配合。一、StateGraph 的结构通过上一篇我们已初步理解以下三个概念State任务当前有哪些数据Node当前步骤执行什么Edge完成以后执行哪里在StateGraph中它们会组合成一个完整的执行结构。例如有一个订单计算流程START ↓calculate_subtotal ↓apply_discount ↓calculate_total ↓END整个任务需要维护price: 商品单价quantity: 购买数量 subtotal: 小计金额discount: 折扣优惠total: 总计应付这些数据属于 State。三个计算步骤分别是三个 Node。Node 之间的执行顺序由 Edge 描述。对应到代码大致就是builder StateGraph(OrderState) builder.add_node(calculate_subtotal, calculate_subtotal)builder.add_node(apply_discount, apply_discount)builder.add_node(calculate_total, calculate_total) builder.add_edge(START, calculate_subtotal)builder.add_edge(calculate_subtotal, apply_discount)builder.add_edge(apply_discount, calculate_total)builder.add_edge(calculate_total, END)Graph 与普通函数的执行有一个很重要的区别。普通函数调用经常是result function_a()function_b(result)function_a的返回值直接传给function_b。LangGraph 中更常见的运行过程是Node A ↓返回 State 的部分更新 ↓更新当前 State ↓进入下一个 Node ↓Node B 读取更新后的 State因此Node 之间共享的主要是 State。Edge 负责描述执行关系并不承担普通函数调用中“传递返回值”的职责。二、State 的数据范围下面继续使用订单示例。State 可以定义为from typing_extensions import TypedDict class OrderState(TypedDict): price: float quantity: int subtotal: float discount: float total: float再用它创建StateGraphfrom langgraph.graph import StateGraph builder StateGraph(OrderState)这里的OrderState描述了这张 Graph 运行期间会使用哪些状态字段。例如计算小计的 Nodedef calculate_subtotal(state: OrderState): subtotal state[price] * state[quantity] return { subtotal: subtotal }它读取两个字段pricequantity最终只返回subtotal假设执行前的 State 是{ price: 100.0, quantity: 3, subtotal: 0.0, discount: 0.0, total: 0.0,}Node 返回{ subtotal: 300.0}这里返回的并不是完整 State只包含这一步产生的更新。执行完成后当前 State 变成{ price: 100.0, quantity: 3, subtotal: 300.0, discount: 0.0, total: 0.0,}后面的 Node 读取到的已经是这份更新后的状态。这就是前一篇提到的 Partial State Update。State 是 Node 之间的数据约定在实际项目里可以把 State 看成各个 Node 共同使用的一份数据约定。例如计算折扣的节点只需要读取subtotaldef apply_discount(state: OrderState): discount 30.0 if state[subtotal] 300 else 0.0 return { discount: discount }它不需要知道subtotal是怎样计算出来的也不需要直接调用calculate_subtotal()两个 Node 的依赖关系通过 State 建立calculate_subtotal ↓更新 subtotal ↓ State ↓读取 subtotal ↓ apply_discount这样做的意义在简单程序中并不明显。如果只有两三个函数直接调用完全没有问题。但当一个结果后面可能被多个步骤使用或者任务需要暂停、恢复、重试时把跨步骤的数据统一放进 State会比散落在函数参数、局部变量和数据库字段中更易管理与维护。三、Node 的执行范围Node 是 StateGraph 中实际执行业务代码的地方。最常见的 Node 就是一个普通 Python 函数def calculate_subtotal(state: OrderState): return { subtotal: state[price] * state[quantity] }然后注册到 Graphbuilder.add_node( calculate_subtotal, calculate_subtotal)Node 可以完成的工作没有限定为 LLM 调用。例如调用模型执行 Tool查询数据库调用 HTTP API读取文件检查业务规则转换数据生成结果都可以放进 Node。因此Agent 中的一个模型调用可以是 Node一个 Tool 执行可以是 Node一段完全没有 AI 调用的普通 Python 函数同样可以是 Node。Node 适合表示完整步骤写 Graph 时很容易出现一个倾向函数既然可以成为 Node就把每个函数都注册成 Node。例如文本处理代码strip_text ↓lower_text ↓remove_spaces ↓validate_text如果这些操作每次都会连续执行也没有单独重试、路由或保存状态的需求拆成四个 Node 只会让 Graph 变长。放在一个 Node 中更清楚def normalize_text(state): text state[text].strip() text text.lower() text .join(text.split()) return { text: text }实际设计时Node 更适合对应一个相对完整的执行步骤。例如研究 Agent 中的搜索资料 ↓评估资料 ↓生成报告 ↓人工审核这些步骤各自都有明确的输入、输出和运行意义后续也可能分别加入重试、路由或者人工确认。这样的步骤成为独立 Node会让 Graph 更容易阅读和维护。Node 只负责当前步骤还有一个细节很重要。下面这个 Nodedef calculate_subtotal(state: OrderState): return { subtotal: state[price] * state[quantity] }只负责计算subtotal。函数内部没有return apply_discount(...)也没有处理计算完成后应该执行哪个 Node流程由 Graph 本身管理。因此在设计 Node 时可以尽量保持一个清楚的边界读取当前需要的数据 ↓完成当前工作 ↓返回产生的状态更新至于后面执行什么由 Edge 或其他路由机制负责。业务处理和流程控制分开以后一个 Node 的代码通常也会更容易测试。四、Edge 的执行关系普通 Edge 描述固定的执行顺序。例如builder.add_edge( calculate_subtotal, apply_discount)表示calculate_subtotal完成后继续进入apply_discount。对应的 Graph 是calculate_subtotal ↓ apply_discount这里容易产生一个误解。calculate_subtotal返回{ subtotal: 300.0}并不是 Edge 把这个字典直接传给apply_discount。完整过程是calculate_subtotal ↓返回 {subtotal: 300} ↓应用到当前 State ↓沿 Edge 继续执行 ↓apply_discount ↓读取更新后的 StateState 和 Edge 因而承担不同职责State 保存执行过程中持续变化的数据Edge 描述 Node 之间的执行关系在只有固定流程的 Graph 中这种区别很明显。后面我们学习 Conditional Edge 后执行路径还可以根据 State 动态变化但数据仍然保存在 State 中。START 和 END除了普通 NodeGraph 中还经常会看到from langgraph.graph import START, ENDSTART表示 Graph 的入口。例如builder.add_edge( START, calculate_subtotal)表示一次运行从calculate_subtotal开始。END表示执行结束builder.add_edge( calculate_total, END)因此整张图是START ↓calculate_subtotal ↓apply_discount ↓calculate_total ↓ENDSTART和END不需要实现对应的 Python 函数也不负责处理业务数据。它们主要用于描述 Graph 的边界。五、StateGraph 的构建过程State、Node 和 Edge 最终都定义在StateGraph中。创建方式很简单builder StateGraph(OrderState)这里使用builder作为变量名会比直接叫graph更容易区分后面的两个阶段。因为此时我们还在描述 Graph使用什么 State有哪些 NodeNode 怎样连接从哪里开始在哪里结束例如builder StateGraph(OrderState) builder.add_node( calculate_subtotal, calculate_subtotal) builder.add_node( apply_discount, apply_discount) builder.add_node( calculate_total, calculate_total) builder.add_edge( START, calculate_subtotal) builder.add_edge( calculate_subtotal, apply_discount) builder.add_edge( apply_discount, calculate_total) builder.add_edge( calculate_total, END)这段代码只是完成 Graph 的定义。定义完成以后还需要graph builder.compile()之后才能graph.invoke(...)构建与运行是两个阶段Graph 的构建、编译、执行流程如下StateGraph ↓定义 Node 和 Edge ↓compile() ↓CompiledStateGraph ↓invoke()StateGraph是 Graph 的构建对象。compile()会生成真正可以执行的 Graph。所以常见代码结构是builder StateGraph(State) builder.add_node(...)builder.add_edge(...) graph builder.compile() result graph.invoke(...)后面的 Persistence、Interrupt 等能力也会和编译后的 Graph 运行过程发生关系。整个流程可以这样简单区分compile() 之前主要是在定义 Graphcompile() 之后才开始运行 Graph六、Graph 的执行过程我们使用上面的示例完整说明 Graph 的执行过程这里并不会引入 LLM 和 Tool避免其他组件影响对 StateGraph 的理解。代码如下from typing_extensions import TypedDictfrom langgraph.graph import StateGraph, START, END class OrderState(TypedDict): price: float quantity: int subtotal: float discount: float total: float def calculate_subtotal(state: OrderState): subtotal state[price] * state[quantity] print(fcalculate_subtotal: {subtotal}) return { subtotal: subtotal } def apply_discount(state: OrderState): discount 30.0 if state[subtotal] 300 else 0.0 print(fapply_discount: {discount}) return { discount: discount } def calculate_total(state: OrderState): total state[subtotal] - state[discount] print(fcalculate_total: {total}) return { total: total } builder StateGraph(OrderState) builder.add_node( calculate_subtotal, calculate_subtotal) builder.add_node( apply_discount, apply_discount) builder.add_node( calculate_total, calculate_total) builder.add_edge( START, calculate_subtotal) builder.add_edge( calculate_subtotal, apply_discount) builder.add_edge( apply_discount, calculate_total) builder.add_edge( calculate_total, END) graph builder.compile() result graph.invoke( { price: 100.0, quantity: 3, subtotal: 0.0, discount: 0.0, total: 0.0, }) print(result)上例运行结果calculate_subtotal: 300.0apply_discount: 30.0calculate_total: 270.0{price: 100.0, quantity: 3, subtotal: 300.0, discount: 30.0, total: 270.0}这个例子计算逻辑本身很简单重点在 State 的变化。开始执行时price 100quantity 3subtotal 0discount 0total 0Graph 从START进入calculate_subtotal。这个 Node 读取price 100quantity 3返回{ subtotal: 300.0}执行完这一步以后State 中的subtotal更新为subtotal 300接下来执行apply_discount。此时它读取到的已经是subtotal 300因此返回{ discount: 30.0}State 再次更新。之后执行calculate_totalsubtotal 300discount 30得到total 270最终到达END。把状态变化连起来就是初始 State ↓calculate_subtotal ↓subtotal 300 ↓apply_discount ↓discount 30 ↓calculate_total ↓total 270 ↓最终 State从这个结果中可以明确看到两个过程。一个是 State 持续更新State ↓State ↓State另一个是 Graph 按照 Edge 持续推进Node ↓Node ↓Node两者同时发生构成了一次完整的 Graph Run。七、Graph Run 的运行方式对于前面的线性 Graph一次graph.invoke(...)大致经历下面的过程接收输入 State ↓找到入口 Node ↓执行 Node ↓得到 State Update ↓更新当前 State ↓根据 Edge 进入后续 Node ↓继续执行 ↓Graph 结束 ↓返回最终 State整个过程总结如下第一Graph 中始终存在一份当前 State。第二每个 Node 都在当前 State 的基础上执行并产生新的状态更新。第三Graph 根据已经定义的 Edge决定哪些 Node 后续可以继续执行。后面的很多 LangGraph 功能都建立在这套运行方式上。例如普通 Edge 表示A → BConditional Edge 会变成┌→ BA → 判断 └→ CReducer处理的问题是一个 State 字段收到更新以后新旧数据应该怎样合并。Persistence处理的是某一步执行完成以后State 怎样保存下来。Interrupt处理的是Graph 执行过程中怎样暂停并在以后继续。它们处理的问题不同但都发生在同一套 Graph 运行模型中。八、实际建模边界理解 State、Node 和 Edge 并不难。实际项目里更容易出现问题的地方是 Graph 怎么拆。如果粒度过细一张简单的工作流很快会出现十几个甚至几十个 Node阅读成本反而比普通代码更高。因此设计 Node 时可以从“这一步是否需要被 Graph 单独管理”来判断。例如查询资料调用模型执行 Tool人工审核写入外部系统这些步骤通常具有独立运行意义。某一步可能失败需要重试某一步可能需要根据结果走不同路径人工审核还可能暂停很长时间。这类步骤比较适合作为 Node。而下面这样的实现细节字符串 trim大小写转换格式整理简单字段计算如果只属于某个步骤内部的处理通常没有必要单独做成 Node。State 也采用相同原则。任务需要跨步骤保存的数据进入 State。当前函数内部的临时变量留在函数内部。Edge 则只表达有实际流程意义的节点关系。这样设计出来的 Graph 通常会比较稳定State保存跨步骤的数据 Node表示需要独立运行和管理的步骤 Edge描述步骤之间的执行关系 StateGraph组织整个工作流总结本文详细说明了 Graph 中 State、Node 和 Edge 这些对象在运行时怎样配合。一次 Graph 的执行过程中Node 读取当前 State完成当前步骤并返回部分状态更新LangGraph 将更新应用到 State然后按照 Edge 继续执行后续 Node。StateGraph负责定义整个结构经过compile()后得到可以执行的 Graph。后面的 Reducer、条件路由、持久化和中断机制都是基于这套执行过程继续扩展出来的。学AI大模型的正确顺序千万不要搞错了2026年AI风口已来各行各业的AI渗透肉眼可见超多公司要么转型做AI相关产品要么高薪挖AI技术人才机遇直接摆在眼前有往AI方向发展或者本身有后端编程基础的朋友直接冲AI大模型应用开发转岗超合适就算暂时不打算转岗了解大模型、RAG、Prompt、Agent这些热门概念能上手做简单项目也绝对是求职加分王给大家整理了超全最新的AI大模型应用开发学习清单和资料手把手帮你快速入门学习路线:✅大模型基础认知—大模型核心原理、发展历程、主流模型GPT、文心一言等特点解析✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑✅开发基础能力—Python进阶、API接口调用、大模型开发框架LangChain等实操✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经以上6大模块看似清晰好上手实则每个部分都有扎实的核心内容需要吃透我把大模型的学习全流程已经整理好了抓住AI时代风口轻松解锁职业新可能希望大家都能把握机遇实现薪资/职业跃迁这份完整版的大模型 AI 学习资料已经上传CSDN朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】