Part 2 · 核心能力

04 图的三要素:节点、边、状态

04.1 节点就是一个普通函数

2025 年我带新人,最爱用这句话开场:"节点没那么神,它就是一个函数。"

def my_node(state: AgentState):
    last = state["messages"][-1].content
    return {"messages": [f"你说了:{last}"]}

节点返回什么,就更新状态的哪部分。返回 {"messages": [...]} 就往白板贴新消息。

04.2 边决定"下一步去哪"

普通边是无条件走:

g.add_edge("agent", "tools")  # 永远从 agent 走到 tools

条件边看情况走,背后是个路由函数:

def route(state):
    if state["messages"][-1].tool_calls:
        return "tools"   # 要走这条路
    return END           # 否则结束

g.add_conditional_edges("agent", route, {"tools": "tools", END: END})

重点看route 返回的字符串。 它必须和字典的 key 对上。对不上,图编译直接报错。

04.3 状态:图的"共享白板"

最省事的状态是 MessagesState

from langgraph.graph import MessagesState

g = StateGraph(MessagesState)

MessagesState 内部就一个 messages 字段,自带 add_messages 归约。90% 的场景用它足够。

要加自定义字段也简单:

from langgraph.graph import MessagesState
from typing import Annotated
import operator

class MyState(MessagesState):
    # 在消息之外,再加一个累计分数
    score: Annotated[int, operator.add] = 0

04.4 三种"图"的对比

维度 手写函数 LangChain 链 LangGraph 图
循环 自己写 while 不支持 原生支持
暂停恢复 极难 不支持 原生支持
可视化 LangGraph Studio
标叔的结论 玩具级 线性任务 真实 Agent

核心建议:状态要"可序列化" State 里的东西最终要存进数据库。别塞不能 JSON 化的对象,否则中断恢复会炸。

▸ 向前桥接 节点会了。下一章讲 Agent 怎么"自己挑工具"。