从单Agent到agency-agents:多智能体协作系统搭建全攻略

发布时间:2026/10/10 13:12:28

从单Agent到agency-agents:多智能体协作系统搭建全攻略 我一直不太相信给一个Agent配齐所有工具它就能搞定所有事直到自己亲手把项目标题里的agency-agents落地成一套多智能体协作系统才彻底打消了全能单Agent的执念。如果你也是在做AI Agent开发或者正在犹豫要不要从单Agent迁到多Agent协作架构这篇内容值得你花几分钟看完。我在这个项目里做的事简单说就是搭了一个代理事务所多个各司其职的Agent节点共享一套任务协议由编排器统一调度每个Agent只负责自己最擅长的那一段。为什么这么做因为我踩过单Agent的坑。第二个版本我用一个超大上下文、挂了20多个工具的万能Agent跑复杂任务结果它在5个任务步骤里迷路了3次还反复调用错的工具。后来又试了让多个Agent自由对话结果两个Agent互相踢皮球跑了几十轮也没产出。最后做到agency-agents这个方案才把任务成功率从42%拉到了比较稳的水平。不要一听多Agent就觉得复杂我先用一个看得懂的例子说清楚它到底解决了什么问题然后给你看角色设计、编排引擎、调试排错这整条链路怎么做。1. 单Agent到代理事务所的转型动机1.1 单Agent在复杂任务中的三个崩溃点先说万能Agent的问题。很多开发者最初的想法和我一样把所有工具给一个大模型靠它的推理能力自主决定调用哪个工具、执行哪几个步骤。思路没错但一旦任务链条长起来问题就一个接一个地冒出来。第一个问题是上下文记忆偏移。当任务被拆成8个步骤模型在前3步读入大量中间结果后后面的推理会慢慢忘了原始目标。我调试的时候直接把每一次调用的完整prompt打印出来对比发现第6次调用时模型已经开始自由发挥了它说根据用户的最新指令但用户根本没有给过那个指令是模型自己在历史对话里曲解出来的。第二个问题是工具切换成本太高。一个Agent挂了20个工具模型每次都要从超大函数列表里挑参数幻觉出现的概率会呈指数上升。我的调试日志里出现过它把一个文件路径写成/data/report_2023_final_final.csv而这个路径根本不存在。类似的事多了任务卡在工具调用环节的概率就会非常大。第三个问题是并行能力的缺失。单Agent只能串行处理一个复杂的调研任务如果涉及信息收集、数据分析、报告撰写三个阶段它再快也得一步步来。而多Agent架构天然可以把这些阶段拆开并行跑整体耗时能压缩一截。1.2 agency模式是怎么解决问题的所谓agency-agents就是把多个Agent组织成一个类似事务所/小团队的结构。有的Agent做规划有的Agent做检索有的Agent做分析有的Agent做复核各自有明确的任务边界和交付物格式。我用一个不那么严谨但很形象的类比一个正常人聪明不聪明和他能不能同时做前台、会计、工程师、销售是两码事。你也不可能让一个人一边接电话一边写代码一边算账而不出错。Agent也一样把职责拆给专业化的个体再通过一套任务票据来协作可控性和成功率都会好很多。1.3 什么样的任务才值得拆多Agent不是所有任务都适合拆。这就像一个3个人的小团队硬拆成10个角色反而会内耗。我自己总结的判断维度有三条判断维度适合单Agent适合agency-agents任务链条长度短3步以内长5步以上且有递归可能子任务依赖关系线性、无分叉有并行分支、有汇聚与复核容错要求可以接受中间步骤出错关键环节必须有人复核如果任务本身就只有读文件、改格式、输出三个线性步骤单Agent就够了。但如果任务是查找资料、对比多来源、生成建议、再自查一遍那拆开效率会高很多。2. 角色设计每个Agent的岗位说明书2.1 System Prompt的结构化写法在agency-agents项目里我第一步做的不是写代码而是给每个Agent写岗位说明书。这个岗位说明书就是System Prompt但我强烈不建议写一大段自然语言让模型悟而是要结构化。我自己用的模板大致是这样# 角色 你是[角色名称]负责[一句话职责说明]。 # 职责范围 你可以做 - [具体功能1] - [具体功能2] 你不可以做 - [禁止越界的动作或话题] # 输入 你收到的消息格式[约定接收的数据结构] # 输出 你必须返回以下格式的JSON { status: success | need_more_info | failed, data: { ... }, summary: 一句话执行摘要 } # 注意 - 如果信息不足必须返回need_more_info并说明缺什么。 - 只输出最终结果不输出过程思考。这个结构的好处是模型对该干什么、不该干什么、怎么交接的把握会稳定很多。我在同一个任务上做过对比自然语言描述的角色定义Agent跑偏概率大概是结构化定义的3倍左右。2.2 工具集的最小够用原则角色设计里第二个坑是工具泛滥。我最初给检索Agent挂了搜索、读网页、读PDF、读数据库、读Excel五个工具结果它经常把读Excel当成读网页来用报错之后又开始重试。后来我做了减法每个Agent最多挂3个工具而且工具描述里明确写了输入必须是可见清单中的路径或关键词禁止自行拼接路径。比如检索Agent只留了搜索和读取网页两个工具分析Agent只留了读入结构化数据、调用统计函数、输出报告三个工具。工具之间的边界清晰之后参数幻觉的出现频率明显下降。核心原则是Agent能看到的工具越少它就越不会瞎猜。2.3 角色之间的交接协议任务票据多Agent协作里Agent之间传递的不是自然语言那么随意的东西而是一张任务票据。我用JSON协议来定义字段不多但必须严格{ task_id: TASK-20250112-001, origin_agent: planner, target_agent: researcher, objective: 查找近三年行业趋势数据, constraints: [必须给出数据来源链接, 只返回前5条关键趋势], context: { keywords: [智能制造, 供应链], already_known: 客户公司属于中型制造企业 }, deadline: 60, max_retries: 2 }为什么用JSON而不是直接让模型传递自然语言因为自然语言在多个Agent之间转述时信息损耗很严重。Agent B 转述给 Agent C 时会添加自己的理解和推测经过两三轮接力原始指令已经面目全非。用JSON票据每个字段都是结构化的Agent只能读取和填充不能自由发挥信息保真度会高非常多。3. 编排引擎的演进先跑通再追求优雅3.1 第一阶段静态流水线编排第一版编排引擎我用的很简单任务进来后按照一个提前定义好的DAG有向无环图顺序调度Agent。虽然项目里不让用图表但你可以把它理解成一个从左到右的流水线规划Agent做完规划交给检索Agent检索完成后交给分析Agent最后汇总Agent输出结果。每个阶段用一个任务队列接住Agent从队列里取任务、执行、回写结果。伪代码如下import json import queue import threading class TaskTicket: def __init__(self, task_id, target_agent, payload): self.task_id task_id self.target_agent target_agent self.payload payload self.status pending self.result None class Orchestrator: def __init__(self): self.queues {} # agent_name - queue.Queue self.results {} # task_id - result self.registry {} # 注册所有Agent def register_agent(self, name, agent_func): self.queues[name] queue.Queue() self.registry[name] agent_func def dispatch(self, ticket: TaskTicket): self.queues[ticket.target_agent].put(ticket) def run_worker(self, agent_name): def worker(): while True: ticket self.queues[agent_name].get() if ticket is None: break result self.registry[agent_name](ticket.payload) self.results[ticket.task_id] result ticket.status done t threading.Thread(targetworker, daemonTrue) t.start()这种方式的好处是逻辑简单、每个环节都可控。坏处是一旦某个前置节点失败后面所有节点都会卡住。所以我又加了一层超时重试机制某个Agent超过deadline没返回编排器直接把这张票据标记为失败并触发重试重试两次之后还不行就直接走降级逻辑。3.2 第二阶段加入路由器与复核员静态流水线跑通之后我遇到了一个新问题规划Agent输出的任务序列不一定是最优的有些任务明明可以并行它却串行排了。于是我在规划Agent和具体执行Agent之间加了一个路由器角色。路由器的职责很简单读懂规划Agent产出的任务票据按依赖关系判断哪些可以并行哪些必须串行然后决定并行分发货还是逐个转交。加了这个环节后任务总耗时能缩短大概30%到40%。同时我在所有任务集合到最终汇总Agent之前加了一个复核Agent。它不参与具体工作只做检查结果里有没有数据来源、有没有逻辑断层、有没有字段缺失。发现异常就驳回给对应Agent重新执行。这个设计在agency-agents里是最重要的一个节点。因为多Agent系统最怕的就是一路顺畅地做到最后结果发现第一步就错了。有了复核Agent低级错误能提前被截住。3.3 为什么我不用完全自治的Agent动态规划不少框架支持让大模型自己决定调用哪个Agent、自己决定下一跳这听起来很酷但我实测下来发现模型在10步以内的任务里动态规划失误率依然很高而且一旦失误排查成本非常大。它的决策过程藏在模型的权重里你根本看不到它为什么把任务转给了错误的Agent。所以我的建议是在工程落地上先用确定性的代码控制流转规则把大模型的创造力限制在内容生成和工具参数选择这些局部环节里不要赌它的全局调度能力。等任务量大了、数据积累多了再一点点放开自主性都来得及。下面是三类编排方式的对比可以直接当选题参考编排模式可控性运行开销适用场景静态流水线最高低流程固定、依赖明确路由器 复核中高中复杂度上升后的主流选择完全自治动态规划低高且难以预测探索性任务、可以丢弃结果4. 多Agent协作最容易翻车的三个环节这一节是重点中的重点。我在agency-agents项目里踩过的坑每一个都值得写进你自己的避坑清单。以下三个问题如果你在多Agent协作里遇到了基本都能对号入座。4.1 上下文膨胀导致角色越界第一个坑是上下文被上一手Agent的内容污染。现象是Agent B 在生成输出时突然以 Agent A 的口吻说话甚至直接复述 Agent A 的思考过程。排查链路是这样的我先在编排器里给每个Agent记录它实际收到的消息原文然后定位到出问题的某个Agent发现它的输入里包含了上一个Agent 3轮完整推理过程的全部文本而这些推理步骤根本不该流入。模型看到这些文本后自然就学习了上一位Agent的口吻开始越界发挥。修复方案有两个方向一是压缩流转信息所有Agent之间只传任务票据和最终交付物不传过程推理二是把短期记忆从统一大上下文改为项目级隔离的独立存储每个Agent只读取自己专属的记忆片段。我两件事都做了角色越界问题基本绝迹。4.2 工具参数幻觉请求里全是影子文件第二个坑出在工具调用上。某个Agent在执行读取数据文件这个动作时生成了一个不存在的路径。它自己却非常自信连着重试了三次同样的错误参数。排查方式很典型我在工具调用层打印了完整的入参和报错信息发现报错的路径模式并不存在于任何工具描述或列表里纯粹是模型脑补的。我又翻了它前几步的输出确认它并没有从任何前置节点拿到过这个路径。根本原因有两个一是工具介绍里没有写清楚可用文件的枚举清单模型不知道有哪些合法路径就只能猜二是Agent处于一个太自由的状态参数填错后没有任何校验层拦它。修复时我在工具入口加了强制入参校验层用JSON Schema和枚举值检查所有字段from pydantic import BaseModel, ValidationError, Field class FileReadParams(BaseModel): file_path: str Field(pattern^/data/raw/[a-z0-9_]\.csv$) encoding: str utf-8 def safe_tool_call(agent_name: str, tool_name: str, raw_params: dict): try: validator TOOL_VALIDATORS.get(tool_name) if validator: params validator(**raw_params) else: params raw_params return TOOL_MAP[tool_name](**params) except ValidationError as e: log_agent_warning(agent_name, tool_name, str(e)) return {error: invalid_params, detail: str(e)}同时在Agent的System Prompt里固定写入当前可用的文件清单和参数值必须从中选择的硬约束。两件事加一起参数幻觉率下降了至少70%。4.3 Agent之间的死循环与数据炼金第三个坑是死循环。现象很常见Agent A说信息不够需要更多数据Agent B收到这个请求后说请先给我确定的分析目标然后再传回去两个Agent就一直在交换需求确认的票据谁也推进不了。我调试的时候数了一下两个Agent最夸张的一次来回踢了11轮每次都只是重复表达对方已经知道的信息。这本质上是因为它们都被允许在信息不足时申请更多材料但没有一条规则说你不可以重复申请同一类材料。修复可以分三步加入最大往返次数限制比如同一任务最多路由3次超过后直接返回人工介入标志。要求每次返回的信息必须携带新增字段或状态变化如果和上一轮内容完全重复就判定为死循环并终止任务。在任务票据里增加一个iteration_count字段每次转交时递增方便追踪卡在哪个节点。还有一个和死循环相关的隐藏问题我把它叫数据炼金Agent B 对 Agent A 的结果做了轻微改写然后声称这是新发现。如果没人检查内容是否真的新增了信息这种假进展会一路伪装成成功。复核Agent的职责里有一条就是对比前后版本的相似度相似度高于阈值就判定为无效周转。5. 工程化调优从Demo到可稳定复现5.1 关键参数的配置经验多Agent系统并不是模型越强越好很多时候是参数配比问题。我自己用的参考参数如下参数项规划Agent执行Agent复核Agent温度0.20.40.1每任务最大生成token15003000800单步超时60s180s45s最大重试122温度这一项我吃过亏。规划Agent如果温度太高输出的任务拆解会天马行空复核Agent如果温度太高会连正确结果都判成不够好然后打回重做。所以规划、复核这两类Agent的温度都压得很低执行Agent稍微放开一点温度让它有一定创造性。5.2 成本与延迟的取舍多Agent系统的一大痛点是token消耗翻倍因为同一个任务要经过多个Agent每个Agent都要把任务描述、上下文、工具描述算一遍token。我的应对策略如下用轻量模型做路由和分类。路由器这种逻辑判断型任务不需要很强的大模型一个体量小很多的模型就能跑得很好成本能省不少。用主力模型做复杂推理。规划、分析、报告生成这些环节再换回强模型。复用任务票据中的公文字段。所有Agent共享的项目背景不重复塞进每个Agent的prompt里而是只在首次调用时注入后续通过索引引用。实测下来在任务质量不降的前提下成本大概能省30%到40%。5.3 可观测性给每次调用挂一条链路ID多Agent系统debug起来非常痛苦因为你不知道错误是在哪个Agent产生的。我一开始的排查方式是逐个看日志效率极低。后来我给每次任务生成一个全局链路IDrequest_id所有Agent的输出、工具调用、报错都带上这个ID然后整理成下表这种状态视图request_id | task_id | agent_name | step | status | elapsed_ms REQ-1001 | TASK-01 | planner | split | ok | 1150 REQ-1001 | TASK-01 | researcher | search | ok | 2200 REQ-1001 | TASK-01 | researcher | read_page | failed | 3100 REQ-1001 | TASK-01 | orchestrator | retry | ok | 4200有了这个视图我可以秒级定位到哪个Agent、哪一步、为什么失败而不需要盲猜。这个基建虽然做起来有点工作量但绝对值得尤其当你的系统跑起来之后调试多Agent问题的成本会不成比例地高。多Agent系统的调优不是一蹴而就的。我在一个内部测试集上做过对比初始方案单Agent加全量工具任务成功率为42%拆成初步的agency-agents架构后升到61%加入路由器与复核Agent后到了80%再做上下文隔离和参数校验后稳定在89%。这个提升足够说明问题也用不着昂贵的模型。6. 接下来可以往哪些方向扩展6.1 长期记忆与项目级知识库当前版本里每个Agent只有短期记忆也就是任务票据和当次结果中的上下文。遇到跨项目的相似任务每个项目都得从零开始。扩展方向是给系统加一个长期记忆层按项目维度存向量索引Agent启动时可以查询这个项目之前有没有做过类似的事。6.2 人在环上的审批节点不是所有环节都适合让Agent自主完成。我在规划Agent给出一份任务分解后加了可选的审批节点使任务处于待审批状态人工确认后才进入执行队列。这样虽然会引入人工延时但对高价值任务来说安全性的收益远大于速度损失。6.3 人机混合的复核模式复核Agent的判定标准有时候让模型自己拍板不靠谱所以我在复核环节预留了置信度字段。复核Agent给结果打一个置信度分数低于某个阈值时自动把结果转给人工评审队列而不是直接打回重做。这能减少低质量任务反复折腾Agent的时间也可以让人工精力花在最需要判断的地方。最后说一个最接地气的经验。如果你也是从零开始搭一套这样的系统建议第一版只设计三个角色规划Agent、执行Agent、复核Agent。先把这三者之间的票据协议跑稳定再逐步加角色。一上来就设计七个Agent结果只会是多花几倍的调试时间。另外一个小技巧每个Agent的System Prompt里最好明确写上一句如果输入信息不完整优先从任务票据中补充其次向编排器申请不要自行发挥假设。这句话能帮你挡掉很多无谓的幻觉。
延伸阅读

更多相关文章

2026/10/10 13:12:28

Linux磁盘分区与LVM管理核心考点:从设备命名到备份恢复实战

2. 模块一:磁盘与分区核心考点2.1 磁盘设备的命名规则很多初学者一上来就被 /dev/sda、/dev/nvme0n1 这种设备名搞晕。实际上命名规则并不复杂,理解了规律之后基本不需要死记硬背。传统的 SATA/SAS 接口硬盘采用 sd 前缀命名,后面跟一个英文字…

2026/10/10 13:12:28

大学生网购行为调查数据挖掘:从问卷到Python分析实战

简介:这份调查报告文档面向高校学生、市场调研人员及电子商务相关课程的学习者,围绕大学生网络购物行为展开系统梳理,可用于课程作业参考、论文数据引用或校园消费调研的模板借鉴。资源包共1个doc文件,大小约1.49MB,内…

2026/10/10 13:12:28

Windows电脑没声音的5层排查法:从硬件到应用的系统化诊断

1. 为什么“电脑没声音”这个问题总在最要命的时候爆发?我见过太多次:线上会议刚连上,对方说“听不到你声音”,你手忙脚乱点开音量图标——它灰着;剪辑好的视频导出后播放,耳机里只有电流声;孩子…

2026/10/10 15:23:12

程序员真实工作流:从写代码到让系统持续运转

1. 这不是职业说明书,而是一份“程序员生存实录”“程序员是做什么的”——这个问题我被问过至少两百次。问的人里,有刚高考完填志愿的高中生,有想转行的35岁销售主管,有给孩子挑兴趣班的家长,甚至还有某高校教务处老师…

2026/10/10 15:23:12

WinCC用户归档实战:从建表到SQL查询的完整指南

简介:WinCC用户归档案例是一份面向工业自动化工程师的SCADA数据管理实践资源,聚焦西门子WinCC中用户归档功能与动作、标准模块的协同应用。资源通过具体项目演示如何配置归档触发条件,利用动作响应变量变化或按钮事件来启动归档,同…

2026/10/10 15:23:12

个人知识管理进阶:从笔记库存到可调用资产的版本迭代实践

“1.27的学习笔记”这个标题,如果你以为是某个人在某年1月27号随手记的流水账,那恐怕要失望了。对我来说,“1.27”是我个人知识管理系统的版本号——从我开始正经搭这套学习笔记体系起,已经迭代到第1.27个小版本了。这篇笔记不打算…

2026/10/10 15:23:12

SAP BTP ABAP环境证书配置实战:从信任链到TLS排障的完整指南

从一次半夜的“证书报错”说起。我负责的一个ABAP环境(SAP BTP ABAP environment)集成项目里,某天凌晨出站接口突然大面积失败,日志里只有一句话:证书校验失败。当时大家第一反应都是“证书不是云平台自动管的吗&#…

2026/10/10 15:23:12

SOAP/OData/Event错误日志业务目录:角色分配与权限治理实战

我先把这个标题拆开聊两句。很多人一看到“SOAP / OData / Event 错误日志业务目录”这种说法,第一反应是“这不就是给接口配几个错误码嘛”,结果真正上手才发现,事情远没有那么简单——数据接口报错不是只有一个日志文件,而是散落…

2026/10/10 15:18:11

编译原理实验:手写DFA词法分析器与递归下降语法分析器实践

简介:一份面向计算机专业学生与编译器初学者的C实现资源,围绕编译原理课程中的核心实验展开,完整演示了词法分析器与语法分析器的设计与编码过程。压缩包共9个文件,包括两个cpp源程序、两个可直接运行的exe程序,以及文…

2026/10/10 7:31:36

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/9 20:15:56

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/8 6:05:44

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 0:04:53

从逻辑门到计算机:数字电路核心原理与全加器搭建实战

如果你拆过一台旧电脑的主板,盯着那些黑乎乎的小芯片看上一会儿,可能会冒出同一个疑问:这堆引脚密集的元件,到底是怎么“变”出那么复杂的应用的?答案并不在某个神秘的部件里,而是在所有芯片内部都在反复使…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑