LangGraph 热身:从图开始理解
学习方式:苏格拉底式推导 + 前端知识类比 核心思路:不背定义,从已知推未知
一、代码执行结构的演化
1.1 最初的认知:一条线
我们写的大多数业务逻辑,直觉上是一条从上到下的时间线:
检查表单 → 发送请求 → 处理响应 → 跳转页面用 function 封装、组合,保持 SOLID 原则,看起来清晰有序。
1.2 遇到分叉:线变成了树
当"发送请求"出现成功/失败两种结果时,这条线分叉了:
✅ 成功 → 处理响应 → 跳转页面
发送请求 ──判断──
❌ 失败 → 弹出错误 → 停留表单页这时候,代码的执行结构从「线」变成了「有分叉的树」。
1.3 遇到重试:树变成了图
用户停留在表单页,修改后重新提交——流程回到了之前已经存在的节点(检查表单)。
停留表单页 ──────────────────────────┐
↓(回边)
检查表单 → 发送请求 → 判断 → 处理响应 → 跳转页面
↓
弹出错误 → 停留表单页这条"往回指的箭头",叫做 Back Edge(回边)。它让结构从「树」变成了「有环图(Cyclic Graph)」。
1.4 升维视角:封装的本质
| 时代 | 前端 | AI 开发 |
|---|---|---|
| 原始期 | 直接操作 DOM | 直接 fetch 调 OpenAI API |
| 封装期 | jQuery / 工具函数库 | 封装 callLLM() 函数 |
| 框架期 | React / Vue(操作状态而非 DOM) | LangChain(操作流程而非 API) |
| 编排期 | 状态机 / 微前端 | LangGraph / Multi-Agent(操作图而非流程) |
每一次升维,都是把「你手写的重复细节」抽象掉,让你站在更高的层面思考问题。
二、图的核心概念
2.1 Node 节点
图里每一个「方块」就是一个节点。
节点做三件事:
- 读取
state(我需要什么输入?) - 执行自己的逻辑(我该干什么?)
- 返回新的
state(我产出了什么?)
// 一个节点就是一个函数
function sendRequest(state) {
const response = await fetch('/api/login', { body: state.formData })
return { response } // 返回新的 state 片段
}前端类比: 一个组件 / 一个纯函数
2.2 Edge 顺序边
节点之间固定的连接,表示「执行完 A,下一步一定去 B」。
graph.addEdge("检查表单", "发送请求")前端类比: 顺序函数调用链
a() → b() → c()
2.3 Conditional Edge 条件边
根据 state 的内容,动态决定下一步去哪个节点。
图里用菱形表示,它只判断、不干活,返回一个「路牌」。
// 判断函数:只负责返回"路牌",不做业务逻辑
function judgeResult(state) {
if (state.response.ok) return "success"
else return "fail"
}
// 注册条件边
graph.addConditionalEdges(
"发送请求", // 从哪个节点出发
judgeResult, // 判断函数(菱形)
{
"success": "处理响应", // 返回 "success" → 去这个节点
"fail": "弹出错误", // 返回 "fail" → 去这个节点
}
)前端类比:
if/else/switch/ 策略模式
if/else= 菱形判断本身- 策略模式 = 菱形 + 把两边的执行者也抽象化
2.4 Back Edge 回边
从「后面的节点」指回「前面的节点」,形成循环。
停留表单页 ──回边──→ 检查表单前端类比:
while循环 / 递归
2.5 END 终止节点
图的出口。走到 END,这次执行就结束了。
一张图可以有多个 END 出口:
登录成功 → END ✅
账号锁定 → END 🔒前端类比: 函数的
return/ 页面的终态
2.6 State 状态
节点之间传递信息的「共享数据包」。
// 图运行过程中,state 的样子
const state = {
formData: { username: "xxx", password: "***" }, // 表单节点写入
response: { ok: false, error: "密码错误" }, // 请求节点写入
errorMsg: "密码错误,请重试", // 错误节点写入
retryCount: 3, // 每次回环累加
}| Vue/React State | LangGraph State | |
|---|---|---|
| 是什么 | 组件间共享的数据 | 节点间共享的数据 |
| 谁来读 | 组件读取来渲染 UI | 节点读取来执行逻辑 |
| 谁来写 | 事件 / action 更新 | 每个节点执行完更新 |
| 谁来判断 | computed / watch | Conditional Edge |
注意: 框架自动追踪「当前走到哪个节点」,不需要你手动存入 state。
2.7 Thread 线程实例
图的定义是蓝图(共享),每次执行是独立的实例。
// 同一张图的定义(蓝图)
const loginGraph = new StateGraph(...)
// 每个账号,是一个独立的 Thread(state 互不干扰)
await loginGraph.invoke(input, { configurable: { thread_id: "user_A" } })
await loginGraph.invoke(input, { configurable: { thread_id: "user_B" } })
// user_C 被锁定,完全不影响 user_A 和 user_B| 前端类比 | LangGraph | |
|---|---|---|
| 模板 / 蓝图 | 组件定义 function MyComponent() | Graph 定义 |
| 运行实例 | 组件渲染出的具体实例 | Thread |
| 实例的数据 | 组件自己的 state | 每个 Thread 独立的 state |
前端类比: 组件定义 vs 组件实例。同一个
<LoginForm />组件,可以在页面上渲染多个,各自有独立的 state。
三、完整概念总览
| 概念 | 一句话 | 前端类比 |
|---|---|---|
| Node 节点 | 干活的单元 | 一个函数 / 组件 |
| Edge 顺序边 | 固定的下一步 | 顺序函数调用链 |
| Conditional Edge 条件边 | 根据结果决定走哪 | if/else / 策略模式 |
| Back Edge 回边 | 回到之前的节点 | while 循环 |
| END 终止节点 | 图的出口,可以有多个 | return / 页面终态 |
| State 状态 | 节点间传递的数据 | 组件的 state / store |
| Thread 实例 | 图的一次独立执行 | 组件的一个实例 |
四、一个完整的例子:登录流程图
START
↓
[检查表单]
↓
[发送请求]
↓
◇ 请求成功?
├── ✅ 成功 ──→ [处理响应] → [跳转页面] → END ✅
└── ❌ 失败 ──→ [弹出错误]
↓
◇ retryCount ≥ 5?
├── 是 🔒 ──→ [锁定账号] → END 🔒
└── 否 🔄 ──────────────────→ 回到 [检查表单]这张图包含了:
- ✅ 顺序边(主流程)
- ✅ 条件边(成功/失败判断、次数判断)
- ✅ 回边(重试循环)
- ✅ 多个 END 出口(成功 / 锁定)
- ✅ State 在节点间流转(formData、response、retryCount)
- ✅ Thread 隔离(每个账号独立跑,互不影响)
五、下一步:进入 LangGraph
思考题(带着这个问题进入下一阶段):
把「登录流程」换成「AI 对话流程」: 用户发消息 → AI 思考 → AI 回复 → 用户再发 → ...
- 哪个部分会变成「回边」?
- 这个图什么时候才会走到
END?想清楚这个,你就准备好正式写 LangGraph 了。