做 Agent 开发的人,大概率都经历过这么一幕:你辛辛苦苦把单个 Agent 调教得挺聪明,会规划、会拆任务、会调工具、能写代码,结果真要把它丢进业务流程里,发现根本不够用。一个人干不完一个团队的活,这是单 Agent 架构绕不过去的天花板。
这篇文章写的是慕课上一门叫「DeepAgents + MCP + A2A + Skills 超级多智能体」课程项目的核心内容沉淀,目标很明确:用 MCP 把 Agent 的"手"接长,用 A2A 让 Agent 之间能"对话派活",用 Skills 把高频能力沉淀成可复用积木,最后用 DeepAgents 把这一切串成一个可编排、可互通、可扩展的 Agent 集群。文章里没有照抄 PPT 的理论,全是落地过程中真实踩过的机制、配置和坑,适合已经跑通过单 Agent、正打算往多 Agent 集群方向走的开发者。下面按我的实操顺序来讲。
1. 单 Agent 做得再聪明,也只是"一个人干活"
1.1 我踩过的单 Agent 天花板
先说我自己踩过的坑。早期我做过一个能自动整理会议纪要、查数据库、发邮件的 Agent,单跑起来体验相当好,发出去给同事试用,大家都觉得"有点东西"。但一旦把它真正放进公司业务流程里,问题就全暴露了。
- 工具越挂越多,系统提示词越来越长,模型开始"遗忘"某些工具的正确用法,甚至自己在工具列表里瞎编参数。
- 一个任务往往要串多个系统——查 CRM、算价格、写合同、走审批,单个 Agent 的上下文窗口和推理带宽根本扛不住,做到一半就开始胡说。
- 出问题就是一锅端:Agent 在第 8 步崩了,前 7 步全白干;如果中间还有写库、发消息这类有副作用的操作,还得人工去擦屁股。
这些问题的共性,是"把太多职责塞进了同一个 Agent"。解决办法说起来也很简单——拆,让多个 Agent 各干各的。但拆完以后,更麻烦的问题来了:Agent 之间怎么互相调用?怎么共享工具?怎么避免每个 Agent 都重复造一轮轮子?这就完全进入了另一个复杂度层级,也是"多智能体"和"单 Agent"最本质的区别。
1.2 集群化绕不开的三个问题:编排、互通、扩展
把问题拆开看,多 Agent 集群要解决的无非三件事。
- 编排:谁来决定任务怎么拆、每步交给谁、结果怎么汇?这需要一层独立的"大脑"或者说控制面,而不是让 Agent 们互相猜来猜去、抢活干。
- 互通:A Agent 需要的数据在 B 那里,B 需要调的工具在 C 的机器上,它们之间怎么互相发现、互相调用?这需要一套跨语言、跨框架的标准通信协议。
- 扩展:今天集群里只有 3 个 Agent,明天要加到 30 个;今天只接 PostgreSQL,明天要接企业微信。加一个组件,能不能不动其他组件?这需要标准化的插拔机制。
课程给的答案就是标题里那四个词:MCP 管工具互通,A2A 管 Agent 互通,Skills 管能力复用,DeepAgents 管全局编排。这四个东西对应的解决的问题完全不同,把它们的分工搞清楚,整个集群的骨架就立起来了。
2. 四层技术栈分工:MCP 管手、A2A 管嘴、Skills 管脑、DeepAgents 管全局
如果你在网上搜这四个概念,很容易被各种术语绕晕。我建议用一句话记:MCP 是 Agent 伸出去干活的手,A2A 是 Agent 之间交流的嘴,Skills 是 Agent 脑内积淀的经验,DeepAgents 是统筹全局的神经中枢。各自解决一个层面,千万别混为一谈。
2.1 MCP:Agent 与外部世界的标准插头
MCP 全称 Model Context Protocol,最早由 Anthropic 开源。它解决的问题非常具体:过去 Agent 每接一个新工具,都要为它单独写一套接入代码,工具一多,维护成本直接爆炸。MCP 的做法是把"工具接入"这件事标准化——工具方只需要实现一个 MCP Server,对外暴露统一接口;Agent 侧通过 MCP Client 去连接,一套逻辑到处复用。
打个比方,MCP 之于工具,就像 USB-C 接口之于电子设备。以前每个厂商一个充电口,现在协议统一了,插上就能用。在我这个项目里接入过的 MCP Server 包括:文件系统类(读写本地目录、处理 PDF、OCR)、数据类(PostgreSQL / MySQL / SQLite 查询,查完直接返回结构化行数据)、外部服务类(GitHub 仓库操作、钉钉/企业微信通知、Figma 设计稿取数)。社区里甚至有人把 IDA、x32dbg 都搓成了 MCP 插件,用于逆向工程场景,说明这套协议的生命力确实在爆发。
现在连 Dify 这类低代码平台、ruoyi-vue-pro 这类后台管理脚手架,都开始有人做 MCP 功能合并,MCP 已经不只在 LLM 圈子里玩,而是在渗透各种业务系统。接入方式上,MCP Client 侧主要是配一个 JSON 配置文件(框架里通常叫 mcp_config.json,声明 server 的 name、command、args、env),框架会自动完成握手、发现工具、按需调用。
2.2 A2A:让 Agent 之间真正能"互相派活"
MCP 解决的是 Agent 到工具的问题,但 Agent 到 Agent 的问题它管不了。A2A(Agent2Agent)协议解决的就是后者——它由 Google 在 2025 年提出,后来捐给了 Linux 基金会,核心目标是让不同厂商、不同框架的 Agent 能够互相发现、互相通信。
A2A 协议里有两个关键概念。一个是 Agent Card,相当于每个 Agent 的"电子名片",用 JSON 描述这个 Agent 能干什么、接受什么输入、产生什么输出,供其他 Agent 发现和调用。另一个是 Task 生命周期,A2A 把一次 Agent 之间的协作建模成一个 Task,有明确的输入、状态(pending、working、completed、failed)、输出,并且支持长任务的状态查询和消息流推送。
我的理解是:MCP 是"命令式"的,你调工具、工具返回结果;A2A 是"会话式"的,Agent 之间可以来回协商、分派、汇报。两者定位差异非常清晰,别拿 MCP 去做 Agent 间通信,也别拿 A2A 去接数据库工具。另外,在 Spring 生态里,A2A 已经有 spring.ai.a2a 这样的现成 starter,Java 后端团队的接入成本很低,这也是为什么最近"a2a spring"的搜索热度突然很高。
2.3 Skills:把高频能力包成即插即用的积木
Skills 这个概念,Claude 的 Agent Skills 普及得很到位,但说实话它并不神秘:本质上就是把"一段带指令的代码/脚本/模板"打包成一个标准目录。目录里有一个 SKILL.md 写明技能说明、使用步骤、注意事项,旁边放着可执行的脚本或参考文件。Agent 在需要时加载这个技能,就能立刻按规范行事。
这里的关键在于"按需加载"。如果你把所有能力的说明都塞进系统提示词,上下文会被撑爆,模型反而什么都干不好。Skills 的做法是"渐进式披露"——只有任务需要时,才把相关技能目录内容加载进上下文。用起来很像人脑的肌肉记忆:平时不占用注意力,关键时刻自动调用。
目录结构大概是这样的:
skills/ web-search/ SKILL.md search.py templates/query_guide.md pdf-report/ SKILL.md report_tool.pySKILL.md 里写清楚元信息(name、description、适用场景)、具体操作步骤和禁忌,框架按需解析加载。现在社区里现成的 skills 是真的多,GitHub 上"find skills""skills 推荐"这类关键词热度不减,官方市场里也能直接装现成的技能包。很多团队开始把内部经验整理成 skills 发布:前端开发的、代码审查的、写论文的都有,下载下来就能直接用。这才是 skills 真正厉害的地方——经验可以打包、分发、复用。
2.4 DeepAgents:编排层把三条线串成一张网
讲完三个协议/规范,最后说 DeepAgents。这个名字在课程语境里,指的是一套面向"深度多智能体"的编排框架与设计模式——它不生产具体的智能,而是负责把 MCP、A2A、Skills 组合成一套可运行的集群。
DeepAgents 的核心职责有三块:读取全局任务并拆解为子任务;根据 Agent Card 和能力注册信息,把子任务分配给合适的 Agent;汇合子结果、处理错误与重试,产出最终答案。
很多人分不清 harness(脚手架)和 agent 的区别,我这里顺带说清楚:harness 是跑 Agent 的脚手架,负责处理 prompt 组装、模型调用、工具循环;agent 是脚手架里干活的工人;而 DeepAgents 更像是一套管理多个脚手架的集群运营体系。你可以把它理解成一个项目经理:手下有前端 Agent、后端 Agent、数据 Agent、测试 Agent,项目经理解活、派活、验活,而不是自己亲自下手写代码。
3. 集群架构落地:控制面、执行面、注册中心如何分权
理论讲完,下面讲架构。这一节是我踩坑最多的地方——一开始我把所有逻辑都揉在一个进程里,结果一扩展就乱。最终收敛下来的架构,是严格区分控制面、执行面和注册中心三个角色。
3.1 三个角色的职责边界
- 注册中心(Registry):一台轻量服务,维护所有 Agent 的 Agent Card、已挂载的 MCP Server 列表、Skills 目录索引。它不干活,只管"谁知道谁会什么"。
- 控制面(Orchestrator):接收用户请求,拆任务、派活、收结果。它是最聪明的那个 Agent,但聪明只用在"决策"上,不直接碰工具。
- 执行面(Workers):一批专职 Agent,每个 Agent 挂载自己职责范围内的 MCP Server 和 Skills。比如数据 Agent 只挂数据库 MCP 和 SQL 分析 Skill,前端 Agent 只挂浏览器 MCP 和组件生成 Skill。
这个拆分最直接的好处:某个 Worker 挂了,控制面可以把它标记为不可用,把任务转给其他同类 Worker,整个集群不至于瘫痪。职责边界清晰,也方便逐个调优——数据 Worker 慢就优化数据 Worker,不会牵连到报告 Worker。
3.2 从请求到结果:能力注册与发现的完整流程
用一个实际例子说明三者如何协作。假设用户说"帮我看下这周的销售数据,并写一份带图表的周报":
- 控制面 Agent 先解析任务,拆成三个子任务:查数据、算指标、生报告。
- 控制面查询注册中心,发现数据 Agent(挂 PostgreSQL MCP)和报告 Agent(挂文件输出 MCP)都在线。
- 控制面通过 A2A 协议向数据 Agent 发起一个 Task,传入 SQL 需求和参数。
- 数据 Agent 通过 MCP 调用数据库工具,拿到结构化结果,再通过 A2A 的 Task 状态回调回报。
- 报告 Agent 拿到数据后,加载"图表生成 Skill",通过 MCP 写入文件,返回报告路径。
- 控制面汇总,把最终结果返回给用户。
这个流程里的每一步,消息体都是标准化的。新增一个 Agent 时,只要向注册中心登记自己的 Agent Card、挂好 MCP Server 和 Skills,控制面就能在下一轮任务中发现并使用它——这就是"可扩展"的落地含义,而不是写在方案里的一句口号。
3.3 编排器的任务分解策略
任务分解是编排器最核心的能力,也直接决定集群的智商上限。课程里介绍的三角色模型,我实践后很认同:
- 分析器:把用户意图转化为目标清单,判断需要哪些能力;
- 规划器:生成 DAG(有向无环图),明确执行顺序和依赖关系;
- 调度器:把 DAG 里的每个节点分配到具体的 Worker,并跟踪执行状态。
这里有一个血泪教训:规划粒度太细,Agent 之间的 A2A 通信次数爆炸,延迟飙升;粒度太粗,单个 Agent 又退化回"大而全"的老问题。我目前的经验是,子任务控制在"一次 A2A 能完成、结果可独立验证"的粒度最合适——宁可让执行面的每个 Agent 多做几步内部操作,也尽量不要跨 Agent 做半步协作。跨 Agent 的每一次消息传递,都是潜在的失败点和延迟点。
3.4 三种通信模式怎么选
部署形态上,我分别试过三种通信模式,列个表供参考:
| 模式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 同进程内函数调用 | 验证概念、学习阶段 | 零延迟、好调试 | 无法跨语言、无法水平扩展 |
| stdin/stdout 本地进程 | 本机多 Agent、轻量生产 | 进程隔离、故障不牵连 | 不适合跨主机 |
| HTTP + A2A 协议 | 生产集群 | 跨语言、跨主机、标准协议 | 需要处理网络错误和重试 |
课程项目最终走的是 HTTP + A2A,因为要演示的正是"可互通"的价值——不同语言写的 Agent 也能协作。这一点实操章节会详细展开。
4. 从零跑通最小集群的实操记录
下面进入动手环节。按"最小可用"的原则,从空白环境搭出一套"两个 Worker + 一个控制面"的集群。全程不依赖任何商业闭源组件,都是开源工具和标准协议。
4.1 环境准备与目录设计
我用的是 Python 3.11 + Node.js 20 的混合环境,原因是有意让控制面和执行面跑在不同语言,用来验证 A2A 的跨栈能力。本地需要装好:
- Python 3.11+,用于实现 A2A 控制面和其中一个 Worker;
- Node.js 20+,用于实现另一个 Worker(顺便演示跨语言互通);
- 一个 MCP Server 实例,我选的是最常用的 Filesystem MCP;
- 一个支持 MCP Client 调用的 LLM 网关(框架里一般内嵌,选你熟悉的即可)。
目录结构建议这么搭:
agent-cluster/ orchestrator/ # 控制面 main.py planner.py workers/ >{ "mcpServers": { "filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/workspace/data"], "env": {} } } }写完后,data-worker 启动时框架会自动拉起这个子进程,完成 MCP 握手。此时做个简单的冒烟测试:让数据 Worker 列出 /workspace/data 目录。能返回目录列表,说明 MCP 链路通了。这一步如果失败,九成是 npx 下载依赖的网络问题,或者目录权限问题,先把这两点排除。
这里要特别强调环境变量:MCP Server 大多通过 env 传密钥(数据库密码、API Key),千万别直接写进代码仓库。我在课程项目里踩过这个坑,后来统一改成环境变量注入,配置文件和秘钥完全分离。生产集群里这一步是硬性要求。
4.3 打通 A2A 双 Agent 会话
接下来是重头戏:让两个不同语言的 Worker 通过 A2A 互相通信。以 A2A 协议的开源参考实现为例,每个 Worker 起一个 HTTP 端点,对外暴露自己的 Agent Card。
>{ "name": "data-worker", "description": "负责数据库与文件数据操作,可执行 SQL、读取目录", "url": "http://localhost:8001/a2a", "skills": ["sql-query", "file-read"], "capabilities": { "task": true, "streaming": true } }
report-worker 的 Agent Card 类似,只是描述换成"负责生成报告与图表"。两个 worker 启动后,访问它们的 /a2a 端点能看到各自的 Agent Card,然后让控制面去调用:
- 控制面 POST 一个 Task 到>