多智能体集群落地实战:MCP、A2A与Skills的整合之路

发布时间:2026/10/3 5:39:24
多智能体集群落地实战:MCP、A2A与Skills的整合之路
DeepAgents、MCP、A2A、Skills 这四个词单拎出来现在都有不少教程但真正把它们装进同一个多智能体集群架构里从零跑通能直接参考的实战记录其实不多。这篇文章是我从单 Agent 演示项目转向多智能体产品化的完整落地笔记MCP 管工具接入A2A 管智能体协作Skills 管经验沉淀DeepAgents 这类编排层管全局调度。它能解决什么问题如果你正在搭智能客服、自动化报表、代码生成助手这类系统或者已经受够了单 Agent 的上下文爆炸和工具互不通用这篇里的架构思路、配置示例、联调步骤和踩坑记录应该能帮你少走不少弯路。无论你是刚听说 MCP 协议还是已经在用 Skills 开发技能包下面这些内容都值得花几分钟看完。1. 为什么多智能体集群不是多开几个 Agent1.1 单智能体能力的两个天花板我先说结论单纯把一堆能力塞进一个 Agent和搭一个多智能体集群是两个完全不同的工程问题。第一个天花板是上下文膨胀。单 Agent 只有一个上下文窗口它既要记住用户的历史意图又要消化工具返回结果还要执行推理。当任务链变长比如查询报表 - 发现异常 - 写分析结论 - 生成邮件中间状态全部挤在一个循环里很容易出现两种症状一种是早期的指令被后面的任务冲淡模型开始答非所问另一种是工具多到模型不知道该调哪一个甚至反复调用同一个工具形成死循环。我见过不少团队在单 Agent 里加了十几个工具后效果反而明显变差就是这个原因。第二个天花板是工具孤岛。早期做法是把外部能力直接写死成内部函数查询数据库就定义query_sales()发消息就定义send_email()换来换去全是硬编码。今天换数据源、换消息渠道都要改主程序代码不同 Agent 之间想共享工具还得各自维护一份实现标准还不一致。这跟电脑里每个软件各写各的 USB 驱动没什么区别本质上是一种资源浪费。1.2 多智能体集群真正要解决的三类问题多智能体集群的价值并不是把单 Agent 复制几份而是把复杂系统拆成三个正交的问题分工每个 Agent 只负责一类任务上下文专注工具集小指令提示词不需要互相妥协。协作Agent 之间通过统一协议互相派活、回传结果避免一个全局大脑过度膨胀。复用工具接入和技能经验在集群内共享新增一个 Agent 不需要从零堆基础设施。下面这张表可以很直观地看出差异维度单智能体多智能体集群上下文管理一份窗口塞所有任务每个 Agent 独立窗口只承载子任务工具接入函数硬编码改动成本高MCP 标准化插拔服务共享经验沉淀散落在 Prompt 里Skills 技能包结构化复用故障影响面一个 Agent 挂了全盘瘫单节点失败可隔离、可重试扩展性加能力先考虑改主程序加 Agent 节点即可路由调整1.3 为什么是 MCP、A2A、Skills 组合出现单看 MCP、A2A、Skills 其中一个都有各自的适用场景。但真正把它们组合起来才会发现这三者正好补齐了多智能体系统的三个关键面MCP 解决智能体怎么用工具A2A 解决智能体怎么互相协作Skills 解决团队怎么沉淀经验。DeepAgents 这类编排框架则负责把三者组织成一个可控运行的集群。这也是我最终选型时要考虑的核心逻辑不追求某个平台的独家能力而是优先采用生态广、可替换、能让团队各自独立演进的协议标准。2. MCP把工具从硬编码变成插拔式协议2.1 MCP 是什么以及软件协议这个概念先回应一个经常出现在讨论区的问题MCP 是软件协议还是硬件协议答案是明确的它属于应用层软件协议。你可以把它理解成智能体世界的 Type-C 接口——它规定了一端是 MCP 客户端也就是智能体宿主另一端是 MCP 服务端提供工具和数据的一方双方按照统一的方式打招呼、发现能力、发起调用。所以 MCP 与具体模型、具体代码框架无关它是一个标准。就像 HTTP 之于 Web 服务任何编程语言实现了 HTTP 就能互通同理任何智能体框架实现了 MCP就能调用任何实现了 MCP 的工具服务端。这带来的直接好处是我不用再为每个工具写一套专属的调用逻辑只需要维护一批 MCP Server 配置谁需要谁就挂载用完即走。2.2 MCP 的三类能力与一次完整调用一个 MCP Server 可以向外暴露三类能力Tools工具、Resources资源和Prompts提示模板。很多人只盯着 Tools但实际项目中 Resources 和 Prompts 同样重要。一次典型调用的流程是这样的客户端和服务端先完成一次握手交换协议版本和客户端能力。客户端调用tools/list获取服务端支持的工具清单包括每个工具的名称、描述和参数结构。后续模型决定需要使用某个工具时客户端调用tools/call把参数传给服务端。服务端执行真实逻辑并返回结果结果会以结构化内容回传给模型继续推理。工具调用的消息类似下面这样基于 JSON-RPC 风格{ jsonrpc: 2.0, id: 1, method: tools/call, params: { name: query_postgres, arguments: { sql: SELECT region, SUM(amount) FROM sales WHERE order_date 2025-01-15 GROUP BY region } } }从工程角度看这个流程最重要的价值是把调什么、怎么调、返回什么全部标准化了。智能体不需要知道数据库连的是 PostgreSQL 还是 MySQL也不需要知道底层是 HTTP 还是本地进程它拿到的永远是一个稳定的工具描述和返回值结构。2.3 容易搞混的几个点MCP 生态发展很快但有几个概念经常被搞混这里一次说清楚。第一个是客户端和服务端的关系。MCP 并不是让 Server 与 Server 直接互相调用它的模型是 Host-Server一个 Host智能体宿主连接多个 Server。如果你想让 Agent A 调用 Agent B 的能力那其实是 A2A 的职责而不是 MCP 的职责这一点在架构划分时特别容易混淆。第二个是工具描述质量。MCP Server 暴露给模型的不只是函数实现还包括工具名和自然语言描述。这决定了模型在关键时刻知不知道用这个工具、怎么填参数。我把描述写得太随意结果就是模型明明有查询工具却绕了一整圈去瞎猜数据。第三个是同类 MCP 的选型差异。比如很多人问 Browser Use MCP 和 Playwright MCP 有什么区别直接对比一下就清楚了对比维度Browser Use MCPPlaywright MCP交互方式接收自然语言任务自主拆解为浏览器动作暴露 Playwright 自动化步骤按结构化指令执行适用场景需要 AI 自主判断页面行为的任务需要稳定、精确、可复现的自动化流程控制粒度偏高层由模型决定怎么操作偏底层每一步都需要明确命令适合人群快速验证浏览器自动化不想写太多代码有一定前端自动化基础需要精细控制还有一个实践建议MCP Server 不要把所有接口都暴露出去。比如后台管理系统里数据库查询 MCP 只开放白名单工具写操作单独做一个 MCP Server并加上二次确认机制这能显著降低事故率。2.4 实操示例写一个最小 MCP Server用一个常见的 Python SDK 写一个最简 MCP Server 是很快的。下面是我用来给数据分析 Agent 提供销售查询服务的例子from fastmcp import FastMCP mcp FastMCP(sales-service) mcp.tool() def get_sales_by_date(date: str) - str: 按日期查询销售总额。 Args: date: 日期格式为 YYYY-MM-DD。 # 这里实际会连接 PostgreSQL并执行聚合查询 return {date: date , total_amount: 128500.00} mcp.resource(postgres://sales/schema) def get_schema() - str: 返回销售表结构用于帮助模型理解字段含义。 return 表结构sales(id, region, amount, order_date) if __name__ __main__: mcp.run()启动后在客户端配置文件里注册一下即可{ mcpServers: { sales: { command: python, args: [mcp_sales.py] } } }这样配置之后任何支持 MCP 的智能体宿主都能发现并使用销售查询工具。如果你用的是深浅技术栈不同的环境MCP Server 的启动方式可以是本地进程也可以是远程服务这完全取决于你的部署形态。2.5 MCP 使用时的几个注意点首先要控制工具数量。一个 MCP Server 暴露几十个工具虽然技术上没问题但模型在决策时要把工具列表都加载进来会占用大量上下文。我的经验是一个 Agent 挂载的 MCP 工具控制在 5 到 10 个以内如果确实有很多能力拆分成多个专用 Server按角色分配给不同 Agent。其次是超时与重试。数据库查询、浏览器操作这类 MCP 工具往往耗时较长如果客户端默认超时太短很容易把正常的查询误判为失败。建议给不同工具设置不同的超时时间并在服务端做好幂等设计避免重试造成重复执行。另外涉及外部平台授权时不要把敏感令牌直接写进 MCP 配置文件。比如接入 Figma 之类的设计工具授权时我通常会用环境变量或者密钥管理服务注入而不是把 token 明文放进仓库。3. A2A 协议让智能体学会互相派活3.1 为什么还需要 A2AMCP 不够吗这是一个高频疑问既然 MCP 已经能让智能体调用工具为什么还需要 A2A关键在于两者解决的关系不同。MCP 解决的是智能体调用工具A2A 解决的是智能体之间发起协作任务。打个比方MCP 像 CPU 与外部设备之间的总线A2A 更像两台计算机之间协同工作的通信协议。如果非要用 MCP 来模拟 A2A你可以把另一个智能体封装成一个 MCP 工具但这种做法很快就会遇到问题任务可能持续很久需要流式反馈中间进度对方可能有自己的状态管理双方可能需要协商、追问、调整参数。这类交互显然不是单向的工具调用能覆盖的。所以我在架构里把 MCP 和 A2A 明确分层MCP 负责能力接入层A2A 负责协作编排层。两者不冲突反而是互补关系。3.2 A2A 的核心概念Agent Card、Task、Message、Artifact要落地 A2A需要先理解它的四个核心对象Agent Card相当于智能体的名片对外声明身份、能力列表和接入端点。其他智能体通过发现机制获取这张卡片才知道谁能干什么、怎么联系。Task一次协作任务的状态载体。它有自己的生命周期创建、进行中、已完成、已取消、失败。任务状态让双方都知道当前进展而不是只靠一来一回的聊天。Message任务过程中的消息单元可以包含文本、结构化数据甚至多模态内容。A2A 的流式消息机制让接收方可以实时感知结果片段。Artifact任务最终产生的成果物可以是文件、结构化数据、代码片段等。把结果放到 Artifact 而不是塞在聊天消息里是保证大任务可控的关键。3.3 一次典型 A2A 交互在 A2A 交互中首先要拿到目标智能体的 Agent Card。一次简化版的卡片请求返回可能长这样{ protocolVersion: 0.2, name: data-report-agent, description: 负责销售数据报表生成与异常分析, url: https://agent-cluster.internal/data-report, capabilities: { streaming: true, tasks: { start: true, subscribe: true } } }拿到 Agent Card 后编排层就可以创建 Task 并向该 Agent 发起请求。核心流程是编排器向url/tasks发送任务创建请求带上自己的身份和任务内容。目标 Agent 返回taskId并在执行过程中持续推送 Message 更新进度。当任务执行完毕目标 Agent 把最终产物写入 Artifact并更新 Task 状态为 completed。编排器拿到 Artifact 后再决定是否进入下一阶段比如把结果交给另一个 Agent 去生成可视化报告。这个流程看起来简单但设计上考虑了异步、流式、失败重试足够覆盖真实系统中的大部分协同场景。3.4 A2A 在既有技术栈中的落地如果你主服务用的是 Spring BootA2A 的官方 Java SDK 可以直接集成把智能体能力发布为一个可被发现的 HTTP 端点还能配合服务注册中心实现动态路由。如果智能体本身是 Python 写的用 Python SDK 实现 Agent 角色也很快。在实际项目中我们是 Spring Boot 写编排控制面Python 写数据分析和知识库 Agent两者通过 A2A 协议互通这样既保留了 Java 生态的稳定性又利用了 Python 的数据处理生态两边都能各自演进。3.5 多智能体集群里的编排策略多智能体集群的编排方式我通常会根据任务特点选择三种模式编排器模式一个主 Agent 负责接收用户请求、拆解子任务并分发给多个子 Agent。适合意图识别、客户服务这类任务入口集中的场景。工作流链模式任务按顺序经过多个 Agent比如数据抽取 - 分析 - 出报告。适合流水线式、阶段依赖强的任务。协商模式多个 Agent 地位对等通过消息协商决定谁来处理任务。适合没有唯一权威入口、需要动态选路的环境。三种模式各有优劣并没有万能答案。在 DeepAgents 的节点编排里我会根据任务耗时、失败重试成本、并发要求来选择。早期不建议直接上太复杂的协商机制先把编排器模式跑稳再逐步演进。4. Skills 机制把高频经验做成可复用技能包4.1 从 Prompt 到 Skills 的进化用过一段时间 Agent 的人都会有种感觉把经验写进 Prompt本质上还是靠口口相传。同一个团队的不同 Agent可能各自维护着一大段风格迥异的指令遇到同类任务时表现忽高忽低。这是因为 Prompt 是零散的文本没有版本、没有结构、没有校验机制。Skills 的解法是把它变成一个目录化的技能包。一个 Skill 不只是一段描述而是一个包含说明文件、执行步骤、脚本、示例的文件夹。模型在任务开始时能根据描述自动加载相关 Skill就像给新员工发一本标准作业指导书而不是让他在工位上到处问前辈。这种转换最大的价值是经验变资产今天调试好的一套代码审查规则整理成 Skill 后明天新 Agent 直接复用效果完全一致。4.2 Skill 包目录结构与元数据一个标准的 Skill 包通常长这样frontend-review/ ├── SKILL.md ├── rules/ │ └── accessibility-rules.md ├── examples/ │ ├── bad-example.tsx │ └── good-example.tsx └── scripts/ └── check-lint.py其中SKILL.md是核心文件它通过 frontal metadataYAML 格式的元数据声明技能的用途并用正文描述执行步骤。元数据部分尤其重要因为模型靠 description 来判断该在什么场景下加载这个技能。写得含糊技能包就不会在关键时刻出现。一个简化的示例--- name: frontend-review description: 用于前端代码评审。当任务涉及 React/TypeScript 代码审查、可访问性检查或组件规范校验时使用。 version: 1.2.0 tags: [frontend, review, accessibility] ---4.3 开发高质量 Skills 的实操经验我在项目里总结出三个原则场景单一、步骤明确、自带验证。场景单一意味着一个 Skill 只解决一个任务不要做成万能工具箱。比如数据库查询类技能就专门负责把自然语言转成安全 SQL 并格式化输出不要掺入报表生成逻辑报表生成应该由另一个 Skill 负责。步骤明确指 SKILL.md 正文要用可执行的自然语言写步骤。以 PostgreSQL 查询 Skill 为例我会在正文里明确写第一步理解用户的查询意图第二步判断涉及的数据表第三步使用 MCP 的get_schema获取表结构第四步生成 SQL并列出必须遵守的规则例如必须加 LIMIT、禁止SELECT *、禁止不带条件的 UPDATE/DELETE。自带验证同样重要。技能执行完后要有检查清单比如结果是否包含空列字段名是否符合约定甚至直接调用一个校验脚本。我把这些写进 Skill 后模型犯低级错误的频率明显下降。4.4 如何获取与甄别现成 Skills社区里已经积累了大量现成技能包常见的渠道包括官方技能市场、GitHub 上的技能合集、以及专门用来检索技能的 find skills 工具。像 superpowers 这类合集就把编码、调试、写作等常见任务拆成了大量可组合的技能包适合刚开始接触 Skills 机制的人直接学习。但获取现成技能包时一定要做甄别重点看三件事description 是否明确、版本是否跟上模型能力变化、以及脚本内容是否安全。Skills 往往包含可执行脚本相当于一次小型代码审计不要从不可信的来源直接引入后不管。4.5 Skills 与 MCP、A2A 的配合关系很多人会困惑这三个概念怎么分工其实从工程角度可以这样理解MCP 回答能做到什么Skills 回答应该怎么做A2A 回答交给谁做。举个例子数据分析 Agent 挂载了 PostgreSQL MCP说明它有查库能力加载了一组报表生成 Skills说明它知道按规格生成图表而它选择把报告提交给前端 Agent 去渲染走的就是 A2A 的协作流程。这三层互相配合多智能体集群才真正有了手、脑、沟通的完整闭环。5. 实战DeepAgents 多智能体集群架构全流程落地5.1 业务需求与角色划分说干就干。我们以一个企业内部运营助手为例系统需要处理客户意图识别、经营报表分析、知识库问答、代码变更辅助四类任务。如果全部塞进一个 Agent交互链路会很长工具也容易互相干扰。所以我拆成了四个专用 AgentAgent 名称核心职责挂载 MCP加载 Skillscore-agent客户意图理解、全局对话管理、任务路由通讯录、工单customer-intent、handoff>cluster: name: ops-agents registry: http://agent-registry:8000 agents: - name: core model: your-llm-model skills: [customer-intent, handoff] a2a: endpoint: http://core-agent:8000/a2a mcpServers: - contact - ticket - name: data model: your-llm-model skills: [db-query, report-format] a2a: endpoint: http://data-agent:8000/a2a mcpServers: - postgres - charts mcpServers: postgres: command: python args: [mcp_postgres.py] charts: command: node args: [mcp-charts-server.js]这里要强调一点配置文件不要照着抄就完事它不是买卖保险的合同而是一个面向你实际环境的蓝图。每个服务的启动方式、endpoint 地址、模型名称都要按自己的环境调整。5.3 启动与联调流程整个集群的启动顺序和联调步骤非常关键我一般按下面这个顺序走启动基础设施先确保 PostgreSQL、向量库、MCP Server 等底层服务都处于健康状态。这一步出问题后面无从谈起。启动各 Agent 节点逐个拉起 core、data、kb、dev 四个 Agent并让它们向 registry 注册自己的 Agent Card。验证 MCP 连接在编排控制台里依次调用tools/list确认每个 Agent 都能发现预期的工具集合。验证 A2A 发现通过 registry 查询每个 Agent 的 Agent Card确保 core 能路由到 data、kb、dev。跑端到端测试用一条真实任务串起全部节点比如查询本周各区域销售差异给出分析并生成一封报告邮件。联调阶段要养成记录日志的习惯。每一个 A2A 任务和 MCP 调用都把输入、输出、耗时、token 消耗写进结构化日志后续排查问题会省很多力气。5.4 协同开发流程集群上线后日常维护的核心是协同开发流程。我把整个变更流程分成三类新增 MCP 工具、迭代 Skills 技能包、调整 Agent 路由策略。Skills 的变更走代码仓库管理SKILL.md 里写版本号改动后跑一遍回归集确认对现有任务没有副作用MCP Server 的发布则按独立服务对待新工具先灰度给一个 Agent验证稳定后再开放路由策略的调整则涉及 Agent Card 和编排规则需要有回滚方案。这套流程执行下来最大的体感是改一个环节不会炸掉整个系统。只要接口和协议稳定各层团队可以并行迭代这正是多智能体集群相比单体 Agent 的工程优势。5.5 可观测性与上下文管理集群一旦跑起来可观测性就从一个加分项变成了必需品。我在每个任务里注入一个全局 trace_id从用户请求入口一直贯穿到 MCP 工具调用和 A2A 子任务日志系统能按 trace_id 把整条链路的决策过程重现出来。上下文管理方面我的建议是不要让 A2A Message 背负大块数据。比如>