"MCP 解决了 Agent 和工具之间的通信,但 Agent 和 Agent 之间呢?"


一个真实的问题

你用 Claude 写了一个财务分析 Agent,同事用 Gemini 写了一个数据采集 Agent。财务分析 Agent 需要数据采集 Agent 提供最新的市场数据。

怎么对接?

最直觉的做法:开一个 REST API,财务 Agent 调采集 Agent 的接口。但问题来了——

  1. 接口要自己定义:你俩得坐下来商量请求/响应格式,写一份接口文档

  2. 状态要自己管:数据采集是个长任务(可能要跑 5 分钟),你得自己实现轮询或回调

  3. 能力发现要自己做:财务 Agent 怎么知道采集 Agent 能做什么?硬编码?

  4. 换一个 Agent 要重来:明天采集 Agent 从 Gemini 换成 Llama,所有对接代码全改

这就是 2024 年多 Agent 系统的现状:每一对 Agent 之间的对接,都是一次定制开发。

如果你的系统里有 5 个 Agent,两两互通需要 C(5,2) = 10 条定制管道。有 20 个 Agent 呢?190 条。这个 N² 爆炸问题,和微服务早期没有 gRPC / OpenAPI 时一模一样。


A2A 是什么:一句话版本

A2A(Agent-to-Agent Protocol)是 Agent 之间的 HTTP——一个标准化的通信协议,让任何框架、任何模型构建的 Agent 都能互相发现、互相委托任务、互相交换结果。

据 Linux Foundation 2026 年 4 月公告,A2A 发布一年内已有 150+ 组织支持,包括 Google、Microsoft、AWS、Salesforce、SAP、ServiceNow、IBM 等,Google ADK、LangGraph、CrewAI、LlamaIndex、Semantic Kernel 均已原生集成。

它的时间线:

时间

事件

2025 年 4 月

Google 发布 A2A 协议

2025 年 6 月

捐献给 Linux Foundation,成为厂商中立标准

2026 年初

v1.0 正式发布,进入生产可用阶段

2026 年 3 月

v1.2 发布,新增签名 Agent Card、公开 RFC 流程

2026 年 4 月

150+ 组织支持,多个行业进入生产部署


先搞清楚:A2A 和 MCP 不是竞争关系

这是最常被问的问题,答案很简单——它们在不同的层

ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line┌──────────────────────────────────────────┐│           多 Agent 系统                   ││                                          ││   Agent A ◄──── A2A ────► Agent B        │  ← Agent 之间:用 A2A│     │                       │            ││    MCP                     MCP           │  ← Agent 到工具:用 MCP│     │                       │            ││   数据库    API    文件    搜索引擎        │└──────────────────────────────────────────┘

维度

MCP

A2A

解决什么

Agent 怎么调工具

Agent 怎么委托另一个 Agent

类比

USB 接口(连接外设)

HTTP 协议(服务之间通信)

交互模式

无状态请求/响应

有状态长任务(submitted → working → completed)

是否知道对方

MCP Server 对 Agent 透明

Agent 有自己的"想法",是黑盒

规范维护

Anthropic

Linux Foundation

一句话:MCP 让 Agent 有工具可用,A2A 让 Agent 有同事可用。 生产系统两个都需要。

据 Augment Code 2026 年分析,2026 年的主流多 Agent 架构已经形成 MCP + A2A 双层模型:单 Agent 用 MCP 访问工具和数据,多 Agent 协作用 A2A 做任务委托和结果交换。


A2A 的三个核心概念

1. Agent Card:Agent 的"简历"

每个支持 A2A 的 Agent 都在 /.well-known/agent-card.json 发布一份 JSON 描述符(据 A2A 官方规范 v1.2),告诉世界"我是谁、我能做什么、怎么跟我说话"。

ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line{  "name": "market-data-collector",  "description": "实时采集全球主要交易所的市场数据",  "version": "2.1.0",  "url": "https://agents.example.com/market-data",  "capabilities": {    "streaming": true,    "pushNotifications": true  },  "skills": [    {      "id": "fetch-realtime-quotes",      "name": "实时行情采集",      "description": "获取指定交易对的最新价格、成交量、深度",      "inputModes": ["text"],      "outputModes": ["text", "application/json"]    },    {      "id": "historical-klines",      "name": "历史K线数据",      "description": "获取指定时间范围的OHLCV K线数据",      "inputModes": ["text"],      "outputModes": ["application/json"]    }  ],  "authentication": {    "schemes": ["Bearer"]  }}

这和微服务的 OpenAPI Spec 是一个思路——先发现,再调用。客户端 Agent 读取 Agent Card 后,就知道对方有哪些 skill、接受什么输入格式、返回什么输出。不需要任何硬编码。

一个常见问题:Client Agent 怎么知道去哪里找 Agent Card?

A2A 规范本身只定义了路径格式(/.well-known/agent-card.json),不规定你如何初次发现对方的域名——这和 HTTP 不规定"你怎么知道服务器 IP"是同一个设计哲学。据 A2A 官方 Agent Discovery 文档,有三种实际做法:

发现方式

机制

适用场景

Well-Known URI

已知对方域名,直接 GET https://domain/.well-known/agent-card.json

公开部署、有独立域名的 Agent

注册表(Registry)

Agent 启动时把自己的 Card 注册到中心注册表,调用方按 skill 查询

内部系统有几十个 Agent,需要动态发现

直接配置

把 Agent Card URL 写进环境变量 / 配置文件

开发调试、已知合作方、数量少

注意:A2A 规范没有标准化 Registry API,注册表的查询接口由各平台自己定义。目前有社区项目在做(如 a2a-registry.dev),尚未成为标准的一部分。

实际工程中最常见的路径是:开发期用直接配置,生产系统 Agent 多了再引入 Registry

2. Task:有状态的工作单元

A2A 里的核心交互单元是 Task,不是简单的 request/response。因为 Agent 之间的工作往往是长时间的——数据采集要跑 5 分钟,代码审查要跑 3 分钟,你不能干等着。

Task 有一个标准状态机(据 A2A 规范):

ounter(lineounter(lineounter(lineounter(lineounter(linesubmitted → working → completed                   → failed                   → canceled            ↕       input-required    ← Agent 需要更多信息时回到这个状态

这个设计很关键:input-required 状态让 Agent 之间可以"对话",而不只是单向发指令。比如数据采集 Agent 发现你要的交易对不存在,它可以把任务设为 input-required,附上"请确认交易对名称"的消息。调用方看到后补充信息,任务继续执行。

3. JSON-RPC 2.0:传输层

A2A 在传输层选择了 HTTP + JSON-RPC 2.0。这个选择很务实——几乎所有语言和平台都支持 HTTP 和 JSON,没有额外的依赖。

三种交互方式:

方式

方法

适用场景

同步 message/send

快速任务(< 30s)

流式 message/stream

需要实时进度反馈

推送

Push Notification

超长任务,客户端不想保持连接


跑一个完整的例子

下面用 Python 实现一个最小的 A2A 交互:一个"翻译 Agent"作为 A2A Server,一个"调用方"作为 A2A Client。

ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line"""A2A 协议最小完整示例
演示 Agent Card 发布 → Agent 发现 → Task 发送 → 结果接收的完整流程。
运行前提:  pip install a2a-python uvicorn httpx"""import asyncioimport jsonimport httpxfrom dataclasses import dataclass, field, asdictfrom typing import Optional

# ============================================================# 第一部分:A2A Server(翻译 Agent)# ============================================================
AGENT_CARD = {    "name": "translator-agent",    "description": "将任意文本翻译为目标语言",    "version": "1.0.0",    "url": "http://localhost:8000",    "capabilities": {"streaming": False, "pushNotifications": False},    "skills": [        {            "id": "translate",            "name": "文本翻译",            "description": "将输入文本翻译为指定的目标语言",            "inputModes": ["text"],            "outputModes": ["text"],        }    ],}

@dataclassclass Task:    id: str    status: str = "submitted"    artifacts: list = field(default_factory=list)    messages: list = field(default_factory=list)

tasks: dict[str, Task] = {}

def handle_jsonrpc(request: dict) -> dict:    """处理 JSON-RPC 2.0 请求"""    method = request.get("method")    params = request.get("params", {})    req_id = request.get("id")
    if method == "message/send":        task_id = params.get("message", {}).get("taskId", f"task-{len(tasks)+1}")        user_text = ""        for part in params.get("message", {}).get("parts", []):            if part.get("kind") == "text":                user_text = part["text"]
        task = Task(id=task_id, status="working")        tasks[task_id] = task
        # 模拟翻译(生产环境调用 LLM)        translated = f"[Translated] {user_text}"
        task.status = "completed"        task.artifacts = [            {"parts": [{"kind": "text", "text": translated}]}        ]
        return {            "jsonrpc": "2.0",            "id": req_id,            "result": asdict(task),        }
    return {        "jsonrpc": "2.0",        "id": req_id,        "error": {"code": -32601, "message": f"Method not found: {method}"},    }

# ============================================================# 第二部分:A2A Client(调用方)# ============================================================
async def discover_agent(base_url: str) -> dict:    """第一步:读取 Agent Card,了解对方能做什么"""    async with httpx.AsyncClient() as client:        resp = await client.get(f"{base_url}/.well-known/agent-card.json")        return resp.json()

async def send_task(base_url: str, text: str) -> dict:    """第二步:发送 JSON-RPC 请求,委托翻译任务"""    payload = {        "jsonrpc": "2.0",        "id": 1,        "method": "message/send",        "params": {            "message": {                "role": "user",                "parts": [{"kind": "text", "text": text}],            }        },    }    async with httpx.AsyncClient() as client:        resp = await client.post(base_url, json=payload)        return resp.json()

async def demo_client():    """完整客户端流程:发现 → 委托 → 获取结果"""    base_url = "http://localhost:8000"
    # Step 1: 发现    card = await discover_agent(base_url)    print(f"发现 Agent: {card['name']}")    print(f"  技能: {[s['name'] for s in card['skills']]}")
    # Step 2: 委托任务    result = await send_task(base_url, "今天天气真好,适合写代码")    task = result.get("result", {})    print(f"  任务状态: {task['status']}")    print(f"  翻译结果: {task['artifacts'][0]['parts'][0]['text']}")

# ============================================================# 第三部分:用 uvicorn 启动 Server(简易版)# ============================================================
if __name__ == "__main__":    import uvicorn    from starlette.applications import Starlette    from starlette.requests import Request    from starlette.responses import JSONResponse    from starlette.routing import Route
    async def agent_card_endpoint(request: Request):        return JSONResponse(AGENT_CARD)
    async def jsonrpc_endpoint(request: Request):        body = await request.json()        return JSONResponse(handle_jsonrpc(body))
    app = Starlette(routes=[        Route("/.well-known/agent-card.json", agent_card_endpoint),        Route("/", jsonrpc_endpoint, methods=["POST"]),    ])
    print("A2A Server 启动: http://localhost:8000")    print("Agent Card: http://localhost:8000/.well-known/agent-card.json")    print("\n另开终端运行客户端: python -c 'import asyncio; from a2a_demo import demo_client; asyncio.run(demo_client())'")    uvicorn.run(app, host="0.0.0.0", port=8000)

运行后你会看到:

ounter(lineounter(lineounter(lineounter(line发现 Agent: translator-agent  技能: ['文本翻译']  任务状态: completed  翻译结果: [Translated] 今天天气真好,适合写代码

整个流程的关键点:Client 不需要知道 Server 内部用的是什么模型、什么框架。它只需要读 Agent Card、发 JSON-RPC 请求、等 Task 完成。明天 Server 从 Claude 换成 Gemini,Client 代码一行不用改。


生产环境的四个工程要点

1. 签名 Agent Card:防止冒充

v1.2 引入了签名 Agent Card(据 A2A 规范 v1.2),用加密签名做域名验证。生产环境必须启用——否则任何人都可以伪造一个 Agent Card,声称自己是你的"财务分析 Agent"。

2. Task 超时和重试

Agent 任务不像 API 调用那样快速返回。数据采集可能要跑 10 分钟,代码审查可能要跑 5 分钟。你需要:

  • 设定合理的超时阈值(建议按 skill 粒度配置)

  • 用 task/get 轮询状态,或用 message/stream 获取实时进度

  • 处理 failed 状态的重试逻辑

3. 认证和授权

Agent Card 的 authentication 字段声明了支持的认证方式。生产环境至少用 Bearer Token,企业内网可以用 mTLS。关键原则:Agent 之间的信任不应该比微服务之间更低。

4. 多 Agent 编排

当系统有超过 3 个 Agent 时,建议引入一个编排 Agent(Orchestrator),负责:

  • 维护所有 Agent Card 的注册表

  • 根据任务描述匹配最合适的 Agent

  • 管理 Task 的依赖关系和执行顺序

  • 处理失败 Agent 的降级策略

这和微服务架构里的 API Gateway / Service Mesh 是同一个思路。


哪些场景该用 A2A,哪些不该

场景

用 A2A?

理由

两个不同团队的 Agent 需要协作

跨团队 = 接口标准化 = A2A 的核心价值

一个 Agent 调外部搜索引擎

不用,用 MCP

搜索引擎是工具,不是 Agent

Agent 需要长时间执行并报告进度

Task 状态机 + 流式反馈

同一个进程内的两个 Agent 函数

不用

直接函数调用,加协议只是增加延迟

跨公司的 Agent 互操作

A2A 是厂商中立标准,双方不需要用同一框架

Agent 读写数据库

不用,用 MCP

数据库是资源,不是自主决策的 Agent

判断标准很简单:对方有没有自己的"想法"? 有自己的推理能力、能自主决策的用 A2A;只是被动执行指令的用 MCP。


工程结论

  1. A2A 解决了多 Agent 系统的 N² 互联问题——标准协议让 N 个 Agent 只需要 N 次适配,而不是 N(N-1)/2 次定制对接。这和 HTTP 之于 Web、gRPC 之于微服务的意义完全一样。

  2. A2A 和 MCP 是互补关系,不是替代关系——MCP 是 Agent 到工具的"USB 接口",A2A 是 Agent 到 Agent 的"HTTP 协议"。2026 年的主流多 Agent 架构已经形成 MCP + A2A 双层标准模型。

  3. 协议已经生产可用——据 Linux Foundation 2026 年 4 月数据,150+ 组织支持 A2A,Google ADK、LangGraph、CrewAI 等主流框架均已原生集成,金融、供应链、IT 运维等行业已有生产部署案例。v1.2 引入的签名 Agent Card 解决了生产环境的身份验证问题。

  4. 现在就该学——A2A 的核心概念只有三个(Agent Card、Task、JSON-RPC),比学 Kubernetes 简单一个数量级。等你需要跨团队、跨公司的 Agent 协作时再学,就晚了。



——新书推荐——

Golang并发编程之美

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐