跳转到内容

9.6.3 LangChain / LangGraph

  • 理解 LangChain 更适合哪些场景
  • 理解 LangGraph 为什么更适合复杂状态流
  • 看懂“链式抽象”和“图式抽象”的真实差别
  • 学会判断什么时候应该从链式流程升级到图式流程

为什么会先有 LangChain,后来又有 LangGraph?

Section titled “为什么会先有 LangChain,后来又有 LangGraph?”

很多 LLM 应用一开始都长这样:

  1. 接收输入
  2. 改写 查询
  3. 检索文档
  4. 调模型回答

这类流程很像一条直线:

上一步输出,喂给下一步。

在这种情况下,“链(chain)”是一种很自然的抽象。

一旦你开始有这些需求:

  • 如果检索为空怎么办?
  • 如果回答不可信要不要重试?
  • 要不要先工具调用,再回到问答?
  • 某些情况要人工确认

流程就不再是直线了,而会变成:

  • 有分支
  • 有状态
  • 有回路

这时你需要的就不只是“把步骤串起来”,而是:

显式表示状态和边。

这也是 LangGraph 之所以重要的根源。


先理解 LangChain:它到底在抽象什么?

Section titled “先理解 LangChain:它到底在抽象什么?”

LangChain 的典型长处在于把这些东西接起来:

  • prompt 模板
  • 模型调用
  • 输出解析
  • 检索模块
  • 工具模块

你可以把它理解成:

一个偏组件编排层的框架。

它很像把“提示词、模型、检索器、解析器”这些零件做成了更容易拼装的积木。

下面这个例子虽然不用真实 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(" 退款政策是什么? "))

预期输出:

Terminal window
根据资料:课程购买后 7 天内可退款

它在表达一个非常清楚的思想:

每一步只做一件事,整个系统通过串联步骤完成任务。

这正是 LangChain 最容易让人上手的地方。


  • 流程基本线性
  • 分支不多
  • 重点是把几个模块组合起来
  • 你想快速搭一个原型

典型例子:

  • FAQ 检索问答
  • 文本抽取
  • 检索后生成
  • 单工具增强问答
  • 上手快
  • 组件生态丰富
  • 很适合把“小模块”先拼起来

当你开始需要:

  • 长状态链
  • 多个判断分支
  • 节点回跳
  • 显式中间状态管理

这时链式思维会越来越勉强。


再理解 LangGraph:它为什么更像“状态机”?

Section titled “再理解 LangGraph:它为什么更像“状态机”?”

LangGraph 的重点不只是节点,而是状态

Section titled “LangGraph 的重点不只是节点,而是状态”

LangGraph 最重要的视角不是:

  • 下一步调哪个组件

而是:

  • 当前状态是什么
  • 这个状态应该走向哪一条边
  • 节点执行后状态怎样更新

你可以先把它理解成:

带状态的工作流图。

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)

预期输出:

Terminal window
plan -> {'query': '退款政策是什么', 'next': 'retrieve'}
retrieve -> {'query': '退款政策是什么', 'next': 'answer', 'docs': ['课程购买后 7 天内可退款']}
answer -> {'query': '退款政策是什么', 'next': None, 'docs': ['课程购买后 7 天内可退款'], 'answer': '根据资料:课程购买后 7 天内可退款'}

这段代码和链式示例最大的差别在哪?

Section titled “这段代码和链式示例最大的差别在哪?”

在链式系统里:

  • 下一步通常是固定的

在图式系统里:

  • 下一步是由当前状态决定的

这就是图工作流最本质的优势。

LangGraph 状态机与条件边图


什么时候你应该从 LangChain 思维切到 LangGraph 思维?

Section titled “什么时候你应该从 LangChain 思维切到 LangGraph 思维?”

如果你画流程图时,发现它已经不是一条直线,而是:

  • 有明显分支
  • 有失败回退
  • 有循环
  • 有“根据中间结果决定下一步”

那通常就该开始考虑图式抽象了。

如果你的代码开始变成:

if ...
if ...
if ...
while ...

并且这些判断全都围绕中间状态,那往往说明:

你已经不再只是“链式应用”,而是在做状态图系统。


为什么很多团队会同时提到 LangChain 和 LangGraph?

Section titled “为什么很多团队会同时提到 LangChain 和 LangGraph?”

因为现实系统往往并不是“二选一”。

  • LangChain 风格负责封装:

    • prompt
    • 检索器
    • parser
  • LangGraph 风格负责控制:

    • 状态迁移
    • 分支
    • 重试
    • 人工确认节点

所以很多时候它们更像:

组件层 + 工作流层。

而不是完全冲突的两派。


  • 单轮 FAQ
  • 简单 RAG
  • 几步固定流程

那先用链式思维通常很够。

  • 多步 Agent
  • 带工具回路
  • 有人工确认节点
  • 明显依赖中间状态

那图式思维会更稳。

不要一开始就为了“高级感”上图

Section titled “不要一开始就为了“高级感”上图”

这也是一个很重要的判断。 图式抽象更强,但也会带来:

  • 更高学习成本
  • 更多结构设计工作

复杂度不高时,链式方式反而更清楚。


还没理解任务结构,就先学一堆框架 API

Section titled “还没理解任务结构,就先学一堆框架 API”

这会让你最后学会的只是“框架语法”,不是系统设计。

系统越写越多 if/else,但还不愿意切到图式抽象。

明明需求很简单,却先把系统做得很重。


学完这一页,至少保留这张证据卡:

问题形态
工作流图、检索应用、角色团队或实验
框架选择
它增加了什么抽象,以及隐藏了什么控制
追踪记录
状态、节点、tool 调用、消息或运行 id
失败检查
框架魔法隐藏状态、重试或权限问题
决策
只有在单代理循环清晰后才选择框架

这一节最重要的不是记住框架名,而是建立这个判断:

LangChain 更像把常见组件串起来,LangGraph 更像把复杂状态流显式画出来。

当你开始用“任务结构”而不是“框架热度”去判断它们时,选型就会稳很多。


  1. 画一下你自己的一个 Agent 系统,判断它更像链还是图。
  2. 把链式示例加一个“如果没找到文档就改写 查询 再查一次”的逻辑,看看它会不会开始变乱。
  3. 用自己的话解释:为什么图式抽象比链式抽象更适合有状态回路的系统?
  4. 想一想:在什么情况下,链式方式其实比图式方式更合适?
解题思路与讲解
  1. 如果每一步只按固定顺序执行一次,它更像 chain;如果系统会分支、循环、重试、暂停或回到之前状态,它更像 graph。
  2. 加上“没找到文档 -> 重写 query -> 再检索”后,chain 往往会变乱,因为代码开始需要条件路由、循环上限和状态历史。这正是 graph 抽象开始有价值的地方。
  3. graph 抽象适合有状态循环,是因为节点和边把转移显式化:什么状态进入、做了什么判断、下一步去哪、什么时候停止。
  4. 当任务线性、短、稳定、容易检查时,chain 更合适,比如格式化输入、调用一次 retriever、生成一段短回答。