尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
LangChain与LangGraph怎么选?从本质差异到学习路线全解析
这段时间私信里问得最多的一个问题已经从怎么把对话记录传给模型变成了LangChain和LangGraph到底该学哪个、项目里到底用哪个。我能理解这种纠结因为LangChain官方文档一边把重心往LangGraph上偏一边又在自己博客里强调LangChain生态的成熟度普通开发者很容易被这种既捧又推的态度搞晕。我自己从LangChain切到LangGraph也经历了差不多半年的过渡中间踩了不少坑。这篇文章我尽量把两套框架的本质差异、代码层面的区别、选型判断标准以及我认为比较合理的上手路线一次说清楚。不管你是刚接触大模型开发还是已经用LangChain写了一段时间的RAG应用这篇都应该能帮你少走弯路。先说一个容易被误解的点LangGraph并不是LangChain的替代品更不是某些人说的LangChain要凉了。它们的关系比大多数人想象的要紧密得多。想明白这一点后面的学习路径和选型判断都会顺很多。所以我会先从定位这件事讲起。1. 先认清本质关系父子框架不是竞品框架1.1 LangGraph是LangChain生态的下半场方案很多人觉得LangChain和LangGraph是两个团队在打架其实LangGraph本来就是LangChain生态里专门负责复杂编排的那一层核心维护者也高度重合。之所以要再做一套新东西根因是LangChain原有的Chain模型在面对带循环、带条件分支的Agent场景时已经非常吃力。Chain这个命名本身就暗示了线性链路A节点执行完走到BB走到C一路往下。你可以做分支也可以并行但本质上这是一张有向无环图节点间的连接方向是单向且无回路的。可真正的Agent应用大量依赖模型决定下一步干什么、干完还要不要再来一轮这种循环结构。你当然可以在某个Chain节点里塞一个AgentExecutor让它在内部循环但这个内部循环对你来说是个黑盒出了问题很难定位。1.2 一个生活化的类比流水线和分拣中心LangChain更像一条装配流水线。原料从传送带一端进去经过工位1、工位2、工位3最后出来一个成品。它适合工艺标准明确、流程相对固定的场景比如经典的检索文档、拼接提示词、生成回答三步式RAG。流水线的优点是简单可靠缺点是改动一条工艺路线就得大拆大改。LangGraph更像一个快递分拣中心。货物进来后根据面单信息可以走A通道也可以走B通道如果发现某个包裹信息不完整还能绕回上一个分拣台重新处理。你能画出这张流转图就能把它实现成代码。这种模型天然支持循环、支持条件跳转、支持人工在旁边拦截确认而这些恰恰是复杂Agent需要的。1.3 生态组件依然是共同的底座这是很多人忽略的一点LangChain的价值不只是Chain更是一整套生态。几十种模型封装、几百种外部工具集成、各种向量库适配、提示词管理和输出解析组件这些资产并不会因为LangGraph的出现而失效。LangGraph在设计上保留了LangChain core层里的抽象你在LangChain里用顺手的ChatPromptTemplate、OutputParser、Tool、Retriever搬到LangGraph里照样直接用。所以先学LangChain再学LangGraph不是重复劳动而是在给后面打地基。2. 从代码看差异数据流、状态和控制逻辑光讲理念容易飘我们直接看代码。我拿一个最典型的工具调用Agent来做对比场景是用户问一句明天上海天气怎么样顺便提醒我晚上八点开会模型需要先查天气、再创建提醒最后汇总回复。2.1 用LangChain写法黑盒AgentExecutorfrom langchain_openai import ChatOpenAI from langchain.agents import create_tool_calling_agent, AgentExecutor from langchain_core.prompts import ChatPromptTemplate llm ChatOpenAI(modelgpt-4o, temperature0) tools [get_weather, create_reminder] prompt ChatPromptTemplate.from_messages([ (system, 你是靠谱的助手可以根据问题调用工具), (human, {input}), (placeholder, {agent_scratchpad}) ]) agent create_tool_calling_agent(llm, tools, prompt) executor AgentExecutor(agentagent, toolstools) result executor.invoke({input: 明天上海天气怎么样顺便提醒我晚上八点开会。}) print(result[output])这段代码很爽十行不到就把一个能自主调用工具的Agent跑起来了。但它的问题也在这AgentExecutor内部到底经历了哪些思考、调用了几次工具、中间的每一步是什么状态你一概看不到。调用结果对了还好一旦结果不对你只能开启盲猜模式是模型没有正确触发工具是工具参数解析错了还是多轮对话串了上下文排查效率非常低。2.2 用LangGraph重写每一步都在你眼皮底下from langgraph.graph import StateGraph, END from typing import TypedDict, Annotated class AgentState(TypedDict): messages: Annotated[list, add_message] next_action: str def call_model(state: AgentState): # 把当前所有消息喂给模型让它决定下一步 response llm.invoke(state[messages], toolstools) if response.tool_calls: return {next_action: response.tool_calls[0][name]} return {next_action: end} def call_tool(state: AgentState): # 根据 next_action 执行对应工具把结果追加回消息列表 tool_name state[next_action] result execute_tool(tool_name, state) return {messages: [ToolMessage(contentresult)]} def decide_next(state: AgentState): return tools if state[next_action] ! end else END builder StateGraph(AgentState) builder.add_node(model, call_model) builder.add_node(tools, call_tool) builder.add_conditional_edges(model, decide_next, { tools: tools, END: END }) builder.add_edge(tools, model) app builder.compile() result app.invoke({messages: [HumanMessage(content明天上海天气怎么样顺便提醒我晚上八点开会。)]})这段代码虽然长了一点但模型决策 - 执行工具 - 回到模型再决策 - 直到结束这个循环被完整展示出来了。调试的时候你可以在任意节点打断看state里到底存了什么模型到底在哪个环节出了问题。这对生产环境来说是质变级的提升。2.3 状态管理两套框架的分水岭对比上面两段代码最核心的分水岭其实是状态管理。LangChain的链与链之间传递的是上一层的输出结果每个节点是独立的节点之间没有共享的内存区域。这种设计在纯线性流程里够用但到了多轮工具调用、多智能体协作的场景就会很别扭你想让两个子任务共享一段上下文要么用global变量要么手动把上下文塞进每个调用参数里代码会逐渐失控。LangGraph不一样它有一张贯穿始终的State可以理解为一块共享工作台。每个节点都能读这块台子上有什么也能往上面追加内容。Annotated[list, add_message]这种写法表示追加模式兼顾了状态可追溯和操作简便。只要你的场景需要多个环节反复读写同一份信息LangGraph的组织方式就明显更接近人类真实的工作方式。3. 选型没那么玄乎什么项目该选谁每次有人问我我该用哪个我不会直接给答案而是先让他回答一个问题你的流程是基本固定的一条线还是模型需要反复决定下一步走哪条路前者用LangChain后者用LangGraph。下面是我按项目类型梳理的判断矩阵。3.1 适合LangChain的项目特征场景特征典型例子RAG问答检索→拼接→生成流程固定无循环企业知识库问答、文档对话简单工具调用模型只调用一次工具或固定顺序调用几次天气查询、计算器、翻译插件快速原型需求验证期追求最短上线时间内部demo、黑客松项目集成生态优先看中的是向量库、模型商、外部工具的现成插件基于成熟组件快速搭建业务这类项目如果硬上LangGraph会有一种明显的杀鸡用牛刀感。图结构需要你显式设计状态、设计节点边界这部分额外的心智负担在简单流程里完全没必要。我见过有人用LangGraph做纯RAG代码比LangChain版长三倍功能却完全一样维护成本还更高。过度设计也是一种风险。3.2 适合LangGraph的场景多轮自主决策的Agent模型要有权决定先做什么、后做什么、做完了再回来从长计议比如数据分析助手、自动化操作浏览器完成复杂任务的Agent。多智能体协作规划者、执行者、审核者分工协作每个角色是图里的一个节点角色之间的交接必须清晰可控。需要人工审批介入流程需要机器先生成人来确认确认后再继续LangGraph的interrupt机制可以停在节点上等待人类输入。需要断点恢复执行到一半进程崩了下次启动能从上次的状态继续跑。LangGraph的checkpoint机制把状态持久化这个能力在生产环境非常实用。对流程的可控性要求极高比如模型走了不该走的分支你要能拦截、能修正、能指定它回到哪个节点重来。3.3 中间地带两套框架本来就可以混用需要强调一下这不是一个非黑即白的选择。LangGraph的节点内部完全可以写一段LCEL组合的子链也就是说你可以在图结构里使用LangChain的prompt | model | parser来快速组建节点内的逻辑。反过来你也可以在一个LangChain应用里把某个复杂的模块单独用LangGraph实现后作为组件嵌入。我的习惯是外层用LangGraph定边界内层用LCEL写细节。这样既有图的灵活性和可观测性又能享受LangChain生态的写码效率。这个组合是我目前在Agent类项目里的默认方案。4. 从入门到能干活我给的学习路径建议聊完选型再聊学习路径。很多新手一上来就听别人说LangGraph才是未来于是直接跳过LangChain去学图结果被State、Node、Edge、Reducer一堆概念劝退。我建议的顺序正好反过来先用LangChain建立组件直觉再用LangGraph建立编排直觉。4.1 阶段一用LangChain打底周期约两到三周这个阶段不要急着钻研多复杂的技巧把基础组件吃透就行模型封装ChatOpenAI这类模型接口如何统一调用如何传温度、max_tokens等参数。提示词管理ChatPromptTemplate的模板写法system、human、placeholder消息的用途。输出解析StrOutputParser、PydanticOutputParser学会让模型输出的文本变成结构化数据。检索组件理解文档切分、向量化、检索器Retriever的基本流程。工具调用自己写一个工具函数加上tool装饰器让模型学会调用它。然后用这些组件拼一个完整的RAG问答应用把组件如何组合沉淀成肌肉记忆。LCEL管道语法prompt | model | parser也在这个阶段掌握虽然它简单但它是理解LangGraph节点内部代码的基础。4.2 阶段二用LangGraph重构Agent周期约二到四周这个阶段直接去啃LangGraph官方教程里的Agent部分按顺序做四个练习最简单的两步图先做一个关键词分类→走不同处理节点的图理解Node和Edge。这一步不要掺Agent先把图的骨架搞明白。一个需要循环的Agent做一个模型决定调用工具→执行工具→结果回填→模型继续决策的循环图这是Agent应用最核心的骨架。一个人工介入流程做一个生成结果后停在人工审批节点等待确认消息再继续或终止的流程理解interrupt和外部状态恢复。一个双节点协作流程做一个研究员节点产出资料→写作节点基于资料写文章的两Agent协作理解多角色之间如何通过共享State传递信息。每做完一个练习都顺手把graph.get_graph().draw_ascii()打印出来看看自己画的图长什么样。这一步能帮你建立很强的空间感。4.3 阶段三工程化能力补全按需分配时间到了这个阶段框架本身你已经不怵了真正拉开差距的是工程化能力流式输出研究graph.stream()和stream_mode参数搞清楚怎么把模型增量输出的token通过SSE推给前端。持久化使用checkpointer比如SqliteSaver实现进程重启后从上次状态继续跑。测试把图里的每个节点函数抽成独立单元先测单函数再测整图。节点函数的输入输出越纯测试越好写。可观测性至少理解一次tracing的原理知道如何把每次模型调用、每一步图流转记录下来实战排查问题全靠它。我的感受是阶段一和阶段二加起来一个月到一个月半可以覆盖绝大多数Agent开发岗位的笔试和实际需求阶段三是工作中的持续修行不用急于一时。5. 实战中容易踩的坑和我的处理习惯5.1 别把AgentExecutor当成默认Agent不是所有Agent都需要Executor。项目早期图省事用AgentExecutor跑通demo完全没问题但如果你的Agent要处理多工具、多轮循环尽早迁到LangGraph风格。我在生产环境复盘过几个模型表现不稳定的问题最后根因几乎都指向同一个点黑盒执行器内部状态无法干预模型一旦陷入重复调用工具的怪圈你只能干着急。把执行过程显式展开成图之后这类问题立刻变得可控。5.2 State设计混乱是最大的坑很多人在LangGraph里把状态字段当垃圾桶什么都往里面塞最后State里十几个字段互相耦合条件边的逻辑写到你想骂人。我现在的习惯是按职责拆字段messages只放对话记录next_action只放下一跳决策tool_results放工具执行结果final_answer放最终回答。每个节点只关心它需要的字段不要动不动就把中间计算结果塞进messages那样上下文很快会乱掉。5.3 版本迭代快文档教程要对准版本LangChain和LangGraph的API变化速度比较快。你今天在网上搜到的一篇教程很可能用的是半年前的API。我的做法是requirements.txt锁定大版本升级时逐个看changelog不要无脑pip install --upgrade。看教程时也先确认对方用的包版本版本不同导致API不兼容是非常常见的坑。5.4 调试技巧把图的每一步摊开调试LangGraph比调试LangChain舒服得多但也有技巧。我一般是三件套组合使用在节点函数里加打印观察当前state的内容。用graph.stream()或stream_modevalues看每一步执行完后的状态快照。用graph.get_graph().draw_ascii()把结构打印出来确认边和条件边的连接关系是否符合预期。这套组合能让模型为什么在这个节点停住了这类问题在几分钟内定位而不是靠猜。5.5 有时候根本不需要图说实话并不是所有大模型项目都需要LangGraph。如果你的现状是一个接口调用、一个几行提示词就能返回结果那我建议你连LangChain都别上直接用原生SDK调模型就行。学习曲线和依赖成本都是实打实的选型的第一原则永远是够用就好复杂度匹配问题复杂度。用LangGraph最舒服的时刻是你确实遇到了多步骤、多分支、需要反复决策的问题发现手写状态机维护成本已经高到离谱。那时候它带来的确定性会让你觉得之前花时间理解图结构完全值得。最后再分享一个我个人的体会。LangGraph带给我的最大改变不是性能也不是代码量而是心理上的确定性。以前用黑盒执行器我心里总悬着一块石头模型到底会不会走偏会不会卡死现在把图摊开每一条可能的路径都明明白白画在眼前该在哪一步拦截、在哪一步人工介入、在哪里兜底全部一目了然。这种确定性在往生产环境发布时尤其重要。如果你正在做Agent类项目我的建议是先别急着追求什么炫酷的多智能体架构老老实实把一张图的节点、边和状态管清楚你会发现很多曾经玄学的问题其实只是结构没理顺而已。
RELATED

相关推荐

JDK8 HashMap源码拆解:散列、红黑树与扩容机制一次讲透

JDK8 HashMap源码拆解:散列、红黑树与扩容机制一次讲透

1. 先看清HashMap的底层结构:数组、链表、红黑树是怎么拼在一起的HashMap大概是Java容器里被面试官问得最多、被线上故障坑得最惨的一个类。我最早认真读它的源码,正因为某个跨平台系统的压测频繁出现CPU100%,抓完线程栈发现所有线程都卡在Ha…

📅 2026/10/16 4:56:39
ARM64中断处理全链路解析:从GIC硬件触发到Linux驱动回调

ARM64中断处理全链路解析:从GIC硬件触发到Linux驱动回调

这段时间一直在调一块 ARM64 板卡上的外设中断丢事件问题,被迫把 ARM64 中断处理这条路从头到尾捋了一遍。说实话,网上讲 ARM64 中断的文章不少,但大多停留在"GIC 是中断控制器、内核里有中断子系统"这种概念层面,真正从…

📅 2026/10/16 4:56:39
AI日报系统设计:分层流水线架构与本地化实践

AI日报系统设计:分层流水线架构与本地化实践

1. 项目概述:这不是一份新闻简报,而是一套可复用的AI信息流处理系统“AI 日报(2026年10月8日)”这个标题乍看像一份时效性极强的媒体简报,但作为从业十多年、亲手搭建过二十多个垂直领域信息聚合系统的博主&#xff0c…

📅 2026/10/16 4:51:38
MORE NEWS

更多资讯

📰

SAP Fiori Elements实战:从CDS注解到RAP应用开发全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

实训5指纹设置全解析:从传感器原理到实操与安全

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

语音特征提取全流程:从原始波形到MFCC特征向量

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

Java线程start()方法原理与线程生命周期解析

1. 线程生命周期与start()方法本质当面试官抛出"为什么线程start()不能重复调用"这个问题时,实际上是在考察你对Java线程生命周期的理解深度。让我们先看一个典型的错误示例:Thread thread new Thread(() -> System.out.println("Run…

📰

Spring Cloud Gateway GatewayFilter 源码解析与责任链机制

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

粒子群算法优化LQR的二级倒立摆控制设计与避坑实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬