多Agent项目实战,搭建一个产品加开发加测试的AI项目团队

多Agent项目实战,搭建一个产品加开发加测试的AI项目团队

多Agent项目实战,搭建一个产品加开发加测试的AI项目团队

上篇把Agent通信的原理和代码讲完了。道理都懂了,但真要把多个Agent捏成一个团队干活,光有通信层还不够。谁干什么活,谁先干谁后干,中间产物怎么传,出了岔子谁兜底,这些得安排好。

今天这篇就上手搭一个完整的AI项目团队,三个角色,产品经理Agent负责拆需求,开发Agent负责写代码,测试Agent负责写测试用例并执行。我用CrewAI来做,这个框架天然适合定义角色和任务,省得自己搭协作骨架。走完一遍你会发现,从需求到代码到测试,整条流程能自己跑起来。

为什么用CrewAI

CrewAI的核心概念就三个,Agent、Task、Crew。Agent定义角色和工具,Task定义具体任务和期望输出,Crew把Agent和Task组装起来管流程。跟你拉一个项目组的逻辑一样,先定人,再分活,最后排个顺序开干。

对比LangGraph,CrewAI不用你手写状态图和路由逻辑。角色之间的传递顺序用Task的列表顺序就能控制,想搞条件分支也有现成的机制。代价是灵活性差一些,特别定制化的流程CrewAI不好搞。但搭一个标准的项目团队这种场景,CrewAI足够了。

安装很简单,pip install crewai crewai-tools,然后配好OpenAI的API key就行。CrewAI底层用的LangChain的LLM接口,所以你用其他模型也行,换个LLM配置就好。

角色定义和职责划分

三个Agent的职责得划清楚,跟真实项目组一样。

产品经理Agent,拿到一个模糊的需求描述,输出结构化的需求文档。包括功能点列表、验收标准、技术约束。这个Agent要会追问,需求太模糊就给出合理的假设并标注出来。

开发Agent,拿到需求文档,输出可运行的代码。要给出完整的函数实现,加上注释,附上使用说明。不能只给个函数签名就完事。

测试Agent,拿到需求文档和代码,输出测试用例并执行。覆盖正常路径和边界情况,给出测试报告,哪些过了哪些没过。

职责重叠是多Agent最容易出的问题。我一开始让开发Agent也写测试,结果它自己写的代码自己测,bug一个都测不出来。后来把测试单独拆出来,测试Agent拿到代码以后从外部视角挑刺,效果好多了。

协作流程设计

流程是串行的,产品经理先干,开发跟上,测试收尾。前一个的输出是后一个的输入。

需求进来先到产品经理Agent,它分析完输出需求文档。需求文档传给开发Agent,开发根据文档写代码。代码连同需求文档一起传给测试Agent,测试Agent根据需求写测试用例,拿代码跑测试,最后出测试报告。

如果测试没过怎么办。最简单的处理是测试Agent把失败原因反馈回来,人工看一眼决定要不要让开发Agent重写。CrewAI也支持自动重试,测不过就回到开发那一步重做,但我建议先手动跑通再考虑自动化,不然一个bug可能让三个Agent来回折腾消耗大量token。

下面是完整代码,三个Agent加三个Task,组装成一个Crew跑起来。

importosfromcrewaiimportAgent,Task,Crew,Processfromcrewai.llmimportLLM# ---------- LLM配置 ----------# 用OpenAI的模型,也可以换成其他的# 实际项目里把key放环境变量,别硬编码os.environ["OPENAI_API_KEY"]="你的API_KEY"# 创建一个LLM实例,所有Agent共用llm=LLM(model="gpt-4o",temperature=0.3)# temperature低一点,输出稳定# ---------- 定义三个Agent ----------# 产品经理Agent,负责把模糊需求拆成结构化文档pm_agent=Agent(role="产品经理",goal="把用户的需求拆解成清晰可执行的需求文档,""包含功能点、验收标准和技术约束",backstory=("你是一个有10年经验的产品经理,擅长把模糊的需求""拆成开发能直接用的文档。你会主动标注假设和风险。"),llm=llm,verbose=True,# 打印详细执行过程,调试用allow_delegation=False,# 不允许把活派给别人,各干各的)# 开发Agent,负责根据需求文档写代码dev_agent=Agent(role="开发工程师",goal="根据需求文档写出完整可运行的Python代码,""包含函数实现、注释和使用说明",backstory=("你是一个资深Python开发,代码风格简洁清晰。""你写的代码必须能直接运行,不省略关键逻辑。"),llm=llm,verbose=True,allow_delegation=False,)# 测试Agent,负责根据需求和代码写测试并执行test_agent=Agent(role="测试工程师",goal="根据需求文档和代码编写测试用例,""覆盖正常路径和边界情况,给出测试报告",backstory=("你是一个严谨的测试工程师,擅长找边界情况和异常输入。""你会客观评估代码质量,不放过任何潜在问题。"),llm=llm,verbose=True,allow_delegation=False,)# ---------- 定义三个Task ----------# 产品经理的任务,输入是原始需求,输出是需求文档pm_task=Task(description=("分析以下需求,输出一份结构化的需求文档。\n\n""需求描述: {requirement}\n\n""文档要包含以下几个部分:\n""1. 功能概述,一段话说清楚要做什么\n""2. 功能点列表,每个点具体做什么\n""3. 验收标准,怎么算做完了\n""4. 技术约束,用什么语言、有什么限制\n""5. 假设和风险,你做了哪些假设,有什么风险\n"),expected_output="一份Markdown格式的需求文档",agent=pm_agent,)# 开发的任务,输入是产品经理的输出,输出是代码dev_task=Task(description=("根据上面的需求文档,编写完整的Python代码。\n\n""要求:\n""1. 函数要有完整实现,不能只给签名\n""2. 关键逻辑加注释\n""3. 附上使用示例\n""4. 处理常见异常输入\n"),expected_output="完整的Python代码,包含注释和使用示例",agent=dev_agent,context=[pm_task],# 依赖产品经理的输出作为上下文)# 测试的任务,输入是需求文档和代码,输出是测试报告test_task=Task(description=("根据需求文档和开发给出的代码,编写测试用例。\n\n""要求:\n""1. 覆盖所有功能点\n""2. 包含正常输入、边界输入、异常输入的测试\n""3. 给出每个测试用例的预期结果\n""4. 评估代码是否满足验收标准\n""5. 输出测试报告,列出通过和未通过的项\n"),expected_output="测试用例列表和测试报告",agent=test_agent,context=[pm_task,dev_task],# 同时依赖需求和代码)# ---------- 组装Crew并运行 ----------# 创建Crew,三个Agent三个Task,串行执行project_crew=Crew(agents=[pm_agent,dev_agent,test_agent],tasks=[pm_task,dev_task,test_task],process=Process.sequential,# 串行模式,按task列表顺序执行verbose=True,)# 输入需求,启动整个流程requirement=("做一个密码强度检查工具,输入一个密码字符串,""返回强度等级(弱、中、强)和具体建议。""要求长度至少8位才算合格,包含大小写字母、数字、特殊字符的越多越强。")# kickoff启动,result是最后一个Task的输出result=project_crew.kickoff(inputs={"requirement":requirement})# 打印最终结果print("\n"+"="*60)print("最终测试报告:")print("="*60)print(result)# 如果想看中间每一步的输出,可以这样取# pm_task.output 就是产品经理Agent的输出# dev_task.output 就是开发Agent的输出print("\n"+"="*60)print("需求文档:")print("="*60)print(pm_task.output.rawifhasattr(pm_task.output,'raw')elsepm_task.output)print("\n"+"="*60)print("开发代码:")print("="*60)print(dev_task.output.rawifhasattr(dev_task.output,'raw')elsedev_task.output)

效果验证

运行这段代码,你会看到三段输出依次出现。第一段是产品经理Agent输出的需求文档,包含功能概述、功能点、验收标准这些。第二段是开发Agent输出的Python代码,一个完整的密码强度检查函数。第三段是测试Agent输出的测试报告,列出测试用例和通过情况。

判断成功有几个标准。需求文档里功能点和验收标准都齐全,没有遗漏。代码能直接复制运行,不报语法错误。测试报告覆盖了正常输入和边界情况,比如空字符串、超长密码、纯数字密码这些。

一个常见问题是CrewAI跑着跑着卡住不动。大概率是某个Agent的LLM调用超时了。检查网络和API key,确认模型能正常访问。CrewAI默认没有设超时,你可以在LLM配置里加timeout参数。

还有一个问题是Agent输出格式不稳定,有时候给你Markdown有时候给你纯文本。在Task的expected_output里把格式要求写明确,比如"一份Markdown格式的需求文档",比写"需求文档"效果好。

踩坑记录

第一个坑,Agent之间上下文丢失。一开始我没给dev_task加context参数,开发Agent拿不到产品经理输出的需求文档,自己瞎编了一个需求开始写代码。写出来的东西跟原始需求完全对不上。CrewAI的串行模式默认只把上一个Task的输出传给下一个,如果你需要更早的Task输出,得在context里显式指定。我后来给test_task同时加了pm_task和dev_task,测试Agent才能同时看到需求和代码。

第二个坑,角色定义太宽泛导致输出质量差。最早我的开发Agent backstory就写了一句"你是一个Python开发",结果它写的代码经常省略实现,给个pass就完事。后来把backstory和goal写具体了,“代码必须能直接运行,不省略关键逻辑”,输出质量才上来。角色定义越具体越好,别指望模型自己理解你想要什么。

第三个坑,串行流程太慢。三个Agent一个等一个,每个调一次大模型几秒到十几秒,跑完一遍要一分钟。如果需求复杂,产品经理拆出来的功能点多,开发Agent写一大坨代码,测试Agent再写一堆测试,整体可能要两三分钟。后来对于简单需求我把三个Agent的prompt精简了,限制输出长度,速度提升不少。对于复杂需求,可以考虑把功能点拆开,每个功能点独立跑一遍流程再合并。

延伸与判断

这个项目团队的模式可以套到很多场景。把角色换一换就行,比如内容创作团队,策划Agent出选题,写作Agent写正文,编辑Agent做润色。再比如数据分析团队,取数Agent写SQL取数据,分析Agent做统计,报告Agent出可视化报告。

CrewAI也有它的局限。复杂的条件分支和循环不好搞,比如测试不过自动回到开发重写,CrewAI的串行模式做不到,得用Process.hierarchical加一个管理Agent来控制流程,配置起来比较麻烦。对流程控制要求高的场景,还是LangGraph更合适。

还有一个现实问题,token成本。三个Agent每个都要调大模型,跑一遍需求消耗的token不少。如果频率高,成本不低。建议在prompt里限制输出长度,去掉verbose输出,简单需求用便宜一点的模型。

我的建议,先用CrewAI把标准串行流程跑通,理解角色定义和任务编排的思路。流程固定了以后,如果对控制灵活度有要求,再迁移到LangGraph自己搭状态图。两个框架的Agent定义和prompt可以复用,迁移成本主要在流程编排那块。

结尾

三个Agent组成一个项目团队,从需求到代码到测试自动跑一遍,这件事CrewAI做起来不复杂。关键是把角色定义写具体,把任务依赖理清楚,剩下的框架替你搞定。下一篇把这个团队封装成API服务,让它能被外部系统调用。