最近我把手上散落的十几个Agent脚本整理成了一个集群,过程中最大的感触是:单Agent写demo确实爽,但一旦要"接十几个外部工具、让多个Agent互相配合、把一套经验沉淀复用",立刻就乱了。这次用DeepAgents作为编排框架,配合MCP统一工具接入、A2A打通Agent之间的通信、Skills承载可复用能力,总算把整套东西跑通了。这篇文章就把整个项目从0到1的搭建过程、踩坑记录和架构取舍完整聊一遍,适合已经跑通过单个Agent、正准备往多Agent或工程化方向走的同学参考。
1. 先想清楚一个问题:单Agent还够用吗,为什么非要搞集群
1.1 我遇到的三个真实瓶颈
在动手之前,我其实是有点抗拒"多智能体"这件事的,总觉得是概念大于实效。但在持续维护几个Agent之后,有三个问题绕不过去。
第一个是工具墙。一个Agent要干活,就得接各种外部能力:浏览器操作、文件读写、API调用、数据库查询。如果没有一个统一协议,每加一个工具就要写一遍接入代码、处理一遍认证。我最早写的一个爬虫类Agent,代码里有几十个if-else分支来处理不同的工具调用,后来加一个简单的"读取PDF"功能都得小心翼翼地改,生怕碰坏其他逻辑。
第二个是上下文墙。LLM的上下文窗口再大也是有限的。单个Agent既要携带系统提示词、工具说明、历史对话,又要塞进业务规则,一个长任务跑到一半就接近窗口上限了。更麻烦的是,并发来了以后,一个超长任务能拖垮整个进程,其他任务全在后面排队。
第三个是协作墙。当任务拆给不同Agent去做的时候,中间结果靠人肉搬运、格式靠约定,完全不可控。比如信息采集Agent把结果写到JSON文件里,下游分析Agent又得写一套解析器,字段名稍微对不上就静默出错。这本质上不是"多一个Agent"的问题,而是Agent之间没有标准的协作方式。
1.2 集群方案的三根支柱
解决上面三个问题,我最后落地的方案是三根支柱,这也是这门课的项目名称里三件套的含义:
| 组件 | 解决的问题 | 一句话定位 |
|---|---|---|
| MCP (Model Context Protocol) | Agent怎么用外部工具 | 给Agent插上标准化的"工具插座" |
| A2A (Agent-to-Agent) | Agent之间怎么通信协作 | 给Agent发"名片"、派活、回传结果 |
| Skills | 怎么沉淀一套可复用的做事方法 | 把"会做某件事"打包成可共享的交付物 |
这三者其实是不同层面的东西。MCP是工具层协议,A2A是Agent协同层协议,Skills是能力封装层。很多人把它们混在一起比较,其实是没搞清分层。
1.3 用硬件协议类比,理解MCP到底是个什么概念
热搜里有人问"mcp是软件协议,硬件协议那个概念叫什么来着",我猜大家晕的点在于"协议"这个词太抽象。换个类比就好懂了:MCP之于Agent,很像USB接口之于电脑。USB不关心你是U盘还是键盘还是摄像头,只要都按同一个电气和通信规范来插,电脑就能识别、供电、传数据。MCP也一样,它不关心你的工具是GitHub、数据库还是浏览器,只要用同一套JSON-RPC格式去暴露能力,Agent就能调用。
A2A则更像网络里的HTTP。Agent是"服务器",彼此通过AgentCard"主页"介绍自己会干什么,然后用类似HTTP请求的方式把一个任务发给对方,异步回传进度和结果。Skills则更像"安装包里附带的驱动和说明书"——它不只是教模型"要做什么",更强调可执行的脚本、校验规则和验收标准。
搞清楚分层之后,后面每一步搭建就不会乱套了。
2. DeepAgents:把"编排"从代码里抽出来
2.1 DeepAgents在集群里扮演的角色
这套集群里我把DeepAgents定位成编排中枢。它干三件事:接收任务、拆解调度、维护状态。它本身不代替LLM做决策,而是给LLM提供运行环境和协同框架,具体来说就是:
- 编排:把用户发来的一句话任务拆成多个子步骤,决定先后顺序和谁来执行。
- 状态管理:一个Agent任务执行到一半挂了,编排层要知道它挂在哪一步、能不能重试、要不要回滚。
- 节点管理:A2A网络里哪些Agent在线、各自的能力是什么、负载如何。这部分就是热词里大家常说的"agent框架与编排"的核心。
一开始我试过用传统工作流引擎(类似BPMN、DAG拖拽编排)来做这件事,后来放弃了。原因在于LLM Agent的路径是动态的:同一个任务,模型这次可能走三步完成,下次可能走五步,中间还可能根据外部反馈临时调整。传统工作流要求把路径提前画死,根本兜不住这种不确定性。所以DeepAgents的编排方式是"策略驱动"的:定义好每一步的约束和策略,至于具体怎么走,让Agent做计划、编排层做监督。
2.2 核心抽象概念:Task、Step、Policy、Peer
这套框架里我建议先把四个核心概念吃透:
- Task:一次任务的完整意图。比如"检查这个页面上的文案是否合规"。每个Task有全局唯一的TaskId,这个Id是后面做幂等、做追踪的关键。
- Step:Task拆出来的子步骤。一个Step可以对应一个Agent调用,也可以对应一次MCP工具调用。Step之间可以有依赖关系,但顺序不一定完全固定。
- Policy:编排策略。比如"这个Step超时30秒就重试一次""失败3次就转人工""只允许A类Agent执行"。策略是写死的配置,但决策是动态的。
- Peer:A2A网络里的Agent节点。Peer通过AgentCard暴露自己会什么、接收什么格式的任务,DeepAgents通过Peer信息来决定把Task派给谁。
2.3 最小配置示例
用YAML配置一个最简单的编排任务是这样的:
cluster: name: content-review-cluster peers: - id: visual-agent type: a2a endpoint: http://localhost:9101/ tasks: - id: page-visual-review policy: timeout: 60s retry: 2 assign: visual-agent steps: - name: fetch-page use: mcp://playwright/screenshot param: url: ${input.url} - name: review-layout use: skill://frontend-review这段配置的意思是:创建一个内容走查集群,注册一个visual-agent节点;定义了一个页面视觉走查任务,超时60秒、失败重试2次;第一步用Playwright MCP截图,第二步用前端审查Skill来做分析。DeepAgents拿到这个配置后,会动态生成执行计划并分发给对应的Peer。实际跑起来之后,你会发现"流程"不再是一张死板的设计图,而是一个活的执行过程。
2.4 为什么编排层不能直接用代码堆
有人会说:这些逻辑我不用框架,直接写代码也能实现。确实能,但代价是很快失控。我的教训是:把编排逻辑散落在业务代码里,等于把"谁来干、什么时候干、挂了怎么办"这些本该是配置的东西硬编码了。一旦要调整策略,就得改代码、重新部署。而DeepAgents把编排抽成"配置+策略引擎"之后,调并发、改超时、换Agent节点都只需要改配置,运行时不会受到影响。这对我后面解决"Agent怎么扛并发"的问题帮助极大。
3. MCP实战:让每个Agent用上外部工具
3.1 MCP的本质与传输方式
MCP走的是JSON-RPC 2.0,核心是Client-Server模型。Agent这边是客户端,工具那边是服务端,中间还有一个Host(比如IDE、桌面客户端、编排器)负责管理会话。传输方式最常见的是两种:
- stdio:MCP Server以本地子进程方式运行,通过标准输入输出通信。适合本地开发、工具数量不多的场景。
- HTTP/SSE:MCP Server作为独立服务部署,Agent通过网络调用。适合集群化部署、多个Agent共享同一组工具。
实操中我的建议是:开发阶段用stdio,方便调试;上线阶段全部切成HTTP,因为编排层和Agent往往是分离部署的,stdio没法跨机器。
3.2 手写一个最小MCP Server
不管社区里有多少现成的Server,我还是建议亲手写一个最小的,因为这样才能理解MCP的工作机制。下面是一个通过stdio返回"当天天气"的工具示例(这里用Python,基于官方MCP SDK的常见写法):
from mcp.server import Server import json app = Server("weather") @app.list_tools() async def list_tools(): return [ { "name": "get_weather", "description": "查询指定城市的实时天气", "inputSchema": { "type": "object", "properties": { "city": {"type": "string", "description": "城市名称"} }, "required": ["city"] } } ] @app.call_tool() async def call_tool(name: str, arguments: dict): if name == "get_weather": city = arguments["city"] # 这里替换成真实天气服务调用即可 result = {"city": city, "temperature": 24, "weather": "晴"} return json.dumps(result, ensure_ascii=False) # 通过stdio启动服务 if __name__ == "__main__": from mcp.server.stdio import run_server import asyncio asyncio.run(run_server(app))这段代码虽然简单,但结构是完整的:声明了工具名称、描述、参数Schema,并实现了实际调用逻辑。把它注册到Agent的配置里,Agent就能直接调用这个工具了。初次跑通之后你会明显感觉到,MCP带来的不是"调用工具这个动作",而是**"工具的描述、参数校验、调用方式"全都有了一套统一约定**。
3.3 现成Server盘点:Playwright MCP、Browser MCP、Figma MCP
社区里已有的MCP Server非常多,但真正高频用的其实就那么几类,我在项目里重点试了这几组:
| 名称 | 定位 | 优势 | 适用场景 |
|---|---|---|---|
| Playwright MCP | 浏览器自动化操作 | 能截图、点击、填表、读取DOM,贴近测试操作 | 页面走查、自动化测试、爬取 |
| Browser Use MCP | Agent"看网页"并完成网页任务 | 面向大模型优化了可访问性树,减少无效信息 | Agent自主浏览、表单填写、信息提取 |
| Figma MCP | 读取Figma设计稿数据 | 直接拿节点、样式、切图信息 | 设计稿转前端、视觉还原 |
| GitHub MCP | 仓库与Issue/PR操作 | 流程完整、鉴权简单 | 代码审查、CI触发、Issue管理 |
一个高频问题:Playwright MCP和Browser Use MCP到底有什么区别?
我实际对比过。Playwright MCP更偏"操作浏览器",它就像一个遥控器,Agent可以用它精准控制某个页面元素。Browser Use MCP则更偏"用浏览器完成任务",它会自动帮Agent理解页面结构,把干扰信息过滤掉,适合那种"打开某网站、找到目标信息、把信息返回"的开放任务。选型时我的经验是:如果你的任务链路明确(比如"点这个按钮、等结果、截图"),用Playwright MCP;如果任务开放(比如"帮我在这个网站上找到联系方式"),用Browser Use MCP更省Token也更容易成功。
还有一个容易踩的坑是MCP授权。比如Codex CLI接入Figma MCP的时候,经常出现"找不到MCP"或"鉴权失败",大多数情况下不是配置写错,而是授权流程没走完。Figma走OAuth,需要先在Figma侧创建应用拿到Client ID,配置回调地址,然后在本地完成OAuth登录。相比之下GitHub MCP用Personal Access Token就简单很多。我的建议是:先用只读类工具(如天气、搜索、GitHub只读)跑通流程,再逐步开放写操作的工具,这样即使授权出问题也不会造成数据事故。
3.4 MCP接入的常见问题
最近看到社区里有人把MCP功能合入到RuoYi-Vue-Pro这类后台管理框架中,这是个很有意思的方向:以后管理后台的Agent可以直接以MCP方式调用业务模块,而不是把所有业务逻辑卷进Agent里。我自己的经验是,做这类集成时一定要先确认外部系统是否提供了OpenAPI,MCP Server本质上只是"API的翻译层",如果底层接口本身混乱,MCP再标准也没用。
此外,MCP Server应该独立部署、独立进程。不要把它塞进Agent的主进程里,否则一旦某个工具调用死循环,整个Agent都会被拖垮。独立进程的好处是:出了问题只影响工具调用,重启服务即可,主Agent照常运行。
4. A2A:Agent之间怎么"说人话"
4.1 A2A协议要解决的问题
MCP解决了"Agent用工具"的问题,但Agent之间协同还需要一套对话方式。A2A(Agent2Agent)是Google提出来的开放协议,目标就是让不同的Agent框架能互相发现、互相派活。它的核心是三个概念:
- AgentCard:每个Agent对外发布的"名片",写清楚自己会做什么、接收什么类型的任务、回调地址是什么。相当于HTTP世界里的robots.txt加OpenAPI毛坯房。
- Task:跨Agent的任务对象,带状态。从
submitted到working再到completed或failed,整个过程可以被查询、被取消。 - Message与回调:Agent之间通过消息交换中间结果,支持异步Push通知,不用双方一直轮询等待。
我特别喜欢AgentCard这个设计。它把"这个Agent能干什么"变成了一种可发现可查询的信息,编排器拿到所有Peer的AgentCard之后,就能像一个"服务目录"一样做路由,而不是在代码里写死调用关系。
4.2 两种互通模式:点对点调用与总线式路由
我在集群里同时用了两种模式,根据场景切换:
| 模式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 点对点调用 | 节点少、拓扑固定、双方都长期在线 | 实现简单,延迟低 | 新节点需要手动改配置 |
| 总线式路由(注册中心+消息队列) | 节点动态伸缩、任务需要广播或负载均衡 | 扩展性好、解耦 | 引入中间件,运维成本高 |
前期节点少,点对点完全够用;到了十几个Peer之后,我开始把AgentCard注册信息丢进Redis,让编排器统一做路由。后来社区流行的Spring AI也推出了A2A支持,Java技术栈的同学可以直接把一个Spring Boot服务声明成一个A2A节点,自动发布AgentCard、处理任务请求,省了很多底层协议的功夫。
4.3 A2A与MCP的分工红线
很多人刚开始会在这两个协议间纠结,其实分工非常清晰:
- MCP是"Agent到工具"的协议,方向单一,工具不关心谁在调它,也没有会话状态概念。
- A2A是"Agent到Agent"的协议,双方对等,任务有生命周期,需要维护状态、支持回调。
举个实际例子:走查Agent发现页面上某个按钮样式异常,它希望让"视觉设计Agent"出个意见。这时走查Agent不能直接"调用"设计Agent的内部函数,而是应该通过A2A创建一个Task,附上截图和问题描述,让设计Agent处理完毕后回调结果。整个过程中,走查Agent是把设计Agent当作一个对等的协作者,而非一个"工具"。
4.4 一次A2A调用的实际时序
文字描述一次完整流程,我尽量不画图:
- DeepAgents收到用户请求:"检查某个页面的视觉和文案质量"。
- 编排器读取所有Peer的AgentCard,发现visual-agent和copy-agent都可用。
- 编排器向visual-agent发送Task请求,TaskId为
task-001,包含页面URL。 - visual-agent执行过程中使用了Playwright MCP截图、读取DOM,状态从
working更新到completed,并回调返回初步检查结果。 - 编排器发现需要文案方面的二次确认,于是创建
task-002发给copy-agent,并附上visual-agent的结果摘要。 - copy-agent处理完,回调返回文案修改建议。
- DeepAgents把两步结果聚合,返回给用户。
这套流程跑通之后,我发现原来常做的"人肉传JSON"彻底消失了,每个Agent的输入输出都变成了协议规定的数据结构。哪怕以后把某个Agent换成完全不同框架的实现,只要它发布AgentCard、遵守A2A协议,整个集群都不用改代码。
5. Skills:把经验打包成交付物
5.1 Skill到底是什么
热词里"skills"相关的搜索非常多:前端开发skills、codex skills、claude agent skills、superpower skills……这说明社区对"Agent技能"这个概念正处于高度关注期。以我的理解,Skill不是插件,也不只是Prompt模板,而是一套"可执行的做事方法"。
- 说它不是Prompt模板,是因为Skill里除了指令之外,还有可执行脚本、校验规则、参考文件。
- 说它不是插件,是因为Skill不一定需要对外暴露远程工具,它更多是"教模型怎么把一件事做好"。
打个比方:MCP Server是给了Agent一把电钻,Skill则是"如何使用电钻在特定墙体上打孔并验收"的完整操作规程。前者是能力,后者是方法论。
像Claude的Agent Skills和Codex的Skills生态,都遵循一个通用结构:一个SKILL.md文件作为入口,描述适用范围、步骤、验收标准,旁边附带脚本和资源文件。我在项目里给团队沉淀了多个Skill,最常用的两个是"前端视觉走查Skill"和"技术方案评审Skill"。
5.2 Skill包的标准结构
一个典型的Skill包目录大概是这样:
frontend-review/ ├── SKILL.md # Skill说明,模型首先读这个文件 ├── scripts/ │ ├── layout-check.py # 布局校验脚本,检查间距/对齐 │ └── contrast-check.py # 颜色对比度检查脚本 ├── schemas/ │ └── review-result.json # 输出结果的JSON Schema └── assets/ └── design-token.md # 设计规范参考其中SKILL.md是核心,它要做三件事:告诉模型这个Skill解决什么问题,给出标准流程,明确验收标准。我一般还会在里面写清"禁止做的事",避免模型自由发挥。
5.3 写一个"前端开发Skill"的示例
结合热词里大量"前端开发skills"搜索,我分享一下最常见的场景:让Agent把Figma设计稿转成Tailwind页面。这个场景是"MCP + Skill"配合的典型:
- MCP负责取数:Figma MCP把设计稿的节点、颜色、间距、字号这些元数据取出来。
- Skill负责定规则:告诉模型"颜色必须用设计Token,不要硬编码色值""间距只能从8px基准间距里取""先出静态HTML,再谈交互"。
SKILL.md里可以这样写:
# Frontend Implementation Skill ## 适用场景 把Figma设计稿还原为Tailwind HTML页面。 ## 处理步骤 1. 使用Figma MCP读取画板整体结构,先理解布局层次,不要急着写代码。 2. 从设计稿提取颜色值,映射到项目的design-token配置文件,禁止硬编码色值。 3. 间距从8px基准栅格选取,常用值为 8/16/24/32。 4. 先产出无JavaScript依赖的静态HTML,核对布局后再添加交互。 5. 最终输出附上截图对比,供走查Agent使用。 ## 验收标准 - 页面核心区块间距与设计稿一致,误差不超过4px - 所有颜色均来自design-token.md - 输出结果符合schemas/frontend-result.json这写在Skill里的东西,其实是平时开发规范里反复强调、但又很难每次都"教"给模型的东西。有了Skill,这些规范就成了一个可加载、可版本化、可跨Agent共享的交付物。
Skills和MCP的边界,我用一张表总结,这也是团队内部经常被问到的问题:
| 维度 | Skills | MCP Server |
|---|---|---|
| 解决的问题 | 教Agent怎么做一件事 | 给Agent提供外部数据和操作能力 |
| 是否必须联网 | 不需要,本地文件和脚本即可 | 通常要暴露网络服务或本地进程 |
| 典型内容 | 流程、规范、脚本、示例 | 工具列表、输入输出Schema |
| 依赖关系 | Skill内部可以调用MCP Server | MCP Server一般不含业务流程 |
顺便提一下热词里的"harness和agent区别":Harness是Agent运行的承载环境(沙箱、目录、依赖、权限),Agent是决策大脑。Skills往往和Harness绑定——Skill决定"做什么、怎么做",Harness保证"在什么样的环境里做"。生产环境里,同一个Skill要在不同的Harness里跑出可复现的结果,就需要把Harness也容器化、版本化,否则"我本地能跑、你那边跑不了"会变成常态。
6. 端到端实例:把走查、文案、部署三个Agent拼成集群
6.1 场景设定
前面讲了理论,这部分给一个能直接参照的完整实例。我搭的演示集群叫"发布前自动走查集群",解决的是每次上线前人工检查页面所花费的大量时间。集群里有三个Agent:
- 走查Agent:负责页面视觉和布局检查,使用Playwright MCP和前端开发Skill。
- 文案Agent:负责文案风格、错别字、敏感词(合规)检查,使用写作类Skill。
- 部署Agent:负责触发CI、汇总检查结果、阻断或放行发布,使用GitHub MCP。
6.2 编排配置
DeepAgents的配置大致如下:
cluster: name: release-review peers: - id: visual endpoint: http://localhost:9201/ - id: copy endpoint: http://localhost:9202/ - id: deploy endpoint: http://localhost:9203/ task_defs: release_review: assign: [visual, copy] policy: timeout: 120s concurrency: 2 aggregate: merge这里定义了三个Peer,并声明了一个release_review任务,由visual和copy两个Agent并行执行,最后聚合结果。注意我用的是aggregate: merge,也就是说编排器会等两个Agent都返回结果后再合并,而不是串行执行。
6.3 运行过程
用户把一个URL扔给集群后,实际执行过程是:
- DeepAgents创建
task-100,同时发给走查Agent和文案Agent。 - 走查Agent调用Playwright MCP对页面截图,再加载前端开发Skill,逐区块检查布局、对比设计Token,把发现的问题按
review-result的Schema输出。 - 文案Agent用写作Skill对页面文案做审查,同时调用语言模型的拼写检查能力,输出修改建议。
- 编排器收到两个结果后,判断是否存在阻断级问题:如果走查发现页面白屏,直接终止流程,不让部署Agent触发CI;如果只是文案建议,则放行并附上建议。
- 整个流程的TaskId贯穿所有环节,日志里可以清晰看到每个状态变化。
这个demo实际跑通后,我最大的体感是:三个Agent的协同没有变成"三个人的接力",而是真正变成了流水线并行。视觉走查耗时最长(浏览器截图和DOM解析),文案Agent并行跑,总耗时几乎等于最慢那个Agent的耗时,而不是三者之和。
6.4 集群怎么扛并发
热词里有人问"ai agent 怎么扛并发",这个坑我踩得比较深。一开始我把每个Agent任务都当成普通线程去处理,结果LLM调用是秒级甚至分钟级的长耗时操作,浏览器截图又是资源大户,很快进程就被打满了。
后来总结出一套比较实用的做法:
- 异步事件驱动:整个编排层用asyncio这类事件循环,不要让Agent等待期间占用线程。线程是稀罕资源,但协程不是。
- 编排状态外置:把Task状态放进Redis,让多个运行时实例共享同一份状态,这样编排层可以水平扩展,而不是单节点硬扛。
- 模型分级:不是所有步骤都需要最强模型。比如"提取页面标题"这种简单步骤用快模型或规则即可,只有"给出设计方案"这种复杂推理才调用大模型。这一步能把成本降低一大半,同时显著提升吞吐。
- 幂等与去重:同一个TaskId只处理一次。如果某个Agent回调重复了,编排层直接丢弃,这在高并发和重试机制同时存在的场景下非常重要。
| 方案 | 并发能力 | 复杂度 | 何时选择 |
|---|---|---|---|
| 同步阻塞调用 | 低 | 低 | 仅内部demo、任务极少 |
| 协程+异步 | 中高 | 中 | 单集群、中等并发 |
| 协程+Redis状态+多实例 | 高 | 高 | 生产环境、集群扩展 |
6.5 边缘场景:Docker里的Agent集群
集群不只存在于云服务器。热词里有个"docker容器里的ros2 humble, micro-ros agent",这其实是另一个很有意思的方向:把Agent集群推进到边缘和机器人场景。micro-ros agent负责让资源受限的MCU设备能接入ROS2,而上层的DeepAgents可以通过MCP把传感器数据当作"工具"暴露出来,让Agent感知物理世界。
我在一个实验项目里试过类似架构:把负责设备数据采集的Agent放进Docker容器,通过MCP把传感器数据变成"查询当前温度"这样的工具调用,上层决策Agent再通过A2A向它下发"持续观察温度超过阈值就告警"这种长期任务。这套架构的价值在于:云端的强Agent和边缘的轻Agent可以通过标准协议协同,而不是各自写私有接口。对做物联网和机器人的同学来说,MCP/A2A这套东西完全可以复用到非Web场景。
7. 生产环境必须盯住的三个坑:权限、并发、可观测
7.1 Agent安全:权限最小化与沙箱隔离
热词里"agent安全"关注度很高,这也是生产环境最容易被忽略的问题。原因很简单:Agent一旦通过MCP获得了工具调用能力,它不只是一个"聊天机器人",而是一个可以执行命令、写数据、触发发布的自动程序。我的建议是:
- MCP Server默认全只读。写操作工具单独放在另一个Server实例里,显式声明写权限,并走独立鉴权。
- A2A节点之间必须鉴权。至少用API Token,生产环境建议双向TLS或mTLS,不要裸奔在内网。
- 外部命令在Harness沙箱里跑。Skill里的脚本可能会被模型传入不可预料的参数,如果不隔离,一句"删除临时目录"也可能变成灾难。
- 每个Agent配独立的最小权限身份。不要所有Agent共用一个高权限账号,这样一旦某个Agent被恶意提示词注入,伤害也被限制在最小范围。
7.2 可观测性:从TraceId到全链路
多Agent集群不比微服务简单,甚至更复杂,因为这里面有LLM的不确定性。可观测性是我们快速定位问题的唯一依靠。
我给每个Task发一个TraceId,贯穿编排、Agent执行、MCP调用、LLM请求全链路。日志里固定记录几个关键指标:每个Step的耗时、LLM的token消耗、工具调用次数和结果、A2A消息状态变化。这样拿到一个"Agent execution terminated due to error"这类模糊报错时,我能直接看日志定位,而不是瞎猜模型问题。
遇到Codex CLI"无法找到MCP"这类问题,我的排查顺序是:先看MCP配置文件里transport和command是否配对,再看环境变量是否传入了正确的密钥,最后看Server进程有没有启动。很多所谓的"找不到MCP",其实是"Server根本没跑起来",问题根本不在Agent这边。
7.3 一次典型排错案例
最近线上遇到一次故障:走查Agent跑了一个小时还没结束,最后报"Agent execution terminated due to error"。从日志看,Task状态卡在working超过50分钟。我的排查链路是:
- 查编排日志,发现走查Agent一直没有回调进度。
- 直接看走查Agent的进程,发现它在等Playwright MCP的截图返回,但MCP Server所在进程已经因为内存泄漏被系统杀掉。
- 查MCP Server的健康检查接口,发现启动后存活时间只有十几分钟,一跑长任务就崩溃。
- 修复MCP Server的内存问题后,同样任务在4分钟内完成。
这个案例给我的教训是:占满一个完整排查链路的,往往是工具层和基础环境的稳定性,而不是模型的聪明程度。所以搭建集群时,一定要给每个MCP Server加上健康检查和自动重启,这是性价比最高的稳定性投入。
回到标题本身。DeepAgents、MCP、A2A、Skills这四个词,代表的其实是Agent工程化的四个层面:编排能力、工具接入、Agent互通、经验复用。我在这次项目里最大的体会是:不要一上来就追求"七个Agent同时协作"这种宏大场面,先用一个Agent、一个MCP Server、一个Skill跑通最小闭环,再逐步增加节点。Skill从一开始就要写版本号,A2A节点的AgentCard要维护干净,这样后面集群长大了才不会被自己造的混乱拖住。这套东西目前虽然还在快速演进,但"用协议而不是硬编码来解决协作问题"这个方向,我认为是确定无疑的。