LangGraph 入门:用有向图把 Agent 跑起来
如果你已经会用 LangChain 调模型、绑工具,但一碰到「Agent 要循环推理、要分支、要并行」就不知道怎么组织代码——LangGraph 就是为此而生的。
它不是一个 prompt 框架,而是一个编排运行时:把 Agent / LLM 应用建模成一张有向状态图,每个节点读状态、做操作、写回状态,边决定数据往哪流。
三个关键数据结构
回到 LangGraph 的核心,Everything 都可以归结为三个概念:
| 概念 | 一句话 | 本质 |
|---|---|---|
| Node | 数据处理的逻辑 | Python 函数 |
| Edge | 决定数据流转的结构 | Python 函数 |
| State | 存储数据的结构 | TypedDict |
Node 和 Edge 本质上都是函数——Node 接收 State 做操作,Edge 决定下一个 Node 是谁。
State 是三者中设计成本最高的:划分不好,后面加节点、加并行、加汇总都会痛苦。所以第一篇入门,第二篇就专门讲 State,不是巧合。
LangGraph 把 LLM 应用的各部分拆成节点(Node)和边(Edge):
| 概念 | 作用 |
|---|---|
| Node | 数据处理逻辑(调 LLM、调工具、做判断) |
| Edge | 决定节点之间的流转——固定跳转还是条件分支 |
| State | 全局共享的数据结构,所有节点读写它 |
不管是 Node 还是 Edge,底层本质上都是 Python 函数。
和裸写 while 循环比,LangGraph 多了什么?
| 裸 while 循环 | LangGraph |
|---|---|
| 流程藏在代码逻辑里 | 流程显式画在图上 |
| 加分支要改多处 | add_edge / 条件边声明式添加 |
| 不好做并行 | Super-step 自动并行 |
| 中断恢复要自己实现 | checkpointer + interrupt 内置支持 |
| 调试靠 print | LangSmith 可观测 |
最小 Agent:LLM → 工具 → 循环
LangGraph 官方 Quickstart 的标准模式,也是大多数 Agent 项目的起点:
1 | def llm_call(state: dict): |
这三段代码拼起来就是 Agent 的核心循环:LLM 思考 → 决定调工具 → 工具执行 → 结果写回 → LLM 再思考。
用图来表示:
graph LR
START --> llm_call
llm_call --> should_continue
should_continue -->|有 tool_calls| tool_node
should_continue -->|无 tool_calls| END
tool_node --> llm_call
工具(Tools):Agent 的手脚
LangChain 里定义工具很简单,用 @tool 装饰器即可,框架会自动解析并加上 name、description(description 来自函数 docstring):
1 |
|
工具描述写得好不好,直接决定 Agent 能不能正确选择工具。 这是 Agent 工程里最容易被忽视、但影响最大的一环。
完整的工具绑定流程:
1 | from langchain_core.tools import tool |
@tool 装饰器会自动从 docstring 提取 description 给 LLM 看——所以 docstring 不是写给人看的,是写给 LLM 看的。描述越清晰,LLM 选工具的准确率越高。
Super-step:图的调度节拍
LangGraph 内部用 Super-step 来调度节点执行:
- 同一个 Super-step 里,没有依赖关系的节点可以并行跑
- 一个 Super-step 结束后,才进入下一个
- 所有前驱节点都跑完,后继节点才会被触发
flowchart TB
subgraph step1 [Super-step 1]
N1[Node A]
end
subgraph step2 [Super-step 2]
N2[Node B]
N3[Node C]
end
subgraph step3 [Super-step 3]
N4[Node D]
end
N1 --> N2
N1 --> N3
N2 --> N4
N3 --> N4
理解 Super-step 有助于排查「为什么这个节点还没跑」——大概率是它的前驱还没全部完成。
固定工作流 vs 动态 Agent
LangGraph 文档里区分两种模式,选型时要想清楚:
| 模式 | 特点 | 适用场景 |
|---|---|---|
| 固定工作流(Workflow) | 路径 predetermined,每步做什么写死 | 流水线、ETL、固定审核流程 |
| 动态 Agent | LLM 自己决定下一步调什么工具 | 开放式问答、故障诊断、研究助手 |
你的项目如果是 llm_call → tool_node → should_continue 这种循环,就是标准的动态 Agent 模式。
Agent 的本质:一个 while 循环
跳出 LangGraph 的框架视角,Agent 的核心范式其实很简单:
Agent = LLM + Tools + Memory + Planning
- LLM 是大脑,负责推理和决策
- Tools 是手脚,负责和外部世界交互
- Memory 提供跨轮次的记忆力
- Planning 决定任务怎么拆解、按什么顺序执行
Agent loop 本质上就是一个 while 循环:推理 → 调工具 → 写回上下文 → 再推理,直到达到目标或触发停止条件。
但裸写 while 循环有三个现实问题:
- 推理路径极易走偏 — LLM 一步错,后面全废,token 白烧
- 上下文越来越长 — 多轮工具调用后,Memory 管理变成难题
- 流程不可观测 — 出问题了不知道卡在哪一步
LangGraph 的价值在于把这个循环显式建模成图,让你能看清每一步、加分支、加并行、加重试、加持久化——而不是把所有逻辑塞进一个巨大的 prompt 里。
一个设计良好的 Agent 系统分三层:
graph TB
subgraph LLM层
A[推理 / 决策]
end
subgraph Tools层
B[Function Call]
C[MCP 服务]
end
subgraph Context层
D[State / Memory]
E[Prompt / 历史消息]
end
A --> B
A --> C
D --> A
E --> A
B --> D
C --> D
通过 Context 和 Tools 层的编排,能显著提升 Agent 的能力上限。
compile():从图到可运行程序
节点和边定义好之后,还需要 compile() 才能变成可执行的图:
1 | graph = StateGraph(State) |
compile() 之后得到的 app 才有 invoke() / stream() 方法。如果后续需要断点恢复或跨会话记忆,在 compile 时传入 checkpointer 即可。