Agent 框架的选型讨论这两年几乎成了技术社区里最热闹也最容易跑偏的话题之一。打开任何一个技术群都有人在问 LangChain、LangGraph、AgentScope、CrewAI、Dify 到底该选哪个回答往往是一堆功能对比表列完工具调用、记忆管理、多智能体协作这些维度然后给一个看场景的万能结论。但真正上手做过几个 Agent 项目之后你会发现框架之间的差异很多时候并不体现在功能清单上而是体现在一个更底层的问题上下一步由谁决定。这个问题听起来抽象但它直接决定了你写出来的代码长什么样、调试的时候有多痛苦、上线之后能不能控住成本。我前后用 LangChain、LangGraph、AgentScope 以及几个轻量自研方案做过不同类型的 Agent踩过的坑从循环停不下来到状态在节点之间莫名其妙丢失都有。这篇文章不打算给你一张选型对照表就完事而是想把下一步由谁决定这个判断维度拆开讲清楚它为什么是选框架的第一性问题以及不同答案对应什么样的框架、什么样的代码结构、什么样的坑。如果你正在纠结选哪个框架或者已经选了一个但写着写着觉得别扭那大概率是没想清楚这个决定权归属的问题。下面我按自己的理解把这个判断链路完整走一遍。1. 为什么下一步由谁决定比功能对比更重要大多数人选框架的习惯是打开官方文档看特性列表支持多少种工具、有没有内置记忆、能不能做多智能体、社区活跃度如何。这套方法在选 Web 框架、ORM 框架的时候基本够用因为那些框架的职责边界很清晰——处理请求、映射数据流程是确定的。但 Agent 框架不一样它处理的是一个不确定步数、不确定路径的执行过程核心矛盾在于谁来推进流程。1.1 功能清单会骗人控制流不会我举个具体的例子。假设你要做一个根据用户问题自动查资料并汇总的 Agent。用 LangChain 的 AgentExecutor 写大概是给一个 LLM 加一堆 tool然后让它自己决定调哪个、调几次直到它认为可以给出最终答案。用 LangGraph 写你会先画一张图一个节点负责判断意图一个节点负责检索一个节点负责生成边决定从哪走到哪。这两个实现的功能清单看起来一模一样——都能查资料、都能汇总、都支持多轮。但它们的控制流完全不同前者是 LLM 在运行时动态决定下一步后者是你在编码时就把可能的路径定义好了。这个差异带来的后果是全方位的。调试的时候LangChain 那种方式你只能看日志猜 LLM 为什么调了那个工具LangGraph 那种方式你可以精确知道卡在哪个节点。控成本的时候前者你没法预估会调几次 LLM后者你能算出最坏情况下的调用次数。上线之后出问题前者你只能加 prompt 约束后者你能直接改图结构。所以功能清单是能做什么控制流是怎么做到后者才决定了你日常开发的体验和系统的可控性。1.2 决定权归属决定了调试难度我印象很深的一次踩坑是做一个客服场景的 Agent用早期 LangChain 的 ReAct 模式。测试的时候发现它偶尔会陷入查订单→发现信息不全→再查订单→还是不全的死循环跑十几次才出一次但一出就烧掉大量 token。排查的时候非常痛苦因为循环是 LLM 在运行时决定的你没法在代码里找到这里会循环的那一行。最后只能靠加 prompt 里的如果连续两次查询结果相同就停止来缓解属于治标不治本。后来同样的需求换成 LangGraph 重写我把查询订单和判断信息是否完整拆成两个节点在边上加了条件信息完整才走向生成不完整且重试次数小于 2 才回到查询。这个循环上限是写死在图里的LLM 再想循环也循环不起来。调试的时候直接看是哪个条件判断出了问题几分钟定位。这就是决定权归属带来的差异决定权在 LLM 手里你只能祈祷它理性决定权在代码手里你能精确控制边界。前者适合探索性、开放性的任务后者适合有明确流程、需要可控性的任务。1.3 一个判断清单你的任务属于哪一类在选框架之前我建议先回答下面几个问题答案会直接指向你该选哪类框架这个任务的步骤数是否可预估如果最坏情况下的步骤数你能大致算出来说明流程相对确定适合代码主导。中间状态需不需要持久化比如用户中途关掉页面下次回来要接着走那状态管理就是刚需。出错之后能不能重试某一步如果某一步失败需要单独重跑而不是从头来那节点化的框架更合适。是否需要人工介入某个环节比如生成内容后要人工审核再发这种人在回路的场景对控制流要求很高。任务是不是高度开放连你自己都说不清有几种走法如果是那 LLM 主导反而更灵活。把这几个问题答完你基本就能判断自己的任务落在LLM 主导还是代码主导这一光谱的哪一端了。下面我分别展开这两端对应的框架特征。2. LLM 主导型LangChain 式 Agent 的适用边界与代价LangChain 是很多人接触 Agent 的第一个框架它的 AgentExecutor 加上 ReAct、OpenAI Functions 这些 agent type本质上都是让 LLM 在每一步决定调用哪个工具、什么时候停止。这种模式我称之为LLM 主导型因为控制流的核心决策权交给了模型。2.1 它到底解决了什么问题LLM 主导型框架最大的价值在于处理你无法预先枚举路径的任务。比如一个通用的研究助手用户可能问帮我对比一下三个云厂商的定价也可能问帮我找找最近关于某个技术的论文还可能问帮我把这段代码优化一下。这些任务的执行路径差异极大你很难用一张固定的图覆盖所有情况。这时候让 LLM 根据工具描述自己决定调什么反而是最省事的做法。LangChain 在这方面的抽象做得比较到位你只需要把工具用tool装饰器定义好写清楚描述剩下的交给 AgentExecutor。工具描述写得好LLM 基本能选对。我做过一个内部工具助手挂了十几个工具从查数据库到发消息到调内部 API用 ReAct 模式跑起来大部分情况下 LLM 都能选对工具开发效率确实高。2.2 代价一不可预测的调用次数但省事的代价是不可控。LLM 主导意味着你无法在编码阶段确定它会调几次工具、调几次 LLM。我遇到过最夸张的一次一个本该两步完成的任务LLM 因为工具返回格式不理想反复重试了七八次token 消耗是预期的四倍。这种问题在测试环境不容易发现因为测试用例往往比较标准一到真实用户手里各种奇怪的输入就冒出来了。缓解办法有几个一是给工具返回做严格的格式约束减少 LLM看不懂的情况二是设置max_iterations之类的硬上限防止无限循环三是在 prompt 里明确写如果工具返回错误最多重试一次。但这些都只是缓解根治不了因为决定权本来就不在你手里。2.3 代价二状态管理的黑盒感LangChain 的 AgentExecutor 内部维护了一个 scratchpad记录中间步骤。这个设计对简单场景够用但一旦你想在中间步骤之间做点事情——比如某一步的结果要存数据库、要触发一个副作用——就会发现很难插手。scratchpad 是个黑盒你只能通过回调callback去观察但观察和干预是两回事。我做过一个需要每查一次数据就记录一次审计日志的需求用 AgentExecutor 实现得很别扭最后是靠 callback handler 硬塞进去的代码可读性很差。这种需求在代码主导型框架里就是加一个节点的事但在 LLM 主导型框架里要绕一大圈。2.4 什么时候该果断放弃 LLM 主导我的经验是只要满足下面任意一条就该考虑换代码主导型框架任务有明确的合规或审计要求每一步都要留痕步骤数需要严格控制比如成本敏感的场景需要人工审核介入某个环节出错后需要从中间某步重试而不是从头来。反过来如果任务是探索性的、路径高度不确定、对成本不敏感那 LLM 主导型反而更合适别为了可控硬上代码主导最后写出一堆用不上的节点。3. 代码主导型LangGraph 把控制流画成图之后LangGraph 这两年被讨论得很多它的核心思路是把 Agent 的执行过程显式地建模成一张图节点是执行单元边是流转条件状态在节点之间传递。这个模型把下一步由谁决定的答案从 LLM 手里拿回到了代码手里。3.1 图模型为什么让状态变得可见LangGraph 最让我舒服的一点是状态State是显式定义的。你会先定义一个 TypedDict 或者 Pydantic 模型声明这张图里流转的所有字段然后每个节点接收状态、返回状态的更新。这意味着任何时候你都能知道当前系统里有哪些数据而不是像 AgentExecutor 那样只能从 scratchpad 里猜。这个设计对调试的帮助是巨大的。我之前做一个多轮信息收集的 Agent用户要分几次提供信息中间还要查库校验。用 LangGraph 写的时候状态里明确有collected_info、missing_fields、validation_result这些字段每次节点执行完打印一下状态问题一目了然。换成 AgentExecutor这些信息全混在对话历史里得靠肉眼从一长串文本里找。3.2 条件边把如果写进代码而不是 promptLangGraph 的条件边conditional edge是我用得最多的特性。它允许你根据当前状态决定下一步走哪个节点这个判断是纯代码逻辑不经过 LLM。比如def should_continue(state): if state[retry_count] 3: return give_up if state[validation_passed]: return generate return retry这段逻辑是确定性的LLM 再怎么想也绕不过去。这就把很多原本要靠 prompt 约束的东西变成了代码约束可靠性完全不是一个量级。我现在的习惯是凡是能用代码判断的流转条件绝不交给 LLM只有真正需要语义理解的地方才让 LLM 参与决策。3.3 持久化与人在回路LangGraph 的杀手锏LangGraph 的 checkpointer 机制支持把图的状态持久化到数据库这意味着你可以实现暂停-恢复和人在回路。比如一个内容生成流程生成完草稿后暂停等人工审核通过再继续。这个能力在 LLM 主导型框架里几乎没法优雅实现。我做过一个合同审核的 Agent流程是解析合同→提取关键条款→LLM 初审→人工复核→生成报告。中间的人工复核环节用 LangGraph 的interrupt实现图执行到复核节点就停下来把当前状态存起来等人工在界面上点了通过或驳回再带着决定恢复执行。整个流程清晰可控每一步都有记录。这种场景如果硬用 AgentExecutor基本是自找麻烦。3.4 学习曲线到底陡在哪很多人说 LangGraph 学习曲线陡我的体会是陡的不是 API而是思维方式。你得先把任务拆成节点和边这对习惯了写个 prompt 让 LLM 自己跑的人来说是个转变。刚开始我也觉得麻烦明明一句话能描述的任务非要画成图。但拆过几个任务之后发现这个拆解过程本身就是对任务的梳理很多原本模糊的地方在画图的时候被迫想清楚了。真正需要适应的是状态设计。状态字段设计得好节点之间传递顺畅设计得不好会出现这个节点需要的数据上个节点没存的尴尬。我的经验是状态宁可设计得宽一点把可能用到的中间结果都放进去别为了精简导致后面反复改状态定义。4. AgentScope 与多智能体当决定权分散到多个角色AgentScope 是阿里出的多智能体框架它的定位和前面两个不太一样更偏向多个 Agent 协作的场景。这时候下一步由谁决定这个问题变得更复杂了因为决定权不仅涉及 LLM 和代码还涉及多个 Agent 之间的消息传递和角色分工。4.1 多智能体不是多个 Agent 简单叠加很多人对多智能体的理解是把一个大 Agent 拆成几个小 Agent但实际做下来会发现拆开之后最大的挑战是协调。谁先说话、谁听谁的、消息怎么传递、冲突怎么解决这些都是单 Agent 场景不存在的问题。AgentScope 在这方面提供了一套消息传递机制和角色定义方式让多个 Agent 能按一定规则交互。我做过一个模拟辩论的小项目两个 Agent 分别持正反方观点一个裁判 Agent 做总结。用 AgentScope 写的时候消息在 Agent 之间的流转是显式的每个 Agent 有自己的记忆和角色设定。这个场景用单 Agent 很难做因为单 Agent 很难同时持有两个对立观点。4.2 消息传递模式决定了协作的上限多智能体框架的核心差异在于消息传递模式。有的是广播式一个 Agent 发言所有 Agent 都能看到有的是定向式消息只发给特定 Agent还有的是层级式有个协调者 Agent 负责分发任务。AgentScope 支持比较灵活的消息配置你可以定义谁在什么条件下给谁发消息。这个灵活性是双刃剑。配置得好的时候协作流程很顺畅配置得不好的时候会出现 Agent 之间互相等待或者消息风暴的问题。我踩过一个坑两个 Agent 都配置成收到消息就回复结果它们互相回复停不下来token 哗哗地烧。后来加了轮次上限和终止条件才解决。这个坑的本质还是下一步由谁决定没想清楚——如果每个 Agent 都能无条件触发下一步那流程就失控了。4.3 多智能体适合什么、不适合什么我的判断是多智能体适合那些天然可以拆成多个角色、角色之间有明确交互的任务比如模拟对话、多视角分析、分工协作。不适合那些本质上是线性流程、硬拆成多个 Agent 反而增加协调成本的任务。见过不少项目明明一个 Agent 加几个工具就能搞定非要拆成规划 Agent 执行 Agent 审核 Agent结果三个 Agent 之间的消息传递代码比业务逻辑还多。这种为了多智能体而多智能体的做法我是不推荐的。选框架之前先问自己这个任务真的需要多个角色吗如果不需要单 Agent 加好的控制流往往更简单。5. 一张判断表把你的任务映射到框架讲了这么多落到实操上我整理了一张判断表把常见的任务特征和对应的框架倾向列出来。这张表不是绝对的但能帮你快速定位。任务特征决定权倾向推荐框架方向典型场景路径高度不确定步骤数无法预估LLM 主导LangChain AgentExecutor通用研究助手、开放问答流程明确步骤可枚举代码主导LangGraph审批流、信息收集、多步处理需要状态持久化和断点恢复代码主导LangGraph checkpointer长流程、人在回路需要多个角色交互协作混合AgentScope模拟对话、多视角分析快速验证想法不在乎可控性LLM 主导LangChain 或 DifyDemo、原型成本敏感需要精确控制调用代码主导LangGraph 或自研生产环境、高频调用用这张表的时候有个技巧先看步骤数能否预估这一行它基本能帮你排除掉一半的选项。能预估的往代码主导走不能预估的往 LLM 主导走。然后再看有没有持久化、多角色这些附加需求进一步缩小范围。5.1 别忽略自研这条路的性价比表格里我特意加了自研这个选项。很多人一上来就纠结选哪个框架但其实对于流程比较固定的场景直接用一个 LLM SDK 加自己的状态机可能比套框架更清爽。我做过一个只有五个步骤的 Agent用 LangGraph 写要定义状态、建图、编译用原生 SDK 加一个 while 循环和几个 if 判断代码量少一半调试还更直接。框架的价值在于处理复杂度和提供通用能力如果你的场景复杂度不高框架反而成了负担。判断标准很简单如果框架提供的抽象图、节点、状态和你的任务结构天然契合那就用如果为了用框架要把任务硬塞进它的模型里那不如自研。5.2 混合使用是常态别被选一个框住实际项目里我很少纯用一种模式。常见的组合是外层用 LangGraph 控制主流程某个节点内部用 LangChain 的 AgentExecutor 处理开放性子任务。这样既有主流程的可控性又有子任务的灵活性。比如一个报告生成系统主流程是收集需求→检索资料→生成→审核这是确定的用图控制但检索资料这一步具体查什么、查几次是不确定的交给 LLM 主导的 Agent 去做。这种混合模式要求你对两套框架都熟悉但收益是明显的该可控的地方可控该灵活的地方灵活。别被选一个框架的思维框住框架是工具组合使用很正常。6. 选型之后几个我踩过的实操坑框架选定只是开始真正写起来还有一堆细节坑。这部分分享几个我印象比较深的都是文档里不太会写、但实际会遇到的。6.1 状态字段设计过窄导致反复重构前面提过状态设计这里展开说。我第一个 LangGraph 项目状态定义得很精简只放了当前必需的字段。结果写到第三个节点发现需要第一个节点的某个中间结果但那个结果没存进状态只能回头改状态定义、改前面所有节点的返回。改了两三次之后学乖了现在状态里会把所有可能用到的中间结果都放进去哪怕暂时用不上。这个坑的本质是没想清楚状态是节点之间唯一的通信渠道。在 LangGraph 里节点之间不能直接传参只能通过状态。所以状态设计要站在全局视角而不是每个节点只顾自己。6.2 工具描述写不好LLM 主导型直接崩用 LLM 主导型框架的时候工具描述的质量直接决定成败。我见过工具描述写成查询数据四个字的LLM 根本不知道这个工具查什么数据、什么时候该用。好的工具描述应该包含这个工具做什么、什么情况下用、输入参数的含义和格式、返回什么。写得越清楚LLM 选错的概率越低。我的习惯是工具描述里会写一两个使用示例比如当用户询问订单状态时使用此工具输入订单号返回订单的当前状态和预计送达时间。这种描述比干巴巴的一句话有效得多。6.3 循环终止条件不能只靠 LLM 自觉不管是哪种框架只要有循环就必须有硬性的终止条件。LLM 主导型里靠max_iterations代码主导型里靠条件边里的计数器。我踩过的坑是早期觉得LLM 应该知道什么时候停结果它不知道。现在我的原则是任何循环都必须有一个不依赖 LLM 的终止条件哪怕这个条件设得很宽松也比没有强。6.4 多智能体的消息风暴要提前防做多智能体的时候消息传递规则一定要提前设计好终止条件。我那个辩论项目踩的坑就是没设轮次上限两个 Agent 互相回复停不下来。后来加了最多辩论五轮的硬限制才解决。多智能体场景里每个 Agent 都可能触发其他 Agent如果不加全局的轮次或时间限制很容易失控。6.5 别在框架选择上过度纠结最后说个心态问题。我见过不少人花大量时间对比框架迟迟不动手。其实框架之间的差异很多时候要真正写起来才能体会到。与其纠结选哪个不如先用一个上手写个小 Demo感受一下它的控制流模型和你的任务是否契合。不契合就换切换成本没有想象中那么高因为核心的业务逻辑和 prompt 是可复用的换的主要是编排层。选框架这件事想清楚下一步由谁决定这个核心问题剩下的就是动手验证。我自己的经验是凡是流程能画出来的任务用代码主导型框架基本不会错凡是画不出来的先用 LLM 主导型跑通再说。这个判断标准简单但用下来很准。
阅读完成 · 觉得有帮助?