A2A 协议深度解析:让所有 AI Agent 说同一种语言
导语
假设你是一家企业的 IT 负责人,公司内部同时使用了三套 AI Agent 系统:HR 部门用 Google ADK 构建的招聘 Agent,销售部门用 LangChain 打造的客户跟进 Agent,财务部门用 CrewAI 搭建的报销审批 Agent。
一个新员工入职,需要同时触发三个流程:HR Agent 完成背调 → 销售 Agent 分配客户资源 → 财务 Agent 开通报销权限。但三个 Agent 分属不同框架、不同团队开发、甚至部署在不同的云上——它们之间完全无法对话。
这就是 A2A 协议要解决的问题。
2025 年 4 月,Google 在 Cloud Next 大会上开源发布了 A2A(Agent-to-Agent Protocol),并贡献给 Linux Foundation。这是一个让不同框架、不同厂商、不同部署环境的 AI Agent 能够相互发现、通信和协作的开放协议。目前已获得 Atlassian、Salesforce、SAP 等 50+ 家企业的支持。
本文是系列第二篇,将深入 A2A 的技术内核。
官方文档:a2a-protocol.org GitHub:github.com/a2aproject/… 协议规范:a2a-protocol.org/latest/spec…
一、设计目标与核心原则
1.1 A2A 要解决什么问题?
一句话:让"不透明"的 Agent 之间也能协作。
什么叫"不透明"?就是你不知道对方 Agent 内部用了什么模型、什么工具、什么逻辑——你只知道它对外暴露了一组能力。这在企业场景中是常态:Salesforce 不会把自己 CRM Agent 的内部实现公开给你,但你的 Agent 需要和它协作。
A2A 的设计目标是在不暴露内部状态的前提下,实现 Agent 之间的:
- 发现:找到合适的 Agent
- 协商:确认对方能做什么、需要什么输入
- 执行:委派任务并跟踪进度
- 交付:获取结果
1.2 五大设计原则
| 原则 | 含义 | 实际意义 |
|---|---|---|
| Agent 即 Agent | 远程 Agent 是独立的智能体,不是被调用的工具 | 支持多轮对话、长时任务、主动反馈,而非简单的 request-response |
| 基于标准构建 | 使用 HTTP、JSON-RPC、SSE 等已有标准 | 开发者无需学习新的传输协议,降低接入门槛 |
| 默认安全 | 企业级认证和授权 | 支持 OAuth 2.0、API Key、OpenID Connect 等主流认证方案 |
| 支持长时任务 | 处理持续数小时甚至数天的任务 | 通过 SSE 和推送通知实时同步进度 |
| 支持多模态 | 不限于文本 | 支持文本、图片、音频、视频、结构化数据、文件等 |
二、核心概念:Agent Card
2.1 Agent Card 是什么?
Agent Card 是 Agent 的"名片"——一个 JSON 格式的自描述清单,声明了 Agent 的身份、能力、技能和交互要求。
每个 Agent 在一个标准路径下托管自己的 Agent Card:
https://example.com/.well-known/agent-card.json
其他 Agent 通过访问这个 URL,就能了解该 Agent 能做什么、怎么调用、需要什么认证。
2.2 Agent Card 结构解析
一个完整的 Agent Card 包含以下核心模块:
graph TB
AC["Agent Card"]
AC --> ID["基础信息<br/>name / description / version / provider"]
AC --> IF["接口声明<br/>supportedInterfaces<br/>(URL、协议绑定、版本)"]
AC --> CAP["能力声明<br/>capabilities<br/>(streaming / pushNotifications)"]
AC --> SK["技能列表<br/>skills[]<br/>(id / name / description / tags / examples)"]
AC --> IO["输入输出模态<br/>defaultInputModes / defaultOutputModes<br/>(text/plain, application/json, image/png...)"]
AC --> SEC["安全要求<br/>securitySchemes / security<br/>(OAuth2, API Key, OpenID Connect...)"]
AC --> SIG["签名验证<br/>signatures[]<br/>(JWS 签名,验证来源和完整性)"]
style AC fill:#fff,stroke:#333,stroke-width:2px,color:#333
style ID fill:#fff,stroke:#333,stroke-width:1px,color:#333
style IF fill:#fff,stroke:#333,stroke-width:1px,color:#333
style CAP fill:#fff,stroke:#333,stroke-width:1px,color:#333
style SK fill:#fff,stroke:#333,stroke-width:1px,color:#333
style IO fill:#fff,stroke:#333,stroke-width:1px,color:#333
style SEC fill:#fff,stroke:#333,stroke-width:1px,color:#333
style SIG fill:#fff,stroke:#333,stroke-width:1px,color:#333
一个简化的 Agent Card 示例:
{
"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": ["搜索明天北京到上海的航班"]
},
{
"id": "hotel-booking",
"name": "酒店预订",
"description": "根据位置、日期、预算搜索和预订酒店",
"tags": ["travel", "hotel"],
"examples": ["预订陆家嘴附近明天入住的酒店,预算500以内"]
}
],
"securitySchemes": {
"oauth2": {
"type": "oauth2",
"flows": {
"clientCredentials": {
"tokenUrl": "https://auth.travelcorp.com/token",
"scopes": {
"search": "搜索航班和酒店",
"book": "完成预订"
}
}
}
}
},
"security": [{ "oauth2": ["search", "book"] }]
}
2.3 Agent Card 的发现机制
Agent Card 的发现遵循"Well-Known URI"约定(类似 robots.txt):
- 静态发现:客户端直接访问
/.well-known/agent-card.json - 扩展发现:通过
GetExtendedAgentCard方法获取认证后的完整能力描述(部分能力可能仅对已认证客户端可见) - 注册发现:Agent Card 可以注册到目录服务中,供其他 Agent 搜索和匹配
关键设计:Agent Card 支持 JWS 签名。 客户端可以验证 Agent Card 的完整性和来源,防止中间人篡改——这在企业场景中至关重要。
三、核心概念:Task 生命周期
3.1 Task 是什么?
Task 是 A2A 中的核心工作单元。 当一个 Agent 请求另一个 Agent 做事时,就创建了一个 Task。Task 有完整的生命周期管理,支持状态追踪、中断恢复和取消。
3.2 Task 状态机
A2A 定义了 9 种 Task 状态,形成一个清晰的状态机:
stateDiagram-v2
[*] --> SUBMITTED : SendMessage
SUBMITTED --> WORKING : Agent 开始处理
WORKING --> COMPLETED : 任务完成
WORKING --> FAILED : 执行失败
WORKING --> CANCELED : 被取消
WORKING --> INPUT_REQUIRED : 需要更多输入
WORKING --> AUTH_REQUIRED : 需要认证
INPUT_REQUIRED --> WORKING : 用户提供输入
AUTH_REQUIRED --> WORKING : 完成认证
SUBMITTED --> REJECTED : Agent 拒绝任务
COMPLETED --> [*]
FAILED --> [*]
CANCELED --> [*]
REJECTED --> [*]
| 状态 | 含义 | 类型 |
|---|---|---|
SUBMITTED | 任务已提交,等待处理 | 初始状态 |
WORKING | Agent 正在处理 | 进行中 |
INPUT_REQUIRED | 需要用户提供更多信息 | 中断状态 |
AUTH_REQUIRED | 需要额外的认证授权 | 中断状态 |
COMPLETED | 任务成功完成 | 终止状态 |
FAILED | 任务执行失败 | 终止状态 |
CANCELED | 任务被取消 | 终止状态 |
REJECTED | Agent 拒绝执行该任务 | 终止状态 |
关键设计点:
-
中断与恢复:
INPUT_REQUIRED和AUTH_REQUIRED是"中断状态"——Agent 暂停执行,等待客户端提供信息后继续。这支持多轮交互场景。 -
拒绝权:Agent 可以
REJECTED一个任务。这体现了 A2A "Agent 即 Agent"的设计哲学——远程 Agent 不是工具,它有权评估并拒绝不合适的任务。
3.3 Task 与 Message、Artifact 的关系
A2A 中有三种核心数据对象,它们的关系如下:
Task(任务)
├── Message(消息):客户端与 Agent 之间的对话交互
│ └── Part(部分):消息中的最小内容单元
│ ├── text: 文本内容
│ ├── data: 结构化 JSON 数据
│ ├── raw: 二进制文件(Base64 编码)
│ └── url: 文件链接
└── Artifact(产物):任务生成的最终输出
└── Part(部分):产物内容,结构同 Message 中的 Part
Message vs Artifact 的区别:
| 维度 | Message | Artifact |
|---|---|---|
| 用途 | 交互过程中的对话 | 任务的最终产出 |
| 角色 | 有发送方角色(USER 或 AGENT) | 无角色概念 |
| 生成时机 | 任务执行过程中 | 任务完成时 |
| 示例 | "请问您的预算是多少?" | 生成的旅行方案 PDF |
四、通信机制:JSON-RPC + SSE + 推送
4.1 三种交互模式
A2A 支持三种交互模式,覆盖从简单到复杂的所有场景:
sequenceDiagram
participant C as Client Agent
participant S as Remote Agent
Note over C,S: 模式1:同步请求/响应
C->>S: SendMessage (JSON-RPC over HTTP)
S-->>C: Task 结果
Note over C,S: 模式2:流式传输 (SSE)
C->>S: SendStreamingMessage
S-->>C: SSE: Task 状态更新
S-->>C: SSE: 部分结果(流式)
S-->>C: SSE: 最终结果
Note over C,S: 模式3:异步推送通知
C->>S: SendMessage + PushNotificationConfig
S-->>C: Task ID(立即返回)
Note over S: Agent 长时间处理...
S->>C: Webhook 推送:任务完成通知
| 模式 | 适用场景 | 技术实现 |
|---|---|---|
| 同步 | 简单查询、快速任务 | HTTP POST + JSON-RPC |
| 流式 | 生成式 AI 输出、实时进度 | SSE(Server-Sent Events) |
| 异步推送 | 长时间运行任务(小时/天级别) | Webhook 回调 |
4.2 JSON-RPC 方法详解
A2A 基于 JSON-RPC 2.0 定义了一组标准方法:
核心任务方法:
| 方法 | 描述 | 使用场景 |
|---|---|---|
SendMessage | 发送消息,发起或继续任务 | 所有交互的入口 |
SendStreamingMessage | 发送消息并建立 SSE 流 | 需要实时更新的场景 |
GetTask | 获取任务当前状态和结果 | 异步轮询 |
ListTasks | 列出任务(支持过滤和分页) | 任务管理 |
CancelTask | 取消正在进行的任务 | 用户中止操作 |
SubscribeToTask | 对已有任务建立 SSE 订阅 | 中途加入监听 |
推送通知配置方法:
| 方法 | 描述 |
|---|---|
CreateTaskPushNotificationConfig | 为任务创建 Webhook 推送配置 |
GetTaskPushNotificationConfig | 获取推送配置 |
ListTaskPushNotificationConfigs | 列出所有推送配置 |
DeleteTaskPushNotificationConfig | 删除推送配置 |
一个典型的 JSON-RPC 请求示例:
{
"jsonrpc": "2.0",
"method": "SendMessage",
"id": "req-001",
"params": {
"message": {
"messageId": "msg-001",
"role": "ROLE_USER",
"parts": [
{
"text": "帮我搜索明天北京到上海的航班,经济舱"
}
]
},
"configuration": {
"acceptedOutputModes": ["text/plain", "application/json"]
}
}
}
4.3 流式传输的实际运作
当使用 SendStreamingMessage 时,服务端通过 SSE 推送一系列事件:
event: task-status
data: {"taskId": "task-001", "state": "WORKING", "message": {"text": "正在搜索航班..."}}
event: task-status
data: {"taskId": "task-001", "state": "WORKING", "message": {"text": "找到 12 个匹配航班"}}
event: task-artifact
data: {"taskId": "task-001", "artifactId": "art-001", "parts": [{"data": {"flights": [...]}}]}
event: task-status
data: {"taskId": "task-001", "state": "COMPLETED"}
SSE 的优势在于:客户端只需一次 HTTP 请求,就能持续接收 Agent 的状态更新和流式输出——特别适合生成式 AI 的逐步输出场景。
五、安全模型
5.1 认证机制
A2A 不发明新的认证协议,而是复用已有的 Web 安全标准。支持的认证方案包括:
| 认证方案 | 说明 | 典型场景 |
|---|---|---|
http (Bearer) | HTTP Authorization 头 + Bearer Token | OAuth2 访问令牌 |
apiKey | API Key 认证 | 简单的 API 调用 |
oauth2 | OAuth 2.0 完整流程 | 企业级应用 |
openIdConnect | OpenID Connect | 身份认证 + 授权 |
认证信息在 Agent Card 的 securitySchemes 字段中声明,客户端根据声明获取凭证后,通过 HTTP Header 传输:
Authorization: Bearer <token>
A2A-Version: 1.0
5.2 Agent 不透明性
A2A 的一个重要安全特性是 Agent 不透明性(Opacity):
- Agent 不需要暴露内部使用的模型、工具或数据
- Agent 不需要共享内部记忆或推理过程
- Agent 只通过 Agent Card 声明"我能做什么",而不是"我怎么做"
这在企业场景中至关重要: 公司的核心业务逻辑和数据,不会因为接入 A2A 协议而被暴露给合作方的 Agent。
5.3 Agent Card 签名验证
Agent Card 支持 JWS(JSON Web Signature,RFC 7515)签名:
- Agent Card 的发布者使用私钥对内容进行签名
- 客户端获取 Agent Card 时,使用发布者的公钥验证签名
- 签名验证使用 JSON Canonicalization(RFC 8785)确保一致性
这防止了中间人攻击——攻击者无法伪造或篡改 Agent Card 来冒充可信 Agent。
六、A2A vs MCP:互补而非竞争
A2A 和 MCP 是 Agent 生态中最常被提及的两个协议,很多人容易混淆。它们的关系是互补,不是竞争。
6.1 核心差异
graph LR
subgraph "MCP 协议"
A1[AI Agent] -->|"调用工具"| T1[搜索引擎]
A1 -->|"读取数据"| T2[数据库]
A1 -->|"执行操作"| T3[代码执行器]
end
subgraph "A2A 协议"
A2[Agent A] <-->|"对话协作"| A3[Agent B]
A2 <-->|"任务委派"| A4[Agent C]
A3 <-->|"结果同步"| A4
end
style A1 fill:#fff,stroke:#333,stroke-width:2px,color:#333
style A2 fill:#fff,stroke:#333,stroke-width:2px,color:#333
style A3 fill:#fff,stroke:#333,stroke-width:2px,color:#333
style A4 fill:#fff,stroke:#333,stroke-width:2px,color:#333
style T1 fill:#fff,stroke:#333,stroke-width:1px,color:#333
style T2 fill:#fff,stroke:#333,stroke-width:1px,color:#333
style T3 fill:#fff,stroke:#333,stroke-width:1px,color:#333
| 维度 | MCP | A2A |
|---|---|---|
| 通信方向 | Agent → Tool(纵向) | Agent ↔ Agent(横向) |
| 对方的身份 | 工具/数据源(被动) | 独立 Agent(主动、有自主性) |
| 交互模式 | 调用-返回(同步) | 对话、协商、多轮交互 |
| 状态管理 | 无状态 | 有状态(Task 生命周期) |
| 对方能否拒绝 | 不能(工具只有成功/失败) | 可以(Agent 可以 REJECTED) |
| 提出方 | Anthropic | Google(Linux Foundation) |
| 类比 | USB 接口 | 人与人之间的对话协议 |
6.2 协同场景
一个典型的协同场景:
用户 → 你的 Agent
├── [A2A] → 航空公司 Agent:协商机票方案
│ └── [MCP] → 航空公司数据库:查询实时票价
├── [A2A] → 酒店 Agent:协商住宿方案
│ └── [MCP] → 酒店预订系统:查询空房
└── [MCP] → 用户日历工具:获取行程安排
MCP 解决的是"Agent 如何使用工具",A2A 解决的是"Agent 如何与另一个 Agent 合作"。 两者共同构成了 Agent 能力的完整拼图。
七、开发者快速入门
7.1 多语言 SDK
A2A 提供了丰富的 SDK 支持:
| 语言 | 安装方式 |
|---|---|
| Python | pip install a2a-sdk |
| Go | go get github.com/a2aproject/a2a-go |
| JavaScript | npm install @a2a-js/sdk |
| Java | Maven 依赖 |
| .NET | dotnet add package A2A |
7.2 快速体验:3 步创建一个 A2A Agent
Step 1:定义 Agent Card
from a2a.types import AgentCard, Skill
card = AgentCard(
name="Weather Agent",
description="提供全球天气查询服务",
version="1.0.0",
skills=[
Skill(
id="weather-query",
name="天气查询",
description="根据城市名查询当前天气",
tags=["weather"],
examples=["北京今天天气怎么样?"]
)
],
default_input_modes=["text/plain"],
default_output_modes=["text/plain", "application/json"]
)
Step 2:实现消息处理逻辑
from a2a.server import A2AServer, TaskHandler
class WeatherHandler(TaskHandler):
async def handle_message(self, message, context):
city = extract_city(message.parts[0].text)
weather = await get_weather(city)
return {
"parts": [{"text": f"{city}当前天气:{weather}"}]
}
Step 3:启动 Agent 服务
server = A2AServer(
agent_card=card,
handler=WeatherHandler()
)
server.start(port=8080)
# Agent Card 自动托管在 http://localhost:8080/.well-known/agent-card.json
八、写在最后
A2A 协议的出现,标志着 AI Agent 从"单兵作战"进入了"组队协作"时代。
它的设计哲学有三个值得关注的点:
-
尊重 Agent 的主体性:Agent 不是工具,它可以拒绝任务、主动要求补充信息、异步回报结果。这为构建复杂的多 Agent 系统奠定了基础。
-
基于已有标准:JSON-RPC、HTTP、SSE、OAuth——A2A 没有发明新轮子,而是组合了已被验证的技术标准。这极大降低了开发者的学习成本。
-
不透明协作:Agent 之间可以协作,但不需要暴露内部实现。这让企业在享受 Agent 协作红利的同时,保护了核心业务逻辑。
下一篇,我们将深入 AP2(Agent Payments Protocol)——看看当 Agent 需要"花钱"时,如何用可验证数字凭证来确保每一笔交易都有用户的真实授权。
关注公众号「coft」,获取更多 AI 时代的深度洞察和技术实战干货。