Graph的基本流程理解

19 阅读2分钟
# 完整代码
from typing import TypedDict
from langgraph.graph import StateGraph, START, END

## 定义状态
class MyState(TypedDict, total=False):
    node1: str  
    node2: str  
  • TypedDict:说明这个类是「类型描述字典」,用来约定state的数据结构,给IDE类型提示。
  • total=False :默认情况下 TypedDict 要求你必须提供所有字段;total=False 意思:字段可选,可以不存在。
  • node1和node2:state中的通道(channel) ,是state字典里的key,用来存放数据。⚠️ 注意:不是运行节点,这里只是刚好和节点同名,容易混淆。
## 实例化图
workflow = StateGraph(MyState)

这句代码的意思是告诉graph:整个工作流所依据的数据容器,必须符合 MyState 这个结构。

## 定义节点
def node1(state: MyState):
    return {"node1": "node1 result"}

def node2(state: MyState):
    return {"node2": "node2 result"}
  • state:当前最新的状态字典。图运行到这个节点时,框架自动把当前 state 传给函数。
  • return:返回的字典不是完整新 state,是增量补丁 patch。只会更新指定通道,不会覆盖整个state。
## 添加节点和边
(
workflow.add_node("node1", node1)
.add_node("node2", node2)
.add_edge(START, "node1")
.add_edge("node1", "node2")
.add_edge("node2", END)
)

这个workflow的工作流为:START —— node1 —— node2 —— END。

## 编译及运行
graph = workflow.compile()
result = graph.invoke({})

运行过程

  1. invoke 传入初始 state:{}
  2. START 触发,进入节点 node1
  3. node1 收到 state{},返回 patch {"node1": "node1 result"}
  4. LangGraph 合并,state 变成{"node1": "node1 result"}
  5. 静态边流转,走到节点 node2
  6. node2 收到 state {"node1": "node1 result"},返回 patch {"node2": "node2 result"}
  7. LangGraph 合并,state 变成{"node1": "node1 result", "node2": "node2 result"}
  8. node2 执行完,走到 END,图终止,返回最终 state

疑惑自解

Q1: node节点在定义时,要传参state,但是workflow在add_node时,传入的node并没有带state参。 A1:workflow.add_node("node1", node1),这段代码,将node1函数在workflow进行登记,并将该节点命名为"node1"。 至于node1执行的时机,是在执行graph.invoke({}),图开始执行时:

  1. LangGraph 拿到当前全局 state
  2. 找到要执行的节点对应的函数(也就是我们注册进去的 node1)
  3. LangGraph 自动调用 node1(state) ,把当前 state 当做第一个参数塞进去。

核心区分:

  • 构建期:add_node只是登记函数,不执行,不需要传state
  • 运行期:invoke启动图,框架自动调用节点函数并传入state

概念区分(重点)

  • 节点(Node):def node1 这个函数,代表一段业务逻辑

  • 通道(Channel):state里的key,node1/node2,用来存储数据

    本示例只是名字碰巧一样,二者完全不是同一个东西。