这段内容围绕 DeepAgents、MCP、A2A、Skills 的组合来拆解我把从单个 Agent 走向 Agent 集群过程中的踩坑、选型和落地步骤都整理一下尽量给到可以直接复用的内容。前阵子我把三个 Agent 同时拉进一个项目组本以为可以像一支小队那样分工协作一个负责拆需求一个负责写代码一个负责审查结果。结果它们各写各的代码互相不知道对方干了什么集成的时候满地找补。我排查了两天才意识到问题出在哪——工具、技能、通信全混在了一起每个 Agent 都在用自己那套私有方式去理解外部世界彼此之间根本没有“对话通道”。后来我按 DeepAgents 的编排思路把 MCP、A2A、Skills 各归其位才跑通。这套组合的价值不在于堆技术名词而在于把 Agent 从“单兵作战”变成“可编排、可互通、可扩展的集群”。这篇文章就把这套技术栈的定位、原理、落地步骤和那些文档里不会写的坑讲清楚适合正在从单体 Agent 演示走向多 Agent 生产的开发者。1. 从“单兵 Agent”到“Agent 集群”为什么要把工具、技能、通信拆开1.1 单体 Agent 的三个天花板单个 Agent 做演示很容易让它回答一个带 RAG 检索的问题、调用一两个 API很快就能跑通。但是当任务变复杂比如“根据需求文档生成一套带登录权限的前端项目并做完代码审查”单体 Agent 很快就会撞上三个天花板。第一个是上下文墙。我之前把工具定义、技能说明、历史对话摘要全部塞进系统提示词几千 token 的上下文被静态说明吃掉一大半。留给定推理的空间越来越少经常出现“知道有这个工具但忘了怎么调”的情况。第二个是全靠大模型现场发挥。没有沉淀技能时每次任务的执行策略都是临时的。上一次生成一套登录流程的经验下一次换个项目就被完全抛在脑后。看似在积累其实每次都在重来。第三个是协作失效。多个 Agent 同时参与时如果没有统一的通信协议就得人工在代码里写大量胶水逻辑Job A 的返回值格式、Job B 的输入字段全部靠硬编码加一个 Agent 就要改一遍全套配置。1.2 拆开之后四个组件各管哪一块后来我按 DeepAgents 的思路做了分层每个组件只解决一类问题。深层的逻辑是不要靠大模型自己去猜外部世界长什么样而是用协议把外部世界标准化。组件解决的问题类比核心产物MCPAgent 如何连接外部工具与数据标准插座Tools、Resources、PromptsSkillsAgent 如何复用一套成熟的方法论岗位说明书SKILL.md 与配套资源A2AAgent 之间如何发现彼此并协作名片 对话协议Agent Card、JSON-RPC 消息DeepAgents如何把集群编排成一个可扩展系统团队主管任务路由、会话调度、结果汇总MCP 解决“会用工具”Skills 解决“会干活”A2A 解决“会沟通”DeepAgents 解决“怎么组织这一群人”。这四个层的边界一旦清楚整个系统就从一团乱麻变成了可以描述、可以排查的结构。1.3 DeepAgents 到底是框架还是一套集群工程思想DeepAgents 在我理解里更像一套集群工程思想而不是某个具体框架。它回答的核心问题是当系统里有多个智能体时如何让它们各司其职、可替换、可增量扩展。支撑这套工程思想落地的主要是三类做法把 Agent 的能力外化成标准接口调用方不关心 Agent 内部用了什么模型、什么提示词。把任务路由与执行逻辑分离编排器只负责任务拆解与结果汇总不该参与每个 Agent 的具体实施。用配置代替代码每加一个 Agent不需要动主程序只需要新增一张能力声明。我在第一章就把这套逻辑理清楚往下每一层的细节都有章可循。2. MCP 层给 Agent 装标准插座让外部世界不再需要专用说明书2.1 MCP 为什么能成为事实标准在没有 MCP 之前接入一个外部工具基本是“布线和焊接”的工作。比如要让 Agent 查询数据库要么写一段 Python 代码把它封装成函数要么在 prompt 里手抄一份 SQL 方言说明。这些做法的问题非常明显换了 Agent 环境全得重来。MCPModel Context Protocol模型上下文协议把“Agent 与外部工具之间的交互”标准化了。协议定义好之后Agent 只需要学会一种跟 MCP Server 通信的方式就能使用任何遵循该协议的服务器。这就跟标准插座一样不论你生产的是台灯还是冰箱只要插头规格一致插上就能用。2.2 MCP Server 是怎么被调起来的我以一个查阅数据库的 MCP Server 为例说明调用过程宿主Host也就是 Agent 应用启动时读取配置里的 server 列表。客户端通过 stdio 或 HTTP 发起连接握手。Server 向 Host 暴露自己的能力清单每个工具用 JSON Schema 描述参数。大模型从清单中挑选合适的工具生成参数调用 Server。Server 执行操作并返回结构化结果结果回到大模型的上下文里。这里有一个很多初学者容易忽略的点MCP Server 本身只是一个协议转换层。它把系统里的任何能力包一层协议外壳比如读文件、查库、调内部服务。真正做决策的还是大模型。2.3 实操写一个最小 MCP Server 并接进 Agent我用 Python 的 FastMCP 库写一个最小 Server。功能很朴素提供一个加法工具演示协议链路。from mcp.server.fastmcp import FastMCP mcp FastMCP(demo-server) mcp.tool() def add(a: int, b: int) - int: 返回两个整数之和用于验证 MCP 链路。 return a b if __name__ __main__: mcp.run(transportstdio)然后在 Agent 宿主的配置里注册这个服务器。以 Claude Code 或 Codex 一类的配置文件为例本质是一样的{ mcpServers: { demo-server: { command: python, args: [demo_server.py] } } }配置完成后我在对话里直接问“用 demo-server 里的 add 工具算一下 137 加 286”宿主会自动检索工具、注入参数、发起调用最后把结果带回来。这套流程本身不复杂我真正想强调的一点是MCP 的价值不在某一个 Server 多强大而在“一次适配、到处复用”。同一个小工具今天接到 A Agent明天可以原样接到 B Agent只要宿主支持协议。2.4 MCP 正在渗透的领域业务系统、调试工具、设计协同从我最近关注的社区动态看MCP 的接入方向已经远远超出“连个数据库”的范畴业务系统集成在一些开源项目里我看到有人把 MCP 直接合并进后台管理框架让 Agent 能以自然语言操作业务模块。这个方向的潜力很大因为成熟的业务系统拥有大量 CRUD 接口正是 Agent 擅长的工具集。调试与逆向工具有人把调试器通过 MCP 桥接给大模型让 Agent 能读寄存器、查内存结构辅助分析问题。传统 IDE 里的智能提示在这条链路上变成了更深层的运行时洞察。设计协同Figma、蓝湖这类设计工具陆续被 MCP Server 包起来前端同学让 Agent 读取设计稿标注、直接生成样式这件事已经可以落地了。这些方向印证了一件事MCP 的“插座”一旦铺开各行各业原有的工具链都会逐步变成 Agent 的可调用资源。但我的一个经验是接入前先把权限边界想清楚不要因为方便就把 Server 暴露到公网。MCP 是给大模型开的一扇门门后放什么得由你把关。3. Skills 层把“现场发挥”变成“可复用的手艺”3.1 Skills 不是提示词是岗位说明书我一开始理解 Skills 时以为它就是一段更长的提示词。用了一段时间后才发现它更像“岗位说明书”解决的核心问题不是“告诉模型现在要干什么”而是“把一套经过验证的方法论沉淀下来让模型下次直接按这个流程执行”。区别在于Prompt 是临场指令依赖模型当前的上下文换个上下文效果就不稳定。Skill 是结构化知识包包含触发条件、执行步骤、校验清单、参考示例。只要符合触发条件模型就会按内部定义的流程走。这就好比你给新员工一份 SOP 文档而不是每次任务都当场口述一遍。前者可以版本管理可以测试可以分发。3.2 一个 Skill 的标准构成与加载方式我常用的 Skill 目录结构长这样skills/ frontend-review/ SKILL.md checklists/ accessibility.md performance.md examples/ before.md after.mdSKILL.md 是入口文件frontmatter 部分声明元信息正文是操作流程。一个典型的 SKILL.md 长这样--- name: frontend-review description: 对前端变更执行可访问性、性能与可维护性检查 when_to_use: 收到前端代码审查请求或合并请求包含 CSS/JSX 变更时 --- # 前端代码审查技能 1. 读取变更文件列表 2. 按 checklists 目录中的清单逐项核对 3. 对每项发现给出问题等级与修改建议 4. 生成审查结论标注必须修改项与建议项加载方式也很简单把 skill 目录放进 Agent 的 skills 路径或从技能市场同步。宿主会根据 description 和 when_to_use 决定何时加载进上下文。这个过程本质上是按需加载而不是全部塞进上下文这也是高效使用 Skills 的关键。3.3 Skills 和 MCP 的边界两者经常被人混淆但它们处理问题的层次完全不同。MCP 是“能做什么”提供外部能力执行入口比如查库、调 API、读文件。它强调连接。Skills 是“怎么做得对”提供方法、流程、检查点。它强调经验沉淀。我做过一个实验同样让 Agent 生成一个登录页。接入 MCP 的 Agent 知道可以调用 UI 组件库但生成的代码质量起伏很大后来加了写前端代码的 Skill里面定义了组件选型规则、状态管理约定、可访问性检查点生成结果明显稳定下来。原因很简单MCP 给了它工具Skill 给了它“会用工具的正确姿势”。3.4 开发 Skills 的几条原则经过几轮迭代我总结出这样几个原则保持原子化。一个 Skill 只解决一类任务比如“代码审查”和“生成登录页”拆成两个而不是塞进一个“前端超能力”。明确定义触发条件。description 和 when_to_use 写得越具体宿主按需加载的成功率越高。随身带 checklist。模型在现场执行时很容易漏步骤清单能显著提高稳定性。迭代版本。我把每个 Skill 都纳入 Git 管理效果不好的时候直接回滚到上一个稳定版本。把这些原则落到实处之后集群里的每一个 Agent 才真正有了“专业能力”。这也是标题里把 Skills 单独拎出来的原因没有技能沉淀的集群本质上就是一堆只会聊天的模型在开会。4. A2A 层Agent 之间不是传话而是基于能力的发现与协作4.1 A2A 要解决的核心问题多 Agent 集群里最尴尬的场景是A Agent 完成了一轮分析想把结果交给 B Agent 继续处理结果两者之间没有标准通信格式。最后只能由编排器硬编码去转A 吐出来的字段名还得在代码里做映射。A2AAgent-to-Agent协议把 Agent 之间的交互标准化。它的核心设计目标是让 Agent 像人类团队一样沟通我先知道你是谁、你会干什么然后把任务以标准消息格式发给你。你处理完我再根据返回结果决定下一步。4.2 Agent Card能力发现的关键A2A 里一个非常重要的概念是 Agent Card。可以把它理解成一张“电子名片”用 JSON 描述这个 Agent 的标识、URL、能力列表。A2A 的真正价值在于“发现”集群中的任何 Agent 都可以通过请求 Agent Card 得知当前有哪些可协作对象。编排器不需要在代码里写死“谁负责什么”而是通过卡片动态路由任务。新 Agent 加入集群时只需要发布自己的 Agent Card无需改动现有代码。一张简化的 Agent Card 示例{ name: code-agent, description: 负责代码生成与重构, url: https://agent.internal.local/code-agent/a2a, capabilities: [codegen, refactor, explain] }有了这张卡片编排器就能完成“看卡片、选对象、发任务”三步而不是写死一条调用链。4.3 把一个现有 Agent 暴露成 A2A Server在项目里我写了一个非常薄的 FastAPI 服务把现有 Agent 包装成符合 A2A 消息格式的端点。核心思路是外部发来的 JSON-RPC 消息我只是把它翻译成 Agent 的 run 方法入参再包装返回值。from fastapi import FastAPI from pydantic import BaseModel app FastAPI() class RpcMessage(BaseModel): jsonrpc: str 2.0 method: str params: dict {} id: int | None None app.post(/a2a) async def a2a_endpoint(req: RpcMessage): if req.method message/send: text req.params.get(message, {}).get(text, ) reply my_agent.run(text) return { jsonrpc: 2.0, id: req.id, result: {message: {role: agent, text: reply}}, } if req.method agent/card: return {jsonrpc: 2.0, id: req.id, result: get_agent_card()} return {jsonrpc: 2.0, error: {code: -32601}, id: req.id}这段代码不需要特殊框架关键在于把 Agent 的逻辑封装成标准消息入口。我在团队里给三个 Agent 各加了一层这样薄薄的 A2A 包装之后编排器的工作就从“处理各种私有数据结构”简化成了“统一收发标准消息”。市面上也陆续有 A2A Spring、C 等各语言的实现说明这个协议正在被不同技术栈接纳。4.4 MCP 与 A2A 的分工对照整理一个常见对比方便选型时快速判断维度MCPA2A通信双方Agent 与工具/数据源Agent 与 Agent核心内容工具调用、资源读取、Prompt 模板任务发送、消息回复、能力卡发现类比手和工具人和人协议形态Host-Client-ServerClient-Server Agent Card主要收益一次接入处处复用动态发现按能力合作两者是互补关系不是竞争关系。我经常会告诉你这位 Agent 通过 MCP 去调数据库同时通过 A2A 把分析结果交给另一位 Agent。这样的组合在实际项目中已经足够应对绝大多数复杂任务。5. DeepAgents 编排层集群大脑与任务路由5.1 两种编排模式有了 MCP 管工具、Skills 管方法、A2A 管通信最后一块拼图就是编排。我在项目中尝试过两种编排模式各有适用场景。第一种是中心化编排。一个 Orchestrator 负责接收大任务、拆解成子任务、分发给具体 Agent、收集结果、然后汇总。优点是流程清晰适合任务链相对固定的场景。缺点是编排器容易成为单点所有通信都要经过它。第二种是去中心化编排。基于 A2A每个 Agent 都可以直接向其他 Agent 发起协作编排器只做轻量调度。优点是并行度高、模块更独立不容易出现中心瓶颈缺点是调试难度大需要约定好协作规范。实际项目里我采用的是混合模式核心任务链用中心化编排保证稳定旁边挂一个去中心化的轻量协作通道让两个 Agent 在需要时可以互相对话。5.2 任务分解与会话摘要编排器的两个基本功编排器最核心的两个能力一是任务分解二是会话摘要。任务分解的本质是把一个大任务拆成多个子任务并确保子任务之间有明确的输入输出契约。一个“生成项目脚手架并完成代码审查”的请求会被拆成需求分析 Agent 读取需求文档输出模块清单。编码 Agent 根据模块清单生成项目代码。审查 Agent 检查代码输出问题列表。编排器把问题列表回传给编码 Agent进入修复循环。会话摘要也很关键。Agent 之间传递完整上下文是不现实的因为每次都把所有历史消息发过去token 消耗会高得吓人。我的做法是让每个 Agent 在完成任务后输出一段紧凑的结构化摘要编排器只把摘要向下游传递。这样既保持了信息连贯又控制了上下文成本。5.3 一份编排器最小实现我用异步任务调度的方式写了一个最小编排器骨架import asyncio async def orchestrate(goal: str, agents: dict): # 1. 由规划 Agent 拆解任务 plan_text await agents[planner].run(goal) tasks parse_plan(plan_text) # 2. 并行分发子任务 async def dispatch(task): agent agents[task[agent]] result await agent.run(task[prompt]) return {task_id: task[id], result: result} results await asyncio.gather(*(dispatch(t) for t in tasks)) # 3. 汇总并交给审查 Agent merged \n.join(r[result] for r in results) final await agents[reviewer].run(merged) return final这个骨架的扩展方式很关键当我要新增一个测试 Agent 时不需要修改编排器的分发逻辑只需要在 agents 字典里注册它并让规划 Agent 在拆解时知道它可以处理“写测试”类任务。这就是“可编排、可扩展”落到代码层面的体现。5.4 可扩展性不是堆功能是改配置我在最初设计时犯过一个错误总想在编排器里加更多控制逻辑比如专门处理某种特殊任务的分支。结果代码越来越复杂每加一个 Agent 都要改一遍编排逻辑。正确的方向是反过来——让编排器保持极简把复杂的能力放到 Agent Card 和 Skills 里。编排器只认“能力标签”任务需要什么能力就路由到什么 Agent。新加一个具备“安全审查”能力的 Agent我只需要注册它的 Agent Card并在规划 Agent 的 Skill 里补充一条“发现安全审查任务时路由给安全审查 Agent”。这种模式跑起来之后加 Agent 就真的变成了加配置而不是加代码。6. 落地实操搭一个“需求分析→编码→审查”的三 Agent 流水线6.1 分工与能力声明我选了一个非常典型的场景来演示生成一个带登录和权限控制的前端页面。三个 Agent 的分工如下Analyst Agent负责拆需求输出页面结构和功能清单。Coder Agent负责写代码按清单生成 React 项目。Reviewer Agent负责审查安全性与可访问性并输出修改建议。分工确定后我给每个 Agent 写一份 Agent Card。这样做的好处是编排器永远通过能力标签选择 Agent而不是通过 IP 地址或函数名。6.2 挂载 Skills 与 MCP三个 Agent 都不是白板需要挂上对应的 Skills 和 MCP 服务。我当时的配置大致长这样agents: analyst: skills: - requirement-analysis mcp: - codebase-search a2a_url: http://localhost:8001/a2a coder: skills: - frontend-coding - codegen mcp: - codebase-search - figma-mcp a2a_url: http://localhost:8002/a2a reviewer: skills: - code-review - security-check mcp: - codebase-search a2a_url: http://localhost:8003/a2a这里 frontend-coding skill 里定义了“登录页要遵循密码强度校验、Token 存储要用 HttpOnly Cookie”等约定codebase-search MCP 让每个 Agent 都能检索仓库已有代码避免重复造轮子。6.3 用 A2A 通起三个 Agent三个 Agent 的 A2A 包装逻辑完全一致。Coder 收到 Analyst 的输出时拿到的是一份标准 JSON-RPC 消息它内部把消息转成自己的 Skill 输入生成代码后再以标准消息发回给编排器。Reviewer 同样通过标准消息收到代码检查完输出“必须修改项”和“建议项”。这一层做扎实之后三个 Agent 之间的耦合就彻底降到最低。任何一个 Agent 内部重构都不会影响上下游。6.4 跑一轮真实任务的完整记录实际跑一轮任务的流转记录步骤负责 Agent输入输出1Analyst用户需求登录页 权限控制功能模块清单、状态设计建议2Coder功能模块清单React 页面源码、路由配置3ReviewerReact 页面源码2 个必须修改项、3 个建议项4Coder审查问题列表修订后的代码第一步的清单解析很顺利因为 Analyst Agent 挂了 requirement-analysis Skill输出格式是固定的。第二步生成代码时出现过一次组件命名不符合仓库规范的问题Reviewer 在第三步抓了出来回传给 Coder 修正。第四步修订完成后整条流水线跑完。整个过程中编排器做得很少它只是把上一步的输出作为下一步的输入转发并维护一份状态。真正决定工作质量的是每个 Agent 身上挂的那组 Skills 和外部工具。这个案例验证了开头的判断单个 Agent 的强能力不等于团队能力只有协议层和技能层都标准化了集群的产出才会稳定。7. 半年实战里我总结的坑与经验7.1 MCP Server 卡死先查同步阻塞我第一次把 MCP 接入生产环境时遇到了 Agent 长时间无响应的问题。刚开始以为是模型推理变慢了排查了很久发现是 MCP Server 里一个文件压缩函数是同步阻塞的处理一个大目录时把整个事件循环卡住了。排查链路是这样的先确认不是 Agent 本身的问题单独调用模型响应正常。在 MCP Server 入口打日志发现请求到达了但迟迟没有返回。进一步定位到是函数内部同步 IO 阻塞了异步循环。改成异步 IO 后问题消失。这类问题在本地调试时不容易暴露因为数据量小。我的经验是把 MCP Server 当成一个正经的后端服务来对待加超时、加日志、跑压测而不是写完一个函数就丢给 Agent 用。7.2 Skills 贪多引发的上下文爆炸有一段时间我见到好用的 Skills 就想装装了十几个结果 Agent 的表现反而变差了。后来我才想明白原因宿主并不是把所有 Skill 都塞进上下文但它需要先浏览一遍所有 Skill 的 description 来判断是否触发。Skills 数量太多时判断本身就消耗了大量上下文真正留给任务的 token 就少了。调整方式是我现在只给每个 Agent 保留三到五个最相关的核心 Skill其余按任务动态加载。并且每个 Skill 的 description 都写得足够精确让宿主能快速“命中”而不是反复比对。7.3 A2A 死循环与编排器单点A2A 让 Agent 之间可以互相通信也带来了一个头疼的问题循环调用。有一次 Reviewer 发现自己不确定某个业务逻辑就去问 CoderCoder 又回头问 AnalystAnalyst 为了回答这个问题又要看代码最后形成了一串没有终点的调用链。我的解决方法是设两层防护第一层在编排器里设置最大协作深度和总调用次数上限超过就强制终止第二层在每条 A2A 消息里带上任务来源与优先级标识收到回环消息时 Agent 可以识别并放弃响应。编排器作为单点的问题同样踩过所有消息都经过它的时候它成了性能瓶颈。现在的混合模式把高频执行路径上的消息改为 Agent 间直连编排器只保留决策路径上的消息压力明显降下来。7.4 我的几条经验法则这套组合跑了大半年我最后沉淀下来的经验法则很简单一个集群的稳定性取决于协议边界是否清晰而不是单个 Agent 能力是否强大。新 Agent 入集群先补 Agent Card再讨论功能实现没有能力声明的 Agent 一律不接入。Skill 宁可少而精不要多而杂一个任务真正用到的 Skill 通常不超过三个。任何跨越 Agent 边界的消息都要有超时和审计日志否则出问题只能靠猜。编排器结构保持简单复杂逻辑放在 Agent 内部消化。把 DeepAgents、MCP、A2A、Skills 这套组合完整落地之后我的感受是多智能体集群并没有玄学它就是把工具、方法、通信、调度四件事一件一件做好。每次踩坑基本都能回到这四个层里找到原因。希望这篇内容能让你在搭自己的 Agent 集群时少走一些弯路。