Agent 协议怎么选:一张工程分层地图
最近 Agent 协议一下子多了起来。MCP、Skills、A2A、ACP、AG-UI、A2UI、AP2、UCP、ARD、ANP,名字摆在一起,很容易让人误以为它们在解决同一个问题。
其实不是。它们更像一条工程链路上的不同接口:用户从前端或 IDE 发起任务,Agent runtime 负责规划和执行,中途会调用工具、加载技能,必要时把任务交给别的 Agent;如果任务涉及开放发现、交易和支付,还会多出目录、信任、授权和审计。
所以我不会先问”哪个协议最流行”,而是先问一句:它在 Agent 系统的哪一层?
先看地图:
flowchart LR
U["用户"] --> C["视图层<br/>AG-UI / A2UI / ACP"]
C --> R["Agent Runtime"]
R --> K["能力层<br/>MCP / Skills"]
K --> S["外部系统<br/>数据库 / SaaS / 内部 API"]
R -.-> A["协作层<br/>A2A"]
D["发现层<br/>skills.sh / MCP Registry / ARD / ANP"] -.-> K
R -.-> O["观测层<br/>OTLP"]
R --> T["业务层<br/>UCP / AP2"]
T --> B["商家 / 支付 / 订单"]
这张图只保留几条关键线:视图层回答”用户怎么参与”;能力层回答”Agent 能调用什么”;协作层处理 Agent 之间的委托;发现层回答”能力从哪里来,能不能信”;观测层把过程串起来。UCP 和 AP2 这种业务层协议,则等任务真的进入交易场景时才需要。
一、快速选型参考
先按你遇到的问题选,不要按协议热度选:
| 工程问题 | 分层 | 优先看什么 | 什么时候不需要 |
|---|---|---|---|
| 前端要展示 Agent 状态、工具调用、用户确认、中断 | 视图层 | AG-UI | 只有一个普通聊天框,SSE/WebSocket 自己约定也够 |
| Agent 要返回卡片、表单、按钮,但不能让模型吐任意 JSX | 视图层 | A2UI | UI 很固定,前端自己写死即可 |
| IDE 想接不同 Coding Agent,统一会话、diff、权限确认 | 视图层 | ACP | 只是运行一个 CLI,不需要深度编辑器集成 |
| Agent 要查库、读文件、调内部 API | 能力层 | MCP | 只有一两个固定 HTTP API,普通 tool calling 更简单 |
| 一套操作经验要复用给不同 Agent,比如 Vercel 优化、React 性能审查 | 能力层 | Agent Skills、skills.sh | 只是单个函数调用,不需要打包知识和流程 |
| MCP Server 太多,客户端不想分别配置、认证、监控 | 能力层 | MCPHub / MCP Gateway | 只有一个 MCP Server |
| 一个 Agent 要把任务交给另一个独立 Agent | 协作层 | A2A | 只是同一进程里的几个工具函数 |
| Agent 要动态发现 MCP Server、Skills、Agent、OpenAPI 工具 | 发现层 | MCP Registry、ARD | 能力清单很小,手工配置即可 |
| Agent 要完成购物、结账、支付、售后 | 业务层 | UCP + AP2 | 不碰交易和支付 |
| 想做开放 Agent 网络里的身份、发现、加密通信 | 发现层 | ANP | 只需要静态内部目录时,内部 catalog 更简单 |
| 想追踪一次 Agent run 里模型、工具、检索、子 Agent 的耗时和错误 | 观测层 | OpenTelemetry / OTLP | Demo 或一次性脚本,普通日志先够用 |
下面按这几层展开。
二、视图层:用户怎么和 Agent 一起工作
这里不是模型能力,也不是工具调用。它解决的是用户界面和 Agent runtime 之间怎么协作。
1. AG-UI:前端和 Agent 后端之间的事件流
AG-UI 的定位是开放、轻量、事件驱动的协议,用来标准化用户前端和 Agent 后端的连接。它关心任务状态、文本增量、工具调用、用户确认、中断和共享状态。
一个长任务 Agent App 里,AG-UI 的位置大概是这样:
graph LR
U["用户点击生成报价单"] --> FE["前端"]
FE -->|"AG-UI run input"| AG["Agent Runtime"]
AG -->|"AG-UI events"| FE
FE -->|"展示状态、工具调用、确认按钮"| U
U -->|"确认、中断、修改参数"| FE
FE -->|"AG-UI user action"| AG
你可以把它理解成 Agent App 的”前后端事件合同”。没有 AG-UI,很多团队会自己发明一堆事件名:message_delta、tool_started、human_approval_required、run_cancelled。短期能跑,长期就会变成每个 Agent 后端一套前端适配。
一个简化的事件可能长这样:
{
"type": "tool_call_start",
"runId": "run_42",
"toolCallId": "call_weather",
"toolName": "get_weather",
"args": { "city": "Hangzhou" }
}实现时别把 AG-UI 当成”聊天流换皮”。它真正适合的是长任务:用户能看见 Agent 正在做什么,能在关键步骤确认,也能中断。
2. A2UI:Agent 只给 UI 描述,不给可执行代码
A2UI 解决的是另一个问题:Agent 怎么生成可交互界面,但又不直接生成任意 HTML/JSX。Google 的介绍里强调过一点:A2UI 是声明式数据格式,不是可执行代码;客户端维护可信组件目录,Agent 只能请求渲染这些组件。
这比”让模型返回一段 React 代码”安全得多。一个 A2UI payload 可以像这样:
{
"surfaceId": "checkout",
"components": [
{
"id": "confirm-card",
"component": "PaymentConfirmationCard",
"props": {
"merchant": "Acme Store",
"amount": 129.99,
"currency": "USD",
"primaryAction": "confirm_payment"
}
}
]
}客户端看到 PaymentConfirmationCard 后,决定能不能渲染、用哪个本地组件渲染、按钮点击后发什么事件。Agent 只描述意图,不碰前端执行环境。
AG-UI 和 A2UI 可以一起用:AG-UI 负责通道和事件,A2UI 负责某些事件里携带的 UI 描述。
3. ACP:编辑器怎样接入 Coding Agent
ACP(Agent Client Protocol)是 Zed 推出的编辑器/IDE 与 coding agents 通信协议。它假设用户主要待在编辑器里,Agent 可以是本地子进程,也可以是远程服务。
ACP 关心的是这些东西:
- 会话和 prompt 如何传给 Agent。
- Agent 的流式输出如何展示在编辑器面板里。
- 文件 diff、补丁、工具调用如何展示。
- 用户怎样确认 shell、文件写入、MCP 工具配置。
这和 A2A 不同。ACP 是”编辑器客户端到 Coding Agent”;A2A 是”Agent 到 Agent”。VS Code、Zed、JetBrains、Neovim 这类编辑器里的 Agent 面板更适合看 ACP;普通 Web App 里的聊天式 Agent,更贴近 AG-UI。
注意:历史上 IBM / BeeAI 也有一个 Agent Communication Protocol,同样缩写 ACP,但那个方向已经并入 Linux Foundation 旗下的 A2A 生态。现在说编辑器里的 ACP,通常指 Zed 的 Agent Client Protocol。
三、能力层:Agent 到底能做什么
Agent 本身只是推理和决策循环。真正让它有用的是接入外部系统、工具、文档、脚本和团队经验。
1. MCP:把工具、资源和提示词接进来
MCP(Model Context Protocol)是连接 AI 应用和外部系统的开放标准。官方文档里常见的三个 server 能力是 tools、resources、prompts:
| 概念 | 怎么理解 |
|---|---|
| Host | 用户正在使用的 AI 应用,比如 IDE、桌面客户端、Agent 平台 |
| Client | Host 里负责连接 MCP Server 的部分 |
| Server | 暴露工具、资源、提示词的服务 |
| Tools | 可执行动作,比如查库、发请求、创建 issue |
| Resources | 可读取上下文,比如文件、文档、记录 |
| Prompts | 可复用任务模板 |
用官方 TypeScript SDK 写一个最小 MCP tool,大概是这样:
import { McpServer } from '@modelcontextprotocol/server'
import { StdioServerTransport } from '@modelcontextprotocol/server/stdio'
import * as z from 'zod/v4'
const server = new McpServer({
name: 'order-server',
version: '1.0.0',
})
server.registerTool(
'get_order',
{
description: '按订单号查询订单摘要。',
inputSchema: z.object({
orderId: z.string(),
}),
},
async ({ orderId }) => ({
content: [
{
type: 'text',
text: JSON.stringify({
orderId,
status: 'paid',
total: 129.99,
}),
},
],
}),
)
const transport = new StdioServerTransport()
await server.connect(transport)这个例子很小,但边界已经出来了:MCP Server 暴露一个命名稳定、schema 明确的工具;Host/Client 决定什么时候把这个工具提供给模型;模型只看到工具描述和参数 schema,不需要知道后面是数据库、HTTP API 还是一段脚本。
落地时,MCP 的重点不是”我支持了多少工具”,而是权限边界。一个 MCP Server 如果暴露了 run_shell_command、delete_file、send_email、update_database 这类工具,就已经进入高风险区域。我会设几条底线:工具名和 schema 要稳定,别让模型猜参数;高风险工具默认需要确认;读写权限分开;工具返回要短而结构化;每次工具调用都要能审计。
MCP 是 Agent 的手,不是 Agent 的同事。
2. Skills:把工具、知识和流程打包成可复用能力
Skills 解决的不是”怎么通信”,而是”怎么把一套会做事的方法交给 Agent”。
Agent Skills 的基本格式很简单:一个目录,里面必须有 SKILL.md。可选地再放脚本、参考文档、模板和资产。
一个客服退款 Skill 可能长这样:
refund-support/
├── SKILL.md
├── scripts/
│ └── validate-refund.ts
├── references/
│ ├── refund-policy.md
│ └── escalation-rules.md
└── templates/
└── customer-reply.mdSKILL.md 可以写成这样:
---
name: refund-support
description: 处理客服退款请求。适用于判断退款资格、生成客服回复、必要时升级给人工。
---
先读取 references/refund-policy.md。
如果订单超过 30 天,除非商品损坏,否则不要直接退款。
高于 500 美元的退款必须升级给人工。
需要校验订单状态时,调用 MCP 工具 get_order。
需要创建退款时,先运行 scripts/validate-refund.ts,再调用 create_refund。这和 MCP Tool 的粒度完全不同:
| 概念 | 粒度 | 举个例子 |
|---|---|---|
| MCP Tool | 一个可调用动作 | get_order、create_refund、send_email |
| Skill | 一套完成任务的方法 | ”处理客服退款”,里面包含政策、脚本、工具调用顺序、升级规则 |
skills.sh 可以理解成 Skill 生态里的包目录。Vercel 的 Agent Skills 文档和 vercel-labs/agent-skills 就是很好的例子:vercel-react-best-practices 不是一个 API,也不是一个 MCP Server,而是一组 React/Next.js 性能和架构经验,给 coding agent 在写代码或审查代码时加载。
安装方式也接近包管理器:
npx skills add vercel-labs/agent-skills --skill vercel-react-best-practices什么时候该用 Skills?一个判断很简单:如果你发现自己在不同 Agent 里反复解释同一套项目规约、调试步骤、发布流程、代码审查标准,就该把它变成 Skill。MCP 给 Agent 手,Skills 给 Agent 工作手册。
四、协作层:什么时候需要 A2A
A2A(Agent2Agent Protocol)的目标是让不同供应商、不同框架、不同平台里的 Agent 可以互相通信、交换状态、协调任务。规范里常见的核心概念包括 Agent Card、Task、Message、Artifact。
A2A 的价值只在一种情况下明显:系统里真的有多个独立 Agent。
不要把一个 Agent 里的几个函数拆成 A2A。也不要为了显得”多 Agent”就拆。A2A 适合的是这种边界:
graph LR
PM["项目管理 Agent"] -->|"A2A Task"| Code["代码 Agent"]
PM -->|"A2A Task"| Data["数据分析 Agent"]
PM -->|"A2A Task"| Docs["文档 Agent"]
Code -->|"Artifact: PR"| PM
Data -->|"Artifact: report.csv"| PM
Docs -->|"Artifact: spec.md"| PM
判断要不要 A2A,我会问三个问题:
- 对方是不是独立运行、独立部署、独立拥有权限边界的 Agent?
- 任务是不是需要生命周期,比如排队、执行中、等待用户、完成、失败、取消?
- 结果是不是需要作为 artifact 被另一个系统消费,而不只是返回一段文本?
如果答案都是”是”,A2A 才真正合适。
一个简化的 Agent Card 可以像这样:
{
"name": "code-review-agent",
"description": "审查 GitHub PR,返回风险列表和可操作建议。",
"url": "https://agents.example.com/code-review",
"skills": [
{
"id": "review_pull_request",
"name": "Review Pull Request",
"description": "输入仓库和 PR 编号,输出审查报告。"
}
],
"capabilities": {
"streaming": true,
"pushNotifications": false
}
}A2A 允许远端 Agent 保持黑盒。你能看到它能做什么、任务状态是什么、产物是什么,但不需要知道它内部用了哪些 MCP Server、哪些 prompt、哪套模型。跨团队、跨供应商协作时,暴露接口比暴露内部实现现实得多。
五、发现层:能力从哪里来
早期 Agent 系统通常把工具写死在配置里。小系统可以这么干,企业里很快就会出问题:工具、MCP Server、内部 Agent、Skills、OpenAPI 越来越多,Agent 怎么知道现在有哪些能力可用?怎么判断哪个可信?怎么避免所有能力都塞进上下文?
1. Skills 目录:给可复用能力找入口
skills.sh 是 Vercel 推出的 Agent Skills 目录和 leaderboard。Vercel changelog 里给的定位很直白:skills 是安装和管理 skill packages 的 CLI,skills.sh 是发现 skill packages 的目录。
这类目录解决的是”我需要一个现成工作手册”。比如:
- 做 React/Next.js 性能审查,可以找 vercel-react-best-practices。
- 做 UI 审计,可以找
web-design-guidelines。 - 做 Vercel 成本优化,可以找
vercel-optimize。
2. MCP Registry 和社区目录:让 MCP Server 可发现、可管理
当 MCP Server 多起来,问题会从”怎么写一个 server”变成”怎么发现、管理、路由、审核这些 server”。这里至少有三类东西:
| 类型 | 代表 | 解决什么 |
|---|---|---|
| 官方元数据注册表 | MCP Registry | 公开 MCP Server 的元数据、命名空间、安装信息 |
| 社区目录/市场 | mcp.so、mcpservers.org、LobeHub MCP | 搜索、筛选、评分、安装指引 |
| 本地/企业 Hub 或 Gateway | MCPHub、mcp-hub、内部网关 | 管理多个 MCP Server,向客户端暴露一个统一 endpoint |
官方 MCP Registry 承载 metadata,不承载实际代码。MCPHub 这类项目是运行时管理器——多个 MCP Server 接进去,客户端只连一个 /mcp endpoint,Hub 负责命名空间、路由、认证和状态管理。
从发现到调用的完整链路:
graph LR
REG2["MCP Registry<br/>公开元数据"] --> MARKET["目录 / 市场<br/>mcp.so、mcpservers.org"]
MARKET --> DEV["开发者筛选和安装"]
DEV --> HUB2["MCPHub / 企业 MCP Gateway"]
CLIENT["Claude / Cursor / Codex"] --> HUB2
HUB2 --> S1["GitHub MCP"]
HUB2 --> S2["Postgres MCP"]
HUB2 --> S3["内部 API MCP"]
一个企业里的实际部署:
graph LR
C["Claude / Cursor / Codex"] --> HUB["MCPHub / 企业 MCP Gateway"]
HUB --> FS["filesystem MCP"]
HUB --> GH["GitHub MCP"]
HUB --> PG["Postgres MCP"]
HUB --> CRM["内部 CRM MCP"]
REG["MCP Registry / 内部目录"] -.-> HUB
3. ARD:更通用的 Agentic Resource Discovery
ARD(Agentic Resource Discovery)是更通用的发现协议。Google 的介绍里说,一个 provider 可以在自己的域名下发布 ai-catalog.json,catalog 里可以列 MCP servers、A2A agents、OpenAPI tools,甚至其他 catalog。Agent 发现资源后,再用对应的原生协议连接。
这和 MCP Registry 的区别在于范围:MCP Registry 主要围绕 MCP Server 元数据;ARD 试图发现所有 Agentic resources。你可以把 ARD 看成”能力目录协议”,它不替代 MCP/A2A/OpenAPI,而是在调用之前回答:
- 这个组织公开了哪些 Agent 能力?
- 发布方是谁,域名是否可信?
- 这些能力应该用 MCP、A2A、OpenAPI 还是别的协议调用?
4. ANP:更远的开放 Agent 网络设想
ANP(Agent Network Protocol)目标更大,关注开放 Agent 网络里的身份、发现、消息、安全通信,甚至支付。在这张地图里,它更接近发现层和信任边界,不是工具调用协议。
六、业务层:Agent 开始花钱时,协议会变严肃
只要 Agent 不碰交易,很多系统还能靠用户确认和日志兜底。一旦 Agent 可以代表用户购物、下单、付款,责任链就必须清楚。
1. UCP:商品、库存、购物车、订单
UCP(Universal Commerce Protocol)覆盖的是完整商业流程:商品发现、库存、购物车、结账、订单、售后。Google 的 UCP 技术介绍也提到,它支持 REST、MCP、A2A 等多种绑定方式。
UCP 不是支付协议。它更像 Agent 和商家系统之间的商业语言。
一个购物 Agent 可能先用 UCP 做这些事:
{
"capability": "search_products",
"query": "适合剪 4K 视频的笔记本",
"constraints": {
"maxPrice": 2000,
"currency": "USD",
"delivery": "today"
}
}2. AP2:授权、凭证、收据、争议证据
AP2(Agent Payments Protocol)关心的是 Agent 参与支付时怎么证明授权和交易事实。Google Cloud 的介绍强调 mandates,也就是可验证、可签名的授权材料。
AP2 想回答的问题很具体:
- 用户到底授权了什么?
- Agent 有没有超出预算、时间、商品条件?
- 商家看到的 checkout 和用户确认的是不是同一件事?
- 支付凭证、收据、争议证据在哪里?
- 人不在场的自动购买,约束条件怎么被验证?
UCP 和 AP2 的关系可以这样理解:
graph LR
USER2["用户:帮我买一台电脑"] --> AGENT2["购物 Agent"]
AGENT2 -->|"UCP: 搜索商品、查库存、建购物车"| MERCHANT["商家系统"]
AGENT2 -->|"A2UI: 展示候选商品和确认卡片"| USER2
USER2 -->|"确认预算和商品约束"| AGENT2
AGENT2 -->|"AP2: mandate、支付凭证、收据"| PAY["支付网络"]
AGENT2 -->|"UCP: 订单状态、售后"| MERCHANT
UCP 管”怎么买、买什么、订单怎么跑”;AP2 管”谁授权、怎么付款、争议时怎么证明”。涉及钱的 Agent,必须把这两件事分开。
七、观测层:任务出问题时怎么追(OTLP)
观测层不是 Agent 专属,但 Agent 一进生产,它就绕不开。
传统后端出问题,通常还能从接口状态码、日志和数据库记录里往回查。Agent 麻烦一点:它可能是模型选错工具、MCP Server 超时、检索拿错文档、A2A 子任务卡住,也可能是用户确认和支付授权之间断了。只看最后一句回答,很难知道错在哪里。
OpenTelemetry 是通用的可观测性框架,覆盖 traces、metrics、logs。OTLP 则定义这些遥测数据怎么从应用、collector 送到后端。在 Agent 系统里,可以把一次 agent.run 当成一条 trace,把模型调用、MCP 工具调用、检索、A2A 委托、支付授权都记成 span:
trace agent.run run_id=run_42
span llm.call model=gpt-5.5
span mcp.tool_call server=postgres tool=query_orders
span retrieval.search source=knowledge_base
span a2a.task target=research-agent
span ap2.mandate.create如果你关心 LLM/Agent 里的字段怎么命名,可以看 OpenTelemetry GenAI Semantic Conventions 和 OpenInference。它们不是传输协议,而是给模型调用、工具调用、检索、token、prompt 这些字段一套更统一的描述方式。
八、几种真实架构组合
前面的分层只是框架。落到工程里,通常会组合使用。
1. Coding Agent / IDE
graph LR
IDE["Zed / VS Code / JetBrains"] -->|"ACP"| CA["Coding Agent"]
CA -->|"加载"| S["Skills<br/>react-best-practices、deploy-to-vercel"]
CA -->|"MCP"| HUB3["MCPHub / MCP Gateway"]
HUB3 --> GH["GitHub MCP"]
HUB3 --> FS["Filesystem MCP"]
HUB3 --> CI["CI / Logs MCP"]
这套组合里,ACP 管编辑器体验,Skills 管工程经验,MCP 管外部工具。A2A 只有在 Coding Agent 要把任务交给另一个独立 Agent 时才需要,比如”把性能分析交给一个 observability Agent”。
2. 企业知识 Agent
graph LR
FE2["员工前端"] -->|"AG-UI"| KA["知识 Agent"]
KA -->|"加载"| KS["企业问答 Skill"]
KA -->|"MCP"| HUB4["MCPHub / 企业 MCP Gateway"]
HUB4 --> CF["Confluence"]
HUB4 --> GD["Google Drive"]
HUB4 --> PG["Postgres"]
HUB4 --> API["内部 API"]
DIR["内部 MCP Registry / ARD Catalog"] -.-> HUB4
这里关键是 MCP 和权限治理。知识 Agent 的价值来自读取内部资料、调用内部系统、生成可验证回答。AG-UI 负责让前端展示流式回答、检索来源、工具调用状态和用户确认。
不要一开始就拆成十个 Agent。先确认一个 Agent + MCP + Skills 是否够用。如果法务、财务、数据分析确实都有独立权限边界和任务生命周期,再加 A2A。
3. 多 Agent 自动化工作流
graph TB
U3["用户"] -->|"AG-UI"| PA["规划 Agent"]
PA -->|"A2A"| RA["研究 Agent"]
PA -->|"A2A"| DA["数据分析 Agent"]
PA -->|"A2A"| WA["写作 Agent"]
PA -->|"A2A"| RV["审校 Agent"]
RA -->|"MCP"| WEB["浏览器 / 搜索"]
DA -->|"MCP"| DB["数据库"]
WA -->|"Skills"| STYLE["写作风格 Skill"]
RV -->|"MCP"| DOCS["文档库"]
这类系统很容易失控。A2A 可以帮你传任务和状态,但不会自动帮你设计组织结构。每个 Agent 都要有明确的输入、输出、退出条件和权限边界。
4. Agent 购物 / 支付
graph LR
UI["购物前端"] -->|"AG-UI"| SHOP["购物 Agent"]
SHOP -->|"UCP"| MERCHANT2["商家 / 商品 / 库存 / 订单"]
SHOP -->|"A2UI"| UI
SHOP -->|"AP2"| PAYMENT["支付授权 / 凭证 / 收据"]
UI 也很关键。用户应该看到商品、价格、配送、预算约束和支付确认,而不是只看到一句”我帮你买好了”。涉及钱的 Agent,授权边界必须成为界面的一部分。