ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

从线性Chain到状态图:一文讲透LangChain与LangGraph的协作范式

从线性Chain到状态图:一文讲透LangChain与LangGraph的协作范式

前言

本篇文章的目的主要是把LangChain的能力边界、LangGraph的核心设计逻辑,以及两者在生产场景下的配合方式讲透。读完你能清楚知道:什么场景用LangChain写最快,什么场景必须上LangGraph,两者怎么搭才能不绕弯路。


引子:为什么我们需要跳出「Chain思维」

很多开发者第一次接触大模型应用开发,都是从跟着教程写第一个Demo开始的:用LangChain把Prompt模板、大模型、知识库检索器串起来,几行代码就跑通了一个能回答问题的RAG助手,当时会觉得整个开发体验无比顺畅——所有组件像乐高积木一样,拼起来就能用。

但真的要把这个Demo做成能上线的生产应用时,问题会集中爆发:用户连续聊了半小时的多轮对话,服务一次重启上下文就全丢了;想加一个质量校验环节——AI回答完用户问题之后,要自己检查有没有事实错误,答错了就回到检索环节重新生成,原来的线性Chain根本塞不进去这个回退逻辑;想在流程涉及用户隐私、金额确认的时候暂停一下,等人工审核通过了再继续往下走,光是自己写状态管理、中断回调、跨请求的会话同步就花了整整一周,还经常出现不同节点读到的状态不一致的bug。

这些问题的根源,不在于你用的LangChain版本不对,而在于传统的「线性Chain」从设计之初,就没有考虑复杂大模型应用的核心特征:它不是一条从起点到终点走一次就结束的直线,而是一个有记忆、会循环、需要动态决策、甚至需要人类介入的长期运行的状态机。

LangGraph的出现,就是为了补上这个缺口。


一、回到起点:LangChain到底解决了什么问题

1.1 核心定位:大模型应用的「可复用积木工具箱」

要理解LangGraph,首先要把LangChain的定位说清楚。LangChain从来不是一个「工作流编排框架」,它的本质是一个通用大模型应用的组件抽象层——把开发大模型应用时会重复造轮子的所有环节,都做成了标准化、可复用的积木。

你在开发中会遇到的绝大多数通用需求,LangChain都已经封装成了开箱即用的组件:统一的大模型接入接口(不管是OpenAI、通义千问还是本地部署的开源模型,调用方式完全一致)、Prompt模板引擎、结构化输出解析器、向量检索封装、工具调用规范、对话内存管理、文档加载器、文本切分器等等。

这些组件的价值在于,你不需要在每个项目里重复写「怎么把历史对话拼进Prompt」「怎么把大模型返回的文本解析成结构化JSON」「怎么把文档切块存到向量库」这些重复逻辑,直接调用现成的组件就能省掉80%的样板代码。

1.2 LCEL:LangChain的原生组合逻辑

LangChain为了把这些积木拼起来,设计了LCEL(LangChain Expression Language)——它的核心逻辑非常简单:所有组件都实现了统一的Runnable接口,支持用管道符|把不同组件串成一条处理链,数据像水流一样从管道的一端流进去,经过每一个组件的处理,从另一端输出结果。

比如一个最简单的RAG流程,用LCEL写出来就是几行:文档加载器把原始文档切块→向量检索器根据用户query召回相关片段→Prompt模板把召回的片段和用户问题拼好→传给大模型生成回答→输出解析器把文本转成结构化结果。整个流程是完全线性的,每一步的输出就是下一步的输入,没有分支,没有循环,写起来非常直观。

1.3 Chain模式的天然能力边界

这种线性管道的设计,决定了LangChain的Chain只能搞定「流程固定、逻辑单向、状态简单」的场景。一旦你的流程里出现以下任何一种需求,Chain的模式就会开始变得捉襟见肘:

  • 需要循环:比如ReAct Agent的「思考-调用工具-观察结果-再思考」循环,或者生成内容之后反复检查、不达标就重写的回退逻辑,Chain本身不支持回路,要实现循环只能自己在外面套while循环,状态管理完全靠自己写;
  • 需要动态分支:比如根据用户的意图,自动把请求路由到不同的处理节点(知识查询、投诉处理、转人工),Chain的分支能力非常弱,复杂一点的路由逻辑就要写一堆嵌套判断,代码会变成乱麻;
  • 需要持久化状态:Chain默认的内存是存在进程里的,服务一重启就丢,也没有办法把流程的执行历史存下来做回溯,跨请求的状态同步完全没有官方支持;
  • 需要人机介入:Chain是一次性把整个流程跑完的,没有办法在中途暂停,等人工操作完成之后再接着跑,要实现这个功能得自己写中断、存状态、做回调,工程量极大。

很多人用LangChain写了复杂流程之后吐槽「代码越写越乱」,本质上不是你写得不好,而是用线性的Chain模型,硬去套一个本质是状态机的复杂流程——就像用直线画一个有回路、有分支的电路图,自然会越画越歪。


二、为什么LangGraph会从LangChain生态里长出来

2.1 最常见的认知误区:LangGraph不是LangChain的替代品

网上很多教程会把LangGraph和LangChain对立起来,说「LangChain过时了,现在都用LangGraph」,这是完全错误的认知。

LangGraph本质上是LangChain生态内部,专门解决「复杂流程编排」问题的核心组件——它没有替代LangChain,反而需要完全依赖LangChain的组件生态才能发挥作用。打个通俗的比方:如果把大模型应用开发比作盖房子,LangChain是你能买到的所有建材(钢筋、水泥、门窗、管线),LangGraph是帮你把这些建材按设计图纸搭起来的施工组织系统,它自己不生产建材,但是没有它,复杂的房子就盖不起来。

你在LangGraph里写的每一个节点,都可以直接调用LangChain的ChatModel、Retriever、Tool、Prompt模板、甚至原来写好的LCEL Chain,所有在LangChain生态里积累的组件,都可以无缝迁移到LangGraph的流程里,完全不存在「学了LangGraph就要把之前写的LangChain代码全部推翻重写」的问题。

LangChain官方现在的技术路线非常明确:简单的线性流程继续用LCEL写就行,开发快、代码轻;所有涉及复杂状态、循环、分支、持久化、人机协同的生产级流程,全部用LangGraph来编排,原来的老版AgentExecutor(硬编码的ReAct循环实现)已经进入维护模式,不再推荐新项目使用。

2.2 LangGraph的本质:把大模型应用建模为可持久化的有状态图

LangGraph的核心设计思想非常简单:把整个大模型应用的运行过程,抽象成一张有向图。

和传统的DAG工作流(比如Airflow、Camunda)不一样的是,这张图是允许存在回路的,而且图里有一个全局共享的、带持久化能力的状态对象,所有节点的执行、边的流转规则,都是围绕这个共享状态来运行的。

你可以把它理解成一个专门为大模型应用设计的简化版有限状态机:你定义好所有的执行节点,定义好节点之间怎么跳转(这个跳转规则甚至可以是大模型动态判断的,不是硬编码写死的),然后整个流程的状态流转、持久化、断点恢复,全部由LangGraph帮你管,你不需要自己写任何状态同步的逻辑。


三、LangGraph核心概念逐字拆解

LangGraph的核心概念非常少,总共就四个,搞懂这四个,就能覆盖90%的日常开发场景。

3.1 State:整个系统的共享记忆核心

State是LangGraph的灵魂,也是它和传统工作流框架最大的区别。

你可以把State理解成整个流程运行时的全局共享数据结构——通常用Pydantic或者TypedDict定义,里面放所有节点需要读写的字段:比如用户的原始提问、历史对话消息、检索到的知识库片段、大模型判断出来的用户意图、当前流程走到了哪一步、是否满足结束条件等等。

所有节点执行的时候,拿到的都是当前State的完整快照;节点执行完之后,不需要返回值,只需要输出对State的增量更新,LangGraph会自动把这些增量更新合并到全局State里,然后带着更新后的State,走到下一个节点。

这里有一个新手最容易踩坑的细节:State里每个字段都可以定义自己的Reducer(合并规则)。比如「历史对话消息」这个字段,不是每次节点更新就把原来的内容覆盖掉,而是要把新产生的消息追加到历史列表里——这个「追加而不是覆盖」的规则,就是通过Reducer定义的。如果不定义Reducer,默认的合并规则就是覆盖,你会发现历史消息莫名其妙丢了,这是绝大多数新手第一次用LangGraph会遇到的经典bug。

3.2 Node:单一职责的执行单元

图里的每一个Node,本质上就是一个普通的Python函数。它的输入是当前的全局State,输出是对State的增量更新,没有任何特殊的魔法。

一个Node里可以做任何事:调用大模型生成内容、调用LangChain的检索器拉取知识库数据、执行一段固定的规则判断、调用外部的业务接口、甚至把原来写好的一整条LangChain Chain包进来跑。

LangGraph对Node的设计原则是「单一职责」:一个Node只做一件事,比如不要把「调用大模型+解析结果+调用工具+写数据库」全塞到一个Node里,拆成四个独立的Node,整个图的可维护性、可观测性会好非常多。

3.3 Edge:支持动态决策的流转规则

Edge就是定义「一个Node执行完之后,下一步该走哪个Node」的规则,分两种:

  • 固定边:执行完A节点,无条件跳到B节点,适合流程完全固定的场景;
  • 条件边:执行完A节点之后,跑一个判断函数,根据当前State里的字段值,决定下一步跳哪个节点。这个判断函数可以是硬编码的规则(比如State里的意图字段是「投诉」就跳到投诉处理节点),也可以直接调用一个大模型,让大模型根据当前状态动态决定下一步走哪里——这也是为什么LangGraph比传统工作流框架更适合大模型场景的核心原因:它的流转规则不是写死的,是可以动态决策的。

3.4 内置关键能力:让复杂流程真正落地

除了上面三个核心概念,LangGraph内置了几个生产级流程必须的能力,不需要自己开发:

  • Checkpointer(检查点机制):每一个节点执行完之后,LangGraph都会自动把当前的完整State序列化存到后端(支持内存、SQLite、Postgres、Redis等多种存储),这意味着哪怕服务挂了重启,流程也能从上次执行到的节点接着跑,甚至可以回到任意一个历史检查点,修改State之后重新执行,相当于给整个流程装了「时间机器」;
  • Interrupt(中断机制):你可以在任意一个节点后面加中断点,流程跑到这里就会自动暂停,把当前的State存下来,等外部(比如人工审核界面)拿到结果、传入新的状态值之后,再从断点接着往下跑,不需要自己写任何状态同步和回调逻辑;
  • Subgraph(子图机制):你可以把一段常用的流程封装成一个独立的子图,在主图里直接调用,类似代码里的函数封装,避免整个主图变得过于庞杂难以维护。

四、LangGraph到底比传统Chain强在哪

4.1 原生支持循环:打破线性流程的枷锁

这是LangGraph最核心的能力优势。传统Chain是纯线性的,没有办法画回路,而绝大多数大模型应用的核心逻辑,本质上都是循环:

  • 标准的ReAct Agent:思考→调用工具→观察结果→再思考,直到找到足够的信息生成答案;
  • 内容生成流程:写初稿→质量检查→不达标就回到写初稿的环节重写,直到满足质量要求;
  • 多Agent辩论场景:两个Agent互相反驳对方的观点,经过多轮迭代之后收敛到最终结论。

用LangGraph实现这些循环,只需要在图里把「检查节点」的出口连回「生成节点」就行,循环的逻辑、状态的传递全部由LangGraph自动管,不需要自己在外面套while循环,也不需要手动维护循环过程中的临时状态。

4.2 全链路状态持久化:可回溯的时间机器

传统LangChain的Memory是存在进程内存里的,服务一重启所有上下文就没了,也没有办法回溯某一步的执行过程。而LangGraph的Checkpointer机制,相当于给整个流程的每一步都拍了快照:

  • 多轮长对话的上下文可以永久存下来,哪怕用户隔了三天回来接着聊,也能接上之前的状态;
  • 排查线上问题的时候,可以直接拿到某一步的State快照,看到当时大模型拿到了什么输入、输出了什么,而不是对着黑盒Chain猜哪里出了问题;
  • 流程跑到某一步发现逻辑错了,可以直接回到出错前的快照,修改参数之后重新跑,不需要从起点开始重新执行整个流程。

4.3 开箱即用的人机协同能力

现在的生产级大模型应用,几乎没有完全不需要人介入的场景:涉及金额、隐私、合规的内容需要人工审核生成结果,高风险的操作需要人工确认之后再执行,内容生成类的流程需要人工批注之后再继续润色。

这些场景用传统Chain实现的工程量极大,而LangGraph的Interrupt机制是原生内置的:你只需要在需要人工介入的位置加一个中断点,流程会自动暂停,把当前状态推到人工审核界面,等审核人员确认或者修改之后,调用接口把结果传回来,流程就会自动从断点继续往下走,整个过程不需要自己写任何状态管理的代码。

4.4 自然的多Agent协作骨架

现在越来越多的复杂应用开始采用多Agent架构:一个主管Agent负责拆解任务、分给不同的专业子Agent,子Agent执行完之后把结果返回给主管Agent,主管Agent再整合结果给用户。这种多角色协作的流程,本质上就是一个有多个节点、动态流转的状态图,用LangGraph可以非常自然的搭出来——不需要自己写复杂的消息队列、Agent之间的通信逻辑,所有的协作状态都存在全局State里,整个协作流程的可视化、可观测性也非常好。


五、实战中的常见误区与最佳实践

第一个最常见的误区,是上来就用LangGraph写所有东西——哪怕是一个只需要单轮Prompt生成的简单流程,也要搭一套图结构,这属于典型的杀鸡用牛刀。

最佳实践的原则非常简单:简单的线性流程用LCEL写Chain最快,什么时候流程里出现了循环、多节点状态共享、需要人工介入、长任务持久化的需求,再上LangGraph,不要为了用新工具而用新工具。

第二个误区,是把一个Node写得特别大,把所有的逻辑都塞进去。正确的做法是保持Node的单一职责,每一个Node只做一件事,这样不仅调试方便,还能在任意两个Node之间加中断、加分支,整个流程的灵活性会高很多。

第三个误区,是生产环境用LangGraph自带的内存版Checkpointer。内存版的检查点只能在开发调试的时候用,服务一重启所有状态就丢了,生产环境一定要把Checkpointer换成Postgres、Redis这类持久化存储,不然多轮对话、断点续跑的能力完全发挥不出来。

第四个误区,是把State设计得过于复杂。State是全局共享的,字段越多、嵌套越深,节点之间的耦合就越重,后面改逻辑的时候很容易牵一发动全身。尽量把State设计成扁平化的字段,每个字段的含义清晰,没有冗余信息。


六、技术栈的长期演化方向

从LangChain到LangGraph的演化,本质上是整个大模型应用开发范式的转向:早期我们把大模型应用当成一个「单轮的文本生成工具」,用线性的Chain拼起来就能用;但现在我们越来越把大模型应用当成一个「长期运行、有记忆、能动态决策、需要人和AI协作的智能系统」,这种系统天然就是有状态的、带图结构的。

未来的技术栈分工也会越来越清晰:LangChain负责提供所有可复用的组件积木,让你不用重复写样板代码;LangGraph负责提供状态机编排的骨架,管流程流转、状态持久化、人机协同的底层逻辑。两者不是替代关系,是从「零件」到「系统」的分层配合——你完全不需要抛弃已经写好的LangChain代码,只需要在需要复杂流程编排的环节,把原来的Chain包成Node放进LangGraph的图里,就能平滑升级到生产级的架构。

本质上,大模型应用开发的核心难点,从来不是怎么调用大模型的API,而是怎么管理好复杂流程里的状态、决策和流转——LangGraph的价值,就是把这些原本需要自己手写的底层能力,全部封装好,让开发者可以把精力放在业务逻辑本身,而不是陷入无止境的状态管理的bug里。

RELATED READING

延伸阅读

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