一、为什么我们需要 A2A?
1.1 一个正在发生的问题
假设你是一家企业的 CTO。你的团队已经部署了:
- 一个基于 LangGraph 的客服 Agent
- 一个基于 CrewAI 的数据分析 Agent
- 一个基于 Google ADK 的代码审查 Agent
这些 Agent 各自都很强大。但当你想让客服 Agent 把用户的退款请求转交给数据分析 Agent 来核实订单数据,再让代码审查 Agent 检查退款逻辑是否有 bug 时——它们互相不认识。
每个框架都有自己的通信方式、自己的数据格式、自己的状态管理。要让它们协作,你需要为每对 Agent 写定制化的集成代码。3 个 Agent 需要 3 条集成线,10 个 Agent 就需要 45 条。这就是经典的 N² 集成问题:
graph LR
A[Agent A] <-->|自定义接口| B[Agent B]
A <-->|自定义接口| C[Agent C]
A <-->|自定义接口| D[Agent D]
B <-->|自定义接口| C
B <-->|自定义接口| D
C <-->|自定义接口| D
style A fill:#ffcdd2,stroke:#e53935
style B fill:#ffcdd2,stroke:#e53935
style C fill:#ffcdd2,stroke:#e53935
style D fill:#ffcdd2,stroke:#e53935
🔴 每新增一个 Agent,集成线数量按 N² 增长——这就是「N² 集成问题」
这还只是技术层面的问题。在组织层面,A 公司的 Agent 和 B 公司的 Agent 更是天然隔离——谁也不愿意把内部实现暴露给对方。
1.2 第一性原理:Agent 协作的本质需求
退到最底层思考:两个独立的 AI Agent 要协作,最少需要什么?
- 发现:我得先知道你是谁、你能干什么
- 信任:我得确认你的身份,才能安全地交互
- 沟通:我们得有一种共同语言来传递意图和数据
- 协作:我们需要一种方式来跟踪共同的任务进展
- 隐私:我们各自不需要暴露内部实现
这五条,就是 A2A 协议的设计起点。
1.3 A2A 是什么
Agent2Agent(A2A) 是由 Google 于 2025 年 4 月在 Google Cloud Next 大会上发布的开放协议,旨在让不同框架、不同平台、不同供应商构建的 AI Agent 能够互相发现、安全通信、协同工作。
2025 年 6 月,A2A 移交 Linux Foundation 治理,已发布 v1.0 规范,获得 50+ 合作伙伴支持(Atlassian、Salesforce、SAP、ServiceNow 等)。
一句话总结:A2A 是 AI Agent 世界的「SMTP 协议」——就像 SMTP 让不同邮件系统互通一样,A2A 让不同 Agent 互通。
二、A2A vs MCP:不是竞争,是互补
2.1 两个协议解决不同的问题
很多人第一次接触 A2A 时会问:它和 Anthropic 的 MCP(Model Context Protocol) 是什么关系?是竞争吗?
不是。它们解决的是完全不同层面的问题:
| 维度 | MCP | A2A |
|---|---|---|
| 全称 | Model Context Protocol | Agent2Agent Protocol |
| 发起方 | Anthropic (2024) | Google (2025) |
| 解决问题 | Agent ↔ 工具/数据源 | Agent ↔ Agent |
| 类比 | 人使用工具(计算器、搜索) | 人与人之间的沟通协作 |
| 交互模型 | Client → Tool | Client ↔ Server(角色可互换) |
2.2 一个类比
想象一个公司:
- MCP 是员工使用各种工具的能力——用 Excel 处理数据、用 Slack 发消息、用日历查日程
- A2A 是员工之间的沟通协作能力——A 同事请 B 同事帮忙审核报告,B 同事完成后把结果传回来
一个高效的员工两种能力都需要。同样,一个成熟的 AI Agent 既用 MCP 连接工具,又用 A2A 与其他 Agent 协作。
graph TB
subgraph Agent[AI 智能体]
MCP[MCP<br/>连接工具<br/>向内]
A2A[A2A<br/>连接其他 Agent<br/>向外]
end
MCP -->|调用| DB[(数据库)]
MCP -->|调用| Search[(搜索引擎)]
MCP -->|调用| FS[(文件系统)]
A2A <-->|协作| OtherAgent[另一个 Agent<br/>独立运行]
style Agent fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
style MCP fill:#fff9c4,stroke:#f9a825
style A2A fill:#c8e6c9,stroke:#388e3c
style DB fill:#f5f5f5,stroke:#999
style Search fill:#f5f5f5,stroke:#999
style FS fill:#f5f5f5,stroke:#999
style OtherAgent fill:#e8f5e9,stroke:#388e3c
2.3 实际协作场景
在一家企业里,一个 HR Agent 通过 A2A 接到「安排技术面试」的任务,它把这个任务委托给一个 Calendar Agent(也是 A2A 通信)。Calendar Agent 收到请求后,通过 MCP 调用日历工具查询空闲时段,最终通过 A2A 把结果传回给 HR Agent。
A2A 管 Agent 之间的任务委派和结果传递,MCP 管 Agent 与工具之间的具体调用。 天然互补。
三、核心架构:优雅的三层设计
A2A 规范采用了清晰的三层架构,这是一种非常工程化的设计——让核心语义与传输协议解耦:
graph TB
subgraph L3[Layer 3 — 协议绑定 Protocol Bindings]
L3a[JSON-RPC 2.0<br/>最常用]
L3b[gRPC]
L3c[HTTP+JSON/REST]
end
subgraph L2[Layer 2 — 抽象操作 Abstract Operations]
L2a[SendMessage]
L2b[SendStreamingMessage]
L2c[GetTask]
L2d[ListTasks]
L2e[CancelTask]
L2f[SubscribeToTask]
end
subgraph L1[Layer 1 — 数据模型 Canonical Data Model]
L1a[AgentCard]
L1b[Task]
L1c[Message]
L1d[Part]
L1e[Artifact]
L1f[Extension]
end
L1 --> L2 --> L3
style L1 fill:#e1f5fe,stroke:#0288d1,stroke-width:2px
style L2 fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
style L3 fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
- Layer 1(名词):定义了协议中所有核心数据结构,用 Protocol Buffers 描述,保证语言无关性
- Layer 2(动词):定义了 Agent 能执行的操作,与具体传输协议无关
- Layer 3(绑定):把操作映射到具体的网络协议上(JSON-RPC、gRPC、REST)
这种分层的好处是:你可以换传输协议,但不用改业务逻辑。就像你换了一部手机,但你的通讯录和通话功能不受影响。
四、Agent Card:Agent 的「数字名片」
4.1 概念
A2A 的发现机制基于一个叫做 Agent Card 的 JSON 文档。你可以把它理解成 Agent 的「LinkedIn 个人主页」——上面写了:我叫什么、我会什么、怎么联系我、需要什么认证。
每个 A2A Server 会在一个标准的 well-known URI 上发布自己的 Agent Card:
4.2 结构详解
一个完整的 Agent Card 长这样:
{
"name": "Corporate Flight Booking Agent",
"description": "处理国内外航班预订。",
"version": "1.0.0",
"provider": {
"organization": "Corp Internal",
"url": "https://internal.corp"
},
"supportedInterfaces": [
{
"url": "https://flights.internal.corp/a2a",
"protocolBinding": "JSONRPC",
"protocolVersion": "1.0"
}
],
"capabilities": {
"streaming": true,
"pushNotifications": true
},
"defaultInputModes": ["text/plain", "application/json"],
"defaultOutputModes": ["application/json", "text/plain"],
"skills": [
{
"id": "book_flight",
"name": "预订航班",
"description": "根据出发地、目的地和日期预订航班。",
"tags": ["travel", "booking"],
"examples": ["7月25日订 SFO 到 LAX 的直飞航班"]
}
],
"securitySchemes": {
"corporate_oauth": {
"type": "oauth2",
"flows": {
"clientCredentials": {
"tokenUrl": "https://auth.internal.corp/token",
"scopes": {
"flights:read": "读取航班时刻",
"flights:write": "预订航班"
}
}
}
}
},
"security": [
{ "corporate_oauth": ["flights:read", "flights:write"] }
]
}
关键字段解读:
| 字段 | 用途 |
|---|---|
skills[] |
Agent 能干什么(技能列表),客户端据此判断谁最适合某个任务 |
supportedInterfaces[] |
怎么连接(协议+地址),支持多种绑定 |
capabilities |
支不支持流式、推送等高级特性 |
securitySchemes + security |
怎么认证(对齐 OpenAPI 3 规范) |
4.3 防篡改:AgentCardSignature
Agent Card 本身是攻击面——如果有人篡改了 skills 或 url,可以把请求重定向到恶意 Agent。A2A v1.0 引入了 AgentCardSignature:用 JWS(JSON Web Signature,RFC 7515)对规范化后的 Agent Card 签名,确保完整性。
五、Task 生命周期:一个完整的状态机
5.1 为什么需要 Task
A2A 不只是「发个消息就完了」。Agent 之间的协作往往涉及多步骤、长时间的复杂工作。比如「帮我分析这份 100 页的财报」可能需要几分钟,「帮我安排下周的所有面试」可能需要人类介入确认时间。
所以 A2A 引入了 Task 这个概念——一个有状态的、可跟踪的工作单元。
5.2 完整状态机
stateDiagram-v2
[*] --> SUBMITTED: 提交任务
SUBMITTED --> WORKING: 开始处理
WORKING --> INPUT_REQUIRED: 需要更多信息
WORKING --> AUTH_REQUIRED: 需要认证
WORKING --> FAILED: 不可恢复错误
WORKING --> COMPLETED: 成功完成
INPUT_REQUIRED --> WORKING: 补充输入后恢复
AUTH_REQUIRED --> WORKING: 重新认证后恢复
SUBMITTED --> CANCELED: 取消
SUBMITTED --> REJECTED: 拒绝
WORKING --> CANCELED: 取消
COMPLETED --> [*]
FAILED --> [*]
CANCELED --> [*]
REJECTED --> [*]
各状态含义:
| 状态 | 分类 | 含义 |
|---|---|---|
SUBMITTED |
进行中 | 任务已接受,排队等待处理 |
WORKING |
进行中 | Agent 正在积极处理 |
INPUT_REQUIRED |
中断 | 需要用户或其他 Agent 提供更多信息 |
AUTH_REQUIRED |
中断 | 需要补充认证信息 |
COMPLETED |
终态 | 成功完成,返回结果 |
FAILED |
终态 | 处理过程中发生不可恢复的错误 |
CANCELED |
终态 | 被主动取消 |
REJECTED |
终态 | Agent 拒绝执行(策略、能力、配额等原因) |
进入终态后,Task 的 SSE 流自动关闭,不再接受新消息。
六、通信模式:三种姿势,按需选择
A2A 支持三种通信模式,覆盖从毫秒级响应到天级长任务的全场景:
6.1 同步请求/响应(最简单)
客户端发请求,等 Agent 处理完直接返回结果。适合简单、快速的任务。
6.2 流式更新(SSE)
通过 Server-Sent Events 实时推送任务进展。适合需要进度反馈的中长时间任务。
sequenceDiagram
participant C as 客户端
participant S as 服务端 Agent
C->>S: SendStreamingMessage (提交任务)
S-->>C: SSE: TASK_STATE_SUBMITTED
S-->>C: SSE: TASK_STATE_WORKING
S-->>C: SSE: artifactUpdate (部分结果)
S-->>C: SSE: TASK_STATE_COMPLETED (流关闭)
6.3 异步推送(Webhook)
客户端注册一个 Webhook URL,Agent 完成任务后主动 POST 结果过来。适合超长任务或客户端可能断线的场景。
sequenceDiagram
participant C as 客户端
participant S as 服务端 Agent
C->>S: 注册 Push Notification (webhook URL)
Note over C,S: ... 时间过去 (几小时/几天) ...
S->>C: HTTP POST 到 Webhook (携带任务结果)
七、消息、部件与产物
7.1 数据结构层次
A2A 的数据交换模型可以用一棵树来理解:
graph TB
subgraph Task[Task 任务]
subgraph Msg[Message 消息]
P1[Part: TextPart<br/>帮我订一张北京到上海的机票]
P2[Part: DataPart<br/>origin: PEK, dest: SHA]
P3[Part: FilePart<br/>差旅审批.pdf]
end
subgraph Art[Artifact 产物]
P4[Part: TextPart<br/>已为您预订 CA1501 航班...]
P5[Part: DataPart<br/>flight: CA1501, seat: 12A]
end
end
style Task fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
style Msg fill:#fff3e0,stroke:#f57c00
style Art fill:#e8f5e9,stroke:#388e3c
style P1 fill:#fffde7
style P2 fill:#fffde7
style P3 fill:#fffde7
style P4 fill:#f1f8e9
style P5 fill:#f1f8e9
- Message:一次对话交互,有角色(
user或agent),包含一个或多个 Part - Part:最小内容单元,支持文本、文件、结构化数据
- Artifact:Agent 产出的交付物(文档、图片、结构化数据等)
7.2 多模态支持
Part 的设计天然支持多模态。一条 Message 可以同时包含文本指令、JSON 参数和文件附件:
{
"role": "ROLE_USER",
"parts": [
{"text": "请分析这份财报"},
{
"data": {
"company": "ACME Corp",
"fiscal_year": "2025"
},
"mediaType": "application/json"
},
{
"file": {
"url": "https://example.com/report.pdf",
"mediaType": "application/pdf"
}
}
]
}
这种设计让 Agent 可以在一条消息中传递所有必要的上下文,而不需要多次往返。
八、实战:从发现到获取结果的完整代码
下面用 Python 演示一个完整的 A2A 工作流:发现 Agent → 提交任务 → 流式监听 → 获取结果。
步骤 1:发现 Agent,检查能力
import requests
REMOTE_AGENT_URL = "https://flights.internal.corp"
# 1. 获取 Agent Card
response = requests.get(
f"{REMOTE_AGENT_URL}/.well-known/agent-card.json"
)
agent_card = response.json()
print(f"Agent: {agent_card['name']}")
print(f"Skills: {[s['id'] for s in agent_card['skills']]}")
# 2. 检查是否有所需技能
skill_ids = {s['id'] for s in agent_card.get('skills', [])}
assert 'book_flight' in skill_ids, "缺少预订航班技能!"
# 3. 获取通信端点
interface = agent_card['supportedInterfaces'][0]
endpoint = interface['url'] # https://flights.internal.corp/a2a
步骤 2:提交任务(JSON-RPC over HTTP)
import json
task_request = {
"jsonrpc": "2.0",
"id": 1,
"method": "SendMessage",
"params": {
"message": {
"role": "ROLE_USER",
"parts": [
{"text": "预订7月25日 SFO 到 LAX 的直飞航班,员工号 4432"}
]
},
"configuration": {"returnImmediately": True}
}
}
response = requests.post(
endpoint,
json=task_request,
headers={
"Authorization": "Bearer <oauth_token>",
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream"
}
)
task = response.json()
task_id = task["id"]
print(f"Task created: {task_id}, state: {task['status']['state']}")
# 输出: Task created: task-9876-abcd, state: TASK_STATE_SUBMITTED
步骤 3:通过 SSE 流式监听进展
import sseclient # pip install sseclient-py
subscribe_request = {
"jsonrpc": "2.0",
"id": 2,
"method": "SubscribeToTask",
"params": {"taskId": task_id}
}
response = requests.post(
endpoint,
json=subscribe_request,
headers={
"Authorization": "Bearer <oauth_token>",
"Accept": "text/event-stream"
},
stream=True
)
client = sseclient.SSEClient(response)
for event in client.events():
data = json.loads(event.data)
if "statusUpdate" in data:
state = data["statusUpdate"]["status"]["state"]
print(f"状态更新: {state}")
if state in ("TASK_STATE_COMPLETED", "TASK_STATE_FAILED",
"TASK_STATE_CANCELED"):
break
elif "artifactUpdate" in data:
artifact = data["artifactUpdate"]["artifact"]
print(f"收到产物: {artifact['name']}")
# 输出: 收到产物: itinerary
print("任务完成!")
步骤 4:获取最终结果
get_task_request = {
"jsonrpc": "2.0",
"id": 3,
"method": "GetTask",
"params": {
"taskId": task_id,
"historyLength": 5 # 获取最近5条消息
}
}
response = requests.post(
endpoint,
json=get_task_request,
headers={"Authorization": "Bearer <oauth_token>"}
)
final_task = response.json()
# 提取产物
for artifact in final_task.get("artifacts", []):
print(f"\n=== {artifact['name']} ===")
for part in artifact["parts"]:
if "text" in part:
print(part["text"])
elif "data" in part:
print(json.dumps(part["data"], indent=2, ensure_ascii=False))
完整流程示意
sequenceDiagram
participant C as Client Agent
participant R as Remote Agent
C->>R: GET /.well-known/agent-card.json
R-->>C: Agent Card (skills, endpoint)
Note over C: 检查 skills, 确认 endpoint
C->>R: POST SendMessage (预订航班请求)
R-->>C: Task (TASK_STATE_SUBMITTED)
C->>R: POST SubscribeToTask
R-->>C: SSE: TASK_STATE_WORKING
R-->>C: SSE: artifactUpdate (部分结果)
R-->>C: SSE: TASK_STATE_COMPLETED (流关闭)
C->>R: POST GetTask (获取完整结果)
R-->>C: Task + Artifacts
九、安全架构:企业级设计
9.1 多层安全模型
A2A 的安全设计从第一天就考虑了企业需求:
graph TB
subgraph Security[安全架构]
T[传输层: HTTPS / TLS 加密]
subgraph Auth[认证层]
O[OAuth 2.0]
OID[OIDC]
AK[API Key]
MTLS[mTLS]
end
subgraph AuthZ[授权层]
SC[Scope → Skill 映射]
subgraph Integrity[完整性]
SIG[AgentCardSignature<br/>JWS 签名防篡改]
end
end
P[隐私层: Opaque Execution<br/>不暴露内部实现]
end
T --> Auth --> AuthZ --> P
style Security fill:#fff8e1,stroke:#f57f17,stroke-width:2px
style T fill:#ffebee,stroke:#c62828
style Auth fill:#e3f2fd,stroke:#1565c0
style AuthZ fill:#f3e5f5,stroke:#6a1b9a
style Integrity fill:#fce4ec,stroke:#ad1457
style P fill:#e8f5e9,stroke:#2e7d32
style SIG fill:#fce4ec,stroke:#ad1457
9.2 认证方案
A2A 支持 OpenAPI 3 规范定义的所有标准安全方案:
| 方案 | 场景 | 特点 |
|---|---|---|
| OAuth 2.0 | 企业应用间协作 | 细粒度 scope 控制 |
| OIDC | 跨组织身份验证 | 密码学证明身份 |
| API Key | 简单的 M2M 认证 | 轻量但粒度粗 |
| mTLS | 高安全要求场景 | 双向证书认证 |
安全方案在 Agent Card 中明文声明,客户端在连接前就知道需要什么认证:
"securitySchemes": {
"corporate_oauth": {
"type": "oauth2",
"flows": {
"clientCredentials": {
"tokenUrl": "https://auth.internal.corp/token",
"scopes": {
"agent:delegate": "允许其他 Agent 委托任务",
"flights:write": "预订航班"
}
}
}
}
},
"security": [
{ "corporate_oauth": ["agent:delegate", "flights:write"] }
]
9.3 不透明执行(Opaque Execution)
A2A 的一个核心隐私设计原则:Agent 之间协作基于声明的能力,不暴露内部状态。
这意味着:
- Agent 不需要共享内部记忆(memory)
- 不需要暴露推理逻辑(reasoning)
- 不需要暴露使用的工具实现(tool implementations)
就像你请同事帮忙,你关心的是他能不能完成任务,而不是他脑子里怎么想的。
十、SDK 与生态系统
10.1 官方 SDK
A2A 已经覆盖了主流编程语言:
| 语言 | 安装命令 | 仓库 |
|---|---|---|
| Python | pip install a2a-sdk |
a2aproject/a2a-python |
| Go | go get github.com/a2aproject/a2a-go |
a2aproject/a2a-go |
| JavaScript | npm install @a2a-js/sdk |
a2aproject/a2a-js |
| Java | Maven | a2aproject/a2a-java |
| .NET | dotnet add package A2A |
a2aproject/a2a-dotnet |
| Rust | cargo add a2a-lf |
a2aproject/a2a-rs |
10.2 框架集成
主流 Agent 框架已经支持 A2A:
- Google ADK:原生支持
- LangGraph:通过 A2A SDK 集成
- CrewAI:通过适配器接入
- BeeAI (IBM):原生支持
10.3 MCP 集成
Google 和 DeepLearning.AI 联合推出了 A2A + MCP 的短课程(1小时27分钟),教你如何构建同时使用两种协议的多 Agent 系统。
十一、实战场景:多 Agent 协作完成招聘流程
最后,用一个完整的场景串联所有概念:
graph TB
User[👤 用户<br/>帮我招聘一名高级前端工程师]
HR[HR Agent<br/>A2A Client<br/>收到请求,开始编排]
subgraph viaMCP1[通过 MCP]
DB[(简历数据库)]
end
subgraph viaMCP2[通过 MCP]
CAL[(日历系统)]
end
Resume[Resume Screening Agent<br/>筛选候选人]
Sched[Schedule Agent<br/>安排面试时间]
User --> HR
HR <-->|A2A| Resume
HR <-->|A2A| Sched
Resume --- viaMCP1
Sched --- viaMCP2
Resume -->|Artifact: 候选人列表| HR
Sched -->|Artifact: 面试日程| HR
HR -->|汇总结果| User
style User fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
style HR fill:#fff9c4,stroke:#f9a825,stroke-width:2px
style Resume fill:#c8e6c9,stroke:#388e3c
style Sched fill:#c8e6c9,stroke:#388e3c
style DB fill:#f5f5f5,stroke:#999
style CAL fill:#f5f5f5,stroke:#999
整个流程中:
- HR Agent 通过 A2A 发现 Resume Screening Agent 和 Schedule Agent
- 通过 Agent Card 确认它们的能力
- 通过 OAuth 2.0 认证后发送任务
- 通过 SSE 实时接收筛选进度和日程安排结果
- 汇总两个 Agent 的 Artifact,返回给用户
十二、A2A 的设计哲学与未来
12.1 五大设计原则回顾
| 原则 | 含义 | 体现 |
|---|---|---|
| Simple | 复用现有标准 | HTTP + JSON-RPC 2.0 + SSE |
| Enterprise Ready | 企业级安全 | OAuth、mTLS、签名验证 |
| Async First | 原生异步 | Task 状态机 + SSE + Webhook |
| Modality Agnostic | 多模态 | TextPart、DataPart、FilePart |
| Opaque Execution | 不透明 | 不暴露内部记忆和逻辑 |
12.2 未来方向
A2A v1.0 的路线图包括:
- 授权增强:在 Agent Card 中正式纳入凭证管理
- 动态能力查询:
QuerySkill()方法,运行时检查未预期的能力 - 动态 UX 协商:对话中途切换模态(文本→音频→视频)
- 流式可靠性:改进 SSE 和推送通知的可靠性
- 更多协议绑定:支持 gRPC 和 REST 之外的传输层
12.3 为什么 A2A 值得关注
在 AI Agent 爆发的前夜,互操作性比单个 Agent 的能力更重要。
就像互联网的伟大不在于任何一台服务器,而在于 TCP/IP 让所有服务器都能互联。A2A 正在尝试成为 AI Agent 世界的 TCP/IP。
如果你的团队正在构建 AI Agent,现在就了解 A2A,意味着你在为未来的多 Agent 协作生态做准备。
参考资源
本文撰写于 2026 年 6 月,基于 A2A v1.0 规范。协议仍在持续演进中,请以官方最新文档为准。