
1. 从单体到集群为什么我们需要重新思考 Agent 的构建方式过去一年我一直在折腾各种 Agent 项目从最简单的单轮对话机器人到带工具调用的复杂工作流踩过的坑可以说能写一本书。最开始我的做法很朴素一个 Agent 配一套工具把所有能力都塞进去让它自己判断该干什么。结果就是提示词越写越长工具描述越堆越多模型在关键时刻开始犯迷糊——该调工具的时候不调不该调的时候乱调上下文窗口被工具定义占掉一大半真正有用的信息反而被挤出去了。这个问题的本质其实和软件工程早期从单体应用走向微服务的演进逻辑一模一样。当系统复杂度超过某个临界点把所有东西耦合在一起只会让维护成本指数级上升。多智能体Multi-Agent的思路就是从这里来的与其造一个无所不能的超级 Agent不如造一群各司其职的小 Agent让它们通过标准化的协议互相协作。但光有多还不够。我见过太多所谓的多智能体系统本质上只是把几个提示词拼在一起轮流调用Agent 之间没有真正的通信机制也没有能力发现机制扩展一个新 Agent 就得改一遍主流程代码。这种伪多智能体在实际项目里根本扛不住需求变化。真正让多智能体从概念走向工程化的是最近这一波协议和框架的成熟。MCPModel Context Protocol解决了 Agent 与外部工具、数据源之间的标准化连接问题A2AAgent-to-Agent解决了 Agent 与 Agent 之间的互通问题Skills则把可复用的能力封装成模块让 Agent 可以像装插件一样获得新技能。而DeepAgents这类框架负责把这些零件编排成一个可运行、可扩展的集群。这套组合拳打下来Agent 系统的构建范式就变了从写一个聪明的提示词变成设计一套可编排、可互通、可扩展的架构。这篇文章我想把这几个概念串起来讲清楚重点不是复述官方文档而是分享我在实际搭建过程中对每个环节的理解、选型考量和踩坑经验。不管你是刚接触 Agent 的新手还是已经做过几个项目想升级架构的老手应该都能从中找到能直接抄作业的部分。2. 四个核心概念拆解MCP、A2A、Skills、DeepAgents 到底各管什么在动手之前必须先把这四个东西的边界理清楚。我刚开始接触的时候也犯过迷糊觉得它们功能好像有重叠后来画了一张职责图才彻底想明白。简单说它们分别解决的是连接、通信、能力、编排四个层面的问题缺一不可。2.1 MCPAgent 与外部世界的标准化接口MCP 是什么用一句话概括它是一套让模型能够以统一方式访问外部工具和数据源的协议。在没有 MCP 之前每接一个工具你都得写一套适配代码——查数据库写一套调 API 写一套读文件又写一套工具一多就是灾难。MCP 把这些访问方式抽象成标准的 ServerAgent 作为 Client 去连接工具的描述、参数、返回值都有统一的格式。我实测下来MCP 最大的价值在于解耦。工具的实现和 Agent 的逻辑彻底分开了工具团队可以独立开发、独立部署、独立升级Agent 这边只需要知道有这么个 MCP Server 提供这些能力就行。这跟微服务里服务注册发现的思路是一致的。MCP 的核心概念有三个Resources资源比如文件、数据库记录这类可读取的数据、Tools工具可执行的操作、Prompts预置的提示词模板。实际用的时候Resources 适合放那些需要被引用的上下文Tools 适合放需要主动触发的动作。很多人一开始会把所有东西都做成 Tool结果就是工具列表爆炸模型选择困难。我的经验是只读的、作为上下文注入的用 Resource会产生副作用或需要参数交互的用 Tool。2.2 A2A让 Agent 之间能互相说话A2A 解决的是 Agent 之间的通信问题。如果说 MCP 是 Agent 对外部工具的手那 A2A 就是 Agent 之间的嘴和耳朵。它定义了一套 Agent 之间发现、协商、委派任务的标准。这里有个关键概念叫Agent Card可以理解成 Agent 的名片里面描述了它是谁、能干什么、怎么调用它。有了 Agent Card一个 Agent 就能动态发现其他 Agent 的能力而不需要硬编码调用关系。我见过有人问如何把 agent 暴露出 a2a agentcard其实就是在问怎么给自己的 Agent 生成这张名片——通常框架会提供自动生成的能力你只需要声明 Agent 的元数据和能力列表。A2A 和 MCP 的区别经常被搞混。我的理解是MCP 面向工具A2A 面向对等体。工具是被动的、无状态的、执行完就返回而对等 Agent 是有自己上下文的、可能进行多轮协商的、甚至可能反过来委派任务给你的。所以 A2A 的协议设计比 MCP 更复杂涉及任务生命周期管理、状态同步这些。2.3 Skills可插拔的能力模块Skills 这个概念最近特别火各种skills 推荐、skills 下载平台的讨论满天飞。它的本质是把一组相关的提示词、工具调用、处理逻辑打包成一个可复用的模块Agent 需要的时候加载进来就行。我特别喜欢 Skills 的一个设计理念渐进式披露。也就是说Agent 平时不需要知道所有 Skill 的细节只需要知道有这么个技能存在等真正用到的时候再加载完整定义。这直接解决了上下文窗口被撑爆的问题。你想想如果一个 Agent 挂了 50 个技能每个技能定义 500 字光技能描述就 25000 字还没开始干活上下文就满了。渐进式披露让这个开销降到最低。Skills 和 MCP Tool 的关系也值得说清楚。一个 Skill 内部可以调用多个 MCP Tool也可以包含纯提示词逻辑。Skill 是更高层的封装面向完成一类任务而 Tool 是更底层的原子操作。打个比方Tool 是螺丝刀、扳手Skill 是修水管这个完整技能包。2.4 DeepAgents把上面三个编排成集群DeepAgents 这类框架的角色是总指挥。它负责管理多个 Agent 的生命周期、根据任务分配合适的 Agent、协调它们之间的 A2A 通信、按需加载 Skills、连接 MCP Server。没有它前面三个协议就是散落的零件有了它才能组成一台能运转的机器。一个设计良好的 DeepAgents 集群应该具备几个特征可编排能灵活定义 Agent 之间的协作流程、可互通Agent 之间通过 A2A 自由通信、可扩展加一个新 Agent 或 Skill 不需要改动核心逻辑。这也是标题里那三个可字的含义。概念解决的问题类比关键抽象MCPAgent 与外部工具/数据的连接手和感官Server / Client / Tool / ResourceA2AAgent 之间的通信与协作嘴和耳朵Agent Card / Task / MessageSkills能力的模块化封装与复用技能包Skill 定义 / 渐进式披露DeepAgents整体编排与生命周期管理大脑和神经系统Agent 编排 / 任务路由3. 架构设计一个可编排、可互通、可扩展的 Agent 集群长什么样理解了四个概念之后接下来是真正考验功力的部分——怎么把它们组装成一个能跑的系统。我前后重构过三版架构前两版都因为扩展性问题推倒重来第三版才算稳定下来。这一节我把设计思路和关键决策讲透。3.1 分层设计为什么一定要分层我的架构分成四层从下到上依次是连接层、能力层、协作层、编排层。连接层由 MCP Server 组成负责对接所有外部系统——数据库、API、文件系统、第三方服务。这一层的原则是只做连接不做业务逻辑每个 Server 尽量单一职责。我见过有人把一堆不相干的工具塞进一个 MCP Server结果就是任何一个工具出问题都影响整组排查起来极其痛苦。能力层是 Skills 的天下。每个 Skill 封装一类任务的完整处理逻辑内部可以调用多个 MCP Tool。比如一个数据分析Skill内部可能调用数据库查询 Tool、图表生成 Tool、统计计算 Tool。这一层的关键是高内聚——一个 Skill 应该能独立完成一类任务而不是把任务拆得七零八落。协作层处理 Agent 之间的 A2A 通信。这里要定义清楚哪些 Agent 是专家 Agent负责具体领域任务哪些是协调 Agent负责任务分解和分派。协调 Agent 不直接干活它只负责把大任务拆成小任务然后通过 A2A 委派给合适的专家 Agent。编排层是 DeepAgents 框架所在的位置负责整个集群的启动、注册、路由、监控。这一层对上层应用暴露统一的入口对下层管理所有 Agent 的生命周期。分层的最大好处是变更隔离。加一个新工具只动连接层加一个新技能只动能力层加一个新 Agent 只动协作层编排逻辑基本不用改。这就是可扩展的工程含义。3.2 Agent 粒度怎么定太粗和太细都是坑这是我在实际项目里纠结最久的问题。Agent 拆得太粗又回到了单体 Agent 的老路拆得太细Agent 之间通信开销爆炸一个简单任务要经过七八个 Agent 转手延迟高得没法用。我的经验法则是按领域边界而不是功能点来划分 Agent。比如一个电商场景按领域划分是商品 Agent、订单 Agent、客服 Agent、推荐 Agent如果按功能点划分就会变成查询 Agent、计算 Agent、格式化 Agent后者明显不合理因为一个查询任务往往需要跨多个功能点。判断粒度是否合适的标准是一个 Agent 应该能独立完成一类完整的用户意图。如果用户的一个请求需要三个以上 Agent 接力才能完成说明拆得太细了如果一个 Agent 内部逻辑复杂到需要几十个 Skill 才能覆盖说明拆得太粗了。3.3 通信模式同步、异步还是事件驱动A2A 通信有三种模式各有适用场景我在项目里是混用的。同步请求-响应适合那些需要立即拿到结果的场景比如协调 Agent 问专家 Agent这个订单状态是什么必须等答案才能继续。这种模式实现简单但会阻塞调用方链路长了延迟会累积。异步任务适合耗时操作比如生成一份月度报告这种可能要跑几分钟的任务。协调 Agent 提交任务后拿到一个任务 ID然后可以继续处理其他事情等专家 Agent 完成后通过回调或轮询获取结果。事件驱动适合松耦合的广播场景比如库存变化这种事件可能同时被订单 Agent、推荐 Agent、补货 Agent 关心。发布方不需要知道谁在监听订阅方按需订阅。提示不要一上来就全用事件驱动看起来优雅但调试极其困难。我的建议是默认用同步只在明确需要解耦或耗时的场景才引入异步和事件。3.4 状态管理多智能体系统最容易翻车的地方多智能体系统比单体 Agent 复杂十倍的地方就在状态管理。单体 Agent 只有一个上下文多智能体系统里每个 Agent 都有自己的上下文还要维护共享状态、任务状态、会话状态。我的做法是三层状态分离Agent 私有状态只属于自己比如自己的对话历史、任务状态一次任务协作过程中的共享状态任务结束就销毁、全局状态跨任务的持久化状态比如用户偏好、长期记忆。任务状态是最容易出问题的。多个 Agent 并发读写同一个任务状态很容易出现竞态。我的解决方案是给任务状态加版本号每次更新检查版本冲突就重试。听起来很土但实测比引入复杂的分布式锁简单可靠得多。4. 实操搭建从零跑通一个多智能体集群理论讲完了这一节直接上干货。我会用一个智能客服集群作为示例完整走一遍搭建流程。这个场景足够典型涉及工具调用、技能复用、Agent 协作能覆盖大部分实际需求。4.1 环境准备与依赖安装先把基础环境搭起来。我用的 Python 3.11太老的版本有些异步特性支持不好。python -m venv agent-env source agent-env/bin/activate pip install deepagents mcp a2a-sdk这里有个坑要提醒MCP 和 A2A 的 SDK 版本更新非常快接口经常变。我建议在 requirements 里锁死版本号别用否则某天自动升级后代码直接跑不起来。我踩过一次一个周末回来发现 CI 全红排查半天才发现是 SDK 的 breaking change。环境变量方面至少需要配置模型 API 的 key 和 base url。我习惯用.env文件管理配合python-dotenv加载。MODEL_API_KEYyour_key_here MODEL_BASE_URLyour_endpoint_here MCP_CONFIG_PATH./mcp_config.json4.2 搭建第一个 MCP Server先做一个最简单的 MCP Server提供订单查询能力。我用官方 SDK 的装饰器风格代码量很少。from mcp.server import Server from mcp.types import Tool, TextContent app Server(order-service) app.list_tools() async def list_tools(): return [ Tool( namequery_order, description根据订单号查询订单详情, inputSchema{ type: object, properties: { order_id: {type: string, description: 订单号} }, required: [order_id] } ) ] app.call_tool() async def call_tool(name: str, arguments: dict): if name query_order: order_id arguments[order_id] result await fetch_order_from_db(order_id) return [TextContent(typetext, textstr(result))]写完 Server 之后在mcp_config.json里注册它Agent 启动时会自动连接。{ mcpServers: { order-service: { command: python, args: [servers/order_server.py] } } }注意MCP Server 的description字段非常关键模型就是靠它来判断什么时候该调用这个工具。描述写得太模糊模型就会漏调或误调。我的经验是描述里要包含什么时候用和返回什么而不只是这是什么。4.3 定义可复用的 Skills接下来把订单相关的操作封装成一个 Skill。Skill 的定义通常包含元数据、触发条件、执行逻辑三部分。from deepagents.skills import Skill, skill skill( nameorder_inquiry, description处理用户关于订单状态、物流、退换货的咨询, triggers[订单, 物流, 发货, 退货, 换货] ) class OrderInquirySkill(Skill): async def execute(self, context): order_id await self.extract_order_id(context.query) if not order_id: return 请提供订单号我来帮您查询 order await self.call_mcp_tool(order-service, query_order, {order_id: order_id}) return self.format_response(order)这里体现了 Skills 的核心价值触发条件让 Agent 知道什么时候该用这个技能执行逻辑封装了完整的处理流程而 Agent 本身不需要知道内部细节。渐进式披露就体现在这里——Agent 平时只加载 Skill 的 name 和 description只有触发时才加载完整实现。4.4 用 A2A 连接多个 Agent现在定义两个专家 Agent订单 Agent 和物流 Agent让它们通过 A2A 协作。from a2a import Agent, AgentCard order_agent Agent( nameorder_expert, cardAgentCard( nameorder_expert, description处理订单相关的所有问题, capabilities[order_query, order_modify, order_cancel], endpointhttp://localhost:8001 ), skills[OrderInquirySkill()] ) logistics_agent Agent( namelogistics_expert, cardAgentCard( namelogistics_expert, description处理物流追踪、配送异常问题, capabilities[track_package, report_delay], endpointhttp://localhost:8002 ), skills[LogisticsSkill()] )Agent Card 里的capabilities是 A2A 发现的关键。协调 Agent 拿到用户请求后会先匹配 capabilities找到合适的专家 Agent 再委派。4.5 编排层让 DeepAgents 把一切串起来最后是编排层定义协调 Agent 和整体流程。from deepagents import Orchestrator orchestrator Orchestrator( namecustomer_service, agents[order_agent, logistics_agent], routing_strategycapability_match, fallback_agentgeneral_expert ) async def handle_request(user_query): result await orchestrator.dispatch(user_query) return resultrouting_strategy我选了capability_match也就是根据 Agent Card 里的能力匹配来路由。还有llm_route让模型判断该给谁和round_robin轮询等策略。实测下来能力匹配在 Agent 数量少于 20 个时最稳定超过之后建议上向量检索做语义匹配。4.6 参数调优几个我反复调过的关键参数搭建过程中有几个参数我调了很多次才找到合适的值这里直接给结论。参数作用我的推荐值调整理由max_handoff_depthAgent 间最大委派深度3超过 3 层延迟明显且容易死循环skill_load_threshold技能加载的匹配阈值0.75太低会误加载太高会漏加载task_timeout单任务超时60s大部分任务 30s 内完成留一倍余量context_window_ratio上下文占用上限0.7留 30% 给工具返回和推理max_handoff_depth这个参数特别重要。我一开始没设限制结果两个 Agent 互相委派形成了死循环任务永远跑不完。加上深度限制后超过就返回无法处理给用户至少不会卡死。5. 常见问题与排查技巧实录这一节是我踩坑踩出来的经验很多问题官方文档里不会写但实际项目里几乎一定会遇到。5.1 Agent 不调用工具怎么办这是最高频的问题。模型明明有工具可用却选择直接回答。排查顺序是这样的先看工具描述是否清晰。我遇到过描述写成查询数据的模型根本不知道查什么数据、什么时候该查。改成根据用户提供的订单号查询订单的详细状态包括支付、发货、物流信息之后调用率立刻上来了。再看工具数量是否过多。超过 20 个工具后模型的工具选择准确率会明显下降。这时候要么用 Skills 做分组要么引入工具检索机制只把相关的工具注入上下文。最后检查提示词里有没有明确的调用引导。有时候加一句遇到需要实时数据的问题优先调用工具而不是凭记忆回答就能解决。5.2 A2A 通信超时或丢消息A2A 通信出问题八成是网络或序列化的问题。我的排查清单检查 Agent Card 里的 endpoint 是否可达用 curl 直接打一下检查消息序列化格式A2A 对消息结构有严格要求字段缺失会静默失败检查超时设置跨机器的 A2A 调用默认超时可能太短检查是否有防火墙或网络策略拦截提示A2A 调试时一定要开详细日志把每条消息的收发都打出来。我吃过亏一个字段名拼错导致消息被丢弃但没有任何报错排查了整整一天。5.3 Skills 加载失败或冲突Skills 的问题通常是两类加载失败和触发冲突。加载失败多半是路径或依赖问题。Skills 如果依赖特定的 MCP Server要确保 Server 先启动。我建议在编排层加一个启动顺序管理按依赖关系依次启动。触发冲突是指多个 Skill 的触发条件重叠导致模型不知道该用哪个。解决办法是给 Skill 加优先级或者在触发条件里加更具体的限定词。比如订单查询和订单修改都含订单就要在描述里明确区分场景。5.4 上下文爆炸与性能下降多智能体系统跑久了上下文会越来越长响应越来越慢。这是渐进式披露要解决的核心问题但如果实现不到位还是会爆。我的做法是三层控制Skill 层面只加载元数据用到才加载完整定义Agent 层面定期压缩历史把久远的对话总结成摘要编排层面给每个 Agent 设上下文上限超了就触发压缩或清理。实测下来做好这三层控制一个跑了几个小时的会话上下文占用能稳定在初始值的 2 倍以内而不是线性增长。5.5 常见问题速查表现象可能原因排查方向解决思路Agent 不调工具描述模糊/工具过多看工具描述和数量优化描述分组或检索A2A 超时网络/序列化/超时设置打日志看消息收发检查 endpoint 和格式Skill 不触发触发条件不匹配看触发词和查询调整触发词或加优先级响应变慢上下文膨胀看 token 占用三层上下文控制任务死循环委派无深度限制看 handoff 链路设 max_handoff_depth结果不一致状态竞态看并发读写加版本号乐观锁6. 扩展方向这套架构还能怎么玩搭好基础集群之后我陆续做了几个扩展效果都不错这里分享给想继续深入的朋友。第一个扩展是给 Agent 加长期记忆。基础架构里 Agent 只有会话内的上下文会话结束就忘了。我接了一个向量数据库作为长期记忆层把重要的交互和结论存进去下次遇到相关问题时先检索记忆再回答。实测下来用户重复问类似问题时体验提升明显。第二个扩展是引入 Agent 自省机制。让 Agent 在完成任务后自己评估一下这次做得怎么样把评估结果反馈给编排层用于优化路由策略。这个机制让系统有了自我改进的能力跑得越久路由越准。第三个扩展是多模态能力接入。现在的 Agent 主要处理文本但实际场景里图片、语音、文档都很常见。通过 MCP 接入多模态处理工具让 Agent 能看懂图片、听懂语音应用范围一下子打开了。这也是最近多模态大模型进展带来的红利工具侧的成熟让 Agent 的多模态能力落地变得简单了很多。第四个扩展是跨集群协作。单个集群的 Agent 数量有上限超过之后路由效率会下降。可以把集群按领域拆分集群之间通过 A2A 互通形成一个更大的 Agent 网络。这时候 Agent Card 的发现机制就变得更重要了需要一个类似服务注册中心的角色来管理所有集群的 Agent 信息。我在实际项目里最深的一个体会是多智能体系统的复杂度不在于单个 Agent 有多聪明而在于它们之间的协作是否顺畅。我见过太多团队把精力花在优化单个 Agent 的提示词上结果协作层一塌糊涂整体效果还不如一个简单的单体 Agent。把 MCP、A2A、Skills、编排这四层的地基打牢比什么都重要。另外一个小建议先用最少的 Agent 跑通端到端流程再逐步拆分和扩展一上来就设计一个十几个 Agent 的复杂集群大概率会在调试阶段就崩溃。