A2A 协议:Agent 与 Agent 的协作 本节摘要:MCP 是「Agent 调工具」。A2A(Agent2Agent)是「Agent 调 Agent」——一个让基于不同框架构建的、互不透明的 Agent 互相协作的开放协议。2025 年 4 月由 Google 发布,2025 年 6 月捐给 Linux Foundation,2026 年 4 月达到 v1.0,获 AWS、Cisco、Microsoft、Salesforce、SAP、ServiceNow 等 150+ 方支持。它吸收了 IBM 的 ACP,并加入了 AP2 支付扩展。本节走通 Agent Card、Task 生命周期,以及两种传输绑定。
本节摘要:MCP 是「Agent 调工具」。A2A(Agent2Agent)是「Agent 调 Agent」——一个让基于不同框架构建的、互不透明的 Agent 互相协作的开放协议。2025 年 4 月由 Google 发布,2025 年 6 月捐给 Linux Foundation,2026 年 4 月达到 v1.0,获 AWS、Cisco、Microsoft、Salesforce、SAP、ServiceNow 等 150+ 方支持。它吸收了 IBM 的 ACP,并加入了 AP2 支付扩展。本节走通 Agent Card、Task 生命周期,以及两种传输绑定。读完本节,你能区分 Agent 调工具(MCP)与 Agent 调 Agent(A2A),发布 Agent Card,走完 Task 生命周期,并用带 Parts 的 Message 与作为产出的 Artifact。
阅读完本节,你应当能够:
/.well-known/agent.json 发布带 skills 与端点元数据的 Agent Card。一个客服 Agent 需要把「写报告」这件事委托给一个专门的写作 Agent。A2A 之前的选项:
A2A 填这道缝。它把交互建模成一个 Agent 向另一个 Agent 发送一个 Task,带生命周期、消息与产出。被调 Agent 的内部状态保持不透明——调用方只看到 Task 状态转移与最终产出。
A2A 是「让跨框架的 Agent 互相对话」的协议。它不取代 MCP,两者互补。
每个 A2A 合规的 Agent 在 /.well-known/agent.json 发布一张卡片:
{ "schemaVersion": "1.0", "name": "research-agent", "description": "总结学术论文并起草引文。", "url": "https://research.example.com/a2a", "version": "1.2.0", "skills": [ { "id": "summarize_paper", "name": "Summarize a paper", "description": "读一篇论文 PDF,产出三段摘要。", "inputModes": ["text", "file"], "outputModes": ["text", "artifact"] } ], "capabilities": {"streaming": true, "pushNotifications": true} }
发现基于 URL:拉卡片,得知 A2A 端点 URL,枚举 skills。
AP2 扩展(2025 年 9 月)给 Agent Card 加密码学签名。发布者用自己的 JWT 签自己的卡片,消费方校验。防冒充。
submitted -> working -> completed | failed | canceled | rejected -> input_required -> working (经消息循环)
客户端用 tasks/send 发起。被调 Agent 在状态间转移,客户端经 SSE 订阅状态更新或轮询。
一条 Message 带一个或多个 Part:
text——纯内容。file——base64 blob,带 mimeType。data——类型化的 JSON 负载(被调 Agent 的结构化输入)。示例:
{ "role": "user", "parts": [ {"type": "text", "text": "总结这篇论文。"}, {"type": "file", "file": {"name": "paper.pdf", "mimeType": "application/pdf", "bytes": "..."}}, {"type": "data", "data": {"targetLength": "3 paragraphs"}} ] }
产出是 Artifact,不是裸字符串。Artifact 是命名的、类型化的产出:
{ "name": "summary", "parts": [{"type": "text", "text": "..."}], "mimeType": "text/markdown" }
Artifact 可以作为分块流式输出,调用方累积。
/a2a 端点,请求用 POST,流式可选 SSE。默认绑定。两种绑定承载同样的逻辑消息形状。
一条核心设计原则:被调 Agent 的内部状态是不透明的。调用方看到 Task 状态与 Artifact。被调 Agent 的思维链、它的工具调用、它的子 Agent 委托——全部不可见。这与 MCP 不同,后者的工具调用是透明的。
理由:A2A 让竞争对手在不暴露内部的前提下协作。「调这个客服 Agent」时,调用方无需知道那个 Agent 怎么实现客服。
| 维度 | MCP | A2A |
|---|---|---|
| 用例 | Agent 调工具 | Agent 调 Agent |
| 不透明度 | 工具调用透明 | 内部推理不透明 |
| 典型调用方 | Agent 运行时 | 另一个 Agent |
| 状态 | 工具调用结果 | 带生命周期的 Task |
| 授权 | OAuth 2.1(第 16 节) | JWT 签名的 Agent Card(AP2) |
| 传输 | Stdio / Streamable HTTP | HTTP 上的 JSON-RPC / gRPC |
想调一个具体工具就用 MCP;想把一整件事委托给另一个 Agent 就用 A2A。许多生产系统两者都用:一个 Agent 用 MCP 做工具层,用 A2A 做协作层。
def run_task(endpoint, message_parts): task = httpx.post(f"{endpoint}", json={ "jsonrpc": "2.0", "method": "tasks/send", "params": {"message": {"role": "user", "parts": message_parts}}}).json() while task["status"]["state"] not in ("completed", "failed", "canceled", "rejected"): if task["status"]["state"] == "input-required": ans = clarify(task) # 调用方/用户补信息 task = httpx.post(endpoint, json={"method": "tasks/send", "params": {"id": task["id"], "message": ans}}).json() else: task = httpx.post(endpoint, json={"method": "tasks/get", "params": {"id": task["id"]}}).json() return task["artifacts"]
设计要点:A2A 的精髓是「生命周期 + 不透明产出」。调用方只关心 Task 走到哪了、产出是什么;被调方怎么推理、调了哪些工具,一概不可见。这种边界让互不信任的双方也能协作。
| 维度 | MCP | A2A | 自定义 REST |
|---|---|---|---|
| 调用对象 | 工具 | Agent | 任意 |
| 不透明度 | 透明 | 不透明 | 视实现 |
| 标准化 | 强(MCP 规范) | 强(A2A v1.0) | 无 |
| 生命周期 | 无(即时返回) | 有(submitted→completed) | 视实现 |
| 跨框架 | 是 | 是 | 否 |
| 流式 | 支持 | SSE / gRPC 流 | 视实现 |
💡 心法:别把 A2A 当成「另一个 MCP」。MCP 的工具是透明的原子动作;A2A 的 Task 是不透明的整件事。判断标准很简单:这件事要不要一个会思考、会用工具的 Agent 来完成?要就 A2A,不要就 MCP。
本节产出 outputs/skill-a2a-agent-spec.md——给定一个应能被其他 Agent 调用的新 Agent,这个 skill 产出 Agent Card JSON、skills schema 与端点蓝图。
code/main.py 实现一个最小 A2A 测试具:一个 research Agent 发布它的卡片,一个 writer Agent 收到一个 tasks/send,带含 PDF 与文本指令的 parts,经 working → input_required → working → completed 转移,返回一个文本 Artifact。全 stdlib,用内存传输聚焦消息形状。可重点看:Agent Card JSON 形状、Task id 分配与状态转移、混合类型 parts 的消息、Task 中途的 input-required 分支、完成时的 Artifact 返回。
追踪生命周期:运行 code/main.py,追踪完整 Task 生命周期,包括被调 Agent 请求澄清时的 input-required 暂停。
加签名卡片:用 HMAC 对卡片的规范 JSON 签名,写一个校验器,确认它对被篡改的卡片失败。
Task 流式:让 writer Agent 经 SSE 发出三个增量 Artifact 分块,调用方累积。
包 MCP 服务端:设计一个 A2A Agent 包裹一个 MCP 服务端,把每个 MCP 工具映射成一个 A2A skill。留意代价——丢了什么不透明度?
读 v1.0 公告:读 A2A v1.0 公告,找出截至 2026 年 4 月尚无任何框架实现的那一个特性(提示:与多跳 Task 委托有关)。
/.well-known/agent.json:URL 发现,枚举 skills 与端点;AP2 用 JWT 签名防冒充。下一节,我们看怎么把这些跨进程的调用串成一条 trace——OpenTelemetry GenAI 语义约定,以及 LLM / 工具 / MCP / Agent 的 span 层次。