☰
CrewAI多代理实战:从Agent创建到任务编排与排错
2026/10/22 9:19:48 网站建设 项目流程

1. 为什么是CrewAI:多代理不是装饰品

最近一直有人在问“多智能体到底是不是噱头”。说句实在话,如果只是把一件事塞给一个大模型,用单条Prompt也能办,那确实用不上多代理;可任务一旦复杂起来,既要查资料、又要做交叉分析、还要产出文案,让同一个Agent从头做到尾,前面表现还行,后面往往开始丢三落四、风格漂移。CrewAI解决的就是这个痛点:它把Agent当作可以扮演不同角色的队员,通过任务(Task)和流程(Process)把这些队员组织成一支“虚拟团队”,由大家分工协作完成一个整体目标。

我第一回认真接触CrewAI,是给某电商公司做一个促销活动舆情归类的内部小项目。那时候手头工具链还不成熟,前面用单Agent跑了三天,结果整理出来的归类报告总是“看着全面、用起来没重点”。后来切到CrewAI,拆成“信息采集员”“分类整理员”“摘要撰写员”三个角色,一轮跑下来效果立刻不一样。从那以后我又拿它做过技术方案预研报告生成、代码审查辅助、市场调研材料整理等场景,整体感受是:框架本身不复杂,真正难的是把“人怎么分工”这件事翻译成Agent配置。这篇就把我实际用下来的经验完整写一遍,重点放在Agent的创建、参数含义,以及多Agent协同时的管理与排错。

1.1 单Agent的边界在哪,逼我重新思考多代理

单个Agent的本质是什么?是一个带有系统提示词、工具集合和任务描述的大模型循环。它能连续调用工具、自己拆步骤、最后输出结果。听起来已经很强了,但在真实业务里有一个非常实际的问题:角色不稳定。比如让同一个Agent先做“数据收集”,再做“观点提炼”,再干“文案润色”,前面步骤产生的中间内容会全部堆在上下文里,模型越往后跑越容易被无关信息干扰。我做过一组对照实验:同一份资料,让一个Agent把“汇总+结论+宣传语”全干完,和拆成三个Agent分工干完,后者的结论质量和条理性明显更好,虽然总token会高一些。

第二个问题是没法并行。单Agent只能线性执行,查资料的时候不能同时写大纲,做定量分析的时候不能去跑定性素材。多代理可以一部分任务异步执行,这在信息收集类场景里能省不少时间。第三个问题更隐蔽:单Agent一旦出错,责任无法定位。到底是大模型理解错了,还是工具返回了脏数据,还是步骤拆分不合理?日志里全糊在一起。而拆成多个Agent后,每个Agent的输入输出边界都很清楚,哪个环节出问题直接看那一个环节的日志就能定位,排查成本低很多。所以我的建议是:任务简单时别硬上多代理,那是自己给自己增加成本;一旦任务超过三个明显步骤,或者需要并行收集信息,或者角色之间产出形态差异很大,就值得用CrewAI来组织。

1.2 Crew、Agent、Task、Flow,一次把概念弄清楚

CrewAI的核心概念不多,但很多人刚开始会被名字绕晕。用公司来类比就很好理解:Crew是一个“项目组”,里面既有人(Agent)也有活(Task);Agent是“项目组成员”,每个人都有明确的岗位、目标和做事风格;Task是“任务工单”,上面写着要干什么、交什么东西出来、验收标准是什么;而Flow是更高一层的流程编排能力,用于定义Agent和Task之外更灵活的事件驱动流程。

具体来说,Crew负责把Agent和Task绑定在一起,同时决定这批活是按顺序执行还是层级管理式执行;Agent是执行者,可以配置大模型、工具、记忆开关、协作权限;Task是执行单元,通过context参数可以引用其他Task的输出,形成依赖关系。Flow我放到后面讲,它解决的问题是“多个Crew或Agent之间的动态流转”,当你需要根据上一步结果决定下一步触发谁、什么时候触发时,Flow比硬写在Crew里更优雅。

这四者的关系,用一句话总结:用Crew搭班子,用Agent定角色,用Task派活,用Flow控节奏。一下把一个复杂项目拆成了可独立维护的模块。

1.3 角色是灵魂,但角色不等于“你是谁”

CrewAI设计里最值得琢磨的是角色体系:Role(职位)、Goal(目标)、Backstory(背景故事)。很多人把这三项当成“填了就行的配置项”,其实它们共同决定了一个Agent的“思维方式”。同一个底层大模型,给它不同的Role和Backstory,输出的风格、关注点、取舍标准可能截然不同。比如把某电商促销数据分别给“运营总监”身份和“客服主管”身份的Agent整理,前者会关心活动ROI、引流和转化,后者会关心退换货话术和用户投诉点。这不是大模型随机发挥,而是角色设定真的会改变模型内部的注意力分配。

我填Backstory的原则是:不要写成长篇人物传记,而要写成“工作偏好说明书”。比如“你是一名有10年快消行业经验的市场研究员,习惯用数据判断,不使用没有出处的数据,输出务必分级列出关键结论”,这比“你是个经验丰富、充满热情的研究员”有用得多。Goal也要可衡量,“做一份报告”是无效目标,“输出一份包含市场规模、头部玩家、价格带分布的调研报告”才是有效目标。后面创建Agent的环节我会再细化一套填法。

2. 创建Agent:参数不是填完就行,得会填

Agent是CrewAI的最小执行单元,创建时主要靠一组参数把它的行为框住。我见过的很多翻车现场,问题都不出在框架,而是参数填得太随意。下面我按实际使用频率从高到低,把关键参数逐个拆开讲,每个都给建议写法和为什么这么写。

2.1 五个核心参数怎么填不踩坑

在CrewAI里创建一个Agent,最基础的参数是role、goal、backstory,加一个llm模型指定。下面这份示例是某调研场景里我最常用的模板:

from crewai import Agent from crewai_tools import SerperDevTool search_tool = SerperDevTool() researcher = Agent( role="行业研究员", goal="针对可降解包装材料,输出近一年的市场规模、政策动态、主要品牌案例的结构化要点。", backstory=( "你是一名有8年新材料行业研究经验的分析师。" "你习惯先看数据再下结论,所有观点必须附带来源说明。" "输出时使用分级标题,不要泛泛而谈。" ), tools=[search_tool], llm="gpt-4o-mini", verbose=True, memory=True, max_iter=5, max_rpm=30, allow_delegation=False )

role别写太宽泛。“数据分析师”这种角色放在具体任务里等于没说,写“跨境电商行业数据分析师”立刻清晰很多。goal一定要包含任务对象和产出形式,最好能用一句话说明“输入是什么、输出是什么”。backstory的价值在于约束风格和提供判断标准,它不是在编故事,而是在给模型划“怎么工作”的边界。max_iter我建议默认在3到6之间,太小任务容易完不成,太大容易在错误方向上空转。max_rpm是每分钟最多请求次数,用来控制接口频率,如果只有单Agent任务,写不写无所谓;多Agent并发时建议写,否则容易把自己接口打爆。allow_delegation默认是False,表示这个Agent能不能把任务甩给别人,这个我后面专门讲。

2.2 工具绑定:不是越多越好,而是越聚焦越好

Agent的tools参数用来绑定工具,比如网页搜索、网页抓取、数据库查询、代码执行等。CrewAI官方工具包里提供了不少现成的,像SerperDevTool、ScrapeWebsiteTool、FileReadTool,用起来倒是很方便。但这里有个最常见的误操作:一次给Agent塞五六个工具,觉得“这样它什么都能干”。实际效果恰恰相反,工具越多,Agent在做决策时越容易犹豫,甚至出现幻觉调用。

我现在的原则是:一个Agent最多绑定三个工具。拿前面那个调研员来说,我给它的就是SerperDevTool(搜索摘要)加ScrapeWebsiteTool(抓取具体页面),足够覆盖“搜索—打开页面—摘信息”这条链路。如果调研任务里要打开本地Excel做统计,再加一个FileReadTool,但不做统计就不加。工具列表会拼到Agent的系统提示里,每多一个工具,模型需要评估的选项就多一组,出错概率也随之上升。

遇到框架没有的工具,可以用@tool装饰器包一层普通函数,比如查内部库存、调用公司内部接口等:

from crewai.tools import tool @tool("查询实时库存") def query_stock(sku: str) -> str: """传入SKU,返回当前库存和补货状态。""" # 内部伪代码,替换成真实接口调用 return f"SKU {sku} 当前库存 1200,补货状态正常"

自定义工具的关键是写好函数docstring,CrewAI会让模型根据docstring决定何时调用它,所以描述必须包含“这个函数接收什么、返回什么、什么时候适合调用”。工具是做给模型用的“说明书”,不是给自己看注释。

2.3 记忆:开了省事,但别盲目开

CrewAI的memory=True会启用短期记忆和长期记忆。短期记忆是任务过程中保留对话上下文;长期记忆则会把执行结果存下来,下次同类任务能参考。听起来很好用,但代价是token和存储成本。

对单次离线分析任务,比如“把这份PDF总结一下”,我建议关掉记忆,因为任务不需要跨对话回看,开着只会让上下文更臃肿。对客服机器人、持续对话类Agent,memory=True很有价值,它能让Agent记住用户的偏好。另一种跟记忆相关的配置是knowledge,可以往Agent里塞知识库文件,让它在回答时优先参考指定资料。这个类似RAG,需要额外指定embedder。我个人的经验是:小团队起步阶段先全关,跑通了再说。等真遇到“Agent应该记住上次处理结果”的场景,再开memory并接好向量库,否则一上来就开记忆,成本和排查难度都会上来。

2.4 委派权限与代码执行,两个容易失控的开关

allow_delegation是我最谨慎的开关之一。把它设为True后,Agent可以在觉得“自己做不来”的时候,把任务委托给Crew里的其他Agent。这个功能在层级流程里很有用,比如manager Agent发现数据采集量过大,会拆成多份派给多个采集Agent。但放在小规模顺序流程里,它很容易引发失控:Agent A把任务委托给B,B又委托回A,两个Agent来回踢皮球,日志刷得很热闹,结果什么都没有产出。

另外一个需要慎用的是代码执行。CrewAI的Agent默认不执行代码,只有显式设置code_execution_mode为"safe"(沙箱环境)或"unsafe"(本机执行)时才会调用代码工具。我的建议是:没有特殊需求一律不开。如果确实需要让Agent写代码做数据分析,优先用"safe"沙箱,并且严格控制输入内容来源。来源不明的内容坚决不交给Agent直接执行,这是一个基本安全底线。

3. 一次能跑通的双代理实战:调研员+文案手

参数讲得再多,不如直接跑一遍。这一节我完整复现一个“双Agent协作生成营销内容”的案例:调研员负责收集整理资料,文案手基于调研结果写一篇面向品牌方的推广文章。这个案例虽然简单,但包含了Task依赖、上下文传递、输出格式控制这些最核心的东西。

3.1 先给团队定一个可验收的目标

我选“可降解包装材料”这个虚拟场景做演示,目标是这样:调研近一年可降解包装的行业动态和代表性品牌案例,产出结构化调研要点,然后基于这些要点写一篇800字左右的推广文章草稿,语气要适合品牌市场部阅读。注意,这里的验收标准很明确:调研输出必须是“分类要点”,文章草稿必须引用调研里的具体数据或案例,不能泛泛而谈。

为什么一定是双Agent而不是单Agent?因为这两个角色的产出形态差异太大,一个要结构化、重数据,一个要叙事化、重表达。让同一个Agent先做调研再做写作,第二个阶段很容易被第一阶段积累的代码块、网址和中间格式干扰。分开之后,文案手拿到的就是一个干净的、被整理好的输入,写作质量会稳定很多。

3.2 Agent与Task定义:代码怎么落

两个Agent定义如下:

from crewai import Agent, Task, Crew, Process from crewai_tools import SerperDevTool, ScrapeWebsiteTool search_tool = SerperDevTool() scrape_tool = ScrapeWebsiteTool() researcher = Agent( role="新材料行业调研员", goal="围绕可降解包装材料,整理近一年行业市场规模、政策动态和代表性品牌案例,输出分类要点。", backstory="你是一名新材料行业分析师,习惯用数据说话,每个观点都要有来源。输出使用分级标题与要点列表。", tools=[search_tool, scrape_tool], verbose=True, memory=False, max_iter=5, allow_delegation=False ) writer = Agent( role="品牌营销文案写手", goal="阅读行业调研要点,写一篇约800字、面向品牌市场部的可降解包装推广文章草稿。", backstory="你擅长把行业数据转化成有说服力的品牌叙事,语气专业、克制,不使用夸张口号,文中必须出现调研中的具体数据或案例。", verbose=True, memory=False, allow_delegation=False )

注意到没有:调研员绑定了工具,文案手没有绑工具。因为文案手的核心任务是基于给定文本写作,不需要再去搜索,给它绑工具反而容易让它跳出角色去查东查西,拖慢节奏。

Task定义是另一个关键:

research_task = Task( description=( "搜索并整理可降解包装材料近一年的信息,覆盖市场规模、政策动态、" "代表性品牌案例三个板块。每块输出3到5条要点,每条必须附来源。" ), expected_output="一份包含三个板块、每块3到5条要点的调研摘要。", agent=researcher ) writing_task = Task( description=( "阅读下方提供的调研摘要,写一篇约800字的文章,面向品牌市场部," "主题是可降解包装材料为什么值得关注。文中必须引用调研摘要里的具体数据或案例。" ), expected_output="一篇约800字的推广文章草稿,含标题和三个段落。", agent=writer, context=[research_task] )

这里最容易被忽视的就是Writing任务里的context=[research_task]。它告诉CrewAI:这个任务的输入是research_task的输出。如果不写这一行,文案手只会看到自己的Task描述,根本拿不到调研结果,到时候它就会依据自己的“常识”硬写,产出就和调研脱节。

3.3 Crew编排:顺序执行最适合这种链条

两个任务一前一后是天然的依赖关系,用Process.sequential排列最合理:

crew = Crew( agents=[researcher, writer], tasks=[research_task, writing_task], process=Process.sequential, verbose=True ) result = crew.kickoff() print(result.raw)

kickoff()是启动入口。运行结束后,result里带了整体输出和每个Task的结果。result.raw是最终文本,想单独看某个中间任务的结果,用result.tasks_output访问,数组顺序和tasks定义顺序一致。

顺序流程适合这种“A的产出是B的输入”的链条式结构。反过来,如果两个任务之间没有依赖,比如“收集市场数据”和“收集竞品公司新闻”互不相干,那应该把它们标成async_execution=True并行跑,省时间。这儿的经验是:能并行就并行,但有依赖关系的任务永远不要标并行,否则会拿到空上下文。

3.4 运行日志怎么读,怎样判断协作成功

第一次跑的时候务必打开verbose=True。日志会按“Task assigned to 角色 — Agent开始执行 — 工具调用记录 — Final output”这个顺序打印。你要重点看两条:

第一,文案手拿到的输入,是不是真的包含调研员的输出。办法很简单,看日志里有没有类似“New task received”的内容,或者看research_task的输出是否成功传给下一环。第二,文案手的成稿里是否引用了调研摘要的具体信息。如果文章看起来“每个字都对,但没有任何实测数据”,八成是context没传或调研摘要本身太虚。

这个案例是我日常测试“多Agent协作链路”时最常用的原型,结构简单,变量少,出问题一眼能定位。复杂项目再基于这个原型往上扩,先保证一条链路跑通,再谈规模。

4. 管理多代理:从“能跑”到“能管”

两个Agent协作跑通相对容易。一旦进入五个、八个Agent同时干活,问题就会从“写代码”变成“做管理”:任务怎么拆、依赖怎么控制、上下文怎么控制、成本怎么控制。这一章的方法,都是我多Agent项目里踩过坑后沉淀下来的。

4.1 层级流程:让Manager Agent当“小领导”

CrewAI支持两种流程,Process.sequential是顺序执行,按tasks列表一个个跑;Process.hierarchical是层级执行,由manager Agent统一指挥。层级流程下,manager Agent接收总目标,自行决定如何拆分任务、分配给哪些Agent、什么时候验收。

使用方式有两种,一种是自己定义manager Agent:

from crewai import Agent, Crew, Process manager = Agent( role="项目经理Agent", goal="把总任务拆解为子任务,分派给合适的成员Agent,并检查最终产出是否符合要求。", backstory="你是资深项目经理,擅长任务分解和质量把关,遇到成员产出不达标时要求返工。", allow_delegation=True ) crew = Crew( agents=[researcher, writer], tasks=[research_task, writing_task], process=Process.hierarchical, manager_agent=manager, verbose=True )

不传manager_agent的话,CrewAI会自动创建一个manager。我建议初期自己定义,因为自动创建的manager用的是默认prompt,未必贴合你团队的语境。

层级流程适合“总目标明确、但路径本身需要动态规划”的场景。比如一个综合市场分析任务,你只知道“出一份完整分析”,至于中间要检索哪些情报、访谈哪些素材,做完第一轮才知道,这时候让manager动态派活就比死板定义Task序列灵活。代价是,manager自身有对话开销,发指令、收结果都要占token,我测下来一般会让总消耗增加30%到50%。所以任务链条清晰时,顺序流程优先;任务开放性大时,再考虑层级。

4.2 任务编排细节:避免Agent“各说各话”

多Agent项目里最常见的翻车,是Agent多但目标散:每个Agent都在认真干活,合在一起不成体系。要解决这个问题,在Task的description和expected_output里就得把边界钉死。

我给每个Task写描述时都会回答三个问题:输入是什么、输出给谁、按什么标准验收。比如“阅读调研摘要,按‘市场规模、政策、案例’三个板块输出200字中文摘要,每条要点必须带数据来源”,这就是一个不容易跑偏的Task描述。而expected_output是给模型的验收标准,场景里别只写“一份摘要”,要写“约200字、三板块、每条含来源的中文摘要”。

另一个很有用的参数是output_pydantic,它能让Task输出一个结构化对象,而非纯文本:

from pydantic import BaseModel class MarketReport(BaseModel): market_size: str policy: str cases: list[str] research_task = Task( description="围绕可降解包装材料,整理市场规模、政策动态和代表案例。", expected_output="包含market_size、policy、cases三个字段的结构化报告。", agent=researcher, output_pydantic=MarketReport )

有了结构化输出,后面的流程代码就能直接result.tasks_output[0].pydantic.market_size取字段,而不是去解析一篇长文本。这在多Agent链条里非常有用,避免“输出了一段漂亮话,但后续代码不知道怎么接”。

4.3 上下文与成本管理:多Agent项目的隐性天花板

多Agent协作的显性成本是模型调用的次数,隐性成本是上下文膨胀。每个Agent都会携带自己的系统提示词、Task描述、工具说明和中间输出,这些token会层层传递。我以前做过一个六Agent的内容工厂,一次完整跑下来花了接近单Agent任务的三倍token,原因就是每个环节都把中间结果完整传给下一环,信息重复率极高。

我后面总结了一套“三层瘦身法”。第一层,裁剪系统提示词:backstory控制在三行以内,只保留风格约束和判断标准,不要写大段人物经历。第二层,裁剪传递内容:后置Agent真正需要的往往不是前置Agent的完整输出,而是其中的结论和要点,所以前置Agent的expected_output就要写“输出要点列表,不要输出完整过程”。第三层,按需分配工具和记忆:做检索的Agent带搜索工具,做写作的Agent不带工具;做单次分析的关记忆,做持续对话的开记忆。

成本控制本质上不是“省token”,而是“让每个token都服务于最终目标”。这一条想明白之后,多Agent项目才真正能从Demo走向可维护的内部工具。

5. 常见问题与排查实录

最后这部分是我最想写的,因为多Agent项目的坑,90%不在CrewAI框架本身,而在配置和使用习惯。我把自己真实项目中遇到过的问题、排查思路、以及怎么解决都列出来,后面每一条背后都有一次实实在在的“跑飞”经历。

5.1 上下文爆炸,Agent开始胡说八道

现象是:流程跑到一半,Agent输出的内容明显偏离主题,或者重复、或者开始“建议你使用专业工具”这种空话。原因是任务链条太长,上下文堆积过多,模型注意力被分散。CrewAI虽然有窗口管理机制,但多Agent场景下上下文叠加情况更严重。解决办法有三个:一是降低max_iter,从默认偏大的值收到3到4,逼它在有限步数内收敛;二是缩小backstory和description,把“背景故事”压缩成“行为准则”;三是把一个“大Agent”拆成多个“小Agent”,每个Agent只负责一个窄环节,这样上下文各自独立,反而更干净。

5.2 工具调用失败,Permission error和API error

工具失败是我遇到最多的问题,绝大多数不是代码问题,而是三类情况:一是工具对应的API Key没有配环境变量或者已经过期,比如用SerperDevTool时SERPER_API_KEY失效,Agent就会在搜索环节反复报错。二是自定义工具函数抛异常,但Agent会尝试“换个参数再调”,反而放大了报错日志。三是工具返回的内容格式超出预期,Agent拿到乱码就开始臆测。

排查办法:先把verbose=True打开,看日志里工具调用的原始返回。如果确认是Key过期,直接换Key;如果是自定义工具的问题,先用普通Python函数测一遍,确认无异常后再包成@tool。另一点建议:工具函数内部要做异常兜底,别让底层异常直接暴露给模型,否则模型会把错误信息当成正常内容处理。

5.3 任务结果不达预期,泛泛而谈

最常见的是文案类任务“看起来正确,但没有任何实质信息”。这种问题十有八九出在Task描述和expected_output上。描述里没有给模型限定“必须使用哪些数据”“必须按什么结构输出”,模型自然按它最熟悉的路径写。我试过把expected_output改成“必须引用调研摘要中的具体数据,至少出现2个品牌案例名和1组市场规模数据”,输出质量立刻提升一个档次。记住一条:把验收标准写细,Agent就不会跑偏。

5.4 Agent陷入循环或运行超时

层级流程里尤其容易碰到:manager把任务派出去,成员Agent认为应该再派回去,任务来回转就是没有结果。或者某个Agent在工具调用上反复重试直到超时。我的手段是:给关键Agent设置max_iter=3或更小;给Crew增加max_execution_time,超过就自动中断;在日志里观察是哪个Agent一直在“handoff”,把它allow_delegation关掉。层级流程里建议保持manager自己能委托,但普通成员不开放委托权利。

5.5 排查速查表,建议保存一份

遇到问题先看日志,日志永远比猜测更接近真相。这篇文章里的排查思路汇总成一张表,方便实际用的时候对照。

常见症状可能原因优先排查手段
Agent输出偏离主题上下文过长、backstory过于宽泛缩减提示词、拆小Agent、降低max_iter
反复调用工具但报错API Key失效、函数异常未兜底开verbose看原始返回,单独测工具函数
后置Agent拿不到前置结果Task未配置context参数检查context=[前置task]是否配置
输出正确但无实质信息expected_output过于宽泛写明必须引用的数据和结构
任务循环、运行超时委派权限开放、max_iter过大关闭成员委派权限、设置max_execution_time
多Agent并行后结果乱套有依赖的任务被标成异步检查async_execution是否误开

这张表是我自己排查问题时的一个动作清单,不能覆盖所有场景,但能解决多Agent日常开发里80%的“跑飞”情况。

最后再分享一个经验:从单Agent跨到多Agent,我最大变化不是代码写法,而是视角。写Agent不是写脚本,是搭班子;Agent之间配合得好不好,靠的不是把Prompt写多长,而是边界划得清不清楚。先跑通一个最小双Agent链路,再加第二个,再加Manager,每加一层都观察上下文和token的变化,这样踩坑成本最低。CrewAI多代理的上限不取决于框架,而取决于你有没有把它当作一个真正的团队来管理。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询