当前位置: 首页 > article >正文

【AI Agent工程实战系列⑤】多Agent系统:比单Agent难的不是技术而是协调

多Agent系统:比单Agent难的不是技术而是协调AI Agent工程实战系列 · 第05篇 / 共10篇Orchestrator模式、任务分解、冲突解决、结果聚合以及为什么大多数多Agent系统最终退化成了单Agent一个让我们返工三周的架构决策去年我们给一个法律科技公司搭了一套合同审查系统。需求很清楚:上传一份合同,AI自动识别风险条款、检查合规性、对比行业标准条款、生成修改建议。四个任务,我们自然地想到用四个Agent:Demo效果出色,四个Agent各司其职,输出丰富。但上线之后问题来了:风险识别Agent认为第7条是严重风险,修改建议Agent却建议"轻微调整措辞即可"——两个Agent的结论互相矛盾,用户不知道听谁的合规检查Agent和条款对比Agent都需要读原始合同,但它们拿到的"原始合同"版本不一样——前一个Agent处理时做了格式清洗,后一个Agent用的是原始版本,导致段落编号对不上整个流程串行执行,四个Agent加起来要等90秒,但其实风险识别和合规检查完全可以并行某个中间Agent失败了,后续Agent拿到的是空输入,但它不知道,继续生成了一堆基于空输入的"建议"这四个问题,一个都不是模型能力的问题。全是协调问题。多Agent的本质:分布式系统的所有问题,加上LLM的不确定性在引入多Agent之前,必须先问自己一个问题:为什么不用单Agent?这不是反问,是真实的决策依据。多Agent带来的复杂度是真实的,收益必须大于成本才值得引入。值得用多Agent的场景① 任务天然可并行,且每个子任务足够独立 例:同时分析一份文档的多个维度,各维度没有依赖关系 ② 需要专业化分工,不同子任务需要不同的工具集或System Prompt 例:一个Agent专门做数学计算,一个专门做文本生成, 混在一起会互相干扰 ③ 单个任务超过单个Agent的上下文窗口上限 例:分析一份500页的合同,需要分段处理再聚合 ④ 需要多视角交叉验证 例:医疗诊断,多个Agent从不同角度分析, 再由主Agent综合判断不值得用多Agent的场景① 任务是线性的,每步都依赖上一步的结果 → 用单Agent更简单,中间状态不需要序列化传递 ② 子任务之间高度耦合,一个子任务的输出频繁影响另一个的输入 → 多Agent的通信开销会大于并行带来的收益 ③ 团队对分布式系统缺乏经验 → 多Agent的故障排查难度远超单Agent ④ 总任务复杂度不高,3步以内可以完成 → 引入多Agent是过度设计Orchestrator模式:多Agent的标准架构所有生产级多Agent系统,最终都需要一个协调者。这个协调者叫做Orchestrator(编排器)。Orchestrator不执行具体任务,只负责协调。子Agent不做决策,只负责执行分配到的任务。这个职责分离是多Agent系统稳定运行的基础。一旦子Agent开始自行决定"我觉得应该做点额外的事",系统就开始失控。任务分解:Orchestrator最核心的能力任务分解不是"把大任务切成小块",而是要识别:哪些子任务可以并行? 哪些子任务有依赖关系,必须串行? 哪些子任务的输出需要传递给其他子任务? 哪些子任务失败后,整体任务还能继续?fromdataclassesimportdataclass,fieldfromtypingimportList,Optional,Dict,Any,SetfromenumimportEnumimportasyncioimportuuidfromdatetimeimportdatetime,timezoneclassExecutionMode(Enum):PARALLEL="parallel"# 可以并行执行SEQUENTIAL="sequential"# 必须串行执行@dataclassclassSubTask:"""Orchestrator分配给子Agent的子任务"""task_id:strname:strdescription:stragent_role:str# 分配给哪类Agent("risk_analyzer" / "compliance_checker"等)execution_mode:ExecutionMode# 依赖关系:这个子任务需要等哪些子任务完成才能开始depends_on:List[str]=field(default_factory=list)# 输入:需要哪些上游任务的输出作为输入input_from:Dict[str,str]=field(default_factory=dict)# 格式:{"参数名": "上游任务ID"},例如 {"risk_summary": "task-001"}# 容错:这个子任务失败了,整体任务是否可以继续optional:bool=False# 结果status:str="pending"# pending / running / completed / failedresult:Optional[Any]=Noneerror:Optional[str]=Nonestarted_at:Optional[str]=Nonecompleted_at:Optional[str]=NoneclassTaskDecomposer:""" 任务分解器 输入:用户的高层目标 输出:有依赖关系的子任务DAG(有向无环图) """def__init__(self,llm):self.llm=llmasyncdefdecompose(self,goal:str,available_agents:Dict[str,str],context:Dict=None)-List[SubTask]:""" 将高层目标分解为子任务列表 available_agents: {"agent_role": "agent的能力描述"} 返回的子任务列表已经包含依赖关系,可直接用于调度 """agents_desc="\n".join([f"-{role}:{desc}"forrole,descinavailable_agents.items()])prompt=f"""你是一个任务编排专家。请将以下目标分解为可执行的子任务。 目标:{goal}可用的Agent角色:{agents_desc}要求: 1. 识别哪些子任务可以并行执行,哪些必须串行 2. 明确每个子任务依赖哪些其他子任务的输出 3. 每个子任务分配给最合适的Agent角色 4. 可选任务(失败不影响整体)请标注optional=true 请以JSON格式输出子任务列表: [ { { "name": "子任务名称", "description": "具体任务描述", "agent_role": "assigned_agent_role", "execution_mode": "parallel|sequential", "depends_on": ["依赖的子任务名称列表"], "input_from": { {"输入参数名": "来源任务名"}}, "optional": false }} ] 重要:只输出JSON,不要有任何额外文字。"""response=awaitself.llm.ainvoke([{"role":"user","content":prompt}])importjson raw_tasks=json.loads(response.content)# 转换为SubTask对象,生成唯一IDname_to_id={}subtasks=[]fori,tinenumerate(raw_tasks):task_id=f"subtask-{i+1:02d}"name_to_id[t["name"]]=task_id subtasks.append(SubTask(task_id=task_id,name=t["name"],description=t["description"],agent_role=t["agent_role"],execution_mode=ExecutionMode(t["execution_mode"]),depends_on=[],# 先空着,下面填input_from=t.get("input_from",{}),optional=t.get("optional",False)))# 填入依赖关系(用ID而不是名称)fori,tinenumerate(raw_tasks):subtasks[i].depends_on=[name_to_id[dep_name]fordep_nameint.get("depends_on",[])ifdep_nameinname_to_id]# 验证DAG无环self._validate_dag(subtasks)returnsubtasksdef_validate_dag(self,subtasks:List[SubTask]):"""验证任务依赖关系不存在循环"""id_to_task={t.task_id:tfortinsubtasks}visited:Set[str]=set()rec_stack:Set[str]=set()defhas_cycle(task_id:str)-bool:visited.add(task_id)rec_stack.add(task_id)task=id_to_task.get(task_id)iftask:fordep_idintask.depends_on:ifdep_idnotinvisited:ifhas_cycle(dep_id):returnTrueelifdep_idinrec_stack:returnTruerec_stack.remove(task_id)returnFalsefortaskinsubtasks:iftask.task_idnotinvisited:ifhas_cycle(task.task_id):raiseValueError(f"任务依赖图存在循环,请检查任务 '{task.name}' 的依赖关系")

相关文章:

【AI Agent工程实战系列⑤】多Agent系统:比单Agent难的不是技术而是协调

多Agent系统:比单Agent难的不是技术而是协调 AI Agent工程实战系列 第05篇 / 共10篇 Orchestrator模式、任务分解、冲突解决、结果聚合 以及为什么大多数多Agent系统最终退化成了单Agent 一个让我们返工三周的架构决策 去年我们给一个法律科技公司搭了一套合同审查系统。需求…...

用强化学习优化CI/CD流水线:部署效率提升300%实录

测试工程师的困境与智能化的曙光在现代软件开发的快节奏战场上,持续集成与持续部署(CI/CD)流水线已成为保障软件质量与加速交付的生命线。对于软件测试从业者而言,这套流程的每一次构建、测试与部署,都是我们捍卫产品质…...

告别VLC和浏览器:用Python+OpenCV实时处理mjpg-streamer视频流的三种方法

PythonOpenCV实时处理mjpg-streamer视频流的三种实战方案 当我们需要从网络摄像头获取实时视频流进行计算机视觉处理时,mjpg-streamer是一个非常轻量级且高效的选择。与直接使用VLC或浏览器查看不同,通过Python编程获取视频流可以让我们实现更灵活的实时…...

2026降AI率工具性价比比拼:SpeedAI凭实力突围

2026年毕业季临近,不少同学都在问:现在哪款降AI工具性价比最高?这个问题其实很难一概而论,毕竟“性价比”对不同人来说标准完全不同:有人觉得单价低就是性价比高,有人觉得功能全更重要,还有人只…...

颠覆性突破:如何在Windows上无缝运行Android应用的终极指南

颠覆性突破:如何在Windows上无缝运行Android应用的终极指南 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 你是否曾渴望在Windows电脑上直接运行心仪的And…...

如何高效配置云端视频播放:115proxy-for-kodi插件实战指南

如何高效配置云端视频播放:115proxy-for-kodi插件实战指南 【免费下载链接】115proxy-for-kodi 115原码播放服务Kodi插件 项目地址: https://gitcode.com/gh_mirrors/11/115proxy-for-kodi 想要在电视上直接播放115云盘中的高清视频,却苦于没有合…...

揭秘ComfyUI-SUPIR核心技术:从架构设计到实战调优的深度解析

揭秘ComfyUI-SUPIR核心技术:从架构设计到实战调优的深度解析 【免费下载链接】ComfyUI-SUPIR SUPIR upscaling wrapper for ComfyUI 项目地址: https://gitcode.com/gh_mirrors/co/ComfyUI-SUPIR ComfyUI-SUPIR作为ComfyUI生态中专业的图像超分辨率插件&…...

解锁云端影视:115proxy-for-kodi插件让电视直连云盘视频

解锁云端影视:115proxy-for-kodi插件让电视直连云盘视频 【免费下载链接】115proxy-for-kodi 115原码播放服务Kodi插件 项目地址: https://gitcode.com/gh_mirrors/11/115proxy-for-kodi 还在为电视无法直接播放115云盘中的影视资源而烦恼吗?今天…...

LinkBoy实战:用GD32驱动彩屏做动态小项目(植物生长、中国结动画源码解析)

GD32LinkBoy彩屏动画开发实战:从图形算法到动态效果优化 在嵌入式开发领域,将静态显示升级为生动动画是许多开发者向往的里程碑。GD32系列微控制器凭借其出色的性价比和丰富的外设接口,成为中小型可视化项目的理想选择。当搭配LinkBoy这一融合…...

别再乱用connect了!Qt信号槽传参的四种实战姿势(附代码避坑)

Qt信号槽传参的四种高阶用法与避坑指南 在开发复杂Qt桌面应用时,对象间的通信往往需要传递各种参数。看似简单的connect操作,实则暗藏玄机。我曾在一个多控件编辑器项目中,因为信号槽传参不当导致内存泄漏和性能问题,调试了整整三…...

手把手教你配置STM32 IAP跳转:从BootLoader关中断到APP开中断的完整流程

STM32 IAP跳转实战指南:从BootLoader到APP的中断管理全解析 引言 在嵌入式开发领域,IAP(In-Application Programming)技术为产品固件升级提供了极大便利,但其中的跳转过程却暗藏玄机。许多开发者第一次尝试实现STM32的…...

避坑指南:Windows下WhisperX安装全流程(解决cudnn.dll报错和HuggingFace连接超时)

Windows下WhisperX实战安装指南:从环境配置到语音转文字全流程 最近在折腾语音转文字工具时,发现WhisperX这个基于OpenAI Whisper的增强版项目确实让人眼前一亮。它不仅保留了原版的识别准确度,还通过批量推理和音素对齐等技术大幅提升了处理…...

物品申领审批发放管理系统

内容目录一、详细介绍二、效果展示1.部分代码2.效果图展示一、详细介绍 物品申领审批发放管理系统是一种小型办公软件,系统由ASPACCESS/MSSQL语言开发集成,适合各种单位在物品申领审批发放管理流程登记.后台可设管理员各种人员角色权限分配。 以下是系…...

如何为AndroidPdfViewer添加PDF打印功能:完整实现指南

如何为AndroidPdfViewer添加PDF打印功能:完整实现指南 【免费下载链接】AndroidPdfViewer Android view for displaying PDFs rendered with PdfiumAndroid 项目地址: https://gitcode.com/gh_mirrors/an/AndroidPdfViewer 你是否在为Android应用中集成PDF打…...

如何免费重置Navicat Premium试用期:macOS用户的终极解决方案

如何免费重置Navicat Premium试用期:macOS用户的终极解决方案 【免费下载链接】navicat-premium-reset-trial Reset macOS Navicat Premium 15/16/17 app remaining trial days 项目地址: https://gitcode.com/gh_mirrors/na/navicat-premium-reset-trial 你…...

SAP PO实战:手把手教你用Postman测试REST接口,搞定SLD到IB的完整配置流程

SAP PO实战:从SLD配置到Postman测试的REST接口全流程解析 当你第一次在SAP PO中配置REST接口时,是否遇到过这样的困惑:明明按照教程一步步配置了SLD、ESB和IB,却在最后用Postman测试时总是报错?本文将带你深入理解每个…...

避开华为PoE供电的5个大坑:配置了poe enable为啥设备还是不亮?一次讲清功率预留、优先级与兼容性检测

华为PoE供电实战避坑指南:从配置到排障的深度解析 凌晨三点,机房告警灯突然亮起——刚部署的无线AP集体离线,监控大屏瞬间黑了一半。这种场景对网络工程师来说绝不陌生,而问题往往出在最基础的PoE供电环节。明明按照手册配置了poe…...

解密6自由度KUKA机械臂的智能搬运实战:前沿工业自动化技术深度剖析

解密6自由度KUKA机械臂的智能搬运实战:前沿工业自动化技术深度剖析 【免费下载链接】pick-place-robot Object picking and stowing with a 6-DOF KUKA Robot using ROS 项目地址: https://gitcode.com/gh_mirrors/pi/pick-place-robot 在工业4.0浪潮中&…...

别被128TB吓到!深入浅出解读Linux /proc/kcore的ELF内存布局与物理内存映射

别被128TB吓到!深入浅出解读Linux /proc/kcore的ELF内存布局与物理内存映射 第一次在终端里敲下ls -lh /proc/kcore时,那个醒目的128TB文件大小确实让我倒吸一口凉气——我的硬盘总共才1TB,这玩意儿是怎么存在的?相信不少Linux开发…...

从刷题到实战:一文搞懂C/C++进制转换(含itoa、strtol、bitset函数避坑指南)

从刷题到实战:C/C进制转换全攻略与避坑指南 引言:为什么进制转换如此重要? 记得第一次参加技术面试时,面试官抛出一道看似简单的题目:"如何将十六进制的颜色代码转换为RGB值?"当时手忙脚乱的样子…...

终极Chrome书签管理指南:如何用树状结构告别混乱

终极Chrome书签管理指南:如何用树状结构告别混乱 【免费下载链接】neat-bookmarks A neat bookmarks tree popup extension for Chrome [DISCONTINUED] 项目地址: https://gitcode.com/gh_mirrors/ne/neat-bookmarks 你是否经常在数百个杂乱的书签中迷失方向…...

好写作AI:你的“学术方向盘”,让论文写作从“换工具”变成“换车道”

打开手机应用商店,搜索“AI写作”,你会看到上百个图标。 你一个个点开,发现有的工具擅长写营销文案,有的专攻英文润色,有的号称一键生成千字论文。你试了一个又一个,写出来的东西要么像通稿,要…...

家电工厂10人设计团队应用云飞云智能共享云桌面:从3D建模到模具开发的无缝衔接

一、制造业现有困境在家电制造行业,产品更新换代迅速,设计周期不断压缩,对设计团队的协作效率和创新能力提出了更高要求。对于10人规模的家电设计团队而言,如何实现从3D建模到模具开发的高效、无缝衔接,成为提升整体竞…...

深入C++浮点数取整:除了round和ceil,你还需要了解rint和nearbyint的隐藏玩法

深入C浮点数取整:除了round和ceil,你还需要了解rint和nearbyint的隐藏玩法 在量化交易策略回测中,一个看似简单的浮点数取整操作可能导致千分之一的基础误差被放大成百万级资金偏差。某对冲基金曾因使用round而非rint函数处理欧元/美元汇率转…...

从‘亚利桑那大学多项式’到Zemax实操:一文理清Zernike条纹多项式与标准多项式的区别与选用指南

从‘亚利桑那大学多项式’到Zemax实操:一文理清Zernike条纹多项式与标准多项式的区别与选用指南 在光学设计和波前分析领域,Zernike多项式就像是一把瑞士军刀,能够将复杂的波前畸变分解为一系列正交的基函数。但当你第一次打开Zemax的波前分析…...

qPCR实验翻车实录:从扩增曲线异常到熔解曲线双峰,我踩过的坑和填坑指南

qPCR实验翻车实录:从扩增曲线异常到熔解曲线双峰,我踩过的坑和填坑指南 凌晨三点的实验室,qPCR仪嗡嗡作响,屏幕上那条扭曲的扩增曲线仿佛在嘲笑我的徒劳。这是本周第三次重复实验,熔解曲线依然倔强地分裂成双峰。作为刚…...

告别SDR时代:手把手教你配置ONFI NV-DDR接口,让NAND Flash性能起飞

告别SDR时代:手把手教你配置ONFI NV-DDR接口,让NAND Flash性能起飞 在嵌入式存储领域,NAND Flash的性能瓶颈往往源于接口技术的滞后。当项目面临启动速度不足或数据吞吐量受限时,工程师们常发现传统SDR接口已成为系统性能的"…...

从陀螺仪漂移到位置修正:图解SINS精对准中的误差传递链

从陀螺仪漂移到位置修正:图解SINS精对准中的误差传递链 在自动驾驶和无人机领域,精确的导航系统是确保安全与性能的核心。想象一下,当你的设备在复杂环境中飞行或行驶时,一个微小的陀螺仪漂移如何像蝴蝶效应般最终导致显著的定位偏…...

蓝奏云直链解析架构解析:三步实现自动化文件获取的最佳实践

蓝奏云直链解析架构解析:三步实现自动化文件获取的最佳实践 【免费下载链接】LanzouAPI 蓝奏云直链,蓝奏api,蓝奏解析,蓝奏云解析API,蓝奏云带密码解析 项目地址: https://gitcode.com/gh_mirrors/la/LanzouAPI …...

3分钟掌握Windows和Office智能激活:KMS_VL_ALL_AIO完整指南

3分钟掌握Windows和Office智能激活:KMS_VL_ALL_AIO完整指南 【免费下载链接】KMS_VL_ALL_AIO Smart Activation Script 项目地址: https://gitcode.com/gh_mirrors/km/KMS_VL_ALL_AIO 还在为Windows系统激活而烦恼吗?KMS_VL_ALL_AIO是一款开源免费…...