
1. 先拆解这个标题到底在说什么如果你最近关注AI Agent开发一定被这几个词反复刷屏DeepAgents、MCP、A2A、Skills。说实话我第一次把这四个词放到一起时也有点懵——每一个单独拎出来都能讲半天组合在一起更像是一个“既要又要还要”的技术愿景。但真正上手做过Agent项目的人三分钟就能明白这个标题背后的痛点在哪。我之前的项目是这样的公司要做一个内部AI助手能查数据库、能看工单、能对接企业微信机器人、还能调外部天气接口。一开始我按老办法每个工具写一个Python函数硬编码在Agent的Prompt里让模型自己选。结果呢Agent的上下文长度被我塞爆工具参数格式不统一换一个模型就得重调所有调用逻辑最难受的是公司另一个小组也在做类似的事我们各写了一套工具调用完全没法互通。这就是没有协议和标准化的下场。后来我彻底重构了一版用的就是标题里这套组合思路MCP统一工具接入A2A打通Agent之间的通信Skills沉淀可复用的能力再用编排层把多个Agent组合成集群。跑通之后整个系统从“一个什么都会一点的单体机器人”变成了“一群各司其职、能互相调度的智能体团队”。这篇内容就是把我重构过程中踩过的坑、验证过的方案、实际能落地的配置完整梳理出来适合正在做多Agent系统、或者想从单体Agent升级到可编排集群的开发者参考。我先用一句话说清楚它们各自解决什么问题MCPModel Context Protocol解决Agent“用什么工具”的问题——统一接入外部数据和工具规范化工具描述和调用协议。A2AAgent-to-Agent解决Agent“怎么互相配合”的问题——让不同Agent能发现彼此、派发任务、回传结果。Skills解决Agent“具备什么能力”的问题——把一套可复用的知识、步骤、规则打包成标准化能力单元。DeepAgents解决Agent“如何自主决策”的问题——让Agent具备任务拆解、规划执行、长上下文处理的能力充当集群中的核心执行体。这套组合想做的事情就一句话把Agent从一个个孤立的“对话接口”升级成可观测、可管理、可扩展的分布式智能体网络。2. 架构设计从单体Agent到智能体集群的关键拆解2.1 单体Agent的瓶颈所有事情都塞给一个大脑先说说为什么非要做集群。很多人一开始觉得一个Agent让模型多轮思考、配上ReAct框架不就能干所有事了吗确实能但只是在小规模、低复杂度场景下能。我用过一个对比很直观单体Agent就像一家公司里只有一个“全能员工”你什么都问他他的办公桌上下文窗口堆满了文件他联系的每个系统工具都要靠人肉翻译自定义封装。一旦任务变多上下文窗口被工具描述、历史记录、中间推理占满真正有用的业务信息反而塞不进去每次新增工具都要改Prompt、改JSON Schema、改调用后处理逻辑改一处动全身Agent在长链路任务中容易出现“遗忘”——第一轮规划好的事第三轮就忘了关键约束没有并发隔离一个新任务正在执行另一个任务又挤进来互相污染上下文。而集群化的核心思路是“拆分协作”让专门Agent负责专门领域由编排层统一调度。每个Agent只需要维护自己的上下文、自己的工具清单、自己的Skills库体量小、响应快、可以独立扩展。2.2 一个类比MCPA2ASkills 如何组成团队我用“跨部门项目组”来类比这四者的关系DeepAgents编排器 项目经理负责拆解用户需求、分派任务、汇总结果MCP服务器 公司的标准化接口系统——每个部门数据、工单、邮件都按同一套接口规范暴露能力项目经理不需要关心每个系统内部的调用细节A2A协议 部门间的协作流程A部门做完一件事按标准格式把任务单传给B部门Skills 员工培训和SOP手册把那些“怎么做好一件事”的经验固化成标准作业流程。有人可能要问MCP不是已经能让Agent调用外部工具了吗为什么还要A2A因为MCP是“Agent调用工具”A2A是“Agent调用Agent”。这两者是不同层级的关系不是替代关系。MCP是纵向的连接Agent与外部资源A2A是横向的连接Agent与Agent。再说的直白一点如果一个任务需要调用两个不太相关的工具比如先查天气再查航班MCP就够了。但如果一个任务需要“先让规划Agent生成方案再让研究员Agent收集资料最后让报告Agent汇总输出”这中间流转的是任务状态和结果内容单纯靠工具调用协议是表达不清楚的就必须有A2A这种Agent间通信协议。2.3 四层架构协议栈的分工边界我落地时的分层大概是这样的层级组件职责典型实现编排层DeepAgents编排器任务拆解、路由、状态管理LangGraph / 自研编排器通信层A2A协议Agent与Agent之间的任务分发、结果回传A2A SDK / HTTP JSON-RPC工具层MCP服务器统一接入外部工具、API、数据库FastMCP / Python SDK能力层Skills沉淀可复用的知识流程与操作规范SKILL.md 配套资源目录这个分层的关键在于每一层只关心自己的事互相之间通过标准协议沟通。当你需要新增一个Agent时只需要实现A2A接口、挂上自己的MCP工具和Skills改动只局限在一个模块内部当你需要新增一种工具时写一个MCP服务器注册到网关完全不影响其他Agent。这就是“可扩展”的真正含义——不是加功能而是加节点。3. 核心机制逐个拆MCP、A2A、Skills到底怎么用3.1 MCPAgent的工具插线板MCP我从实际使用角度讲三个要点架构角色、传输方式、注册流程。MCP架构里三个角色HostAgent宿主程序、Client宿主内与服务器建立连接的客户端、Server暴露工具资源的服务器。说白了Agent是Host它内部会启动一个ClientClient负责与各个MCP Server建立连接、列举资源、调用工具。传输层目前主流就两种stdioAgent与MCP Server走标准输入输出适合本地启动的子进程式服务器配置简单适合局域网内自己用Streamable HTTP通过HTTP端点暴露适合远程部署、跨服务调用也是目前多Agent集群场景下的首选。我的建议是生产环境尽量用Streamable HTTP原因很直接stdio服务器生命周期跟随Agent宿主Agent挂了工具也跟着挂了而且无法被多个Agent共享。HTTP端点则可以独立部署、独立扩容多个Agent可以同时连一个工具服务。后面我实操部分就是用HTTP模式部署的。一个MCP服务器核心就是三件事定义tools工具描述、处理call_tool工具调用、返回结构化响应。用FastMCP写一个工具几乎是模板化的。跑通一次之后后面加工具就是往里填函数。另外MCP里资源Resources和提示词Prompts也值得提一下。Resources适合暴露非工具类的读数据比如把一份文档、一个配置文件暴露给模型Prompts可以预置“怎么使用这个服务器”的指令片段。做复杂服务器时三者配合能显著降低模型对工具用法的理解成本。3.2 A2AAgent与Agent之间怎么互相“派活”A2A协议的核心概念有这么几个Agent Card能力名片、Task任务实体、Message消息、Artifact产物、Part内容分片。A2A对我的价值在于它定义了一套标准的“Agent对接Agent”语义Agent Card是一个JSON描述文件包含Agent名称、能力说明、端点地址。其他Agent拿到这个Card就能知道“这个Agent能做什么、怎么调”。Task是通信的基本单元。一个客户端Agent向服务端Agent发出tasks/send请求传入任务内容服务端Agent返回任务状态如completed、failed和产物。异步场景下还有tasks/get轮询或者用SSE订阅任务状态变化。Message和Part定义了消息结构Part内可以携带文本、文件、结构化数据且能标记内容的类型。刚才说过A2A和MCP是互补的。实际场景里每个Agent内部用MCP接自己的工具Agent之间用A2A互通消息。换句话说MCP管“Agent能调用哪些资源”A2A管“Agent能请求哪些其他Agent”。如果你用Spring开发后端社区已经有A2A的Spring实现把Agent定义成Bean、暴露成HTTP服务。C也有对应的SDK支持。所以语言不是大问题关键是遵循协议。我在项目里用Python实现了一个轻量级A2A服务端本质上就是在FastAPI里实现几个JSON-RPC端点tasks/send、tasks/get、tasks/cancel然后提供一个符合规范的Card JSON。就这么简单。3.3 SkillsAgent能力的标准化封装Skills这个词在Anthropic的Agent Skills规范出来之后火了一波。所谓Skill本质上是一套带特定结构的目录一个SKILL.md文件作为入口里面用frontmatter写name、description正文部分写这个技能的详细使用步骤、规则、注意事项还可以附带脚本、模板、示例文件。它和MCP Tools的区别很重要。MCP Tool是一个可调用的具体函数比如get_weather(city)Skills是一套“做事情的方法论”它最终会指导模型怎么去调用一个或多个工具、按照什么顺序处理信息、输出什么格式。举个例子。我做一个“竞品分析”SkillSKILL.md里写了获取竞品官网信息用搜索工具收集用户评价按SWOT框架整理输出。这里每一步都对应工具调用但Skill本身封装的是“分析流程”不是单个工具。所以Skill可以理解成“把优秀经验固化下来让任何Agent都能复现同样高质量的工作方式”。我在实际项目中踩过一个坑一开始把方法论写进系统Prompt结果改一版Prompt就要重新测试整个链路非常痛苦。改成Skill之后按需加载不同任务加载不同Skill上下文只塞当前需要的效率提升很明显。现在GitHub上已经有大量Skills市场官方也出了Marketplace机制类似npm的Agent技能生态正在形成。你可以直接下载别人写好的Skills也可以自己写Skill发布。我在团队里推的规范是每个Agent必须把常用的工作流程沉淀成Skill不允许只写在个人笔记里。4. 实操落地搭一个最小可运行的DeepAgents集群4.1 搭建目标与总体流程纸上谈兵讲了这么多现在进入能直接抄作业的部分。我搭了一个最小集群包含三个Agent调度Agent负责入口与规划、搜索Agent负责信息检索、报表Agent负责生成汇总。其中一个Agent通过MCP接入两个外部工具Agent之间通过A2A通信公共能力用Skills封装。整个流程分五步搭建MCP服务器并暴露HTTP端点编写Skill目录并接入Agent上下文实现A2A服务端和Agent Card编写调度Agent完成Task分发联调测试并验证全链路。我用Python来实现主要依赖FastMCP搭建MCP服务器、FastAPI搭建A2A HTTP服务、LangGraph编排调度逻辑。你也可以换成你熟悉的框架核心逻辑是一致的。4.2 第一步搭建MCP服务器我先建了一个最简单的信息查询MCP服务器暴露两个工具search_web(query)模拟一个搜索引擎接口返回相关链接列表fetch_article(url)抓取文章内容并提取正文摘要。用FastMCP实现大致是这个样子from fastmcp import FastMCP mcp FastMCP( InfoService, host0.0.0.0, port8001, transportstreamable-http, # 关键使用HTTP模式 ) mcp.tool() def search_web(query: str) - list[dict]: 搜索引擎查询返回相关链接与标题 # 实际场景中可接入SerpAPI、Bing API等 return [ {title: f{query} - 相关结果1, url: https://example.com/1}, {title: f{query} - 相关结果2, url: https://example.com/2}, ] mcp.tool() def fetch_article(url: str) - dict: 抓取文章内容并返回摘要 # 实际可调用爬虫或Jina Reader return {url: url, content: 文章摘要内容示例} if __name__ __main__: mcp.run()注意这里我用的是transportstreamable-http而不是默认的stdio模式。这在多Agent场景下非常关键单独启动该服务后其他Agent可以通过HTTP端点http://localhost:8001/mcp访问这些工具而不是依赖某个Agent的进程内环境。我需要再强调一下为什么这样设计如果你用stdio的MCP服务器只在某个Agent内部可用改成HTTP模式后它实际上变成了一个对集群内所有Agent开放的公共工具服务。这个差异在多Agent场景里是本质性的。4.3 第二步让Agent上下文支持Skills接着我建了一个skills/目录每类能力一个子目录里面包含SKILL.md。这就是Agent Skills的标准结构Anthropic官方规范就是这个思路现在很多框架也都支持直接读取这个结构skills/ ├── deep_research/ │ ├── SKILL.md │ ├── templates/ │ └── examples/ └── weekly_report/ ├── SKILL.md └── scripts/一个SKILL.md文件长这样--- name: deep_research description: 用于从互联网收集信息整理成结构化研究报告。适合竞品调研、行业分析等场景。 --- # 深度调研技能 1. 先调用 search_web 获取相关主题的信息来源 2. 对每个有价值的来源调用 fetch_article 获取全文 3. 提取关键信息数据、观点、趋势 4. 按照摘要、核心发现、数据支撑、结论的格式输出在实际开发Agent时这个skills/目录会被作为Reference注入到Prompt里或者通过检索按需加载。这样Agent就知道它有哪些可用能力并且知道每个能力的具体执行流程。这里有一个我踩过的坑要提醒大家不要把所有Skill一骨碌全塞进上下文。每个Skill的正文几百字到几千字不等十几个Skill全部加载下来上下文就废了。正确做法是让Agent先看Skill的description根据当前任务加载相关的1-2个完整Skill正文。这就是Skills检索增强类似于RAG的思路。4.4 第三步实现A2A服务端与Agent Card接下来我实现了一个A2A兼容服务端。A2A协议的传输层本质是JSON-RPC 2.0我基于FastAPI自己实现了一个轻量版本。核心是暴露tasks/send端点from fastapi import FastAPI from pydantic import BaseModel app FastAPI(titleSearchAgent) class TaskMessage(BaseModel): task_id: str message: dict app.post(/a2a/tasks/send) async def send_task(req: TaskMessage): # 实际逻辑接收调度Agent发来的搜索任务 result process_search_task(req.message) return { id: req.task_id, status: completed, artifacts: [ {name: result.md, content: result} ] } app.get(/.well-known/agent-card.json) async def agent_card(): return { name: search-agent, description: 负责信息检索与来源收集, skills: [deep_research], endpoints: [/a2a/tasks/send], version: 1.0.0 }这个/.well-known/agent-card.json就是Agent Card的存放位置类似Web世界的robots.txt。其他Agent可以通过读取这个Card知道“这个Agent叫什么、擅长什么、端点是什么”。这是A2A协议设计中很关键的一点整个Agent发现机制就是靠这个Card文件。我在实操中发现虽然A2A规范里定义了复杂的Task生命周期submitted、working、completed、failed等状态但最小实现其实只要实现send和get两个端点就够跑通了。复杂的cancel、progress等功能可以后续按需加。4.5 第四步编排Agent的Task分发逻辑所有子Agent就绪后最后是顶层调度Agent。它的职责是接收用户输入判断任务类型决定是自己直接调用MCP工具还是把子任务通过A2A派发给其他Agent汇总结果输出最终答案。我用LangGraph做了一个简单编排核心思路是让大模型输出一个结构化计划然后代码按计划执行。一个关键动作是编排器通过agent-card.json获取可用Agent列表这是动态发现的。当集群里新注册了一个数据Agent编排器下一次就能自动感知到不需要改代码。a2a_clients discover_agents(http://internal-registry:8000/agents) # 返回 [{ # name: search-agent, # endpoint: http://search-agent:8101/a2a/tasks/send # }, ...]然后按任务类型路由。到这一步你就可以看到一个典型的跨Agent协作流程了用户输入“帮我调研一下AI编码工具的最新趋势” → 调度Agent判断需要搜索 → 发起A2A请求到搜索Agent → 搜索Agent内部使用MCP工具search_web和fetch_article收集信息 → 返回结构化结果 → 调度Agent生成最终报告。这个链路里每个技术都找到了自己的位置MCP在子Agent内部打通工具A2A在子Agent之间传递任务Skills规范了子Agent处理任务的方法DeepAgents编排器控制了整体流程。4.6 性能与配置优化的几个实测数据整个集群在本机跑通之后我做了几轮压测把热词里大家关心的“ai agent怎么扛并发”这个问题也整理了出来瓶颈往往在MCP服务器因为工具调用是IO密集操作。我用简单连接池把并发从5提升到50关键在于复用HTTP会话A2A的Task状态轮询会占用大量请求。长任务用轮询没问题但短任务直接把结果在tasks/send响应里返回更高效避免多一轮请求上下文管理是硬伤。实测发现调度Agent如果保留所有子Agent的完整产出上下文很快会爆。我的方案是调度Agent只保留子Agent产出的摘要和关键结论原始全文写入本地文件用户需要时再按需读取。还有一点和模型选型相关的经验集群里不同Agent用不同模型是合理的。调度Agent建议用推理能力强的大模型比如带深度思考能力的因为它负责规划子Agent可以用响应快的小模型因为它们的任务边界已经通过Prompt和Skills收窄了不需要太强的全局推理能力。5. 常见问题与排查技巧实录5.1 问题速查表下面这份排查清单全部来源于我实际跑集群时遇到的真实报错按出现频率排序问题现象可能原因解决方案MCP服务器启动正常但Agent找不到工具传输模式不匹配Agent端用stdio配置去连HTTP端点统一配置为streamable-http检查endpoint地址是否带/mcp路径A2A请求一直超时子Agent的HTTP服务没注册到服务中心或者编排器拿到了错误地址启动时校验Agent Card可达性用curl测试tasks/send端点Agent执行Skill时步骤错乱跳过关键步骤SKILL.md的步骤说明不够结构化模型自由发挥空间太大在Skill里用“必须/禁止”等约束词把步骤写成强制有序列表多Agent并发调用同一MCP工具时互相阻塞MCP服务器的连接池太小换成Streamable HTTP模式并配置连接池或者用异步处理调度Agent上下文爆炸把所有子Agent的完整产出都保留了只保留摘要完整内容落盘按需读取Agent反复调用同一个失败工具不停重试缺少错误反馈机制在工具返回中附带error字段告诉Agent该换一种方案5.2 我踩过的三个深刻的坑第一个坑MCP工具的返回数据塞满上下文。我第一次接入搜索工具时把搜索结果和文章全文直接从工具返回到Agent上下文。结果一个调研任务跑下来上下文里堆了几万字原始资料后续生成报告时模型已经“记不住”最初的任务要求了。后来我把工具返回改成“压缩信息全文落盘”工具只返回标题、摘要和文件路径Agent需要特定信息时再通过read_file工具读取。第二个坑A2A协议里Task ID必须全局唯一否则状态会串。我一度用自增数字当Task ID结果两个子Agent同时运行任务状态全部错乱。改成uuid4之后一切正常。这看着像个低级错误但实际在分布式系统里ID设计问题真的会晚上做梦都梦见。第三个坑Skills写得太抽象等于没写。我写过一份描述为“分析市场机会”的Skill正文只有三句话。模型看了等于没看输出质量一点没提升。后来我把Skill改成了带明确判断标准、输出模板、检查清单的版本效果立竿见影。Skill不是写给程序员看的文档是写给模型看的标准作业程序必须足够具体、足够可执行。5.3 关于调试强烈建议做的三件事给A2A配一个可视化页面。我后来给集群加了一个简单的状态看板能直接看到每个Agent当前执行的任务、运行状态、Token消耗。排查问题的时候能直观看到任务卡在哪一跳比瞎猜效率高太多了。MCP服务器一定要能单独测试。用mcp-inspector或直接Curl调用工具确认工具本身没问题再接入Agent。不然Agent调用失败了你分不清是模型选错了工具还是工具本身bug。日志里打上Task ID和Agent名。这是分布式系统的基础素养但真的很多人忽略。多Agent联调时没有Trace ID日志就是一团乱麻。6. 最后分享一点我的体会做这套东西的过程中我最大的感受是Agent领域的“标准化红利”才刚刚开始。MCP解决了工具接入的碎片化问题A2A正在解决Agent互联的碎片化问题Skills市场则试图解决能力复用的碎片化问题。这个演进路径很像当年Web开发从“每个网站自己写一套HTTP解析”走向“统一协议框架生态”的过程。我个人觉得接下来半年内多Agent集群会成为企业AI落地的常规形态而不是少数人玩的概念。现在动手搭建一个最小的MCPA2ASkills集群比到时候再仓促追赶要划算得多。最后再留一个小经验不要一开始就追求架构的完备性。先用最简单的模式让两个Agent、一个MCP工具、一个Skill跑通全链路。架构的复杂度跟着业务需要慢慢长这才是最稳的方式。