资讯动态

A2A、MCP、A2UI:多Agent系统三层协议栈分工与实战

发布时间:2026/10/20 22:35:21 来源:尧图企业网站定制
原本我还以为“A2A、MCP、A2UI 到底怎么分工”又是一篇抄来抄去的概念对比文。直到我连续踩了几个多 Agent 项目的坑才意识到这三个缩写根本不是同一维度的东西硬把它们放在一张桌面上比较方向就错了。A2A 管的是智能体之间的对话MCP 管的是智能体跟工具怎么握手A2UI 管的是最终结果怎么以界面形态回到人眼前。它们不是一个协议的三层实现而是三个职责完全不同的“协议栈”。这篇文章我从实际集成时的切肤之痛出发把每一层到底解决什么、边界在哪、选型时怎么判断一次说透。1. 为什么多 Agent 系统突然需要“协议栈”一个被反复低估的复杂度问题如果你只是写个 Python 脚本调用一个大模型 API 拿回一段 JSON那确实不需要关心协议分层。但一旦进入多 Agent 场景——几个智能体各有分工有的负责检索、有的负责写代码、有的负责审批、有的负责把结果渲染到页面上——你就会发现沟通成本根本不是“模型能力强不强”能解决的。我最早做的一个模拟项目X里团队直接让 Agent A 拿着 Agent B 的返回结果去调工具硬编码函数调用。当时感觉挺顺等到 Agent 数量从两个涨到五个函数签名改了三次、工具地址换了两次、前端渲染方式变了一版我才意识到问题出在哪我们一直在写“点对点”的对接代码而不是在搭建一套可扩展的协作基础设施。这个阶段最容易出现的典型问题是Agent A 自己定义了一套“调用工具”的方式Agent B 又定义了一套两边无法互相理解前端工程师拿着 Agent 回传的 Markdown 文本不知道是应该直接渲染、还是先把文本丢给另一个解析器处理想让外部系统接入对方问你要接口文档你发现自己根本没有稳定的“协议边界”全是内部实现细节裸露。如果把这个问题类比成软件开发的演进史单一进程内部你从来不需要考虑网络协议但一旦拆成微服务你就必须有 HTTP/gRPC、必须有标准化的接口定义、必须有服务发现和数据契约。多 Agent 系统现在也走到了这一步——Agent 不再是一个孤立的调用单元而是一个需要彼此通信、协同、呈现结果的分布式系统。在这个背景下A2A、MCP、A2UI 这三层分工才真正有了意义。很多初学者理解不了“协议栈”这个概念总觉得多整一层就是多一份麻烦。我举个生活化的例子你点外卖商家做好饭能力骑手把饭送到你小区配送你在 App 上看到订单状态并确认收货交互。如果这三件事全让商家自己干单量稍微大一点就崩。多 Agent 的分层逻辑类似——MCP 是“商家”A2A 是“骑手”A2UI 是“你的 App 界面”每一层都能独立演进和替换而不牵连其他层。2. 逐层拆解MCP、A2A、A2UI 分别承担什么职责边界画在哪很多对比文章把三个协议放在一起讲但给人的感觉是云里雾里。问题不在这三个概念本身多难而是它们压根不在一个层级。我按从底到顶的顺序一层一层拆。2.1 MCP智能体与工具之间的“统一插头”MCP 最早是某 AI 实验室为解决“模型调用工具碎片化”提出的方案。直白说它解决的是**“Agent 怎么安全、规范地使用外部能力”**这个问题。无论是向量数据库检索、代码执行器、企业ERP接口、还是本地文件系统通过 MCP 都可以包装成一个标准工具。Agent 不必为每个工具单独写一套调用逻辑工具方也不必将自己的接口细节暴露给每个可能的调用者。我在实际项目中配置过一个非常基础的 MCP 服务本质上就是定义一个 JSON-RPC 形式的端点{ mcpServers: { sqlite: { command: uvx, args: [mcp-server-sqlite, --db-path, ./test.db] } } }写完配置之后Agent 就能通过统一接口读取数据库表结构、执行查询语句、拿到结果。这个过程的魔力在于你换掉底层数据库Agent 侧代码完全不用改反过来你换成另一个模型工具侧也不用改。MCP 常用的交互原语大致有五类原语方向含义tools/list客户端→服务端发现这个服务提供了哪些工具tools/call客户端→服务端调用指定工具传入参数resources/list客户端→服务端列出可读的资源resources/read客户端→服务端读取资源内容prompts/list客户端→服务端列出可复用提示词模板你注意看这里的核心思想是“客户端—服务端”模型Agent 是客户端工具是服务端。它关心的永远是**“我怎么把能力暴露给智能体”**而不是“智能体之间怎么沟通”。这个区分非常关键——很多人把 MCP 当成 Agent 间通信协议来用十有八九会撞墙。另外有一点很容易被忽略MCP 自身不解决“谁调用谁”的编排问题。它只是把工具能力标准化了但具体哪一步调哪个工具还得由上层的 Agent 编排逻辑来控制。2.2 A2A智能体与智能体之间的“协作语言”如果说 MCP 是“人和工具”的接口那么 A2A 就是“Agent 和 Agent”的接口。它的出现晚于 MCP但解决的问题完全不同当你有多个智能体协同处理一个复杂任务时它们之间如何交换信息、如何请求协助、如何传递上下文、如何确认任务完成。A2A 的核心抽象是**“任务Task”**。一个 Agent 向另一个 Agent 发起请求本质上是创建了一个任务对方可以接受、执行、更新状态、最终标记完成。整个对话过程虽然是通过消息传递实现的但本质上管理的是一个有状态的任务生命周期。我拿自己写过的模拟代码举例一个典型的 A2A 任务状态流转大概长这样{ taskId: task-001, sender: agent-planner, recipient: agent-coder, status: working, artifacts: [ { kind: text, content: 请为登录模块生成单元测试覆盖参数为空场景 } ] }A2A 里还有个核心概念叫“代理身份描述Agent Card”相当于每个 Agent 的“自我介绍”告诉别人自己擅长什么、支持哪些消息类型、遵循什么安全策略。这个设计跟微服务里的服务注册表很像——新增一个 Agent 时只要把 Agent Card 发布到目录里其他 Agent 就能自动发现并正确调用它。从分工边界来看A2A 根本不管“工具怎么被调用”——那是 MCP 的事也不管“结果怎么呈现给人类用户”——那是 A2UI 的事。它只关心智能体之间的信息流和任务协作流。2.3 A2UI智能体结果与人类界面之间的“呈现与交互契约”A2UI 是这三者里最容易被忽略、也最容易引起混淆的。很多人以为它不过是“前端渲染模板”但实际它要解决的问题比渲染复杂得多多 Agent 系统产生的结果往往不是一段纯文本而是包含工具按钮、状态卡片、数据表格、操作审批流、多轮确认对话框的复合界面体验。A2UI 需要为这些“智能体驱动的界面”定义一套统一的描述与交付规范。打个比方MCP 决定了 Agent 能不能拿到数据库里的订单数据A2A 决定了多个 Agent 能不能协同完成一个订单审批流程但用户最终在页面上看到的是“订单状态待确认 一个同意按钮 一个驳回按钮”这个界面元素怎么描述、怎么以跨前端框架的方式下发到浏览器、用户点击按钮之后怎么把指令回传给 Agent这就属于 A2UI 的范畴。我在一个内部工具项目里的做法是用一个轻量 JSON 描述界面片段{ ui: { type: action_card, title: 审批待处理, fields: [ { key: amount, label: 金额 }, { key: reason, label: 申请理由 } ], actions: [approve, reject] } }然后把这段 JSON 直接发给前端的渲染器前端根据 type 映射到具体组件。这样做的价值在于界面逻辑不需要写死在某个 Agent 的代码里也不需要跟某个特定前端框架深度耦合。Agent 只需要返回“界面意图”具体怎么渲染由 A2UI 运行时决定。这三层放在一起边界其实非常清晰MCP 连接能力A2A 连接智能体A2UI 连接用户。任何复杂的多 Agent 系统本质都是在这三层的协作中完成业务闭环的。3. A2A、MCP、A2UI 的“夹心结构”实际系统里的交互链路与数据流协议分层不能光在纸面上成立还得能落到实际链路里。我直接把我近期一个多 Agent 系统 Demo 里的完整数据流画了一遍纯文字描述你会发现这三层是“揉在一起”工作的但又职责分明。3.1 一个典型的多 Agent 协作链路实测假设业务场景是“自动生成一份市场调研报告并发送给用户确认”。整个链路大致如下用户在前端页面输入“生成竞品分析报告”前端通过 A2UI 把指令包装成一个用户意图对象编排 AgentPlanner接受到意图后通过 A2A 把任务拆解成“数据采集”“行业分析”“文档生成”三个子任务分发给三个子 Agent数据采集 Agent 通过 MCP 调用外部搜索工具、数据库工具、文件读取工具把原始材料拿回来行业分析 Agent 接收材料通过 A2A 向文档生成 Agent 传递结构化分析结果文档生成 Agent 完成后通过 A2A 回报任务状态给编排 Agent编排 Agent 汇总产出物通过 A2UI 下发一个“报告预览卡片”到前端用户在卡片上点击“确认”按钮A2UI 把这个动作回传触发下一步正式发布流程。这条链路里每一步的数据格式约束都来自对应协议MCP 约束了 Agent 与工具之间“怎么拿数据”A2A 约束了 Agent 之间“怎么派活和交活”A2UI 约束了“怎么把结果推到人面前并收回人的指令”。3.2 为什么说“A2A 不依赖 MCP、A2UI 也不依赖 A2A”是新手常犯的误解有一个认知误区我反复遇到很多人以为一个系统用了 A2A就必须配套 MCP用了 A2UI就必须先打通 A2A。实际上这三层在技术上是可以“独立存在”的。你的系统可以只有 MCP 没有 A2A比如单 Agent 程序直接通过 MCP 调工具完全不需要跟别的 Agent 通信。也可以只有 A2A 没有 MCP比如多个大模型互相传递纯文本内容不需要访问外部工具。A2UI 同样可以独立存在很多应用其实只需要一个 Agent 的输出渲染不需要 Agent 间的协作。但为什么在实际复杂系统里它们又会“绑定”在一起不是因为协议依赖而是因为业务复杂度同时推高了这三方面的需求。当你需要多个角色协同完成任务时自然就需要 A2A当每个角色需要调用专业工具时自然就需要 MCP当最终结果需要反馈给人做决策时自然就需要 A2UI。这三者是在真实业务需求面前被“共同召唤”出来的而不是被彼此强制依赖的。理解这一点非常重要否则你很容易在技术选型时做出“为了层次感而层层叠叠”的蠢事。4. 从零搭一套三层协议最小可运行系统实操向我把理论落到最小可运行系统。你可以不依赖任何重量级框架用 Python 几个轻量库模拟出一套结构完整的三层协议栈。这份配置和代码是我在项目里实际改过的版本拿来就能跑。4.1 环境准备与最小目录结构我建议用 Python 3.11 版本虚拟环境隔离。目录结构如下agent-stack-demo/ ├── mcp_server.py # 模拟 MCP 工具服务端 ├── a2a_agents.py # 模拟 A2A 多 Agent 通信 ├── a2ui_renderer.py # 模拟 A2UI 界面描述渲染器 ├── agent_cards.json # 维护每个 Agent 的 A2A 卡片信息 ├── requirements.txt └── run_demo.py # 端起整个链路的入口requirements.txt 里只需要装以下内容fastapi0.115.0 uvicorn0.30.0 httpx0.27.0 pydantic2.5.0几个包都轻量不引入额外重量级依赖。4.2 第一层MCP 服务端——做一个最简工具暴露接口我在这里不用官方 MCP SDK而是用 FastAPI 的手写 JSON-RPC 风格把“读取当前时间”和“读取数据库订单数量”两个能力暴露出去。核心是让你理解工具提供方应该如何定义接口契约而不是被 SDK 绑架。# mcp_server.py from fastapi import FastAPI, Request import datetime app FastAPI() TOOLS [ {name: get_current_time, description: 返回当前系统时间}, {name: get_order_count, description: 返回模拟订单总数}, ] app.get(/mcp/tools) async def list_tools(): return TOOLS app.post(/mcp/call) async def call_tool(request: Request): payload await request.json() tool_name payload.get(tool) if tool_name get_current_time: return {result: str(datetime.datetime.now())} if tool_name get_order_count: return {result: 128} return {error: tool not found}这就是 MCP 最本质的交互模型先发现“有什么工具”再按名称“调用”。你替换成真实场景时工具数量会更多安全校验会更复杂但骨架不会变。4.3 第二层A2A 协作——用任务对象实现智能体间通信我在这个 Demo 里模拟三个智能体planner编排、researcher检索、writer生成。它们通过一个简单的 A2A 消息总线互相调用。# a2a_agents.py from dataclasses import dataclass, field from typing import List dataclass class Task: task_id: str sender: str recipient: str status: str submitted payload: dict field(default_factorydict) class A2ABus: def __init__(self): self.tasks {} self.agent_handlers {} def register_agent(self, name, handler): self.agent_handlers[name] handler def send(self, sender, recipient, payload) - Task: task_id ftask-{len(self.tasks) 1} task Task(task_idtask_id, sendersender, recipientrecipient, payloadpayload) self.tasks[task_id] task handler self.agent_handlers.get(recipient) if handler: task.status handler(task.payload) else: task.status failed return task def planner_handler(payload): # 简化直接把子任务丢给 researcher 和 writer return working def researcher_handler(payload): return completed def writer_handler(payload): return completed看到没有A2A 的核心不是“传输文本”而是构造一个带状态的任务对象让任何参与方都能理解当前进度。你在真实系统里可以直接套用更成熟的消息队列让任务状态更健壮但基本模型依然一样。4.4 第三层A2UI 渲染器——把 Agent 结果变为可交互界面最后一步把 writer 生成的报告结果转成可以渲染的前端界面描述。我写一个极简的渲染函数# a2ui_renderer.py def render_action_card(title: str, body: str, actions: list): return { ui_type: action_card, title: title, body: body, actions: actions, callback: submit_feedback }这套设计意味着任何前端只要实现了action_card组件拿到这段 JSON 就能渲染出一个带按钮的卡片。用户点击按钮后前端再把callback和用户选择发回给后端这就完成了 A2UI 的闭环。4.5 启动入口与全链路联动run_demo.py把这套系统端起来# run_demo.py from a2a_agents import A2ABus import asyncio from a2ui_renderer import render_action_card bus A2ABus() bus.register_agent(planner, planner_handler) bus.register_agent(researcher, researcher_handler) bus.register_agent(writer, writer_handler) fetch_task bus.send(planner, researcher, {query: 竞品价格}) write_task bus.send(researcher, writer, {data: 竞品数据已收集}) ui render_action_card( title调研报告已生成, body点击确认后发送给客户, actions[confirm, reject] ) print(A2A 任务状态:, fetch_task.status, write_task.status) print(A2UI 界面描述:, ui)跑起来之后你会看到一条完整的链路从 MCP 取数这里用模拟函数代替→ A2A 传递任务 → A2UI 产出界面对象。虽然简单但三个协议层的角色全都在场了。5. 最容易踩坑的边界混淆我的排查记录与判断思路理论归理论。我在真实项目里见到的混乱绝大多数不是“协议实现有问题”而是边界判断出了错。下面这几个场景是最高频的。5.1 场景一把 A2A 当成工具调用协议结果两套机制打架有一段时间我们的团队为了实现“Agent A 让 Agent B 去查天气预报”直接在 A2A 消息里写死了“调用 B 的 get_weather 函数”。看着像没问题但后来我们要把天气查询能力迁移到另一个 Agent C 上结果发现 A 的消息里写死了 B 的地址和函数名一改就崩。这就是典型的把 A2A 当成 MCP 用。正确做法是Agent A 发现“需要有天气能力”通过能力目录找到一个具备该能力的 Agent B然后通过 A2A 发出一个语义化任务“请提供今日天气概况”至于 B 内部是用 MCP 调外部天气服务还是自己算的A 完全不需要知道。A2A 传递的是意图和结果MCP 负责让工具能力可被发现、可被调用。一旦你把实现细节暴露进了 A2A 消息分层就破功了。5.2 场景二让 A2UI 直接承载 Agent 间通信导致 UI 层臃肿另一个常见错误是为了让前端实时展示多 Agent 的中间过程开发者直接让前后端消息格式包含了大量 Agent 内部状态数据。前端被迫维护一套解析逻辑并且当 Agent 数量增加时这套解析逻辑越来越难扩展。我的判断标准是A2UI 只负责“面向用户的呈现意图”不负责“Agent 内部的过程数据”。如果前端需要展示中间进度A2A 层应该主动把进度抽象成用户可见的“进度描述”再交给 A2UI而不是把原始任务状态抛出去。底层细节最好彻底留在内部。5.3 场景三过早追求“全栈协议标准化”忽略业务刚需我还见过一种反向踩坑系统只有两个 Agent 跑得很欢非要把 MCP、A2A、A2UI 全套引入理由是“以后会用到”。结果维护成本一下子上来团队光是理解这些抽象就花了两周。我个人的建议是协议栈不是越完整越好而是越适配越好。当你的系统只有单个 Agent 少量工具时直接调工具函数完全没问题当你不止一个 Agent 时优先引入 A2A当你的 Agent 结果需要频繁跟人交互时再考虑 A2UI 层抽象。MCP 则在你需要频繁增删工具、多 Agent 共享工具能力时引入。渐进式演进比一步到位靠谱得多。6. 真实项目中的选型建议与我的个人判断如果前面讲的都是“协议是什么”那这里想聊的是“怎么选、怎么落地”。我把我自己复盘过的一套判断标准整理出来不敢说绝对正确但至少能帮你少走弯路。6.1 三种规模下的协议引入优先级系统规模典型情况建议引入顺序单 Agent 单工具一个小助手只调一个数据库不引入任何协议直接函数调用单 Agent 多工具一个 Agent 要调用搜索、代码、文件等优先引入 MCP多 Agent 协作多个角色协同完成复杂业务再引入 A2A有用户界面交互时再引入 A2UI这个表格背后有个简单的直觉协议层数是跟着协作复杂度走的不是越早引入越好。过早抽象等于提前负债。6.2 三条实操避坑经验第一MCP 的工具列表设计要跟业务语义对齐别只按技术函数名命名。比如一个“获取订单”工具宁可命名为get_order_detail_with_items也不用get_order因为 Agent 的意图匹配很多时候依赖名称和描述的语义清晰度。工具描述里一行高质量说明比什么玄学调参都管用。第二A2A 的任务消息里尽量少携带大段上下文历史多携带“引用和状态”。一个很常见的问题是Agent A 把上下文全量塞给 Agent BB 又把全量结果塞给 Agent C消息体越来越重响应越来越慢。我现在的习惯是任务消息里只传必要字段和引用凭据比如任务ID、模型产出的关键摘要具体的源数据通过 MCP 工具按需读取。这样即可以保持上下文精简又不丢失可追溯性。第三A2UI 的界面描述要保持“名词化”而不是“过程化”。意思是尽量让 A2UI 对象描述“当前应该呈现什么状态”而不是描述“之前经历了什么步骤”。用户点按钮时可能需要知道“已确认”但不需要看到“Agent 1 完成检索、Agent 2 在做推荐、Agent 3 正在生成总结”——那应该放在审计日志里而不是堆在用户界面上。6.3 这三个协议未来会不会统一成一个经常有人问我未来会不会有一个超级协议把 MCP、A2A、A2UI 全部统一掉我个人持保留态度。因为三者服务的对象完全不同MCP 服务的是“能力供给侧”A2A 服务的是“智能体协作侧”A2UI 服务的是“人机交互侧”。不同对象对协议的设计约束很大强行统一反而可能让协议变得臃肿。更大的概率是它们会在生态层被某个编排框架整合起来对外展示成一个统一开发平台但内部仍然是分层的。拿传统开发类比HTTP、SQL、JSON 不会统一成一个协议因为它们解决的是不同层面的问题。A2A、MCP、A2UI 大概率也走这条路——彼此配合但各司其职。7. 写在最后一次真实的项目复盘与我的体会这个项目做下来我最深的体会是协议分层最难的不是写代码而是改变团队的沟通语言。当所有人口径一致地说“这个数据走 MCP 拿这个任务走 A2A 派这个界面走 A2UI 出”的时候系统的边界感才真正立起来了。否则不管代码里写了多少层抽象最后都会变成一团乱麻。另外一个值得细想的点是A2UI 目前没有像 MCP 和 A2A 那样有比较响亮的标准背书很多团队其实是在用“半自定义方案”推进。我在内部项目里用了 JSON Schema 约束界面描述用版本号管理界面契约效果不错。如果你也遇到 A2UI 生态不成熟的问题我的建议是别畏惧自定义但一定要把契约文档化、版本化否则等组件多了自定义就会变成下一个历史包袱。多 Agent 系统的“三层协议栈”这个概念理解起来并不难难的是在日常迭代里守住边界。希望这篇从实操角度展开的文章能帮你建立起对 A2A、MCP、A2UI 分工的立体认知。下次有人再让你“对比一下这三个协议”你可以直接告诉他——先分层再谈对比。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑