A2A 协议:面向异构智能体的互操作标准与工程实践
说明:本文从一个常见的问题出发——“A2A 协议是什么”——但目标不止于给出一个能应付面试的定义。我们将按照"定位 → 数据模型 → 交互流程 → 传输绑定 → 与 MCP 的关系 → 工程权衡"的顺序,把 A2A(Agent2Agent Protocol)当作一个普通的分布式系统协议来分析:它解决了什么问题、抽象边界在哪里、落地时要注意什么,以及它不是什么。
一、背景:智能体协作的"孤岛"问题
过去两年,围绕单个 Agent 的构建已经形成了相对成熟的工具链:LLM + Prompt + Memory + Tool Use(Function Calling)。但当我们把视野从"单个 Agent"拉到"多个 Agent 协同完成一个复杂目标"时,会立刻撞上一堵墙——异构孤岛。
现实中的 Agent 可能由不同团队、不同框架(LangGraph、CrewAI、AutoGen、Google ADK、Semantic Kernel……)、不同大模型构建,部署在不同的域名与网络环境里。此时让它们协作,常见的临时方案是:把对方的 Agent “包成一个 Tool”,用私有 HTTP 接口 + 自定义 JSON 去对接。这种方式在规模上来后会迅速恶化:
- 发现难:没有统一的能力描述格式,调用方只能靠文档或口头约定。
- 协作语义弱:普通 HTTP 请求-响应无法原生表达"长时任务、状态流转、多轮澄清、主动回调"。
- 重复造轮子:每个集成对都要重新约定鉴权、错误码、进度推送、取消机制。
A2A 的出现,本质上是要把这套"智能体间通信"从私有的点对点集成,提升为标准化的互操作层。它把智能体视为对等的、不透明的协作者(而非被调用的工具),通过一套自描述的能力声明 + 有状态的任务模型 + 可复用的传输绑定,让不同阵营的 Agent 能够互相发现、委派任务、同步状态、交付结果。
一句话定位:A2A 是 Agent 世界的"外交协议"——它不关心对方内部用什么模型、什么框架,只规定"你如何描述自己、如何接活、如何回报"。
二、A2A 是什么:官方定位与演进
A2A 全称Agent2Agent Protocol,是由 Google 于 2025 年 4 月首次发布、后捐赠给Linux Foundation(Agentic AI Foundation)治理的开放标准协议[citation:1]。截至 v1.0.0(2026 年 3 月 GA),规范已经进入稳定维护期,拥有多家云厂商与开源框架的支持[citation:2]。
理解 A2A 最重要的一件事是认清它的设计哲学——“Agents Are Not Tools”:
| 维度 | A2A 的立场 |
|---|---|
| 对端身份 | 远程 Agent 是独立、有推理能力的对等实体 |
| 抽象边界 | 不定义 Agent 内部实现(prompt / memory / tools) |
| 协议范围 | 不做编排框架、不与 MCP 竞争 |
| 标准化方式 | Proto-First,proto 文件为唯一规范性定义 |
这一点决定了 A2A 的"克制":它只规范 Agent 之间的契约面,而把"Agent 内部怎么想"完全留给实现方。正是这种克制,才让跨厂商互操作成为可能。
三、核心数据模型:五个关键概念
A2A 的数据模型可以概括为"五个名词",用一个口诀记忆非常有效:Agent Card 是简历,Task 是派单,Message 是聊天记录,Artifact 是交付物。下面逐一落到工程细节。
3.1 Agent Card:智能体的"自描述名片"
AgentCard是一份机器可读的 JSON 元数据文档,通常发布在符合RFC 8615的 Well-Known URI 路径下:
GET https://{domain}/.well-known/agent-card.json客户端(另一个 Agent 或用户应用)通过解析这张卡片,判断"该不该找它干活、怎么跟它通信、需要什么凭据"。一份较完整的 Agent Card 包含以下模块[citation:16][citation:17]:
{"name":"Travel Booking Agent","description":"搜索并预订机票、酒店","version":"1.0.0","provider":{"organization":"TravelCorp","url":"https://travelcorp.com"},"supportedInterfaces":[{"url":"https://api.travelcorp.com/a2a","protocolBinding":"JSONRPC","protocolVersion":"1.0"}],"capabilities":{"streaming":true,"pushNotifications":true},"defaultInputModes":["text/plain","application/json"],"defaultOutputModes":["text/plain","application/json"],"skills":[{"id":"flight-search","name":"机票搜索","description":"按出发地、目的地、日期搜索可用航班","tags":["travel","flight"],"examples":["搜索明天北京到上海的航班"]}],"securitySchemes":{"oauth2":{"type":"oauth2","flows":{"clientCredentials":{"tokenUrl":"https://auth.travelcorp.com/token","scopes":{"search":"搜索航班和酒店","book":"完成预订"}}}}},"security":[{"oauth2":["search","book"]}]}关键字段解读:
supportedInterfaces:显式声明协议绑定、版本与端点,支持多绑定并存与版本协商(客户端选择兼容版本)[citation:2]。skills:这是能力发现的核心——把"能做什么"结构化、可检索。相比 Tool 清单,它更偏向意图与能力而非具体函数签名。securitySchemes/security:把鉴权要求前置到发现阶段,避免"先调再用、报错才知道要 token"。- 签名(
signatures,JWS):企业场景下可验证卡片来源与完整性,防止中间人篡改[citation:16]。 - Extended Agent Card:认证后可获取更丰富的扩展信息(
GetExtendedAgentCard),实现分层信息披露——对外只暴露摘要,认证后才给细节[citation:2]。
工程提示:发现机制不止 Well-Known URI 一种,还包括策展注册中心(中心化目录,按 skill/tag 查询)与静态配置(已知关系直接硬编码)[citation:17]。协议没有规定中心化注册表,生产环境通常需要自己加一层"发现/治理层"[citation:5]。
3.2 Task:有状态的核心工作单元
如果说 Agent Card 解决"找到谁",Task解决的就是"怎么把活交出去并盯住它"。Task 是 A2A 中唯一同时具备身份、生命周期、状态和产出物的概念,其数据结构大致为:
{"id":"task-123","contextId":"ctx-001","status":{"state":"working","message":{"text":"正在搜索航班..."}},"artifacts":[],"history":[...]}id:任务全局唯一标识,支持跨 Agent 追踪。contextId:所属上下文(会话/流程),用于把多个 Task 归入同一业务流程。status:当前状态,含state与可选的描述消息。artifacts:最终交付物集合。history:交互历史。
Task 状态机是 A2A 区别于普通 API 调用最关键的部分[citation:1][citation:10]:
┌─────────────┐ │ SUBMITTED │ 已提交,尚未开始处理 └──────┬──────┘ ▼ ┌─────────────┐ │ WORKING │ 正在处理,可能持续推送进度 └──┬───┬───┬──┘ ┌───────────┘ │ └───────────┐ ▼ ▼ ▼ ┌──────────┐ ┌──────────────┐ ┌───────────┐ │COMPLETED │ │ INPUT_REQUIRED│ │AUTH_REQUIRED│ │ (终态) │ │ (暂停,等输入)│ │ (暂停,等认证)│ └──────────┘ └──────┬───────┘ └──────┬────┘ │ │ ▼ │ 回到 WORKING ◄────────────┘ │ ┌────────┬───────┴───────┬─────────┐ ▼ ▼ ▼ ▼ FAILED CANCELED REJECTED (unknown) (终态) (终态) (终态)需要特别注意的几点:
- 终态不可重启:一旦进入
COMPLETED/FAILED/CANCELED/REJECTED,该 Task 就不能再次启动,后续操作必须在同一contextId下创建新 Task[citation:7]。这是一个重要的工程权衡——简化了实现与追踪,但意味着"重试"需要由上层业务自己建模。 INPUT_REQUIRED与AUTH_REQUIRED是"暂停态"而非终态:前者支持人机协作 / 多轮澄清,后者把鉴权异常显式建模进状态机,而不是靠错误码偷偷传递。REJECTED≠FAILED:REJECTED表示"拒绝执行"(如权限不足、无法理解意图),FAILED表示"尝试了但出错了"——语义不同,调用方应区别处理。unknown:任务状态无法确定(ID 无效、未知、已过期)[citation:10]。
长时任务是 Task 状态机的第一性驱动力。一个供应链优化任务可能跑几小时甚至几天,单纯请求-响应会让连接和资源管理陷入困境——这正是 A2A 引入状态机、轮询、流式、推送多种同步机制的动因。
3.3 Message 与 Part:通信内容的最小单元
Message表示一次通信轮次,包含role(user= 客户端发送 /agent= 服务端发送)和一个或多个Part:
{"role":"user","parts":[{"type":"text","text":"帮我订明天北京到上海的机票"},{"type":"data","data":{"preferred":"经济舱"}}]}Part是内容与多模态的最小载体,支持text(文本)、file(文件,含 MIME)、data(结构化 JSON)[citation:1]。这让 A2A 天然支持多模态:文本、图片、音频、视频、结构化数据、文件都能在消息/交付物中流转。
Message与Artifact的分工:
- Message:通信过程中的非交付内容——指令、上下文、思考过程、状态更新。
- Artifact:任务完成后正式的、不可变的交付物,可包含多个 Part[citation:12]。
一句话:Message 是过程,Artifact 是结果。把两者分开,才能让"中间讨论"和"最终成果"不混在一起,也便于做产物管理与审计。
四、交互流程:一次完整委派长什么样
把上面四个概念串起来,一个典型的 A2A 交互时序如下:
Client Agent Remote Agent │ │ │── GET /.well-known/agent-card.json ──▶│ ① 发现 │◀── AgentCard (能力/接口/安全) ────────│ │ │ │── SendMessage (Task, Message) ───────▶│ ② 委派 │◀── Task(id, status=SUBMITTED) ───────│ │ │ │◀── SSE: status=WORKING ──────────────│ ③ 进度 │◀── SSE: artifact delta ──────────────│ │ │ │── GetTask (轮询/兜底) ──────────────▶│ ④ 查询 │◀── Task(status, artifacts) ──────────│ │ │ │◀── Task(status=COMPLETED, artifacts) │ ⑤ 交付对应到**抽象操作(Abstract Operations)**层,主要方法为[citation:9][citation:12]:
| 操作 | 作用 |
|---|---|
SendMessage | 发送消息,创建或继续一个 Task |
SendStreamingMessage | 发送消息并通过流接收更新(SSE) |
GetTask | 查询 Task 当前状态与结果 |
ListTasks | 按条件列出任务 |
CancelTask | 请求取消任务 |
SubscribeToTask | 订阅已有 Task 的流式更新 |
Create/Get/List/DeleteTaskPushNotificationConfig | 配置异步 Webhook 推送 |
GetExtendedAgentCard | 认证后获取扩展 Agent Card |
长时任务的三套同步机制
A2A 对"任务进度如何同步到调用方"给出了三种等价机制,开发者按场景选择[citation:2]:
- 轮询(Polling):
SendMessage后周期性GetTask——实现简单,适合秒级延迟可接受的场景。 - 流式(SSE,Server-Sent Events):
SendStreamingMessage,服务端持续推送TaskStatusUpdateEvent/TaskArtifactUpdateEvent——适合需要实时进度、但调用方需维持长连接的场景。 - 推送通知(Push Notification):预先配置 Webhook,任务状态变化时由服务端主动回调——最适合小时级/天级的超长任务,调用方无需维持连接。
这三套机制共用同一套StreamResponse数据模型,是 A2A 设计中"多种传输、统一语义"的典型体现。
五、传输绑定:分层架构的工程价值
A2A 规范按Data Model → Abstract Operations → Protocol Bindings三层组织[citation:9]。第三层协议绑定允许同一套语义映射到多种传输,且规范保证它们之间语义等价[citation:2]:
| 绑定 | 传输方式 | 流式支持 | 典型场景 |
|---|---|---|---|
| JSON-RPC 2.0 | HTTP POST,application/json | SSE(text/event-stream) | 最简单、生态最广 |
| gRPC | HTTP/2 + Protobuf | Server Streaming RPC | 高性能、强类型 |
| HTTP+JSON / REST | 标准 RESTful 端点 | SSE | 对接既有 REST 基础设施 |
示例:一个"发送消息"操作在不同绑定下的映射[citation:9]:
// JSON-RPC 2.0 请求{"jsonrpc":"2.0","id":1,"method":"SendMessage","params":{"message":{"role":"user","parts":[{"type":"text","text":"我要一杯拿铁"}]},"taskId":null}}# REST 等价端点 POST /message:send Content-Type: application/json { "message": {...} }// gRPC 等价服务 service AgentService { rpc SendMessage(MessageRequest) returns (Task); rpc SendStreamingMessage(MessageRequest) returns (stream StreamResponse); }HTTP 层的约定也不容忽视:规范额外定义了A2A-Version头(如1.0)、A2A-Extensions头(逗号分隔的扩展 URI),以及自定义 media typeapplication/a2a+json;生产环境必须使用 HTTPS(推荐 TLS 1.3+)[citation:17]。
为什么这种"分层 + 多绑定"设计值得学习:它把"业务语义"和"传输细节"解耦,让不同技术栈都能接入,同时通过 proto 作为唯一规范性来源消除"规范漂移(specification drift)"。这是协议设计的通用最佳实践,即便你不用 A2A,这套思路也可借鉴。
六、A2A 与 MCP:精确辨析,而非口号
"A2A 管同事、MCP 管工具"是很好记的口诀,但要写出客观的技术分析,需要把边界讲到更细。
6.1 分工:一横一纵
| 维度 | A2A | MCP |
|---|---|---|
| 提出方 / 治理 | Google 发起,LF 治理 | Anthropic 提出 |
| 通信对象 | Agent ↔ Agent | Agent ↔ Tool / 资源 |
| 对端智能性 | 两端都有推理能力 | 仅 Agent 端智能,Tool 端是确定性服务 |
| 核心概念 | Agent Card、Task、Message、Artifact | Tool、Resource、Prompt |
| 状态性 | 有状态,Task 完整生命周期 | 通常无状态Tool 调用 |
| 交互模式 | 多轮对话、委派、协商 | 结构化函数调用、读写资源 |
| 发现机制 | Agent Card(能力声明) | Tool 清单 |
| 典型延迟 | 秒到分钟级(长时任务) | 毫秒级 |
| 认证 | 双向认证,OAuth 2.0 / OIDC | 服务端控制为主 |
| 抽象层次 | 高级(意图与能力) | 低级(具体功能/接口) |
[citation:4][citation:8]
6.2 何时用哪个
判断依据很朴素——对端是"确定性函数"还是"需要推理的实体"[citation:4]:
- 用 MCP:远程端是一个确定性函数——数据库查询、API 调用、代码执行沙箱、读文件。Agent 完全掌控交互过程。
- 用 A2A:远程端需要对模糊指令做推理——解释意图、做判断、调用自己的 Tool、进行多轮对话。
- 两者都用:编排 Agent 通过 A2A 把任务委派给专家 Agent,而每个专家 Agent 通过 MCP 访问自己的工具[citation:4]。
6.3 组合架构:一张分层图
┌──────────────────────────────┐ │ 用户复杂目标 │ └──────────────┬───────────────┘ ▼ ┌──────────────────────────────┐ │ 编排 Agent(总监) │ └──┬───────────┬───────────┬───┘ │ A2A │ A2A │ A2A ← 横向:Agent 间 ▼ ▼ ▼ ┌──────┐ ┌──────┐ ┌──────┐ │机票Agent│ │酒店Agent│ │报销Agent│ └──┬───┘ └──┬───┘ └──┬───┘ │ MCP │ MCP │ MCP ← 纵向:Agent→工具 ▼ ▼ ▼ ┌──────┐ ┌──────┐ ┌──────┐ │航司API│ │OTA平台│ │财务系统│ └──────┘ └──────┘ └──────┘企业差旅实例:用户说"下周去上海,帮我订机票和酒店,还要能报销"。编排 Agent 通过 A2A发现机票、酒店、报销三个 Agent(可能分别来自航司、OTA、公司财务系统),读取各自的 Agent Card,用 Task委派并收集 Artifact,最终汇总成一份完整方案。而机票 Agent 内部,则用 MCP 去查航司库存 API。
常见误区澄清(这也是面试高频扣分点):
- ❌ “有了 A2A,就要统一底层大模型” → A2A不管模型,只规定 Agent 间如何交流。
- ❌ “A2A 只是 API 封装” → 它包含能力发现 + 任务状态机 + 交付物 + 多轮协商等协作语义。
- ❌ “A2A 和 MCP 二选一” → 它们是互补关系,正经企业级系统通常两个都要[citation:8][citation:11]。
七、工程落地:优势与真实挑战
客观分析必须同时讲清楚收益和代价。A2A 的优势很明显:标准化互操作、解耦(新增 Agent 只需加 URL,不改代码)、原生支持长时/多轮/异步任务、安全前置。但它也带来了实实在在的工程挑战:
需要正视的几个问题
- 状态一致性管理复杂:多 Agent 长时协作下,Task 状态、上下文(
contextId)、重试语义的分布一致性,需要业务层自己保证。 - 部分故障处理尚不成熟:一个编排流程里某个 Agent 长时间无响应、返回
unknown、或交付物格式不兼容时,补偿与重试策略规范并未给出标准答案。 - 鉴权与权限治理不可忽视:跨厂商协作必须先确认"你是谁 + 你能做什么"——OAuth2/OIDC、scope、最小权限都要落地,不能因为是"Agent 内部"就省略。
- 协议仍在演进:v1.0 才刚稳定,真实生产部署的规模与最佳实践仍在积累中;生态的采纳广度最终决定协议的实际价值[citation:2]。
- 性能与成本:相比直接函数调用,引入 Agent 推理 + 多轮通信会显著增加延迟与 token 开销,不适合对延迟敏感的确定性链路。
最小可运行骨架(概念代码)
下面这段 Python 伪代码用于理解协议报文结构,不依赖官方 SDK:
# ---------- A2A Server 侧(简化)----------fromuuidimportuuid4fromdataclassesimportdataclass,fieldfromtypingimportList,OptionalimportjsonclassTaskState:SUBMITTED,WORKING,COMPLETED,FAILED,INPUT_REQUIRED=\"submitted","working","completed","failed","input-required"@dataclassclassTask:id:str=field(default_factory=lambda:f"task-{uuid4().hex}")context_id:str=field(default_factory=lambda:f"ctx-{uuid4().hex}")state:str=TaskState.SUBMITTED artifacts:List[dict]=field(default_factory=list)# Agent Card 发现端点@app.get("/.well-known/agent-card.json")defagent_card():return{...}# 见 3.1 完整卡片# JSON-RPC: 同步发送任务@app.post("/message:send")defsend_message(params:dict)->dict:task=Task()# ... 交由 task_handler 异步处理 ...task.state=TaskState.WORKINGreturn{"jsonrpc":"2.0","id":params.get("id"),"result":{"id":task.id,"status":{"state":task.state}}}# SSE: 流式发送任务@app.post("/message:stream")defsend_stream(params:dict):defevent_stream():yield'event: task-status\ndata: {"state":"working","message":"处理中..."}\n\n'yield'event: task-artifact\ndata: {"parts":[{"type":"text","text":"结果"}]}\n\n'yield'event: task-status\ndata: {"state":"completed"}\n\n'returnStreamingResponse(event_stream(),media_type="text/event-stream")# ---------- A2A Client 侧(简化)----------defdiscover(base:str)->dict:returnhttp.get(f"{base}/.well-known/agent-card.json").json()defdelegate(endpoint:str,text:str)->dict:payload={"jsonrpc":"2.0","method":"SendMessage","id":1,"params":{"message":{"role":"user","parts":[{"type":"text","text":text}]}}}returnhttp.post(endpoint,json=payload).json()defget_task(endpoint:str,task_id:str)->dict:payload={"jsonrpc":"2.0","method":"GetTask","id":2,"params":{"id":task_id}}returnhttp.post(endpoint,json=payload).json()生产建议:真实项目优先使用官方 SDK(Python / JS / Java / Go / .NET)而非手写,避免重复实现状态机、错误模型与绑定细节[citation:2]。
八、总结:把单体智能连接成协同网络
回到开头的问题——“A2A 协议是什么”,一个相对完整、能在面试或技术评审中站得住脚的回答是:
A2A 是面向异构 AI Agent 的开放互操作协议。它通过Agent Card(能力发现)、Task(有状态任务生命周期)、Message / Part(多模态通信)、Artifact(交付物)四个核心抽象,配合JSON-RPC / REST / gRPC三种等价传输绑定,解决了不同厂商、不同框架 Agent 之间的发现、认证、委派、状态同步与结果交付问题。它与 MCP 互补而非竞争:MCP 管 Agent 调用工具(纵向),A2A 管 Agent 之间协作(横向)。
更本质地说,A2A 体现的是一种架构视角迁移:把 AI 系统从"单体能力"推向"智能体生态"——单个 Agent 是专家,协议让专家之间能像团队一样协作。这也是它被称为"Agent 世界的 HTTP"的原因。
但要记住客观边界:A2A 不是银弹。它解决的是"通信与协作的标准化",不解决模型能力、工具质量、业务正确性,也不替你处理所有分布式系统的复杂性。引入前请先问自己:你的场景是否真的存在跨框架/跨团队的 Agent 互操作需求?如果只是同一框架内的多 Agent 编排,框架自带机制往往更简单;只有当"异构协作"真实存在时,A2A 的标准化价值才会真正兑现。
参考资料
- A2A 官方规范:https://a2a-protocol.org/latest/specification/
- A2A 项目仓库:https://github.com/a2aproject/A2A
- 腾讯云技术百科:A2A 协议架构与核心组件[citation:1]
- A2A 中文社区规范翻译(TaskState、Message 等)[citation:10]
- A2A vs MCP 精确对比与组合架构[citation:4][citation:8][citation:11]
延伸思考:如果你对"要不要自研一套 Agent 通信协议"还有犹豫,不妨把 A2A 的分层架构(Data Model → Operations → Bindings)当作评估模板——即便最终不用 A2A,这套"语义与传输解耦 + 自描述发现 + 有状态任务"的设计思想,也值得在你的系统里复用。