LangGraph 第3章:核心概念
LangGraph 的核心概念围绕有向图模型展开。理解这四个概念——Graph、State、Node、Edge——就掌握了 LangGraph 的基本思维模型。
四大核心概念
Graph(图)
Graph 是整个工作流的蓝图。它定义了节点(Nodes)和边(Edges)的拓扑结构,描述了数据如何在节点之间流转。
from langgraph.graph import StateGraph
# 创建一个新图
graph = StateGraph(StateType)
Graph 的生命周期:
- 构建阶段:添加节点和边,定义图的结构
- 编译阶段:编译为可执行的应用(拓扑排序、验证)
- 执行阶段:调用应用,输入初始状态,获取最终结果
State(状态)
State 是节点间共享的数据容器。所有节点读取和写入同一个 State 对象。
from typing import TypedDict, Annotated, List
import operator
from langgraph.graph import add_messages
# 使用 TypedDict 定义状态
class MyState(TypedDict):
# 普通字段:后一个值覆盖前一个
counter: int
# 带 reducer 的字段:新值合并到列表中
messages: Annotated[List[str], add_messages]
# 使用 operator.add 作为 reducer
steps: Annotated[List[str], operator.add]
State 的关键特性:
| 特性 | 说明 |
|---|---|
| 共享性 | 所有节点读写同一个 State 实例 |
| 不可变性 | State 对节点是只读的,更新时返回新值 |
| Reducer 机制 | 控制如何将多个节点的返回值合并 |
| 类型安全 | 使用 TypedDict 或 Pydantic 保证类型 |
Nodes(节点)
Node 是图的基本执行单元。每个节点是一个函数或可调用对象,接收 State 并返回状态更新。
# 普通函数节点
def my_node(state: MyState):
# 读取状态
count = state["counter"]
# 执行逻辑
new_count = count + 1
# 返回状态更新
return {"counter": new_count}
# LLM 调用节点
def llm_node(state: MyState):
response = llm.invoke(state["messages"])
return {"messages": [response]}
# 异步节点
async def async_node(state: MyState):
result = await some_async_operation(state)
return {"result": result}
Edges(边)
Edge 定义了节点之间的流转路径。LangGraph 有两种边:
1. 普通边(Edge):固定连接,源节点执行完毕后自动进入目标节点。
graph.add_edge("node_a", "node_b") # A 执行完后自动执行 B
2. 条件边(Conditional Edge):根据当前状态动态选择目标节点。
# 路由函数:根据状态返回目标节点名称
def router(state: MyState):
if state["counter"] > 10:
return "end_node"
else:
return "process_node"
graph.add_conditional_edges(
"decision_node",
router, # 路由函数
{
"end_node": "end_node",
"process_node": "process_node"
}
)
编译与执行流程
编译阶段
编译会将图结构转换为可执行的计算图:
# compile() 执行以下操作:
# 1. 验证图的完整性(入口、出口、所有节点可达)
# 2. 进行拓扑排序(确定执行顺序)
# 3. 优化执行计划
# 4. 创建可执行的应用实例
app = graph.compile()
执行阶段
执行分为两种模式:
# 1. 普通执行:阻塞等待最终结果
result = app.invoke(initial_state)
# 2. 流式执行:逐节点输出状态
for state in app.stream(initial_state):
print(state)
执行流程:
invoke(input)
|
v
[Entry Point] --> [Node 1] --> [Conditional]
|
+-------+-------+
| |
v v
[Node 2] [Node 3]
| |
+-------+-------+
|
v
[END]
|
v
output
条件边路由函数(补:多个目标节点的映射)
当使用条件边时,路由函数的返回值必须匹配映射表中的键名:
def grade_router(state):
"""根据评分路由到不同节点"""
score = state.get("score", 0)
if score >= 90:
return "excellent"
elif score >= 60:
return "pass"
else:
return "fail"
graph.add_conditional_edges(
"grader", # 源节点
grade_router, # 路由函数
{ # 映射表
"excellent": "reward_node",
"pass": "review_node",
"fail": "retry_node"
}
)
如果路由函数的返回值直接就是目标节点名称,且映射表与返回值一致,可以省略映射表:
graph.add_conditional_edges(
"decision",
router
# 省略映射表,直接使用 router 的返回值作为节点名
)
可视化展示
LangGraph 通过 get_graph() 提供图结构可视化:
# 打印 ASCII 图结构
print(app.get_graph().draw_ascii())
# 生成 Mermaid 格式(可用于 Markdown)
print(app.get_graph().draw_mermaid())
# 生成 Mermaid PNG(需要安装 pygraphviz)
with open("graph.png", "wb") as f:
f.write(app.get_graph().draw_mermaid_png())
ASCII 可视化示例:
+--------+ +---------+ +--------+
| start | --> | process | --> | end |
+--------+ +---------+ +--------+
特殊节点:START 和 END
LangGraph 有两个内置特殊节点:
- START (
__start__):图的入口点,通过set_entry_point()设置 - END (
__end__):图的终止点,执行到此节点后停止
graph.set_entry_point("first_node") # 执行从 first_node 开始
graph.add_edge("last_node", "__end__") # 执行到 last_node 后结束
理解这四个核心概念后,你已掌握 LangGraph 的基础。下一章我们将开始动手搭建开发环境并编写第一个程序。