前两天我把一个叫"DeepAgents + MCP + A2A + Skills 超级多智能体"的课程项目从头到尾啃了一遍,还顺手把它从 demo 改造成了一套能接真实业务的 Agent 集群。这套组合之所以值得花时间研究,是因为它几乎把当下多智能体领域最重要的四块拼图凑齐了:MCP 统一工具接入,A2A 统一智能体之间的通信,Skills 统一能力沉淀,DeepAgents 负责把这一切编排成可调度的整体。
这篇文章就是完整复盘,覆盖架构选型、协议细节、代码实现、排坑实录,目标是让看完的人能自己搭一套多智能体集群。适合三类人:刚接触 Agent 开发想找路线的,已经用单个 Agent 但觉得它搞不定复杂任务的,以及在团队里推 Agent 基建但不知道怎么下手的技术负责人。
1. 为什么单 Agent 不够用,集群化才是出路
1.1 单 Agent 的上下文墙与职责混乱
单个 Agent 的本质是"大模型 + 工具 + 记忆 + 循环"。让它查天气、写周报、算个税,体验都还不错。可一旦任务变成"从二十个数据源里抽数据、交叉验证、生成报告、再按角色分发",问题立刻暴露:上下文被撑爆,工具调用链越拉越长,中间任何一步出错都要从头排查。
真正的问题不是模型能力不够,而是所有职责堆在一个循环里。让一个人同时当采购、会计、销售总监,流程一复杂必乱。Agent 也一样——上下文窗口是稀缺资源,塞进去的历史越多,模型注意力越分散,关键信息反而容易被淹没。更现实的是成本,长上下文的 token 消耗是按次计费的,单 Agent 硬扛复杂任务,费用增长几乎是线性的。
1.2 "拆"是核心,不是"多"
多智能体的核心不是把一堆 Agent 堆在一起,而是"拆"。把大任务拆成子任务,子任务按专长分配给不同 Agent,编排者负责合并结果。拆得好,每个 Agent 的上下文都干净,工具职责清晰,出错能定位到具体环节,重跑的成本也低。
但拆的前提是标准化能力。工具接入要标准,否则每个 Agent 各写各的连接器;Agent 之间通信要标准,否则互相调 API 变成蜘蛛网;经验沉淀要标准,否则换个模型所有调优白费。这就是标题里四件套的由来:MCP 管工具,A2A 管互通,Skills 管沉淀,DeepAgents 管编排。四者缺一个,集群就会退化成"一堆脚本互相调接口",比单 Agent 更乱。
2. MCP、A2A、Skills、DeepAgents 各管哪一段
2.1 MCP 管"用手":把工具接入变成标准接口
MCP(Model Context Protocol)由 Anthropic 开源,解决的是模型连接外部工具和数据源难的问题。拿生活类比:以前每个 AI 应用想接数据库、接浏览器、接内部 API,都得单独写适配器,就像每个设备配一种充电线。MCP 相当于把充电口统一成 USB-C,服务端暴露标准接口,客户端统一消费。
需要强调一点,MCP 是软件协议,不是硬件协议,理解成 HTTP 那种应用层协议更准确。它定义了三种角色:Host(宿主应用,比如 IDE 插件或 Agent 运行时)、Client(负责与 Server 建立会话)、Server(暴露工具、资源、提示词)。传输层有两种,本地用 stdio,远程用 Streamable HTTP。
在集群架构里,MCP 就是 Agent 的"手"。我实际测试下来的体感是:这个协议最大的价值不是技术多深,而是生态。以前接一个内部系统要写一整条链路,现在对方只要提供一个 MCP Server,所有 Agent 都能直接用。国内不少后台管理框架把 MCP 能力合并进主线,也印证了这个趋势——它正在从 AI 圈往传统软件圈渗透。
2.2 A2A 管"交棒":Agent 之间说同一种语言
A2A(Agent2Agent)是 Google 在 2025 年推出的开源协议,和 MCP 正好互补。MCP 解决 Agent 连工具,A2A 解决 Agent 连 Agent。它基于 JSON-RPC 2.0 和 HTTP,几个核心概念需要先记住:
- AgentCard:一个 JSON 文件,描述自己是谁、能干什么、怎么连接。相当于 Agent 的名片。
- Task:任务的状态机,包括 submitted、working、input-required、completed、failed 等状态。
- Message:Agent 之间传递的具体内容。
- Artifact:任务产生的结构化产物,比如文件、表格、代码片段。
一个 Agent 拿到对方的 AgentCard,就知道它能不能接这个活,然后发 Task 过去,通过轮询或回调拿结果。简单讲,MCP 让 Agent 长了手,A2A 让 Agent 有了互相交接工作的规矩。我刚开始学的时候总把两者搞混,后来用一句话记住了:MCP 是 Agent 和工具之间的语言,A2A 是 Agent 和 Agent 之间的语言。
2.3 Skills 管"经验":把会做的事打包成可复用单元
Skills 这个概念各家实现略有差异,但本质一致:把一组指令、模板、脚本、校验规则打包成一个目录,让模型按需加载。
最典型的是 Anthropic 提出的 SKILL.md 规范——一个文件夹就是一个 Skill,里面用 Markdown 描述能力、适用场景、操作步骤,模型读到后知道什么时候该调用它,怎么调用它。
实际项目里,我会把"周报生成""代码审查""SQL 优化""竞品信息抽取"这类高频动作做成 Skills,让多个 Agent 共享。Skills 的价值在于把隐性经验显性化:老员工怎么写的周报、团队代码审查关注哪些点,都可以被固化下来。它是 Agent 的肌肉记忆,也是团队知识沉淀的载体。
值得一提的是,市面上已经出现不少现成 Skills 市场,比如 Claude 官方市场、社区维护的 skills 仓库,甚至有人把特定行业方法论也打成了 Skill。后面实操部分我会演示一个完整的 Skill 包长什么样。
2.4 DeepAgents 管"编排":集群的调度中枢
DeepAgents 在这里不是一个特定开源项目的名字,而是一类"深度智能体编排"思路的代号。它的职责是拆解目标、派发任务、收集结果、校验质量、异常重试。
一句话总结四者关系:MCP 让 Agent 聪明地用手,A2A 让 Agent 互相交棒,Skills 让 Agent 记住怎么把事做好,DeepAgents 决定谁在什么时候做什么。
3. 集群架构怎么设计才扛得住真实业务
3.1 三层角色划分
我搭的这套集群采用经典三层结构,每一层职责单一,方便独立扩容:
- 协调层:DeepAgents 编排器。负责接收用户目标、拆分子任务、调度执行 Agent、汇总校验。这是整个集群唯一能"看到全局"的地方。
- 执行层:多个专业 Agent。每个 Agent 只负责一个领域,比如订单 Agent、售后 Agent、内容生成 Agent。它们之间不直接通信,只和协调层通信。
- 资源层:MCP Server 群和 Skills 库。MCP Server 提供可调用的工具和数据源,Skills 库提供可复用的操作流程。
这种分层最大的好处是:任何一个执行 Agent 挂了,协调层可以直接把任务重新派给同类的另一个实例;任何一个 MCP Server 出问题,只影响依赖它的 Agent,不会拖垮整个集群。
3.2 编排模式怎么选
多 Agent 的编排模式大致有四种,各有适用场景:
- Pipeline(流水线):适合有固定顺序的流程,比如"抽取数据 → 清洗 → 分析 → 生成报告",前一个 Agent 的输出是后一个的输入。
- Map-Reduce(并行汇总):适合大量独立子任务,比如让十个 Agent 分别分析十个竞品,再统一汇总。
- Supervisor(主管模式):一个老板管多个下属,老板负责拆解和验收,下属只干活。这是最常用的模式。
- Debate(辩论模式):多个 Agent 从不同角度审视同一个问题,适合需要交叉验证的决策场景,比如风险评估。
我的经验是:真实业务很少只用一种模式。订单售后这个场景,我用的就是 Supervisor 为主、Pipeline 为辅——编排器先把任务拆成"订单查询"和"售后判断"两条线,售后判断那条线内部再走两步流水线。建议新手先从 Supervisor 模式起步,因为它最符合人对"项目经理"的理解。
3.3 通信拓扑与部署边界
Agent 之间的通信拓扑一定要用 Hub-Spoke 模式,而不是全连接。全连接看起来灵活,但每个 Agent 都要维护对所有人的连接配置,排查问题的时候谁都在跟谁说话,根本定位不了。Hub-Spoke 下,所有 A2A 流量都经过协调层,日志集中,问题链路清晰。
部署边界有几个细节值得注意。MCP Server 尽量独立进程部署,别跟 Agent 塞在同一个进程里,否则一个工具崩溃可能带着 Agent 一起挂。Skills 仓库用统一版本管理,每次更新走发布流程,避免不同 Agent 用了不同版本的操作流程。所有 Agent 的地址配置放在一个注册中心或者配置中心里,不要硬编码。
4. 实操:搭一个能跑的三 Agent 集群
4.1 环境准备与技术选型
我的技术栈选用 Python 3.11 + uv + FastAPI,核心依赖是 mcp 和 a2a-sdk。
uv init agent-cluster uv add "mcp[cli]" a2a-sdk fastapi uvicorn httpx选 Python 没什么悬念,MCP 和 A2A 的官方 SDK 生态最成熟的就在 Python。FastAPI 用来承载 A2A 的 HTTP 端点。
4.2 写一个完整的 Skills 包
我先写一个"订单状态速查"Skill。目录结构如下:
skills/order_skill/ ├── SKILL.md ├── scripts/ │ └── check_order.py └── templates/ └── summary.mdSKILL.md 是核心,它告诉模型这个 Skill 是干什么的、什么时候用、怎么用:
--- name: order_status_check description: 快速查询订单状态并生成用户可读的摘要。当用户询问"我的订单到哪了""发货没"时使用。 when_to_use: 订单查询、物流状态、售后入口判断 --- # 订单状态速查 ## 使用步骤 1. 调用 MCP 工具 `query_order` 获取原始订单数据。 2. 根据 `status` 字段映射为用户可读文案: - PENDING → 待支付 - SHIPPED → 已发货 - DELIVERED → 已签收 - REFUNDED → 已退款 3. 使用 templates/summary.md 中的格式生成回复。关键点在于when_to_use字段。模型靠它判断什么时候加载这个 Skill,写得太泛模型会误用,写得太窄又容易被忽略。我踩过的坑是刚开始只写了 description,没有写反例,结果模型在用户问"退款政策"的时候也去加载订单查询 Skill,白费上下文。
4.3 用 MCP Server 暴露工具
接下来写一个订单服务的 MCP Server。这里用的是 FastMCP 这个高层封装,写起来非常快:
from mcp.server.fastmcp import FastMCP mcp = FastMCP("order-service") @mcp.tool() def query_order(order_id: str) -> dict: """按订单号查询订单状态与金额。 Args: order_id: 订单号,格式如 ORD-2025-0001 """ # 实际项目中这里替换为数据库或内部 API 调用 return { "order_id": order_id, "status": "SHIPPED", "amount": 299.00, "tracking_no": "SF1234567890", } if __name__ == "__main__": mcp.run(transport="stdio")然后把它注册到 Agent 的配置里。我在 Agent 用的配置文件中加入:
{ "mcpServers": { "order-service": { "command": "python", "args": ["services/order_mcp_server.py"] } } }这里解释一个很多新手会问的点:MCP 工具函数的 docstring 不是给人看的注释,是给模型看的说明书。模型的工具选择依赖函数名和 docstring 的语义匹配,写得好不好直接影响工具调用准确率。我在测试中发现,把参数格式和示例写进 docstring 后,工具调用成功率大概提升了三成。
4.4 用 A2A 把 Agent 暴露成服务
现在做一个订单 Agent,通过 A2A 协议暴露能力。核心是两件事:提供 AgentCard,处理 Task。
AgentCard 是一个 JSON 文件,相当于名片:
{ "name": "order-agent", "description": "负责订单状态查询与售后前置判断,可并行处理多个查询请求。", "url": "http://localhost:8001/a2a", "skills": ["order_status_check", "refund_check"], "capabilities": { "streaming": false, "pushNotifications": false } }服务端处理 Task 的简化代码:
from a2a.sdk import A2AClient, A2AServer from a2a.types import Task, Message, TaskStatus def handle_task(task: Task) -> Task: # 从消息里提取用户问题 user_text = task.messages[-1].content # 这里会触发模型调用,模型根据 Skills 决定是否调用 MCP 工具 result = run_agent_with_skills(user_text) task.status = TaskStatus.COMPLETED task.artifacts = [{"type": "text", "content": result}] return task server = A2AServer( agent_card=load_agent_card(), handle_task=handle_task, ) server.run(host="0.0.0.0", port=8001)A2A 的好处在这一步体现出来:协调层不需要知道 order-agent 内部是怎么实现的,它只需要读 AgentCard,发 Task,收结果。Agent 内部用的什么模型、什么 Skills,完全透明。
4.5 编排器调度逻辑
最后是 DeepAgents 编排器。它要做的核心事情是三步:拆解、派发、汇总。我用一个大模型做"拆解",用 A2A Client 做"派发",再做一次"汇总校验":
import asyncio from a2a.sdk import A2AClient AGENTS = { "order": A2AClient("http://localhost:8001/a2a"), "refund": A2AClient("http://localhost:8002/a2a"), } async def run(user_request: str): # 1. 拆解:让编排模型输出子任务清单 plan = coordinator_llm.decompose(user_request) # plan 示例: [{"target": "order", "query": "查询订单 ORD-2025-0001"}, ...] # 2. 并行派发 async def dispatch(item): client = AGENTS[item["target"]] return await client.send_task(item["query"]) results = await asyncio.gather(*[dispatch(item) for item in plan]) # 3. 汇总:让编排模型合并结果并校验完整性 final_answer = coordinator_llm.merge(plan, results) return final_answer这段代码是整个集群的中枢。实际项目里还要加超时控制、重试、结果校验(比如让另一个 Agent 检查报告里有没有遗漏数据),但这些是加固项,核心骨架就是拆解、派发、汇总这三板斧。
5. 常见问题与排查技巧实录
5.1 问题速查表
把我在实操中遇到的高频问题整理成了下表,基本覆盖了集群搭建初期 90% 的坑:
| 现象 | 排查思路 | 解决方案 |
|---|---|---|
| MCP 工具列表为空 | 先看 Server 进程是否存活,再看 client 是否连上 | 用mcp dev单独调试 Server,确认工具注册成功后再接 Agent |
| A2A 握手失败 | 抓 HTTP 请求看 AgentCard 能不能正常返回 | 检查 AgentCard 的url是否可达,确认端口和路径一致 |
| Skills 不生效 | 看模型有没有读到 SKILL.md 的when_to_use | 在 prompt 里显式声明可用 Skills 清单;检查目录命名是否被忽略 |
| 并发请求一多就超时 | 看下游 MCP Server 和 Agent 的并发上限 | 给编排器加信号量限流,给 A2A 请求加超时与指数退避重试 |
| 上下文越调越长 | 看是不是把历史全塞进上下文 | 用 Message 摘要代替完整历史,只保留关键产物 Artifact |
| Agent 进入死循环 | 看日志里重复执行同一工具 | 设最大调用次数上限,循环超过阈值就返回 failed |
5.2 几个值得单独说的坑
第一个坑是 MCP Server 的并发隔离。刚开始我把所有 MCP Server 都串在一个进程里,结果一个工具阻塞,所有 Agent 都卡住。后来改成"一个 MCP Server 一个进程 + 独立连接池",情况立刻好转。工具类 MCP 和自动化类 MCP 要分开部署,前者要求低延迟,后者允许长任务,混在一起互相拖累。
第二个坑是幂等设计。A2A 的 Task 重试机制会带来重复执行问题。比如订单查询是幂等的没问题,但"生成退款单"这种写操作如果被重试两次,就会产生两笔退款单。我的做法是给每个 Task 加 request ID,在 Agent 内部做去重,同一个 ID 的重复请求直接返回上一次的结果。
第三个坑是关于 Skills 和模型的适配问题。不同模型对 SKILL.md 格式的敏感度不一样,有的模型能自动遵循,有的模型需要你显式把 Skills 列表写进系统提示词里。别指望协议一接就万事大吉,实测调整 prompt 结构能解决大部分"模型不听话"的问题。另外注意不同客户端对 Skills 的实现有差异,跨环境迁移时先做好兼容验证。
6. 个人经验与后续扩展
这套集群从搭起来到现在跑了两个多月,我最深的体会是:多智能体的复杂度不在单个组件,而在组件之间的接口约定。MCP、A2A、Skills 之所以重要,不是因为它们多先进,而是它们把"接口"这件事提前标准化了。你在设计阶段省下的每一次联调,都是后期运维阶段的救命稻草。
给想上手的人三个建议。第一,先小后大,别一上来就搞十个 Agent,先用一个协调者加两个执行者跑通一个端到端场景,再逐步加角色。第二,日志先行,把协调层的拆解结果、派发记录、汇总结果都结构化落盘,出了问题能按 Task ID 回溯全链路,这比任何调试工具都管用。第三,把 Skills 当产品维护,定期根据真实使用反馈修订 SKILL.md 的描述和步骤,好的 Skills 库是整个集群最有价值的资产。
这套架构后续还可以往几个方向扩展:给协调层加记忆能力,让它记住用户偏好;把 MCP Server 接进消息队列,让 Agent 能处理异步任务;或者给 Skills 库加评分机制,让集群自己淘汰不好用的 Skill。多智能体的路还很长,但先把协议层做扎实,后面怎么长都不会歪。