第 8 章:LangGraph 工作流
章节定位
到了这一章,AI 学习助手 已经具备链式处理、RAG、工具调用和 Agent 决策能力。下一步不是再增加一个“更聪明的模型”,而是把整个应用组织成可控的工作流。
LangGraph 解决的就是这个问题:当一个 LLM 应用不再是单链式直线流程,而是出现分支、循环、状态更新、重试和人工介入时,用图来管理比用一串链更清晰。
配套示例
- 目录:
examples/chapter-08 - 入口:
examples/chapter-08/main.py - 依赖:
examples/chapter-08/requirements.txt - 运行:
cd examples/chapter-08 && python3 main.py
示例层级与边界
- 层级:
教学版 - 本章重点:理解工作流图里的状态、节点和条件分支,而不是马上依赖真实框架细节。
- 不要误判:示例优先讲清图式思维,不覆盖持久化状态、人工介入工作台或线上恢复策略。
本章目标
- 理解为什么复杂应用需要工作流编排
- 学会 LangGraph 的基本组成
- 能把
AI 学习助手改造成带状态的流程 - 知道条件分支、循环和中断恢复为什么重要
- 建立“可调试、可恢复、可扩展”的工程思维
前置知识
- 已理解链、RAG、Tool 和 Agent 的基本用法
- 知道模型输出具有不确定性
- 知道复杂流程需要状态管理
核心概念
1. 为什么从链走向图
链适合线性流程,例如:
输入 -> 检索 -> 总结 -> 输出
但真实业务常常更复杂,例如:
- 如果是课程问题,走资料检索
- 如果是学习路径问题,走目录查询
- 如果答案不确定,先追问
- 如果工具失败,走兜底方案
这类场景已经不是简单线性链可以优雅表达的了。图结构可以把“节点”和“转移规则”分开,让流程更容易理解和维护。
2. LangGraph 的基本组成
LangGraph 常见的四个元素是:
State:流程中的共享状态Node:处理状态的节点Edge:节点之间的连接Conditional Edge:根据状态选择下一步
你可以把它理解成“带状态的流程图执行器”。
3. 状态为什么重要
如果没有状态,Agent 每一步都只能依赖当前输入。
如果有状态,系统可以保留:
- 用户问题
- 当前处理节点
- 检索结果
- 工具调用结果
- 是否需要人工介入
这对于复杂学习助手非常重要,因为用户的问题往往不是一次性回答完就结束。
分模块讲解
1. 从 AI 学习助手 V3 到 V4
上一章的 AI 学习助手 V3 已经会调用工具,但流程还偏“黑盒”。这一章建议升级成 V4:
- 先分类问题类型
- 再路由到不同节点
- 需要检索时走 RAG
- 需要工具时走 Tool 节点
- 需要追问时进入澄清节点
- 需要总结时进入收尾节点
这样系统就不只是“会回答”,而是“会组织回答过程”。
2. 节点设计原则
一个好的节点应该只做一件事:
- 分类节点只判断任务类型
- 检索节点只负责找资料
- 工具节点只负责调用工具
- 汇总节点只负责整合结果
不要让一个节点同时干分类、检索、总结和格式化。那样虽然看起来省事,但后期会很难维护。
3. 条件分支
条件分支的作用是:根据状态决定下一步去哪里。
例如:
- 问题属于章节内容 -> 去资料检索
- 问题属于目录导航 -> 去章节查询
- 问题属于不明确请求 -> 去追问澄清
这类判断在复杂学习站里非常常见,也是 LangGraph 的核心价值之一。
4. 循环与重试
有时候一次执行不够,需要循环:
- 检索结果不够好,重新检索
- 输出格式不符合要求,重新生成
- 工具调用失败,切换兜底策略
图结构对这种“失败后再走一轮”的场景更自然,而链式应用通常会开始变得笨重。
5. 人工介入
当用户提出模糊请求时,系统不应该硬猜。
例如用户问:
- “我想快速学会这个项目”
系统可以先进入澄清节点,追问:
- 你是想先看路线图,还是先看实战示例?
这比直接给一大段长回答更有学习价值。
最小示例说明
下面是一个简化的结构示意,帮助你理解 LangGraph 的组织方式:
python
state = {
"question": "我想先学第 7 章,需要什么前置知识?",
"route": None,
"context": None,
}
graph = build_graph(
nodes=[classify, retrieve, call_tool, summarize],
edges=[...],
)
result = graph.invoke(state)这个示例里最重要的不是语法,而是思路:
- 输入先进入状态
- 状态驱动节点执行
- 节点执行后更新状态
- 根据状态决定下一步
这比单纯的 prompt | model | parser 更适合复杂系统。
真实框架版对照
examples/chapter-08/main.py 现在除了教学版,还补了一版真实 StateGraph 对照。
它把同一个思路映射成更接近实际框架接口的写法:
- 用
TypedDict明确定义状态结构 - 用
StateGraph注册分类、目录查询、RAG、澄清这些节点 - 用条件边把
route显式映射到下一跳
这样你在学 LangGraph 时,就不会停留在“图的概念”,而能直接看到这些概念在真实代码里的落点。
本章实践
建议把本章实践做成 AI 学习助手 V4。
实践目标
- 用户输入问题后,系统先分类
- 如果是课程目录问题,走目录节点
- 如果是知识问答,走 RAG 节点
- 如果是工具问题,走 Tool 节点
- 如果判断不明确,先追问用户
实践步骤
- 定义统一状态结构
- 写一个分类节点
- 写一个检索节点
- 写一个工具节点
- 写一个总结节点
- 用条件边把这些节点串起来
实践判断标准
- 任意一次执行都能看出路径
- 中间状态可以打印和调试
- 某一步失败后不至于整个流程崩掉
- 流程修改时不需要重写整个系统
常见坑
- 把所有逻辑堆进一个节点里,结果图结构失去意义
- 状态字段设计过多,后面没人知道每个字段干什么
- 条件分支太多,但没有统一命名规则
- 过分依赖“看起来很智能”的自动流转,忽略可调试性
- 没有给失败路径设计兜底,导致系统一出错就中断
练习题
- 为
AI 学习助手设计一个最小状态结构,至少包含问题、路由、检索结果和最终答案。 - 设计三个节点:分类、检索、总结,并说明每个节点只负责什么。
- 思考一下:什么时候应该使用条件分支,什么时候应该直接调用固定链?
- 如果一个节点失败,应该如何设计兜底路径,保证用户还能得到可理解的反馈?
本章总结
LangGraph 的核心价值不是“让模型更聪明”,而是“让复杂 AI 应用更可控”。
当 AI 学习助手 发展到需要分支、循环、重试和人工介入时,继续用普通链会越来越难维护。LangGraph 提供的是一种更适合复杂应用的组织方式:把流程显式化,把状态显式化,把转移规则显式化。
如果说前面的章节是在训练“怎么让模型做事”,这一章就是在训练“怎么让一个 AI 系统稳定地做完整件事”。
学完本章,你现在应该会
- 解释为什么复杂 AI 系统需要状态、节点和显式转移
- 为
AI 学习助手 V4设计一个最小状态结构 - 判断哪些步骤应该拆成节点,哪些仍然适合留在单个节点内部
- 给失败路径设计一个可理解的兜底输出
最小验收 checklist
- [ ] 我能画出一条包含分类、检索或工具、总结的最小工作流
- [ ] 我定义的状态字段不多,但足够支撑路由和调试
- [ ] 我能解释至少一个条件分支为什么存在
- [ ] 我已经考虑某个节点失败时,系统如何继续给用户反馈
建议你动手改一版
- 先只做 3 个节点版本:分类、执行、总结,避免一开始把图做太大
- 给状态增加一个
trace或steps字段,用来记录走过哪些节点 - 故意制造一个节点失败场景,看看你的兜底路径是否还能返回可理解说明
卡住时先回看这里
- 如果你把所有逻辑都塞到一个节点里,回看 chapter-08-langgraph-workflows.md 里的
## 分模块讲解 - 如果你不知道状态最少该放什么,回看 chapter-08-langgraph-workflows.md 里的
## 本章实践 - 如果你分不清“图结构”和“普通链”的边界,回看 chapter-08-langgraph-workflows.md 里的
## 最小示例说明
下一章预告
下一章会进入工程化收尾,讨论评估、观测和调试。因为一旦系统变成链、Agent 和图的组合,最难的就不是“能不能跑”,而是“怎么知道哪里出了问题、怎么判断效果是否真的变好”。