ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

LangChain与LangGraph选型指南:从组件到状态图,构建复杂Agent应用

LangChain与LangGraph选型指南:从组件到状态图,构建复杂Agent应用

1. 从两个名字说起:为什么总有人把 LangChain 和 LangGraph 搞混

刚接触大模型应用开发那阵子,我也被这两个名字绕进去过。项目里同事说“用 LangChain 搭个链路”,转头另一个同事又说“这个场景得上 LangGraph”,听起来像是同一套东西的两个版本,实际上它们解决的是完全不同层面的问题。LangChain 是一套用于构建大模型应用的基础组件库,LangGraph 则是构建有状态、可循环、多角色协作智能体流程的编排框架。一个偏“零件和胶水”,一个偏“流程和状态机”。你把它们理解成“乐高积木”和“用积木搭出来的可循环运转的流水线”,基本就抓住核心了。

这篇文章想解决的问题很具体:帮你搞清楚这两个东西各自是什么、边界在哪、什么时候该用哪个、以及从零到能上手做 Agent 应用的学习路线怎么排。适合三类人看——刚入门大模型应用开发、被各种框架名词绕晕的新手;已经用过 LangChain 但遇到多轮循环、状态管理就卡壳的中级开发者;还有在选型阶段纠结“到底要不要上 LangGraph”的技术负责人。我会把选型逻辑、核心概念、实操步骤、踩坑经验都摊开讲,尽量让你看完就能动手。

先说结论性的判断,后面再展开:如果你的需求是单轮或简单多轮的“输入-处理-输出”链路,LangChain 足够;一旦涉及循环、条件分支、多智能体协作、需要跨步骤记住状态,LangGraph 才是正解。两者不是替代关系,LangGraph 底层大量复用了 LangChain 的组件,它们是叠加使用的关系。很多人误以为“学了 LangGraph 就不用学 LangChain”,这是典型的认知误区,后面我会专门拆解。

2. 核心概念拆解:LangChain 到底在解决什么问题

2.1 LangChain 的本质是一套“标准化接口 + 可组合组件”

大模型本身只是一个“文本进、文本出”的黑盒。你要做一个真实可用的应用,中间必然要接:提示词模板、外部知识检索、工具调用、输出解析、记忆管理。LangChain 的价值就在于,它把这些环节都抽象成了统一的接口,让你可以像搭积木一样拼起来。

我举个最直观的例子。没有 LangChain 的时候,你调用一次模型并解析结构化输出,代码大概是这样:手动拼 prompt 字符串、手动发请求、手动用正则或 json.loads 解析返回、手动处理异常。每一步都要自己写,换个模型还得改一遍。有了 LangChain,这些变成PromptTemplate、ChatModel、OutputParser几个对象,链式组合即可,换模型只改一行初始化。

它的核心组件大致分这几类,我按实际使用频率排:

  • Model I/O:统一各家模型的调用方式,Chat 模型、补全模型、Embedding 模型都归这里。
  • Prompts:提示词模板,支持变量注入、少样本示例、消息角色区分。
  • Chains:把多个组件串成一条执行链,最经典的就是LLMChain。
  • Retrieval:文档加载、切分、向量化、检索,RAG 应用的地基。
  • Memory:对话历史管理,让模型“记得”之前说过什么。
  • Agents:让模型自己决定调用哪个工具,是早期 Agent 的实现方式。
  • Tools:把外部函数、API 包装成模型可调用的工具。

2.2 LangChain 的“链式思维”及其天花板

LangChain 最核心的思维模型是DAG(有向无环图)式的链。你定义好 A 到 B 到 C 的顺序,数据顺着流下去,跑完就结束。这种模式对绝大多数场景够用:问答、摘要、翻译、简单的 RAG、单轮工具调用,都能覆盖。

但问题也恰恰出在“无环”这两个字上。真实的智能体场景经常需要循环:模型调用工具,拿到结果后发现不够,再调用一次;或者根据中间结果决定走哪条分支;或者多个角色来回讨论几轮才得出结论。这些在纯 LangChain 的 Chain 体系里表达起来非常别扭,早期大家用AgentExecutor硬凑,但它的循环逻辑是黑盒的,你很难精细控制“什么时候停、走哪条路、状态怎么存”。

我自己踩过的坑:做一个需要“检索-判断-再检索”的问答机器人,用 LangChain 的 Agent 写出来,调试时完全不知道它内部循环了几次、每次为什么做那个决策,日志一团乱。这就是 LangChain 在复杂流程编排上的天花板——它擅长线性组合,不擅长带状态的循环图。

2.3 LangGraph 的本质是把流程显式建模成“状态图”

LangGraph 的思路完全不同。它让你把整个应用显式地画成一张图:节点(Node)是执行单元,边(Edge)是流转方向,状态(State)在节点之间传递和累积。最关键的是,它天然支持环——你可以从节点 A 走到 B,再从 B 回到 A,直到某个条件满足才退出。

这个模型和现实中的智能体工作方式高度吻合。一个 ReAct 风格的 Agent,本质就是“思考-行动-观察”的循环:想一步、调个工具、看结果、再想。用 LangGraph 表达,就是三个节点加一条回边,清清楚楚。而且因为状态是显式定义的,你随时能打印出“当前处于哪一步、状态里有什么”,调试体验比黑盒 Agent 好太多。

我用一个生活类比帮你记住区别:LangChain 像一条传送带,原料从一头进,成品从另一头出,中间工序固定;LangGraph 像一张地铁线路图,有换乘、有环线、有根据情况选择不同路径的岔口,而且每一站都记录着乘客(状态)的信息。传送带能干的活,线路图都能干;但线路图能干的复杂调度,传送带干不了。

3. 关键差异对照:一张表看清选型边界

光讲概念容易飘,我直接上一张对照表,把两个框架在几个关键维度上的差异列清楚。这张表是我自己在做技术选型时反复参考的,建议你收藏。

对比维度LangChainLangGraph
核心抽象Chain(链)、组件Graph(图)、State(状态)
流程结构以 DAG 为主,线性或分支支持环、条件跳转、动态路由
状态管理Memory 组件,偏对话历史显式 State,跨节点累积与更新
循环支持弱,靠 AgentExecutor 黑盒实现原生支持,循环逻辑完全可控
多智能体协作支持有限,需自行拼装原生支持,多节点多角色天然适配
调试体验链路长时较难追踪状态可打印,每步可观测
学习曲线平缓,组件多但概念简单稍陡,需理解图与状态机思维
典型场景RAG、问答、摘要、单轮工具调用复杂 Agent、多轮决策、多角色协作
与对方关系提供底层组件复用 LangChain 组件做编排

从表里能看出一个关键点:LangGraph 不是 LangChain 的升级版,而是它的补充层。LangGraph 里的节点内部,你照样可以用 LangChain 的 PromptTemplate、ChatModel、Retriever。所以正确的学习顺序是先 LangChain 打底,再 LangGraph 进阶,而不是二选一。

再补充一个容易被忽略的差异:可控性。LangChain 的 Agent 在循环时,你很难插入“人工审核”这种环节;而 LangGraph 可以在任意节点前中断,等人工确认后再继续,这在需要审批的业务流里非常关键。我做过一个合同审核的 Agent,就是靠 LangGraph 的断点能力,在“生成审核意见”节点前暂停,让人工过一眼再放行。

4. 学习路线怎么排:从零到能独立做 Agent 应用

4.1 第一阶段:Python 与异步基础(约 1-2 周)

别跳过这步。LangChain 和 LangGraph 都是 Python 生态的产物,而且大量用到异步、装饰器、类型注解。如果你 Python 只会写脚本,遇到async/await、TypedDict、装饰器@tool会一脸懵。

这个阶段的目标很明确:能读懂带类型注解的类、能写简单的异步函数、理解字典和列表推导。不需要学到多深,够用就行。我建议直接拿 LangChain 的官方示例代码当阅读材料,边读边查不懂的语法,比啃语法书效率高得多。

4.2 第二阶段:LangChain 核心组件实操(约 2-3 周)

这个阶段不要贪多,按“模型调用 → 提示词模板 → 输出解析 → 链 → 检索 → 记忆”的顺序逐个击破。每个组件都动手写一个最小可运行示例,别只看文档。

我给你一个实操清单,照着做一遍基本就通了:

  1. 用 ChatModel 调一次模型,打印返回对象的结构,看清楚content、usage这些字段。
  2. 写一个 PromptTemplate,注入变量,观察最终拼出的 prompt 长什么样。
  3. 接一个 OutputParser,把模型输出解析成结构化数据,故意喂个格式错误看它怎么报错。
  4. 把上面三步串成一条 Chain,跑通。
  5. 加载一个本地文档,切分、向量化、检索,做一个最小 RAG。
  6. 加 Memory,做多轮对话,观察历史是怎么被塞进 prompt 的。

这个阶段的核心是建立“组件可组合”的直觉。等你看到任何需求,脑子里能自动拆成“提示词+模型+解析+检索”的组合,就算过关了。

4.3 第三阶段:LangGraph 状态图思维(约 2-3 周)

这是真正的分水岭。前两个阶段是“用工具”,这个阶段是“设计流程”。我建议按下面的顺序推进:

先理解三个核心概念:State(状态)、Node(节点)、Edge(边)。State 通常用一个 TypedDict 定义,里面放所有需要在节点间传递的数据;Node 是一个函数,接收 State 返回 State 的更新;Edge 决定下一个走哪个节点。

然后动手实现一个最简单的循环图:一个“计数器”节点,每次给状态里的数字加一,当数字小于 5 时回到自己,等于 5 时结束。这个玩具例子能帮你彻底搞懂“环”是怎么转起来的。

接着实现一个 ReAct Agent:三个节点分别是“模型思考”“工具执行”“判断是否结束”,用条件边控制循环。做完这个,你就掌握了 LangGraph 最核心的用法。

最后挑战多智能体:定义两个角色节点,一个“研究员”负责检索,一个“写手”负责成文,中间加一个“审核”节点决定是否打回重写。这个练完,复杂 Agent 的编排你就有底了。

4.4 第四阶段:工程化与实战(持续)

到这一步,重点从“能跑”转向“跑得稳、跑得省、跑得可观测”。要关注的东西包括:流式输出、错误重试、超时控制、Token 成本统计、LangSmith 之类的追踪工具、以及把应用部署成 API 服务。

我个人的经验是,工程化阶段踩的坑比学习阶段多得多。比如流式输出和结构化解析经常打架,比如循环没设上限导致无限调用烧钱,比如状态里塞了不可序列化的对象导致断点恢复失败。这些后面会专门讲。

5. 实操演示:用 LangGraph 搭一个带循环的检索问答 Agent

光说路线不够,我直接带你走一遍核心实现。这个例子是一个“检索-判断-再检索”的问答 Agent,正好能体现 LangGraph 相对 LangChain 的优势。

5.1 状态定义与节点设计

先定义状态。这里我用 TypedDict,把问题、检索到的文档、当前答案、循环次数都放进去:

from typing import TypedDict, List class AgentState(TypedDict): question: str documents: List[str] answer: str loop_count: int

为什么要把loop_count放进状态?因为循环必须有终止条件,否则模型可能一直觉得“信息不够”而无限检索。这是新手最容易忽略的点,我见过有人跑测试把额度烧光的。

节点设计三个:retrieve负责检索,generate负责生成答案,should_continue是一个条件判断函数,决定是回到检索还是结束。

5.2 条件边与循环控制

条件边是 LangGraph 的灵魂。它的写法是给add_conditional_edges传一个判断函数,函数返回下一个节点的名字:

def should_continue(state: AgentState) -> str: if state["loop_count"] >= 3: return "end" if "信息不足" in state["answer"]: return "retrieve" return "end"

这段逻辑的意思是:最多循环 3 次;如果模型说信息不足就再检索一轮;否则结束。把终止条件写死在代码里,而不是交给模型判断,是控制成本和避免死循环的关键。模型可以建议“要不要再查”,但最终拍板的是你的代码。

5.3 组装图并运行

组装部分就是把节点和边连起来:

from langgraph.graph import StateGraph, END graph = StateGraph(AgentState) graph.add_node("retrieve", retrieve_node) graph.add_node("generate", generate_node) graph.set_entry_point("retrieve") graph.add_edge("retrieve", "generate") graph.add_conditional_edges("generate", should_continue, { "retrieve": "retrieve", "end": END }) app = graph.compile()

跑起来就是app.invoke({"question": "...", "loop_count": 0})。整个过程你能清楚地看到状态怎么流转、循环了几次、每次检索到了什么。这种透明度是 LangChain 黑盒 Agent 给不了的。

5.4 参数选择与成本考量

几个我实测下来比较稳的参数建议:循环上限设 3 到 5 次,再多基本是模型在无效打转;检索返回的文档数控制在 3 到 5 篇,太多会撑爆上下文还稀释相关性;如果用了大模型做判断,尽量换成小模型或规则判断,能省不少钱。

注意:状态里不要放模型客户端、数据库连接这类不可序列化的对象。LangGraph 支持断点恢复,靠的就是状态可序列化,塞了这些东西断点功能直接失效。

6. 常见问题与避坑经验实录

6.1 高频问题速查表

问题现象可能原因解决思路
循环停不下来没有硬性终止条件在状态里加计数器,代码层强制退出
状态更新丢失节点返回的不是完整更新确认返回 dict 的键与 State 定义一致
断点恢复失败状态含不可序列化对象只存基础类型,外部资源用时再建
流式输出乱序与结构化解析冲突流式阶段只输出文本,解析放最后
多智能体互相等待边没定义清楚明确每个节点的出口和条件
Token 消耗异常高历史或文档全量塞入做截断、摘要或相关性过滤

6.2 我踩过的三个真实坑

第一个坑:把 LangGraph 当 LangChain 用。刚开始我试图用 LangGraph 重写一个简单的单轮问答,结果发现代码量比 LangChain 还多,纯属杀鸡用牛刀。后来才明白,简单链路就用 LangChain,别为了用新框架而用新框架。选型要看流程复杂度,不是看框架新不新。

第二个坑:状态设计太随意。我一开始把所有中间变量都往 State 里塞,结果状态越来越臃肿,节点之间耦合严重,改一个字段牵动全身。后来学乖了,State 只放真正需要跨节点传递的数据,节点内部的临时变量就地消化,不往外抛。

第三个坑:忽视可观测性。早期调试全靠 print,循环一多就晕。后来接入了追踪工具,每一步的输入输出、耗时、Token 消耗都可视化,排查效率提升一大截。复杂 Agent 一定要配可观测工具,这是刚需不是锦上添花。

6.3 关于框架选型的额外建议

市面上 Agent 框架不止这两个,还有 Dify、CrewAI 等。我的判断逻辑是:要低代码快速搭原型,看 Dify 这类平台;要做多角色协作且角色定义清晰,CrewAI 上手快;要做精细可控、带复杂状态和循环的生产级流程,LangGraph 更合适。LangChain 则是所有这些的地基,值得先打牢。

别陷入“哪个框架最好”的争论,它们解决的是不同层次的问题。真正重要的是你脑子里有没有“状态、节点、边、循环、终止条件”这套流程思维,框架只是表达工具。

7. 学习资源与进阶方向

7.1 官方文档的正确打开方式

官方文档永远是第一手资料,但很多人读法不对。我的建议是不要从头读到尾,而是带着具体问题去查。比如你想知道怎么做条件边,直接搜conditional_edges,看示例代码,跑通,再回头看概念解释。文档里的概念部分适合在你已经跑通示例后回头理解,顺序反了会很痛苦。

另外,官方仓库的examples目录比文档还值钱,里面全是可运行的完整项目。我学 LangGraph 多智能体那部分,就是照着示例改出来的。

7.2 从 Demo 到生产的进阶清单

能跑通 Demo 和能上生产是两码事。如果你想让自己的 Agent 真正可用,下面这些迟早要补:

  • 流式输出:用户体验的关键,首字延迟能降一大截。
  • 错误处理与重试:模型调用会失败,工具会超时,必须有兜底。
  • 成本控制:Token 统计、缓存、小模型分流。
  • 可观测性:追踪每一步,出问题能定位。
  • 评测体系:怎么判断你的 Agent 变好了还是变差了,需要一套评测集。
  • 安全与权限:工具调用的边界、敏感操作的审批。

这些内容任何一个展开都能写一整篇,我这里只点出来,让你知道学习路线不止于“会用框架”。

7.3 一个持续受益的习惯

最后分享一个我坚持了很久的习惯:每学一个新概念,就用最小代码验证一遍,并写下“它解决了什么问题、什么时候不该用它”。前者帮你理解,后者帮你选型。很多人只记“怎么用”,不记“什么时候不用”,结果一到真实项目就选错工具。LangChain 和 LangGraph 的边界,就是靠这种反复验证刻进脑子里的。

这套路线我自己走过一遍,也带过几个新人走,基本两到三个月能从零到独立做中等复杂度的 Agent 应用。快慢因人而异,但顺序别乱——先组件后编排,先线性后循环,先能跑后跑稳,这个节奏踩对了,少走很多弯路。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进