跳到主要内容

Agent 间协议 A2A

MCP 解决"Agent 用工具"。A2A 解决"Agent 用 Agent"。Google 2025 年开源 A2A 协议,Anthropic、Microsoft 跟进。本篇讲清楚多 Agent 协作的标准化路径。

学前说明

5-6 第三章讲了 Supervisor-Worker 等多 Agent 架构,但都是"同一团队 / 同一系统内"的多 Agent。

A2A 解决更难的问题:不同厂商、不同部署、不同所有者的 Agent 怎么协作

例:

  • 你的客服 Agent 需要调用财务团队的"开发票 Agent"
  • 你的研究 Agent 需要 OpenAI 的"图像分析 Agent"
  • 用户的个人助理 Agent 需要购物平台的"比价 Agent"

类比:

  • HTTP 之前:每个网站自己定协议,互不通
  • HTTP 之后:浏览器能访问任何网站
  • A2A 之前:每个 Agent 自己定协议
  • A2A 之后:任何 Agent 能调用任何 Agent

学习目标

  • 区分 A2A 与 MCP 的边界
  • 理解 Google A2A 协议的核心机制(Agent Card、Task、Message)
  • 实现简单的 A2A Server 和 Client
  • 设计 Agent 发现和能力协商
  • 评估 Agent Marketplace 生态的工程价值
  • 处理多 Agent 协作的安全风险

与现有知识的衔接

  • 5-6 多 Agent 系统:单系统内多 Agent(前置)
  • 5-7 / 13 MCP 协议:Agent 用工具的协议(前置)
  • 02 Skills 体系:Skills 是另一种"能力共享"
  • 04 Lethal Trifecta:跨 Agent 调用的安全风险

第一章:A2A vs MCP

1.1 边界

很多人混淆 A2A 和 MCP。它们都是协议,但解决不同问题:

维度MCPA2A
调用方LLM AgentAgent
被调用方Tools / Resources / Prompts另一个 Agent
抽象级别函数级(call_tool)任务级(delegate_task)
状态通常无状态(stateless)有状态(task lifecycle)
协作单次调用长期协作(多轮、异步)
例子调用 GitHub API委派 "做一份市场调研"

1.2 类比

MCP 像调函数:
result = github.create_issue(repo, title, body)

A2A 像找人:
task_id = research_agent.delegate({
goal: "调研 AI Agent Marketplace 现状",
deadline: "24 小时",
budget: "$10"
})

// 等结果
result = await get_task_result(task_id)

调函数和找人的差别:

  • 找人有目标,函数有参数
  • 找人有时间,函数瞬间
  • 找人有成本协商,函数固定
  • 找人会回问澄清,函数不会
  • 找人结果可能不达预期,函数确定

1.3 何时该 A2A 而不是 MCP

适合 A2A:

  • 任务复杂,需要 Agent 自主判断
  • 长期运行(小时-天)
  • 跨组织(你的 Agent 调别人的 Agent)
  • 能力是"完成一类任务",不是"执行一个动作"

适合 MCP:

  • 简单工具调用
  • 短期(毫秒-秒)
  • 同组织内部
  • 能力是"执行明确动作"

1.4 实际架构常组合

你的主 Agent
↓ MCP 调本地工具
本地 Tools

↓ A2A 委派子任务
其他 Agent(可能是别家的)
↓ MCP 调它们自己的工具
它们的 Tools

A2A 是"高层",MCP 是"底层"。


第二章:A2A 协议设计

Google 2025 年开源的 A2A 协议是当前最成熟的方案。

2.1 三个核心概念

1. Agent Card

Agent 的"名片"——告诉别人"我是谁、我能干什么":

{
"name": "research-agent",
"version": "1.0.0",
"description": "深度研究助手",
"url": "https://research.example.com/a2a",
"skills": [
{
"id": "deep-research",
"name": "深度研究",
"description": "对一个主题做多源调研",
"inputs": ["topic", "depth", "deadline"],
"outputs": ["report", "sources"]
}
],
"authentication": {
"schemes": ["oauth2", "apikey"]
},
"capabilities": {
"streaming": true,
"pushNotifications": true
}
}

发布在 well-known 路径:/.well-known/agent.json,让其他 Agent 能发现。

2. Task

A2A 的核心抽象——委派的任务有完整生命周期:

created → working → input_required(如需澄清) → completed | failed | canceled
{
"id": "task-abc123",
"status": {
"state": "working",
"message": "已搜索 12 个来源,正在综合"
},
"messages": [
{ "role": "user", "content": "调研 AI Agent Marketplace 现状" },
{ "role": "agent", "content": "需要时间范围吗?" },
{ "role": "user", "content": "最近 6 个月" }
],
"artifacts": [
{ "type": "document", "url": "..." }
]
}

3. Message

Task 内的对话单元。

{
"role": "user" | "agent",
"parts": [
{ "type": "text", "text": "..." },
{ "type": "file", "url": "..." },
{ "type": "data", "data": { ... } }
]
}

2.2 调用流程

2.3 与 MCP 的关键差异

机制MCPA2A
调用call_toolcreate_task
返回立即返回长期任务 ID
轮询不需要需要(或 webhook)
协商不支持支持(输入不够时 server 主动问)
流式单次响应流任务进度流

第三章:实现 A2A Server

3.1 暴露 Agent Card

import express from 'express';

const app = express();
app.use(express.json());

const agentCard = {
name: 'my-research-agent',
version: '1.0.0',
url: 'https://my-server.com/a2a',
skills: [
{
id: 'deep-research',
name: 'Deep Research',
description: 'Multi-source research with citations',
inputs: [
{ name: 'topic', required: true },
{ name: 'depth', required: false, default: 'medium' },
{ name: 'sources', required: false, default: ['web'] }
]
}
],
authentication: { schemes: ['apikey'] },
capabilities: { streaming: true, pushNotifications: true }
};

app.get('/.well-known/agent.json', (req, res) => {
res.json(agentCard);
});

3.2 创建任务

const tasks = new Map<string, Task>();

app.post('/tasks', async (req, res) => {
// 1. 认证
const apiKey = req.headers['x-api-key'];
if (!validApiKey(apiKey)) {
return res.status(401).json({ error: 'unauthorized' });
}

// 2. 创建任务
const task: Task = {
id: crypto.randomUUID(),
status: { state: 'created' },
messages: [{ role: 'user', parts: req.body.parts }],
artifacts: [],
createdAt: new Date(),
metadata: {
clientAgent: req.body.from,
skill: req.body.skill,
}
};

tasks.set(task.id, task);

// 3. 异步开始处理
processTaskAsync(task.id);

// 4. 立即返回任务 ID
res.json(task);
});

async function processTaskAsync(taskId: string) {
const task = tasks.get(taskId);
if (!task) return;

// 更新状态
task.status = { state: 'working' };

try {
// 实际工作(Agent Loop)
const result = await runResearchAgent(task);

// 完成
task.status = { state: 'completed' };
task.artifacts = result.artifacts;

// 通知 client(webhook)
if (task.metadata.webhookUrl) {
await notifyWebhook(task);
}
} catch (err) {
task.status = { state: 'failed', message: err.message };
}
}

3.3 任务查询

app.get('/tasks/:id', async (req, res) => {
const task = tasks.get(req.params.id);
if (!task) return res.status(404).json({ error: 'not_found' });

// 检查权限:只有创建者能查
if (!isAuthorized(req, task)) {
return res.status(403).json({ error: 'forbidden' });
}

res.json(task);
});

// 流式订阅(SSE)
app.get('/tasks/:id/stream', async (req, res) => {
const task = tasks.get(req.params.id);

res.setHeader('Content-Type', 'text/event-stream');

const sendUpdate = () => {
res.write(`data: ${JSON.stringify(task)}\n\n`);
};

// 监听任务变化
taskEmitter.on(`task:${task.id}`, sendUpdate);

req.on('close', () => {
taskEmitter.off(`task:${task.id}`, sendUpdate);
});
});

3.4 多轮对话(input_required)

Server 发现信息不够时,主动要更多输入:

async function runResearchAgent(task: Task) {
const initialMessage = task.messages[0];

// 检查信息完整性
if (!hasEnoughContext(initialMessage)) {
// 进入 input_required 状态
task.status = {
state: 'input_required',
message: '需要更多信息:研究的时间范围?地区?'
};

// 等 client 补充
await waitForUserInput(task.id);
}

// 继续工作
// ...
}

// Client 补充信息
app.post('/tasks/:id/messages', async (req, res) => {
const task = tasks.get(req.params.id);

if (task.status.state !== 'input_required') {
return res.status(400).json({ error: 'task_not_waiting_for_input' });
}

task.messages.push({
role: 'user',
parts: req.body.parts
});

// 触发 Server 继续
taskEmitter.emit(`task:${task.id}:input`, req.body);

res.json(task);
});

第四章:实现 A2A Client

4.1 发现 + 调用

class A2AClient {
async discover(agentUrl: string): Promise<AgentCard> {
const wellKnown = `${agentUrl}/.well-known/agent.json`;
const response = await fetch(wellKnown);
return await response.json();
}

async createTask(
agentUrl: string,
skill: string,
parts: MessagePart[]
): Promise<Task> {
const response = await fetch(`${agentUrl}/tasks`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': this.apiKey
},
body: JSON.stringify({
skill,
parts,
from: this.myAgentId,
})
});

return await response.json();
}

async waitForCompletion(
agentUrl: string,
taskId: string,
options: { onProgress?: (task: Task) => void; timeout?: number } = {}
): Promise<Task> {
// 用 SSE 流式订阅
const eventSource = new EventSource(`${agentUrl}/tasks/${taskId}/stream`);

return new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
eventSource.close();
reject(new Error('timeout'));
}, options.timeout ?? 24 * 3600 * 1000);

eventSource.onmessage = (e) => {
const task: Task = JSON.parse(e.data);
options.onProgress?.(task);

if (task.status.state === 'completed') {
clearTimeout(timeout);
eventSource.close();
resolve(task);
}

if (task.status.state === 'input_required') {
// 处理需要补充输入
this.handleInputRequired(agentUrl, task);
}

if (task.status.state === 'failed') {
clearTimeout(timeout);
eventSource.close();
reject(new Error(task.status.message));
}
};
});
}

async sendInput(agentUrl: string, taskId: string, parts: MessagePart[]) {
return await fetch(`${agentUrl}/tasks/${taskId}/messages`, {
method: 'POST',
headers: { /* ... */ },
body: JSON.stringify({ parts })
});
}
}

4.2 你的 Agent 用 A2A

// 例:你的主 Agent 调用研究 Agent
class MainAgent {
private a2a = new A2AClient();

async handleUserRequest(request: string) {
if (await this.needsResearch(request)) {
// 调用研究 Agent
const card = await this.a2a.discover('https://research.example.com');

const task = await this.a2a.createTask(
card.url,
'deep-research',
[{ type: 'text', text: request }]
);

// 用户实时看到进度
const result = await this.a2a.waitForCompletion(card.url, task.id, {
onProgress: (task) => {
this.showProgressToUser(task.status.message);
}
});

return this.synthesize(result.artifacts);
}

// 否则直接处理
return await this.localProcess(request);
}
}

第五章:Agent 发现机制

5.1 静态发现

最简单:你已经知道目标 Agent 的 URL。

const knownAgents = {
research: 'https://research.example.com',
finance: 'https://finance.company.com',
scheduling: 'https://schedule.example.com',
};

适合:

  • 内部 Agent
  • 数量少
  • 你掌控

5.2 注册表发现

像 npm registry:

// 集中注册表
const registry = await fetch('https://a2a-registry.org/agents?capability=research');

// 返回
[
{ url: 'https://research-agent-1.com', rating: 4.5, price: '...' },
{ url: 'https://research-agent-2.com', rating: 4.2, price: '...' },
...
]

// 选一个
const chosen = pickBest(results);
const card = await a2a.discover(chosen.url);

适合:

  • Agent Marketplace
  • 公开 Agent 生态

5.3 联邦发现(Federation)

类似 ActivityPub。每个 Agent 知道几个"邻居",递归发现:

async function discover(capability: string, depth = 3) {
const visited = new Set();
const queue = [...this.knownPeers];

while (queue.length > 0 && depth > 0) {
const peer = queue.shift();
if (visited.has(peer)) continue;
visited.add(peer);

const card = await a2a.discover(peer);

if (cardMatches(card, capability)) {
return card;
}

// 问邻居"你认识谁会做 X"
const recommendations = await a2a.askForReferral(peer, capability);
queue.push(...recommendations);

depth--;
}
}

适合:

  • 去中心化生态
  • 隐私(不依赖中心注册表)

5.4 现实的中间方案

2026 年大多数 A2A 用混合:

应用层硬编码已知 Agent(你信任的)
+
Agent Marketplace(找新的)
+
未来:联邦发现(实验中)

第六章:能力协商

不同 Agent 能力不同。客户端怎么知道某个 Agent 真的能做你要的事?

6.1 Skill 描述

Agent Card 里的 skill 应该详细:

{
"skills": [
{
"id": "deep-research",
"name": "Deep Research",
"description": "Multi-source web research with citations",

"inputs": {
"topic": { "type": "string", "required": true, "max_length": 500 },
"depth": {
"type": "enum",
"values": ["quick", "medium", "thorough"],
"default": "medium"
},
"sources": {
"type": "array",
"items": { "enum": ["web", "academic", "news"] }
}
},

"outputs": {
"report": { "type": "markdown" },
"sources": { "type": "array", "items": { "type": "url" } }
},

"constraints": {
"max_duration": "PT24H", // ISO 8601: 24小时
"max_sources": 50
},

"pricing": {
"type": "per_task",
"amount": 5.00,
"currency": "USD"
},

"examples": [
{
"input": { "topic": "AI Agent Marketplace 2025", "depth": "thorough" },
"output_preview": "..."
}
]
}
]
}

6.2 协商场景

场景 1:能力不够

Client 请求:研究 50 个来源
Server Agent Card 说:max_sources: 30
→ Client 知道协商:要么减少要求,要么找别的 Agent

场景 2:需要确认

Client:分析这个文档
Server:我支持但需要授权读你的私有 GitHub
→ Client 决定是否授权

场景 3:成本协商

Client:做一个市场调研
Server:根据深度收费 $1-$50
→ Client 选预算

6.3 实现协商

class A2AClient {
async negotiateAndStart(
agentUrl: string,
skill: string,
request: any
) {
const card = await this.discover(agentUrl);

// 检查能力
const skillCard = card.skills.find(s => s.id === skill);
if (!skillCard) throw new Error('skill_not_supported');

// 验证输入
const violations = validateAgainstSchema(request, skillCard.inputs);
if (violations.length > 0) {
// 协商:要么降级要求
throw new NegotiationError(violations);
}

// 检查成本
if (skillCard.pricing.amount > this.budget) {
throw new BudgetExceeded();
}

// OK,正式发起
return await this.createTask(agentUrl, skill, request);
}
}

第七章:Agent Marketplace

类似 MCP Marketplace 但是 Agent 级别。

7.1 现状(2026)

主流方案:

  • Google A2A Directory(Google 主导)
  • Hugging Face Agent Hub
  • 第三方目录(类似 Smithery 之于 MCP)

7.2 评估第三方 Agent

跟评估 MCP 一样小心:

维度检查
来源知名公司 / 开源项目 / 个人
评分用户反馈
安全审查是否有合规认证
数据处理你的数据会被它怎么用
SLA可用性、响应时间承诺
定价透明、可预测

⚠️ 风险:你委派任务给一个 Agent,它可能:

  • 看你的数据
  • 调用别的服务(你不知道)
  • 泄露你的信息
  • 给错误结果

参考 04 Lethal Trifecta:调用外部 Agent 等于把"私有数据"交给"不可信内容"+ "外部通信"。完整 Trifecta

7.3 企业内部 A2A 网关

企业级方案:所有 A2A 调用通过内部网关:

你的 Agent → 内部 A2A Gateway → 外部 Agent

Gateway 做:
- 数据脱敏
- 调用审计
- 成本控制
- 安全策略
- 故障重试

类似 17 Multi-Model Routing 的 LLM Gateway,但是 Agent 级别。


第八章:安全与隐私

A2A 是 04 Lethal Trifecta 的极端场景。

8.1 委派 = 信任

调用别人的 Agent 等于:

  • 把你的需求告诉它(信息)
  • 让它访问它的工具(行动)
  • 等它给你结果(信任)

每个环节都是信任 chain。

8.2 信息泄露

你调用研究 Agent 时:
- 你的研究主题暴露
- 你的研究方向反映商业意图
- 你提供的数据被它看到

→ 谁能保证它不存?
→ 它的提供者不会用来训练?
→ 不会卖给竞品?

防御:

  • 不传敏感数据(研究主题脱敏)
  • 签 DPA(Data Processing Agreement)
  • 只用可信 Agent

8.3 行动滥用

你委派 Agent 做"分析这份文档":
- Agent 可能调用搜索(合理)
- Agent 可能调用邮件(?)
- Agent 可能调用任何它的工具

→ 你怎么限制它"只能做你要的事"?

A2A 协议里 client 不直接控制 server 的工具。Server 自己决定怎么完成任务。

防御:

  • 选成熟的 Agent(有 SLA、有审计)
  • Sandbox 提供的数据(什么都不给除了任务描述)
  • 监控不寻常的成本/时长

8.4 凭证与认证

// API Key 简单但风险高
const apiKey = 'sk-xxx'; // 泄露 = 灾难

// OAuth 2.1 + scope
const token = await oauth.getToken({
scopes: ['research:read', 'research:create_task'],
// 不给 'admin:*'
});

参考 13 MCP 的 OAuth 章。A2A 也用同样规范。

8.5 跨 Agent 的攻击传染

危险场景:

你的 Agent A 调用别人的 Agent B
B 已被 prompt injection
B 返回的结果含有恶意指令
A 看到 B 的结果,被注入
A 干坏事

防御:

  • 把外部 Agent 的输出当作"不可信内容"(参考 01 Context Engineering)
  • 用 XML 标签隔离
  • 不让外部 Agent 的输出直接触发你的工具调用

第九章:实战例子

9.1 案例:客服 + 财务 Agent 协作

// 用户:"给我开张发票"
// 客服 Agent 识别后委派给财务 Agent

class CustomerServiceAgent {
async handleInvoiceRequest(user: User, orderId: string) {
// 用 A2A 调用财务 Agent
const financeAgentUrl = 'https://finance.internal.company.com';

const task = await this.a2a.createTask(financeAgentUrl, 'create-invoice', [
{ type: 'data', data: { orderId, userId: user.id } }
]);

const result = await this.a2a.waitForCompletion(financeAgentUrl, task.id, {
onProgress: (t) => this.notifyUser(`财务系统:${t.status.message}`)
});

return result.artifacts.find(a => a.type === 'invoice_pdf');
}
}

9.2 案例:研究 Agent 的多 Agent 编排

复杂研究任务,主 Agent 协调多个子 Agent:

class ResearchOrchestrator {
async deepResearch(topic: string) {
// 1. 委派"网络调研"
const webTask = await this.a2a.createTask(
'https://web-research.example.com',
'web-search',
[{ type: 'text', text: topic }]
);

// 2. 同时委派"学术调研"
const academicTask = await this.a2a.createTask(
'https://academic.example.com',
'paper-search',
[{ type: 'text', text: topic }]
);

// 3. 同时委派"专家访谈"(可能要排队几小时)
const expertTask = await this.a2a.createTask(
'https://expert-network.example.com',
'find-and-interview-expert',
[{ type: 'text', text: topic }]
);

// 4. 等所有完成
const [web, academic, expert] = await Promise.all([
this.a2a.waitForCompletion(/* ... */),
this.a2a.waitForCompletion(/* ... */),
this.a2a.waitForCompletion(/* ... */),
]);

// 5. 综合
return await this.synthesize([web, academic, expert]);
}
}

每个子 Agent 是独立的服务、独立的团队维护、独立的扩缩。

9.3 案例:用户的个人助理调用商业 Agent

// 用户:帮我订张去东京的便宜机票

class PersonalAssistantAgent {
async bookFlight(request: string) {
// 1. 解析需求
const intent = await this.parseFlight(request);

// 2. 调用比价 Agent(A2A)
const compareAgentUrl = 'https://flight-compare.example.com';
const compareTask = await this.a2a.createTask(
compareAgentUrl,
'compare-flights',
[{ type: 'data', data: intent }]
);
const options = await this.a2a.waitForCompletion(/* ... */);

// 3. 给用户选
const chosen = await this.askUser(options);

// 4. 调用预订 Agent(不同的)
const bookingAgentUrl = 'https://booking.example.com';
const bookingTask = await this.a2a.createTask(
bookingAgentUrl,
'book-flight',
[{ type: 'data', data: chosen }]
);

// 但这一步要用户授权(涉及付款)
return await this.a2a.waitForCompletion(/* ... */);
}
}

注意:跨 Agent 调用涉及钱时,必须用户每步确认。


第十章:A2A vs 多 Agent 框架

10.1 框架(LangGraph、AutoGen 等)

5-6 第三章讲的多 Agent 框架(Supervisor-Worker 等):

特点:

  • 同一进程 / 同一团队
  • 共享内存、共享状态
  • 程序员控制全部
  • 紧耦合

10.2 A2A 协议

特点:

  • 跨进程 / 跨组织
  • 网络通信
  • 各自维护
  • 松耦合

10.3 选型

场景用框架用 A2A
同团队多个 Agent✅ 简单浪费
跨团队调用不能
跨公司调用不能
需要严格状态共享困难
高频小调用网络开销
偶尔大任务浪费内存

可以共用:内部用框架,对外用 A2A。


第十一章:未来方向

11.1 协议成熟化

A2A 2025 才公开,2026 年仍在演进。预期:

  • ISO/W3C 讨论标准化
  • 跨厂商互操作测试
  • 社区的最佳实践沉淀

11.2 Agent 信誉系统

类似 npm 的 weekly downloads + GitHub stars:

  • Agent 评分机制
  • 历史可靠性数据
  • 用户评论

让选 Agent 像选 npm 包。

11.3 经济层

A2A 自然带出Agent 经济

Agent A 调用 Agent B → 付钱
Agent B 自己用 Agent C → 也付钱
形成调用链

需要:

  • 微支付
  • 自动化合约(智能合约?)
  • 防止套娃式高成本

11.4 Agent Identity

Agent 的"身份":

  • 谁创建的
  • 哪些数据训练
  • 经过什么审核
  • 历史行为

类似 SSL 证书之于网站。


第十二章:行动建议

A2A 还相对早期,建议:

起步

  • 内部多 Agent 用 5-6 章的框架(LangGraph 等)
  • 不急着用 A2A

观望

  • 关注 Google A2A 进展
  • 关注 Anthropic Multi-Agent System
  • 看竞争对手是否在用

采用

  • 真有跨组织 Agent 调用需求时
  • 内部多团队,接口稳定后

警惕

  • 不要过度工程(小团队不需要 A2A)
  • 不要轻信第三方 Agent(参考 04 Trifecta)

权威资料

核对日期:2026-06-12