9.6.3 LangChain / LangGraph
- 理解 LangChain 更适合哪些场景
- 理解 LangGraph 为什么更适合复杂状态流
- 看懂“链式抽象”和“图式抽象”的真实差别
- 学会判断什么时候应该从链式流程升级到图式流程
为什么会先有 LangChain,后来又有 LangGraph?
Section titled “为什么会先有 LangChain,后来又有 LangGraph?”早期需求通常是线性的
Section titled “早期需求通常是线性的”很多 LLM 应用一开始都长这样:
- 接收输入
- 改写 查询
- 检索文档
- 调模型回答
这类流程很像一条直线:
上一步输出,喂给下一步。
在这种情况下,“链(chain)”是一种很自然的抽象。
但系统很快就会变复杂
Section titled “但系统很快就会变复杂”一旦你开始有这些需求:
- 如果检索为空怎么办?
- 如果回答不可信要不要重试?
- 要不要先工具调用,再回到问答?
- 某些情况要人工确认
流程就不再是直线了,而会变成:
- 有分支
- 有状态
- 有回路
这时你需要的就不只是“把步骤串起来”,而是:
显式表示状态和边。
这也是 LangGraph 之所以重要的根源。
先理解 LangChain:它到底在抽象什么?
Section titled “先理解 LangChain:它到底在抽象什么?”它最适合的,是“组件管道”
Section titled “它最适合的,是“组件管道””LangChain 的典型长处在于把这些东西接起来:
- prompt 模板
- 模型调用
- 输出解析
- 检索模块
- 工具模块
你可以把它理解成:
一个偏组件编排层的框架。
它很像把“提示词、模型、检索器、解析器”这些零件做成了更容易拼装的积木。
一个最小链式思维示例
Section titled “一个最小链式思维示例”下面这个例子虽然不用真实 LangChain,但它已经有 LangChain 风格。
class SimpleChain: def __init__(self, steps): self.steps = steps
def run(self, value): for step in self.steps: value = step(value) return value
def normalize_query(text): return text.strip().lower()
def retrieve_docs(query): if "退款" in query: return {"query": query, "docs": ["课程购买后 7 天内可退款"]} return {"query": query, "docs": []}
def format_answer(payload): if payload["docs"]: return f"根据资料:{payload['docs'][0]}" return "没有找到相关资料。"
chain = SimpleChain([ normalize_query, retrieve_docs, format_answer])
print(chain.run(" 退款政策是什么? "))预期输出:
根据资料:课程购买后 7 天内可退款这个例子最该你记住什么?
Section titled “这个例子最该你记住什么?”它在表达一个非常清楚的思想:
每一步只做一件事,整个系统通过串联步骤完成任务。
这正是 LangChain 最容易让人上手的地方。
LangChain 什么时候会很好用?
Section titled “LangChain 什么时候会很好用?”适合这些情况
Section titled “适合这些情况”- 流程基本线性
- 分支不多
- 重点是把几个模块组合起来
- 你想快速搭一个原型
典型例子:
- FAQ 检索问答
- 文本抽取
- 检索后生成
- 单工具增强问答
- 上手快
- 组件生态丰富
- 很适合把“小模块”先拼起来
它容易在哪些地方开始吃力?
Section titled “它容易在哪些地方开始吃力?”当你开始需要:
- 长状态链
- 多个判断分支
- 节点回跳
- 显式中间状态管理
这时链式思维会越来越勉强。
再理解 LangGraph:它为什么更像“状态机”?
Section titled “再理解 LangGraph:它为什么更像“状态机”?”LangGraph 的重点不只是节点,而是状态
Section titled “LangGraph 的重点不只是节点,而是状态”LangGraph 最重要的视角不是:
- 下一步调哪个组件
而是:
- 当前状态是什么
- 这个状态应该走向哪一条边
- 节点执行后状态怎样更新
你可以先把它理解成:
带状态的工作流图。
一个最小图式示例
Section titled “一个最小图式示例”def plan_node(state): if "退款" in state["query"]: state["next"] = "retrieve" else: state["next"] = "fallback" return state
def retrieve_node(state): state["docs"] = ["课程购买后 7 天内可退款"] state["next"] = "answer" return state
def answer_node(state): state["answer"] = f"根据资料:{state['docs'][0]}" state["next"] = None return state
def fallback_node(state): state["answer"] = "当前没有找到匹配的流程。" state["next"] = None return state
nodes = { "plan": plan_node, "retrieve": retrieve_node, "answer": answer_node, "fallback": fallback_node}
state = {"query": "退款政策是什么", "next": "plan"}
while state["next"] is not None: current = state["next"] state = nodes[current](state) print(current, "->", state)预期输出:
plan -> {'query': '退款政策是什么', 'next': 'retrieve'}retrieve -> {'query': '退款政策是什么', 'next': 'answer', 'docs': ['课程购买后 7 天内可退款']}answer -> {'query': '退款政策是什么', 'next': None, 'docs': ['课程购买后 7 天内可退款'], 'answer': '根据资料:课程购买后 7 天内可退款'}这段代码和链式示例最大的差别在哪?
Section titled “这段代码和链式示例最大的差别在哪?”在链式系统里:
- 下一步通常是固定的
在图式系统里:
- 下一步是由当前状态决定的
这就是图工作流最本质的优势。

什么时候你应该从 LangChain 思维切到 LangGraph 思维?
Section titled “什么时候你应该从 LangChain 思维切到 LangGraph 思维?”一个很实用的判断标准
Section titled “一个很实用的判断标准”如果你画流程图时,发现它已经不是一条直线,而是:
- 有明显分支
- 有失败回退
- 有循环
- 有“根据中间结果决定下一步”
那通常就该开始考虑图式抽象了。
一个信号非常明显的坏味道
Section titled “一个信号非常明显的坏味道”如果你的代码开始变成:
if ... if ... if ... while ...并且这些判断全都围绕中间状态,那往往说明:
你已经不再只是“链式应用”,而是在做状态图系统。
为什么很多团队会同时提到 LangChain 和 LangGraph?
Section titled “为什么很多团队会同时提到 LangChain 和 LangGraph?”因为现实系统往往并不是“二选一”。
一个很常见的组合方式
Section titled “一个很常见的组合方式”-
LangChain 风格负责封装:
- prompt
- 检索器
- parser
-
LangGraph 风格负责控制:
- 状态迁移
- 分支
- 重试
- 人工确认节点
所以很多时候它们更像:
组件层 + 工作流层。
而不是完全冲突的两派。
一个真实工程里的选择建议
Section titled “一个真实工程里的选择建议”如果你现在要做的是:
Section titled “如果你现在要做的是:”- 单轮 FAQ
- 简单 RAG
- 几步固定流程
那先用链式思维通常很够。
如果你现在要做的是:
Section titled “如果你现在要做的是:”- 多步 Agent
- 带工具回路
- 有人工确认节点
- 明显依赖中间状态
那图式思维会更稳。
不要一开始就为了“高级感”上图
Section titled “不要一开始就为了“高级感”上图”这也是一个很重要的判断。 图式抽象更强,但也会带来:
- 更高学习成本
- 更多结构设计工作
复杂度不高时,链式方式反而更清楚。
初学者最常踩的坑
Section titled “初学者最常踩的坑”还没理解任务结构,就先学一堆框架 API
Section titled “还没理解任务结构,就先学一堆框架 API”这会让你最后学会的只是“框架语法”,不是系统设计。
用链去硬撑图
Section titled “用链去硬撑图”系统越写越多 if/else,但还不愿意切到图式抽象。
一上来就上图式框架
Section titled “一上来就上图式框架”明明需求很简单,却先把系统做得很重。
学完这一页,至少保留这张证据卡:
- 问题形态
- 工作流图、检索应用、角色团队或实验
- 框架选择
- 它增加了什么抽象,以及隐藏了什么控制
- 追踪记录
- 状态、节点、tool 调用、消息或运行 id
- 失败检查
- 框架魔法隐藏状态、重试或权限问题
- 决策
- 只有在单代理循环清晰后才选择框架
这一节最重要的不是记住框架名,而是建立这个判断:
LangChain 更像把常见组件串起来,LangGraph 更像把复杂状态流显式画出来。
当你开始用“任务结构”而不是“框架热度”去判断它们时,选型就会稳很多。
- 画一下你自己的一个 Agent 系统,判断它更像链还是图。
- 把链式示例加一个“如果没找到文档就改写 查询 再查一次”的逻辑,看看它会不会开始变乱。
- 用自己的话解释:为什么图式抽象比链式抽象更适合有状态回路的系统?
- 想一想:在什么情况下,链式方式其实比图式方式更合适?
解题思路与讲解
- 如果每一步只按固定顺序执行一次,它更像 chain;如果系统会分支、循环、重试、暂停或回到之前状态,它更像 graph。
- 加上“没找到文档 -> 重写 query -> 再检索”后,chain 往往会变乱,因为代码开始需要条件路由、循环上限和状态历史。这正是 graph 抽象开始有价值的地方。
- graph 抽象适合有状态循环,是因为节点和边把转移显式化:什么状态进入、做了什么判断、下一步去哪、什么时候停止。
- 当任务线性、短、稳定、容易检查时,chain 更合适,比如格式化输入、调用一次 retriever、生成一段短回答。