1. 从一堆框架里杀出重围为什么我要认真聊聊 LangChain 和 LangGraph 的选型过去大半年我几乎把市面上叫得上名字的智能体编排框架都摸了一遍。从最早期用纯 Python 脚本硬拼提示词到后来引入各种链式调用库再到如今项目里同时跑着好几套不同技术栈的智能体服务踩过的坑足够写一本小册子。身边不少朋友刚接触这块时最常问的一句话就是“我到底该用 LangChain 还是 LangGraph还是干脆自己写”这个问题看似简单背后却牵扯到项目规模、团队习惯、调试成本、长期维护等一系列现实因素。LangChain 和 LangGraph 这两个名字在智能体开发圈子里出现的频率极高。前者像是一把功能齐全的瑞士军刀后者更像是一套可以自由拼装的工业级流水线。很多人第一次接触时会误以为 LangGraph 是 LangChain 的升级版或者替代品实际上它们解决的是不同层面的问题。LangChain 提供的是大量现成的组件和标准接口让你快速把模型、提示词、工具、记忆串起来LangGraph 则把重点放在状态管理和流程控制上用图的方式描述智能体在多个步骤之间如何流转、如何分支、如何回退。这篇文章不打算写成官方文档的中文翻译也不会堆砌一堆抽象概念。我想从实际项目出发把这两个框架的核心设计思路拆开讲清楚它们各自适合什么场景、在什么情况下会让人抓狂、以及我最终在几个不同项目里分别做了什么选择。如果你正在为下一个智能体项目做技术选型或者已经用上了其中一个但总觉得别扭希望这些经验能帮你少走几段弯路。2. LangChain 到底解决了什么问题组件化思维的利与弊2.1 从“手搓提示词”到“标准化组件”的进化早期做智能体最朴素的方式就是写一个函数接收用户输入拼接一段提示词调用模型接口解析返回结果再决定下一步。这种写法在单轮任务里没问题一旦涉及多轮对话、工具调用、上下文管理代码就会迅速膨胀成一座意大利面条山。LangChain 出现的初衷就是把这些重复性的工作抽象成标准组件。它把模型调用封装成 LLM 接口把提示词模板封装成 PromptTemplate把工具调用封装成 Tool把记忆机制封装成 Memory。你只需要按照它的约定把组件拼起来就能快速搭出一个能跑的原型。这种组件化思维最大的好处是降低了起步门槛。一个刚入门的开发者不需要理解太多底层细节就能在半小时内做出一个能查天气、能算数学题的对话机器人。但组件化也带来了一个隐性成本抽象层数变多之后调试变得困难。当一条链路上有七八个组件依次执行时如果最终输出不符合预期你很难一眼看出是哪个环节出了问题。我遇到过好几次这样的情况提示词模板里某个变量没传进去导致模型收到了一段残缺的指令但 LangChain 的默认日志并不会把这个中间状态清晰地暴露出来。后来我养成了一个习惯在关键节点手动打印中间结果或者用回调机制把每一步的输入输出都记录下来。2.2 链式调用的适用边界在哪里LangChain 最核心的概念是 Chain也就是把多个组件按顺序串起来。这种线性结构非常适合那些步骤明确、不需要复杂分支的任务。比如一个典型的问答流程接收问题、检索相关文档、拼接上下文、调用模型生成回答、格式化输出。每一步都是确定的没有循环也没有条件跳转用 Chain 来表达非常自然。但智能体的真实行为往往不是线性的。它可能需要根据模型的输出决定下一步调用哪个工具可能需要在某个条件不满足时回到上一步重新尝试可能需要在多个候选方案之间做选择。这些场景用传统的 Chain 来实现就会变得非常别扭。你不得不把条件判断逻辑硬塞进某个组件的内部或者用大量的 if-else 把多条链拼在一起代码可读性急剧下降。我印象很深的一个案例是做一个多轮信息收集的智能体。用户可能一次性提供所有信息也可能分多次提供还可能中途改变主意。用 Chain 来实现时我不得不维护一个外部状态字典在每一轮调用前手动检查哪些信息已经收集完整然后动态选择下一条链。这种写法虽然能跑通但每次修改需求都要重新梳理整个流程维护成本很高。也正是这个项目让我开始认真考虑 LangGraph 的价值。2.3 生态丰富带来的“选择困难症”LangChain 的生态确实庞大官方和社区贡献了大量的集成组件几乎覆盖了所有主流模型接口、向量数据库、文档加载器、工具库。这既是优势也是负担。优势在于你很少需要从零开始写一个连接器负担在于当你有多个可选方案时往往不知道该选哪个。比如做文本分割LangChain 提供了好几种分割器按字符分割、按递归字符分割、按 token 分割、按语义分割。每种分割器又有若干参数可以调整。对于刚接触的人来说很容易陷入“参数调优”的泥潭花大量时间尝试不同组合却忽略了更根本的问题你的文档结构是什么样的检索目标是什么。我的经验是先选一个默认方案跑通全流程再根据实际效果针对性调整不要一开始就追求最优解。另一个常见问题是版本迭代带来的接口变动。LangChain 的更新频率很高有时候一个小版本升级就会导致某些组件的调用方式发生变化。如果你的项目依赖比较深升级时就需要仔细阅读变更日志做好回归测试。我现在的做法是在生产项目中锁定依赖版本只在有明确需求时才升级并且升级前一定会在独立环境里跑一遍完整测试。3. LangGraph 的设计哲学把智能体当成状态机来管3.1 图结构为什么更适合复杂智能体LangGraph 的核心思想是把智能体的执行过程建模成一个图。图中的节点代表一个具体的操作步骤边代表步骤之间的流转关系。这个模型听起来简单但它带来的表达能力提升是巨大的。因为图天然支持分支、循环、并行、条件跳转而这些恰恰是复杂智能体最需要的。举个例子一个客服智能体可能需要先判断用户意图然后根据意图走不同的处理路径咨询类问题走知识库检索投诉类问题走工单创建闲聊类问题直接回复。如果用 Chain 来实现你需要写一个路由组件根据分类结果选择不同的子链。但如果后续要增加新的意图类型或者调整某个路径的内部逻辑整个结构就会变得难以维护。用图来表达时每个意图对应一个节点或子图新增意图只需要加一个节点和相应的边对现有结构几乎没有影响。更重要的是LangGraph 把状态管理内置到了框架层面。每个节点执行时都会接收当前状态并返回更新后的状态。框架负责在节点之间传递状态并在需要时进行持久化。这意味着你可以随时暂停一个长时间运行的任务保存当前状态稍后再恢复执行。对于需要人工审核、异步等待外部事件、或者分阶段处理的场景这个能力非常关键。3.2 状态、节点与边三个核心概念的实际含义理解 LangGraph 的关键在于吃透三个概念状态、节点和边。状态是一个共享的数据结构通常用字典或类型化的对象来表示里面存放着智能体运行过程中需要记住的所有信息。节点是一个函数接收当前状态执行某些操作返回状态的更新部分。边定义了节点之间的流转规则可以是固定的也可以是基于条件动态决定的。我刚开始用的时候最容易犯的错误是把太多东西塞进状态里。状态应该是智能体的“工作记忆”只存放那些需要在多个步骤之间共享的信息。如果把每个节点的临时变量都放进去状态会变得臃肿调试时也很难看清哪些是真正重要的数据。后来我养成了一个习惯每个节点内部尽量保持无状态只通过输入输出与外部交互这样节点的可测试性会好很多。边的设计也需要仔细考虑。LangGraph 支持条件边也就是根据当前状态决定下一步走哪个节点。这个机制非常强大但也容易导致流程变得难以追踪。我的建议是条件判断的逻辑尽量简单明确避免在一个条件边里塞入过于复杂的判断。如果逻辑确实复杂可以单独抽出一个节点来做决策把决策结果写入状态后续的条件边只根据这个结果做简单路由。3.3 持久化与人工介入生产环境的关键能力LangGraph 的持久化机制是我认为它最适合生产环境的原因之一。它可以把每一步执行后的状态保存到外部存储中比如内存、数据库或者文件系统。这意味着即使服务重启之前运行到一半的任务也不会丢失。对于需要长时间运行的智能体比如监控某个数据源并在特定条件下触发动作这个能力几乎是必需的。人工介入是另一个让我印象深刻的特性。在某些场景下智能体的决策需要人工确认才能继续。比如一个自动生成合同条款的智能体在最终输出前需要法务人员审核。用 LangGraph 可以很自然地实现这个流程在需要审核的节点前暂停把当前状态暴露给外部系统等待人工操作后再恢复执行。这种“人机协作”的模式在纯 Chain 框架里实现起来要麻烦得多。不过持久化也带来了额外的复杂度。你需要考虑存储方案的选择、状态序列化的方式、并发访问的控制等问题。如果项目规模不大或者任务执行时间很短这些复杂度可能并不值得。我在一个小型内部工具里就刻意没有启用持久化因为任务通常在几秒内完成引入持久化只会增加部署和维护的负担。4. 框架选型的实战决策框架从五个维度做判断4.1 任务复杂度线性流程还是网状流程判断该用哪个框架第一个要问的问题是你的智能体流程是线性的还是网状的。如果整个任务可以清晰地拆解成一系列顺序步骤每一步的输入输出都很明确中间不需要根据结果做复杂分支那么 LangChain 的 Chain 模型完全够用而且代码会更简洁。反过来如果流程中存在大量的条件分支、循环重试、并行处理或者需要根据运行时的状态动态决定下一步做什么那么 LangGraph 的图模型会更合适。我通常会用一张纸把整个流程画出来如果画出来的图形状接近一条直线就选 LangChain如果画出来像一张网就选 LangGraph。这里有一个容易被忽略的中间地带有些任务表面上看起来是线性的但每个步骤内部可能包含复杂的子流程。这种情况下可以考虑用 LangChain 做外层编排把复杂的子流程封装成独立的工具或子链。这样既能保持整体结构的清晰又不会让单个组件过于臃肿。4.2 状态管理需求无状态还是有状态第二个维度是状态管理的需求。LangChain 的 Chain 在设计上更偏向无状态每一步的输入输出通过参数传递框架本身不负责维护跨步骤的共享状态。虽然可以通过 Memory 组件来实现一定程度的记忆但这种记忆通常是对话历史层面的不适合用来管理复杂的业务状态。LangGraph 则把状态作为一等公民框架层面提供了完整的状态管理机制。如果你的智能体需要在多个步骤之间共享大量结构化数据或者需要支持暂停恢复、人工介入等操作LangGraph 的优势会非常明显。我做过一个对比实验用两种框架分别实现同一个多步骤审批流程。用 LangChain 时我不得不手动维护一个状态字典在每个步骤前后进行读写代码里充斥着状态检查的逻辑。用 LangGraph 时状态由框架管理每个节点只需要关注自己的业务逻辑代码量减少了将近三分之一可读性也好了很多。4.3 团队技术栈与学习曲线第三个维度是团队的技术背景。LangChain 的抽象层次更高组件更丰富对于熟悉 Python 和基本机器学习概念的开发者来说上手速度很快。官方文档和社区示例也很多遇到问题比较容易找到参考。LangGraph 的概念模型相对更底层一些需要理解图、状态机、持久化等概念。对于没有相关背景的开发者初期学习曲线会更陡。但如果团队里有熟悉工作流引擎或者分布式系统的人这些概念其实并不陌生迁移过来会很快。我的建议是如果团队规模较小项目周期紧张优先考虑 LangChain用最短的时间把原型跑起来。如果项目预期会长期迭代流程会越来越复杂那么早期投入时间学习 LangGraph 是值得的。我在一个长期项目里就经历了从 LangChain 迁移到 LangGraph 的过程虽然迁移本身花了一些时间但后续的维护效率提升非常明显。4.4 调试与可观测性出问题时能不能快速定位第四个维度是调试和可观测性。LangChain 的调用链路通常比较深一个简单的操作可能经过多层封装。当出现问题时堆栈信息往往不够直观需要结合日志和回调才能定位到具体环节。LangGraph 的图结构让执行路径更加显式每个节点的输入输出都可以被单独记录和检查排查问题时更容易缩小范围。不过 LangGraph 也有自己的调试难点。当图变得很大时理解状态在节点之间的流转需要一定的想象力。我通常会配合可视化工具把图的结构和当前状态一起展示出来这样能直观地看到执行到了哪一步、状态里有哪些数据。对于特别复杂的图我还会在关键节点上添加详细的日志记录状态的变化情况。4.5 长期维护与生态演进最后一个维度是长期维护。LangChain 的生态更大社区活跃度更高但这也意味着接口变动可能更频繁。LangGraph 相对更聚焦核心概念稳定但生态还在成长中某些特定场景可能需要自己造轮子。我的做法是对于核心业务逻辑尽量保持与框架的解耦。比如把提示词模板、工具函数、业务规则这些内容放在独立的模块里框架只负责编排。这样即使将来需要更换框架迁移成本也会可控。这个原则在任何一个快速演进的领域里都适用不局限于这两个框架。5. 从零搭建一个选型验证原型我的实操记录5.1 需求定义与场景设计为了更直观地对比两个框架我设计了一个中等复杂度的验证场景一个会议安排助手。它需要理解用户的自然语言请求提取会议时间、参与人、主题等信息检查参与人的日历可用性如果时间冲突则提出替代方案最终生成会议邀请。这个场景包含了信息提取、工具调用、条件判断、循环重试等多个典型要素足够用来评估两个框架的适用性。我刻意没有选择过于简单的问答场景因为那种场景下两个框架的差异不明显。也没有选择过于复杂的多智能体协作场景因为那会引入太多变量不利于聚焦框架本身的特点。会议安排助手这个粒度刚刚好既能体现差异又不会让实现变得过于庞大。5.2 用 LangChain 实现的第一版快速但别扭用 LangChain 实现时我首先定义了几个工具解析时间、查询日历、发送邀请。然后创建了一个提示词模板让模型从用户输入中提取结构化信息。接着用 Chain 把这些组件串起来提取信息 - 查询日历 - 判断冲突 - 生成回复。第一版跑通只用了不到一个小时速度确实快。但问题很快暴露出来当时间冲突时我需要让模型根据可用时间段提出替代方案然后等待用户确认。这个“等待用户确认”的步骤在 Chain 里很难优雅地表达。我尝试了几种方案把确认逻辑放在一个循环里或者把整个流程拆成两条链用外部状态来协调。每种方案都让代码变得更复杂而且状态管理逻辑散落在各处很难一眼看清整个流程。另一个让我头疼的地方是错误处理。如果日历查询接口超时我希望能够重试几次如果仍然失败则告知用户稍后再试。在 Chain 里实现重试需要包裹额外的逻辑而且重试的状态不容易与主流程共享。我最终用了一个比较笨的办法在工具函数内部实现重试但这让工具函数承担了不该它承担的职责。5.3 用 LangGraph 重构结构清晰但需要适应用 LangGraph 重构时我先把整个流程画成了一张图。节点包括提取信息、查询日历、判断冲突、生成替代方案、等待确认、发送邀请、结束。边则根据判断结果动态选择下一步。状态里存放用户输入、提取的信息、日历查询结果、替代方案、确认状态等数据。重构后的代码结构清晰了很多。每个节点只负责一件事节点之间的流转关系一目了然。等待确认这个步骤通过持久化机制实现执行到该节点时暂停把状态保存下来等用户回复后再恢复执行。错误重试也变得更自然可以在节点层面配置重试策略不需要把重试逻辑混入业务代码。当然重构过程也不是一帆风顺。最大的挑战是适应“状态驱动”的思维方式。在 Chain 里我习惯用局部变量来传递数据在 LangGraph 里所有需要跨节点共享的数据都必须放进状态。一开始我总觉得状态太臃肿后来慢慢理解了这种设计的意图状态就是智能体的“记忆”它应该包含所有影响后续决策的信息。把状态管理好整个系统的行为就变得可预测、可追踪。5.4 性能与开发效率的对比数据我在相同环境下对两个版本做了一组简单的对比测试。测试任务是处理 100 个会议安排请求其中 30% 包含时间冲突。结果显示两个版本在端到端响应时间上差异不大主要耗时都在模型调用和日历接口查询上。但在开发效率上LangGraph 版本在后续需求变更时明显更有优势。我记录了三次需求变更的修改时间第一次是增加“会议室预订”功能LangChain 版本花了约两小时主要时间花在理清现有 Chain 的结构和状态传递上LangGraph 版本花了约四十分钟只需要新增一个节点和相应的边。第二次是调整冲突处理逻辑LangChain 版本需要修改多个组件的内部逻辑LangGraph 版本只需要修改判断节点的输出和条件边。第三次是增加人工审核环节LangChain 版本需要引入外部状态存储和协调逻辑LangGraph 版本利用内置的持久化机制很快就实现了。这些数据当然不是绝对的项目规模、开发者经验、具体需求都会影响结果。但趋势是明显的流程越复杂、变更越频繁LangGraph 的结构化优势就越突出。6. 常见踩坑记录与排查技巧6.1 LangChain 使用中的典型问题第一个常见问题是提示词模板的变量传递。LangChain 的 PromptTemplate 要求变量名严格匹配如果传入的字典缺少某个键或者键名拼写错误运行时才会报错。我建议在开发阶段开启严格模式让框架在构建阶段就检查变量完整性。另外对于复杂的提示词可以考虑用 FewShotPromptTemplate 或者自定义的提示词构建函数避免模板过于臃肿。第二个问题是工具调用的参数解析。当模型返回的工具调用参数格式不符合预期时LangChain 的默认处理方式可能不够健壮。我通常会在工具函数内部增加参数校验和容错逻辑对于关键参数还会让模型在调用前先输出一个结构化的确认信息。如果工具调用频繁失败可以考虑调整提示词给出更明确的参数格式示例。第三个问题是回调机制的滥用。LangChain 的回调系统很灵活可以用来做日志、监控、流式输出等。但如果回调函数里执行了耗时操作会拖慢整个链路的执行。我的经验是回调函数尽量保持轻量只做数据收集和转发复杂的处理逻辑放到异步任务里。6.2 LangGraph 使用中的典型问题第一个常见问题是状态更新的并发冲突。当多个节点并行执行时如果它们同时修改状态的同一个字段可能会导致数据不一致。LangGraph 提供了一些机制来处理这种情况比如使用 reducer 函数来合并更新。我的建议是在设计状态结构时尽量让不同节点负责不同的字段减少并发写入的冲突。如果确实需要共享字段一定要仔细测试并发场景下的行为。第二个问题是图的循环导致无限执行。LangGraph 允许图中存在循环这为实现重试、迭代优化等逻辑提供了便利。但如果循环的退出条件设计不当可能会导致智能体陷入死循环。我通常会在循环边上设置最大迭代次数并在达到上限时强制退出同时记录详细的日志以便后续分析。另外在开发阶段可以设置一个全局的执行步数限制防止意外情况消耗过多资源。第三个问题是持久化存储的选择和配置。LangGraph 支持多种持久化后端从简单的内存存储到外部数据库。选择时需要权衡性能、可靠性、部署复杂度等因素。对于开发和测试环境内存存储足够对于生产环境建议使用成熟的数据库方案并做好备份和监控。我曾经在一个项目里因为持久化配置不当导致状态数据在服务重启后丢失后来增加了定期快照和恢复演练才解决了问题。6.3 两个框架混用的注意事项在实际项目中我有时候会同时使用两个框架用 LangGraph 做顶层编排用 LangChain 的组件来实现具体的节点功能。这种混用方式可以兼顾结构清晰和开发效率但需要注意几点。首先是状态传递的兼容性。LangChain 的组件通常期望接收和返回特定的数据结构而 LangGraph 的状态可能是更复杂的对象。在节点内部调用 LangChain 组件时需要做好数据转换。我通常会写一些适配函数把状态中的相关字段提取出来转换成组件期望的格式执行后再把结果写回状态。其次是错误处理的一致性。两个框架的错误类型和传播机制可能不同混用时需要统一错误处理策略。我的做法是定义一个项目级的异常体系在节点内部捕获框架特定的异常转换成项目异常后再抛出。这样上层逻辑只需要处理项目异常不需要关心底层是哪个框架抛出的。最后是依赖管理。两个框架的版本更新节奏可能不同混用时需要仔细测试兼容性。我建议在项目的依赖文件中明确锁定版本并在升级前进行充分的回归测试。如果条件允许可以搭建一个持续集成环境每次依赖变更都自动运行完整的测试套件。7. 我的最终选型建议与后续扩展思路经过这几个项目的实践我逐渐形成了一套自己的选型判断标准。对于快速验证想法、流程简单、生命周期短的项目我会优先选择 LangChain用最短的时间把核心逻辑跑通。对于流程复杂、需要长期维护、对状态管理和人工介入有要求的项目我会选择 LangGraph并在项目早期就投入时间设计好状态结构和图拓扑。如果项目规模介于两者之间我会考虑先用 LangChain 搭建原型在验证核心可行性之后再评估是否需要迁移到 LangGraph。迁移的时机通常出现在以下几种情况流程中开始出现大量条件分支、状态管理逻辑变得分散且难以维护、需要支持暂停恢复或人工审核、团队对代码可读性和可测试性的要求提高。这个内容后续还可以从几个方向继续深入。一是多智能体协作场景下的框架选型当多个智能体需要相互通信、协商、分工时对框架的要求会有所不同。二是与外部系统的集成模式比如如何与消息队列、工作流引擎、监控告警系统配合使用。三是性能优化和成本控制在大规模部署时如何减少模型调用次数、如何缓存中间结果、如何做流量削峰。这些话题每一个都值得单独展开我会在后续的分享里逐步覆盖。最后再分享一个小技巧无论选择哪个框架都建议在项目初期建立一个“框架适配层”把框架相关的代码集中放在一个模块里业务逻辑尽量保持独立。这样即使将来需要更换框架或者框架本身发生重大变更迁移成本也会可控。我在一个项目里因为没有做这层隔离后来从 LangChain 迁移到 LangGraph 时不得不重写了大量业务代码这个教训让我在后续项目里都会提前做好架构上的准备。