ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

四大多智能体框架横向实测:LangGraph、AutoGen、CrewAI与MAF选型指南

四大多智能体框架横向实测:LangGraph、AutoGen、CrewAI与MAF选型指南

每到要做Agent项目,框架选型总会在群里吵一轮。LangGraph、AutoGen、CrewAI、Microsoft Agent Framework(以下简称MAF),这四个名字几乎都能在输入法里打成固定短语了,但真正用起来完全不是一个思路:有的要求你像画流程图一样控制每一个步骤,有的把控制权交给Agent们自己对话,有的把Agent当作岗位角色去编排,还有的干脆不解决“怎么写Agent”,而是要解决“Agent怎么接进企业系统”。这篇文章是我在几个实际项目里的横向实测记录,不是把官方文档抄一遍,而是把每个框架的执行模型、写起来的感觉、适合做什么、会踩哪些坑,用同一个任务跑一遍后摊开讲。适合正在选型,或者刚学多智能体开发想找一个切入点的人。

1. 框架的整体设计思路:四个框架各自在解决哪个层面的问题

1.1 LangGraph:你定义的是状态机,不是简单的流程清单

LangGraph经常被理解成“工作流框架”,但我更愿意叫它状态机框架。它的核心抽象是一个图:StateGraph,节点是做事的Agent或者普通处理函数,边是节点之间的转移,旁边还挂着一个全局状态字典。每个节点从状态里读取自己需要的内容,再把结果写回状态,图会按照你定义的边依次执行,遇到条件边还会根据当前状态自动决定往哪条路走。

这个设计带来的最大好处是流程显式。你可以在撰写和审校之间插入一个条件判断,如果审校不通过就把稿件送回去修改;也可以在最开始时要求人工确认再进入下一步。但这要求你从线性脚本思维切换到图思维。我第一次用的时候写了好几个节点函数,结果发现节点A的返回值覆盖了节点B需要的字段,改了半天才明白所有节点读写的都是同一个状态对象,字段设计才是关键。

我常拿工厂流水线来类比:LangGraph是一个有传送带和质检闸口的工厂,传送带怎么走、在哪个位置停留、不合格品送回哪条线,都由你事先规定。它适合流程明确、需要精确控制的场景,比如订单处理、多轮人工审核、需要随时回放中间结果的业务系统。代价是学习曲线陡,写出来不会像普通脚本那样直白。

1.2 AutoGen:对话即协作,协作即对话

AutoGen的核心假设是:Agent之间的协作方式就是对话。几个ConversableAgent相互发消息,消息里可以是一段自然语言,也可以是一次函数调用,还可以是一段代码;系统里可以有一个GroupChatManager负责决定谁来发言,也可以只有两个Agent你来我往。它的工作方式更像是圆桌会议:大家带任务进场,轮流发言,甚至互相质疑,直到出现某个结果。

这种方式在处理开放式探索任务时特别自然。比如我让一个Agent当程序员、另一个Agent当代码执行者,它会自己把代码写完、执行、看报错、再改,整个过程你只需要在旁边观察。但代价也在这里:你很难在事前画出一条确定的执行路径,第五轮发言时它想到哪里了、会不会跑偏,都不太可控。因此生产环境必须给它戴上紧箍咒:设定最大轮数、定义终止条件、限制代码执行权限、约束消息格式。

AutoGen的适用面更像科研和探索场景:数据分析、自动编程、需要Agent自己决定下一步的对话系统。它把控制权让渡给了模型,换来的是灵活和自主,但对工程化能力的要求其实更高,因为失控风险需要你自己兜住。

1.3 CrewAI:把业务岗位翻译成Agent角色

CrewAI走的是另一条路:把Agent当成一个虚拟员工,用role(角色)、goal(目标)、backstory(背景故事)来定义这个员工怎么思考,用Task定义他要完成什么任务,最后用Crew把这些角色和任务串联起来,再通过Process指定是按顺序执行还是按层级上报。写出来的代码非常像一份部门排班表,可读性很高。

我第一次用CrewAI做内容流程时,感觉有点像在写RPG角色卡:每个Agent有职业、有人设、有产出说明。它非常适合任务边界清晰、协作关系相对固定的场景,比如内容生产、客服工单处理、邮件整理。因为上手门槛低,很多非专业开发者也能快速搭出一个Demo。

不过CrewAI的灵活度不如前两者。如果你想要一个“如果任务失败就跳过这个环节重来一次”的复杂条件分支,或者要在这个流程中间插入一个人工确认点,CrewAI的标准Process会很难表达。它不是不能做,而是要借助外部控制逻辑或自定义工具绕路,绕多了代码反而比LangGraph更乱。

1.4 Microsoft Agent Framework:多Agent能力的企业级插座

Microsoft Agent Framework在四个里面最年轻,它的定位不是“又一个写Agent的库”,而是想成为一套统一的Agent开发和接入层:定义Agent、把Agent托管到运行时、再通过标准API接进各种应用系统。它在设计上吸收了不少企业级需求,比如对话持久化、可观测性、与外部服务的连接、跨语言调用等。简单说,它解决的是Agent开发完之后“去哪儿、怎么跑、怎么被别人调用”的问题。

打个比方,LangGraph、AutoGen、CrewAI像不同风格的生产车间,MAF更像一栋写字楼里的统一水电管网:它不指定你用什么机床,但给你提供标准接口、电表和监控,让你的Agent能稳定接入企业系统。这也意味着,如果你只是做一个快速验证Demo,MAF带来的更多是额外概念负担;如果你的目标是让Agent在一家公司的现有系统里长期服役,那这套标准化的价值会随着规模变大越来越明显。

由于它出现得晚,社区积累和文档完善度明显不如前三者。我看到很多问题只能去官方讨论区翻答案,而且API变动速度也快。所以我的建议是:可以先理解它的定位,但真要上手,一定先做一个小范围PoC,别拿它直接替换已有系统。

2. 核心执行模型的细节拆解:状态、对话、角色和运行时

2.1 LangGraph里的状态管理为什么这么重要

LangGraph的一切围绕State。最常见的写法是定义一个TypedDict或Pydantic模型作为全局状态,每个节点函数接收state参数并返回一个字典,这个字典会被合并进原来状态里。听起来简单,但实际很容易踩几个坑:

  • 返回的字典中,如果某个key在原状态里已经存在,默认会被覆盖。如果你想追加而不是覆盖,需要用Annotated[list, operator.add]声明为可合并字段。
  • 多个节点可能并发修改同一个字段,产生竞态。虽然LangGraph支持并行执行无依赖的分支,但共享状态中的字段设计不好就有问题。
  • checkpointer用于把每一步状态持久化到内存或数据库里,之后可以用thread_id恢复任意历史节点,实现人工中断、断点续跑、时间旅行调试。使用checkpointer后,每次运行都必须提供thread_id,否则恢复逻辑不工作。

我给新人的建议:先不急着加复杂分支,把状态结构当成API设计来做,字段尽量原子化、语义单一。比如一个审查任务,用approved: bool和review_comment: str两个字段,比塞一个review_result: dict然后在节点里猜结构要安全得多。调试的时候,每次节点返回前打印状态摘要,可以省掉一半的困惑。

这个坑的核心是“所有节点共享同一个全局状态”这个设计带来的。你从命令式编程带过来的局部变量思维在这里不适用,状态既是解耦手段,也是冲突来源。

2.2 AutoGen的对话编排和终止条件怎么配合

AutoGen的执行模型是消息循环。如果是两个Agent,默认就是轮流发言;如果是三个以上,通常要用GroupChat和GroupChatManager。GroupChatManager本身也是一个Agent,它要做的事是决定下一个发言者,策略可以是自动选择、轮询、随机等。它看到当前对话的历史,选出最合适的Agent继续发言,直到满足某个终止条件。

所以AutoGen的工程要点有两件:讲清楚每个Agent的system message,里面写清边界和交付物;以及设好终止条件。在我的项目里,最常用的终止条件有两类:一是消息内容里出现“任务完成”这样的指定关键词;二是对话轮数到达上限。如果两个条件都没设,GroupChat不但会浪费大量token,还可能进入死循环。

代码执行是AutoGen的另一大特点。它可以生成Python代码,然后调用执行器运行,再把结果喂回去。这个设计很强大,但也很危险。只要你打开了代码执行,就相当于允许模型在机器上运行任意代码,这在本地开发还好,在生产环境必须先做隔离,比如容器、沙箱或远端执行。我看到不少人把AutoGen跑在服务器上,Agent因为读取外部数据生成了删除命令,好在权限控制及时拦下。真实项目里,尽量把代码执行关掉,只允许预注册的安全函数。

2.3 CrewAI的任务上下文如何跨Agent传递

CrewAI把Agent定义成角色,把Task定义成该角色要产出的一份“工件”。Task不只是prompt,它还有expected_output,进一步约束输出格式。多个Task之间可以用context参数显式传递前一个任务的输出。这个context机制很关键,如果漏掉,后面的Agent就看不到前面的结果,只能凭空发挥。

另一个细节是Process。sequential是严格顺序执行;hierarchical则不是简单的顺序,而是要有一个manager Agent来分配任务和审核结果,适合角色层级更强的场景。使用hierarchical时要单独给manager配置LLM,否则会报错说不支持manager_llm为None。

CrewAI还支持在每个Agent里挂tools,这些工具会被LLM自动选择调用。我建议工具的function schema写清楚参数和返回格式,并且让任务描述里明确“可以用哪些工具、不可以碰哪些工具”。因为角色扮演类Agent很容易在长上下文里忘记约束,你得不断在prompt里重申边界。

最后说个很容易忽略的点:CrewAI在运行时会把每个Agent的任务结果作为一个字符串塞进上下文。如果任务链很长,到后面上下文会越来越长,token消耗明显上升。对超长流式任务,要定期做总结,或者拆分成多个Crew,而不是无限追加任务。

2.4 MAF提供了哪些超越单一框架的企业能力

MAF的定位决定了它的很多细节并不是给你写提示词的,而是给你搭运行时的。它里面有Agent、AgentThread、AgentChat这类抽象:一个Agent可以被创建成可复用服务,多个Agent可以放在一个线程里连续对话,对话状态可以被持久化和恢复,所有交互可以生成trace供观测。对于企业应用来说,这些能力比“这次用什么模型、提示词怎么写”重要得多,因为你需要知道每个环节发生了什么、能不能回溯、能不能在第二天修复问题。

在使用MAF的时候,你把一个Agent发布的动作更像是把接口注册到总线上,而不是一次性调用。它会和现有身份认证、日志系统、消息队列做对接。这意味着MAF的集成成本不低,但一旦接入,后续新增Agent会变得规范。对于要做长期产品、有多环境部署、有审计要求的团队,这种约束反而是效率。

需要注意的一点是,MAF的生态还处在“能力已经画出来,但砖还没完全铺平”的阶段。我在读它文档时,同一件事在一个版本里用这个方法,过两个月再看,推荐写法变了。所以如果选它,一定要锁定版本、保存官方示例,并留出持续跟进升级的时间预算。具体API这里不贴,因为贴了也很快过期,更建议你去看官方快速开始,并且以最新示例为准。

3. 实战演示:同一个“选题-撰写-审校”任务,三种框架三种写法

3.1 统一需求:一个带三层分工的内容生产小系统

为了公平对比,我设计了一个模拟项目X:一个内容生产辅助系统。输入是一个“文章方向”,输出是一篇通过审校的短文章。分成三步:

  1. 选题Agent:根据方向生成3个候选选题;
  2. 撰写Agent:选择第一个候选选题,写500字初稿;
  3. 审校Agent:检查初稿,输出“通过”或修改意见;不通过则回到撰写步骤。

注意第三步要求“不通过回到撰写”,这是LangGraph最舒服的条件边;AutoGen用对话循环也天然适合;CrewAI标准顺序流程做三轮回退比较别扭,我会说明它的替代方案。模型统一用你手头可用的LLM服务,环境变量用LLM_API_KEY占位。

3.2 LangGraph版本:用图把流程钉死,中间加人工审核

LangGraph版本,我写了这段核心代码:

from typing import TypedDict, List from langgraph.graph import StateGraph, START, END from langgraph.checkpoint.memory import MemorySaver from langchain_openai import ChatOpenAI import os class AgentState(TypedDict): direction: str topics: List[str] draft: str review: str approved: bool llm = ChatOpenAI(model="your-model", api_key=os.environ["LLM_API_KEY"]) def topic_agent(state: AgentState): resp = llm.invoke(f"基于方向'{state['direction']}'生成3个文章选题,用数字列表。") topics = [line.split(". ", 1)[1] for line in resp.content.splitlines() if line.strip()] return {"topics": topics[:3]} def writer_agent(state: AgentState): prompt = f"根据选题'{state['topics'][0]}'写500字文章初稿。" return {"draft": llm.invoke(prompt).content} def reviewer_agent(state: AgentState): prompt = ( f"请审校以下初稿。若通过,回复'PASS';若不通过,给出修改建议。\n\n{state['draft']}" ) result = llm.invoke(prompt).content return {"review": result, "approved": result.strip().startswith("PASS")} def should_review(state: AgentState): return "approved" if state["approved"] else "revise" graph = StateGraph(AgentState) graph.add_node("topic", topic_agent) graph.add_node("write", writer_agent) graph.add_node("review", reviewer_agent) graph.add_edge(START, "topic") graph.add_edge("topic", "write") graph.add_edge("write", "review") graph.add_conditional_edges("review", should_review, {"approved": END, "revise": "write"}) app = graph.compile(checkpointer=MemorySaver())

注意,代码里我简写了一点,实际跑通还要加上输入参数和thread_id。核心就在最后几行:review节点跑完后,条件边根据approved字段决定是走END还是回到write。整个流程的控制流完全在图里,任何一步做错,都能用checkpointer恢复到一个历史节点,再指定状态往下跑。

我觉得LangGraph版本最大的优点不是代码短,而是不会跑偏:你想要回退到write,它一定回退到write,不会因为模型心情变成一条新路径。缺点是如果业务规则变化,你要改图结构,而不是改提示词。

3.3 AutoGen版本:让三个Agent在一个组里自由发言

AutoGen版本我用了GroupChat方式:

import os from autogen import ConversableAgent, GroupChat, GroupChatManager llm_config = {"config_list": [{"model": "your-model", "api_key": os.environ["LLM_API_KEY"]}]} topic_agent = ConversableAgent( name="topic_agent", system_message="你是选题策划。只输出3个选题,不要写正文。", llm_config=llm_config, ) writer = ConversableAgent( name="writer", system_message="你是文章写手。根据收到的选题写500字初稿。", llm_config=llm_config, ) reviewer = ConversableAgent( name="reviewer", system_message="你是审校。如初稿通过回复'PASS',否则给出修改建议。", llm_config=llm_config, ) group_chat = GroupChat( agents=[topic_agent, writer, reviewer], messages=[], max_round=10, ) manager = GroupChatManager(groupchat=group_chat, name="manager", llm_config=llm_config) result = topic_agent.initiate_chat( manager, message="请基于'多Agent框架如何选型'完成一篇文章。", )

这段代码是更常见也更稳定的AutoGen写法。它的行为是:manager决定下一个发言Agent,topic先给选题,writer写稿,reviewer审校,如果reviewer不是直接给PASS,就会继续让writer改稿,直到max_round消耗完。

我实际跑下来的感受是:AutoGen在处理“回退”时非常自然,因为对话天然支持“reviewer提出修改,writer接受再改”。但它会把所有历史消息堆在上下文里,跑到第8轮的时候,输出质量会下降,token成本也上去了。所以建议把max_round设置得尽量小,比如5-8轮,并以“PASS”关键词作为终止信号,而不是让它自己觉得可以停了。另外,AutoGen的版本迭代非常快,网上很多教程用的是不同写法,先看你的包版本再抄代码。

3.4 CrewAI版本:顺序流程+任务上下文,代码最像业务说明书

CrewAI版本:

from crewai import Agent, Task, Crew, Process topic_agent = Agent( role="选题策划", goal="生成3个高质量候选选题", backstory="你是一位资深内容编辑,擅长从方向里提炼用户关心的选题。", verbose=True, ) writer = Agent( role="文章写手", goal="根据选题写出初稿", backstory="你是一位擅长科技写作的撰稿人。", verbose=True, ) reviewer = Agent( role="审校编辑", goal="检查初稿质量,输出通过意见或修改建议", backstory="你是一位严格的审校编辑,对逻辑和事实错误零容忍。", verbose=True, ) task_topic = Task( description="根据用户输入方向,生成3个候选选题,用数字列表输出。", expected_output="包含3个选题的列表", agent=topic_agent, ) task_write = Task( description="从选题列表中选择第一个选题,写500字初稿。", expected_output="一篇500字左右的文章初稿", agent=writer, context=[task_topic], ) task_review = Task( description="审校初稿,判断是否通过。通过输出'PASS',不通过输出修改建议。", expected_output="PASS或修改建议", agent=reviewer, context=[task_write], ) crew = Crew( agents=[topic_agent, writer, reviewer], tasks=[task_topic, task_write, task_review], process=Process.sequential, ) result = crew.kickoff(inputs={"direction": "多Agent框架如何选型"}) print(result)

这段代码的清晰度是三份中最高的。Agent像岗位说明书,Task像任务工单,context把前一个任务的输出塞给下一个Agent。如果你要演示给产品经理看,CrewAI版本最容易讲明白。

但也要注意,标准CrewAI sequential流程没有原生的条件回退。如果review不通过需要改稿,实际处理往往是再加一个Task,比如“根据修改意见修改初稿”,或者写一个外部的while循环,又或者直接用hierarchical流程让manager决定是否重来。这不像LangGraph有个条件边那么直观。

所以我的结论是:CrewAI适合流程稳定、一次性顺序执行的任务。如果你的核心业务是一个需要反复迭代的闭环,那就要三思。

3.5 MAF落地时该怎么和现有架构对接

MAF的实际代码我不想在这里贴,因为包名和API变动太快,贴出来很容易过时。我更想讲清楚它的接入思路。之前我用它做过一个企业内部的小规模试水,核心是把Agent部署成一个统一服务,让内部应用通过标准接口调用。第一步是定义Agent的schema:它能做什么、接受什么消息、返回什么格式;第二步是把Agent放到一个运行时进程里,同时接入对话存储、日志和鉴权;第三步是在应用侧用AgentChat之类的高级接口发起对话,并把结果回传给调用方。

这种做法的好处是,前台应用不关心Agent具体是用LangGraph还是AutoGen写的,它只跟MAF的运行时代理交互。当我把LangGraph写好的流程包装成一个MAF Agent后,同一个应用既可以调这个,也可以调另一个,统一观测。缺点是概念层多了一圈,排错的时候要先看MAF的日志,再看底层框架的日志,问题定位链路更长。

如果你所在的团队已经有很多不同技术栈的应用系统,要把Agent能力作为基础设施提供出去,MAF这条路值得认真考虑;如果只是做一个小工具,老实说没必要上这么重的底座。

4. 选型决策:一张表加一套判断逻辑,看完直接拍板

4.1 六项关键指标横向对比

我整理了一张表,用过的人都觉得能直接拿去写方案:

维度LangGraphAutoGenCrewAIMAF
核心抽象状态图对话组角色、任务、流程Agent运行时与接入
控制粒度细,节点/边/条件全可控粗,由对话和manager决定中,流程类型有限不限定,更偏接入
复杂条件分支原生支持依赖对话和终止条件较弱,需要额外绕路不在框架核心
多Agent协作通过子图/多节点实现对话式原生支持角色分工原生支持多Agent线程支持
生产环境风险图设计复杂度高代码执行安全、上下文爆炸上下文增长、依赖冲突版本漂移、资料少
学习曲线高中低中高
典型场景订单流程、人工审核、重放调试数据分析、自动编程、开放探索内容流水线、客服处理企业系统统一接入、多语言服务

这张表不能直接替你拍板,但能帮你快速排除。比如你的核心需求是“流程必须肉眼可查”,LangGraph优先;如果你更关心Agent自主探索,AutoGen;如果你要快速交付一个角色明确的任务流,CrewAI;如果你要接企业系统,MAF。

4.2 根据项目阶段和团队能力做选择

选框架不看谁火,而是看你的项目处在哪个阶段、团队以后能不能维护。

快速原型或学习阶段,我建议CrewAI。它代码最短,概念最容易理解,能让你快速看到“多Agent协作到底是什么感觉”。你不需要一开始就学习图、状态机、checkpointer这些重概念。原型跑通后如果发现流程需要大量分支,再迁到LangGraph也不晚,因为CrewAI的很多工具思想本身和LangChain一脉相承,迁移不会从零开始。

需要精确控制流程的生产级系统,直接考虑LangGraph。流程中有人工审核、状态需要回放、步骤必须记录、某个分支要循环,这些词一出现,就说明不是靠对话自由发挥能搞定的。LangGraph虽然写起来费脑,但它的可控性值回票价。

研究型或开放式Agent实验,AutoGen更合适。它适合让多个Agent相互讨论、产生新思路的场景。前提是你必须设计好终止条件和沙箱环境,否则上线就是事故。

企业应用接入或跨语言统一,重点看MAF。如果公司已经有大量业务系统,未来会涌现几十上百个Agent,需要统一托管和观测,那MAF的方向是对的。施工前先做PoC,把日志、鉴权、版本升级机制都验证一遍。

4.3 多框架混用是否值得尝试

完全可以混用,但要有度。常见的混法是以LangGraph为主编排,把一个CrewAI或AutoGen的Agent作为图里的一个节点;或者把LangGraph跑起来的Agent包装成MAF统一接入。这个思路在大型项目里其实很常见,因为每个框架擅长的颗粒度不同。

但混用不是免费的。每多一层封装,就多一层调试成本。我在一个项目里试过把一个AutoGen团队嵌进LangGraph节点,结果对话内部的执行日志和外层图日志交织在一起,定位一次问题要看三处日志。所以我的建议是:如果一个项目同时用到两个以上框架,尽量按“编排层/执行层”分清楚,不要让两边互相侵入,每层只承担一种职责。新手还是先单一框架跑通,再考虑混用。

5. 常见问题与排查技巧实录:这些坑我都替你踩过了

5.1 LangGraph:状态覆盖、条件边和RecursionError

LangGraph最常见的报错之一是节点返回值覆盖了原本保留的字段。比如你在前一个节点存了topics,后一个节点返回值里没有topics,没问题;但如果你在某个节点不小心返回了topic这个新key,后续节点读state['topic']就会出错。排查方法很简单:在节点函数开头打印state.keys(),结尾打印即将返回的dict,对齐一次就清楚了。

第二个常见问题是条件边的返回值必须和图里的边名字完全一致。我在一个项目里写should_review返回“correct”,但图里注册的边名是“fix”,运行时报了非法目标错误。原因是大小写和拼写都要严格一致,建议用常量而不是手写字符串。

第三个是RecursionError。LangGraph默认有recursion_limit,如果你有循环边,跑几十轮之后就会触发。解决方式是两件事:在条件边函数里加一个“最大迭代次数”字段,或者在节点函数里做计数并主动跳转到END。不要简单粗暴把recursion_limit调到无限,费用和风险都会失控。

5.2 AutoGen:代码执行风险、对话停不下来的问题

AutoGen第一个坑是代码执行安全。只要你在AutoGen配置里允许了代码执行,它就会执行LLM生成的Python代码。本地测试无所谓,但放到服务器上一定要改。我能给的最稳妥建议是默认关闭,只开放你手动注册的安全函数,并且用容器隔离运行环境。代码执行虽然很酷,但在生产里不是默认功能。

第二个坑是对话停不下来。我见过一个GroupChat跑了30多轮还在互相“你说得对,我再补充一点”。这本质是缺少终止条件。在GroupChat里设置max_round=6,并在审校Agent的system_message里明确说“当你回复PASS时任务完成”,再用关键词终止条件监听。如果还停不下来,就是prompt里没把输出规范约束死,检查最后一个Agent的message是否被自动忽略。

第三个是版本混乱。AutoGen不同版本之间的API差异很大,甚至库名都不一样,网上搜到的代码经常不兼容。建议用虚拟环境固定版本,看到教程先看它的包名和版本日期,不要直接复制。

5.3 CrewAI:依赖冲突和上下文丢失

CrewAI最让人头疼的是依赖冲突。它跟LangChain的某些版本绑定得很死,装完CrewAI之后如果手动改了LangChain版本,运行时会出一堆警告甚至导入错误。所以一定要用独立的虚拟环境安装,不要把CrewAI和最新版LangChain塞在一起。

第二个是上下文丢失。如果你在新任务的context里没有把前一个任务挂上去,后面的Agent完全不知道前面发生了什么,输出会前言不搭后语。我曾经把task_write的context写成[task_topic],但漏写task_review的context,审校Agent就像个失忆的人,说“这篇文章写得很棒”,实际它根本没看过文章。检查任务链时,把每个Task的context都列出来逐一核对。

第三个是Process.hierarchical需要一个manager Agent的LLM配置,很多人没配就报错。如果你不是真需要层级管理,建议先用sequential。

5.4 MAF:版本漂移和可观测性不足

MAF最大的问题是“你看到的新教程可能已经过时”。我试过从三个月前的博客复制代码,运行时报错说某个方法已经移到另一个命名空间。在逐步演进但有大量企业依赖的框架上,这是常态。应对办法:固定SDK版本,把官方示例存进自己仓库,每次升级单独做回归测试。

可观测性也比较难卡。虽然MAF官方强调trace,但配置起来并不像宣传中那么顺手。我曾经找半天才发现某个环境变量没有设置,导致trace没上报,还以为是代码问题。所以使用MAF时第一天就应该把日志、trace、指标全部接好,后面所有排错都依赖这些数据,越晚接入越痛苦。

5.5 全框架通用的避坑清单

最后给一张通用清单,每一条都是我付过代价的经验:

  • 不要让Agent自动执行未受限的外部命令或代码,生产环境必须隔离。
  • 每个Agent的prompt必须包含明确的输入、输出格式、边界,像写接口文档一样写。
  • 对话或循环流程都要有限流和终止条件,防止无限调用LLM。
  • 所有LLM调用都要做token和费用监控,一个失控Agent一夜之间烧掉不少预算不是玩笑。
  • 固定依赖版本,别在同一个环境里混合多框架,尤其CrewAI和LangGraph。
  • 先从最小闭环跑通,再加功能。很多人一上来就五六个Agent组队,结果是日志里全是“自我表扬”,最后还要逐个排查。

最后说一点很个人的体会。框架选型这种事,网上吵得再凶,都不如用你自己的业务场景跑一个最小demo来得靠谱。我每次换框架都从那几个标准问题开始:这个流程会不会经常改,改了影响哪条链路;我能不能看到中间每一步发生了什么;如果模型抽风,系统怎么兜底。老实说,LangGraph会在需要控制时给我最大的安全感,AutoGen在探索时给我最多的惊喜,CrewAI让我在写业务脚本时最省心,而MAF让我看到Agent从一个测试功能变成一个企业服务时的可能性。没有哪个框架能通吃所有项目,找到匹配你自己约束条件的那一个,比追逐社区热度重要得多。

RELATED READING

延伸阅读

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