A2A 多智能体协作指南(Google Agent2Agent 协议)

3 阅读5分钟

适用版本:A2A Protocol v0.2+(2025 年 Google 与合作伙伴联合发布的开放标准)

目录


一、A2A 协议概述

A2A(Agent2Agent) 是 Google 联合 50+ 合作伙伴(Salesforce、SAP、Atlassian、LangChain、MongoDB 等)于 2025 年发布的开放协议,目标是让异构 AI 智能体之间能跨厂商、跨框架、跨语言互相通信与协作。

1.1 解决的问题

痛点A2A 的方案
不同厂商 agent 各自封闭统一 HTTP + JSON-RPC 通信契约
无法发现对方能力标准化 Agent Card
长任务无法跟踪Task 生命周期 + 流式更新
异步协作无统一规范SSE / Webhook 推送机制
多模态难以传递Parts(text / file / data)抽象

1.2 与 MCP 的边界

  • MCP(Model Context Protocol):解决"模型 ↔ 工具/数据源"的连接,是 agent 内部 的工具协议
  • A2A:解决"agent ↔ agent"的协作,是 agent 之间 的通信协议

二者互补不冲突,生产系统中常一起使用。


二、核心概念

┌─────────────┐  Agent Card  ┌─────────────┐
│   Client    │ ───────────> │   Server    │
│   Agent     │   (发现)     │   Agent     │
│             │              │             │
│             │  Task / Msg  │             │
│             │ <──────────> │             │
└─────────────┘  (协作)      └─────────────┘

2.1 关键实体

实体说明
Agent Card智能体的"名片",描述能力、端点、认证方式
Task一次有状态的协作任务,有完整生命周期
MessageTask 内的一次发言(用户/agent)
PartMessage 的最小单元(文本/文件/结构化数据)
ArtifactTask 产出的成果物
SkillAgent 声明的某项能力

2.2 任务状态机

submitted → working → input-required ──┐
              │                         │
              ├──> completed            │
              ├──> failed               │
              ├──> canceled             │
              └──> rejected     <───────┘

三、协议规范

A2A 基于 HTTP(S) + JSON-RPC 2.0,主流方法集:

方法作用
message/send同步发送消息并等待响应
message/stream流式发送(SSE 返回)
tasks/get查询任务状态
tasks/cancel取消任务
tasks/pushNotificationConfig/set配置 webhook 推送
tasks/resubscribe断线后重新订阅流

3.1 请求示例

POST /a2a HTTP/1.1
Host: agent.example.com
Authorization: Bearer <token>
Content-Type: application/json

{
  "jsonrpc": "2.0",
  "id": "req-1",
  "method": "message/send",
  "params": {
    "message": {
      "role": "user",
      "parts": [
        { "kind": "text", "text": "帮我分析这份销售数据" }
      ],
      "messageId": "msg-001"
    }
  }
}

3.2 响应示例

{
  "jsonrpc": "2.0",
  "id": "req-1",
  "result": {
    "id": "task-abc",
    "status": { "state": "completed" },
    "artifacts": [
      {
        "artifactId": "art-1",
        "parts": [
          { "kind": "text", "text": "Q3 销售额同比增长 23%..." }
        ]
      }
    ]
  }
}

四、Agent Card

每个 A2A Agent 必须暴露一份 Agent Card,默认地址:

https://<host>/.well-known/agent.json

4.1 完整 Agent Card 示例

{
  "name": "Sales Analyst Agent",
  "description": "分析销售数据并生成洞察报告",
  "url": "https://sales-agent.example.com/a2a",
  "version": "1.2.0",
  "protocolVersion": "0.2.5",
  "provider": {
    "organization": "Example Corp",
    "url": "https://example.com"
  },
  "capabilities": {
    "streaming": true,
    "pushNotifications": true,
    "stateTransitionHistory": true
  },
  "defaultInputModes":  ["text/plain", "application/json"],
  "defaultOutputModes": ["text/plain", "application/json", "image/png"],
  "skills": [
    {
      "id": "analyze-sales",
      "name": "销售数据分析",
      "description": "对 CSV/Excel 销售数据做趋势分析",
      "tags": ["analysis", "sales"],
      "examples": [
        "分析 2024 年 Q4 的销售趋势",
        "对比东西区销售业绩"
      ],
      "inputModes":  ["application/json", "text/csv"],
      "outputModes": ["text/markdown", "image/png"]
    }
  ],
  "securitySchemes": {
    "bearer": { "type": "http", "scheme": "bearer" }
  },
  "security": [{ "bearer": [] }]
}

4.2 关键字段

  • capabilities.streaming:是否支持 message/stream
  • capabilities.pushNotifications:是否支持 webhook 推送
  • skills:能力清单,用于 client agent 选择路由
  • securitySchemes:复用 OpenAPI 3.0 的安全方案定义

五、消息与任务流

5.1 Message 与 Part

type Part =
  | { kind: "text"; text: string }
  | { kind: "file"; file: { name: string; mimeType: string; bytes?: string; uri?: string } }
  | { kind: "data"; data: Record<string, unknown> };

interface Message {
  role: "user" | "agent";
  parts: Part[];
  messageId: string;
  taskId?: string;
  contextId?: string;
}

5.2 Task 生命周期

1. client 发送 message/send,server 创建 Task(state=submitted)
2. server 进入 working,可多次推送 status-update
3. 若需补充信息 → input-required,等待 client 再次 send
4. 完成 → completed,附带 artifacts

5.3 状态更新事件

{
  "kind": "status-update",
  "taskId": "task-abc",
  "status": {
    "state": "working",
    "message": {
      "role": "agent",
      "parts": [{ "kind": "text", "text": "正在加载数据..." }]
    },
    "timestamp": "2026-05-09T10:23:45Z"
  },
  "final": false
}

六、Python SDK 实战

官方 SDK:a2a-sdk(基于 FastAPI/httpx)

pip install a2a-sdk uvicorn

6.1 服务端:实现一个 Agent

from a2a.server import A2AServer, AgentExecutor
from a2a.types import AgentCard, Skill, Task, Message, TextPart, TaskStatus, TaskState
from a2a.server.events import EventQueue

class SalesAnalystExecutor(AgentExecutor):
    async def execute(self, context, event_queue: EventQueue):
        task = context.current_task
        user_text = context.get_user_input()

        await event_queue.enqueue_event(
            TaskStatus(state=TaskState.working,
                       message=Message(role="agent",
                                       parts=[TextPart(text="正在分析...")]))
        )

        result = await self._analyze(user_text)

        await event_queue.enqueue_event(
            TaskStatus(state=TaskState.completed,
                       message=Message(role="agent",
                                       parts=[TextPart(text=result)]))
        )

    async def cancel(self, context, event_queue):
        await event_queue.enqueue_event(
            TaskStatus(state=TaskState.canceled)
        )

    async def _analyze(self, text: str) -> str:
        return f"分析完成:{text} 的销售额同比增长 23%"


agent_card = AgentCard(
    name="Sales Analyst",
    description="销售数据分析智能体",
    url="https://sales-agent.example.com/a2a",
    version="1.0.0",
    protocolVersion="0.2.5",
    capabilities={"streaming": True, "pushNotifications": True},
    defaultInputModes=["text/plain"],
    defaultOutputModes=["text/plain", "text/markdown"],
    skills=[Skill(
        id="analyze-sales",
        name="销售数据分析",
        description="销售趋势分析",
        tags=["sales", "analysis"],
    )],
)

server = A2AServer(
    agent_card=agent_card,
    executor=SalesAnalystExecutor(),
)

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(server.app, host="0.0.0.0", port=8000)

6.2 客户端:调用其他 Agent

from a2a.client import A2AClient
from a2a.types import Message, TextPart
import asyncio

async def main():
    client = await A2AClient.from_agent_card_url(
        "https://sales-agent.example.com/.well-known/agent.json",
        auth_token="your-bearer-token",
    )

    response = await client.send_message(Message(
        role="user",
        parts=[TextPart(text="分析 Q3 销售数据")],
        messageId="msg-001",
    ))

    for artifact in response.artifacts or []:
        for part in artifact.parts:
            if part.kind == "text":
                print(part.text)

asyncio.run(main())

6.3 流式订阅

async def stream_demo():
    client = await A2AClient.from_agent_card_url(...)
    async for event in client.send_message_streaming(message):
        if event.kind == "status-update":
            print(f"[{event.status.state}]", event.status.message)
        elif event.kind == "artifact-update":
            print("产出:", event.artifact)
        if getattr(event, "final", False):
            break

七、TypeScript SDK 实战

官方 SDK:@a2a-js/sdk

npm i @a2a-js/sdk @a2a-js/sdk-server express

7.1 服务端

import express from "express";
import {
  A2AExpressApp,
  DefaultRequestHandler,
  AgentExecutor,
  ExecutionEventBus,
} from "@a2a-js/sdk-server";
import type { AgentCard, RequestContext } from "@a2a-js/sdk";

const agentCard: AgentCard = {
  name: "Translator Agent",
  description: "多语种翻译智能体",
  url: "https://translator.example.com/a2a",
  version: "1.0.0",
  protocolVersion: "0.2.5",
  capabilities: { streaming: true },
  defaultInputModes: ["text/plain"],
  defaultOutputModes: ["text/plain"],
  skills: [{
    id: "translate",
    name: "翻译",
    description: "中英互译",
    tags: ["nlp", "translate"],
  }],
};

class TranslatorExecutor implements AgentExecutor {
  async execute(ctx: RequestContext, bus: ExecutionEventBus) {
    const userText = ctx.userMessage.parts
      .filter(p => p.kind === "text")
      .map(p => (p as any).text).join("");

    bus.publish({
      kind: "status-update",
      taskId: ctx.taskId,
      status: { state: "working" },
      final: false,
    });

    const translated = await translate(userText);

    bus.publish({
      kind: "artifact-update",
      taskId: ctx.taskId,
      artifact: {
        artifactId: crypto.randomUUID(),
        parts: [{ kind: "text", text: translated }],
      },
    });

    bus.publish({
      kind: "status-update",
      taskId: ctx.taskId,
      status: { state: "completed" },
      final: true,
    });
  }

  async cancel(ctx: RequestContext, bus: ExecutionEventBus) {
    bus.publish({
      kind: "status-update",
      taskId: ctx.taskId,
      status: { state: "canceled" },
      final: true,
    });
  }
}

async function translate(text: string): Promise<string> {
  return `[translated] ${text}`;
}

const handler = new DefaultRequestHandler(agentCard, new TranslatorExecutor());
const app = express();
new A2AExpressApp(handler).setupRoutes(app);
app.listen(8001, () => console.log("Translator agent on :8001"));

7.2 客户端

import { A2AClient } from "@a2a-js/sdk";

const client = await A2AClient.fromCardUrl(
  "https://translator.example.com/.well-known/agent.json",
  { headers: { Authorization: "Bearer xxx" } },
);

const result = await client.sendMessage({
  role: "user",
  parts: [{ kind: "text", text: "Hello world" }],
  messageId: crypto.randomUUID(),
});

console.log(result);

// 流式
for await (const event of client.sendMessageStreaming(msg)) {
  console.log(event);
}

八、多智能体编排模式

8.1 路由模式(Router)

一个"调度 agent"根据用户请求路由到合适的下游 agent。

class RouterExecutor(AgentExecutor):
    def __init__(self, downstream: dict[str, A2AClient]):
        self.downstream = downstream

    async def execute(self, ctx, bus):
        intent = await classify_intent(ctx.user_input)
        target = self.downstream[intent]
        async for ev in target.send_message_streaming(ctx.user_message):
            await bus.enqueue_event(ev)

8.2 流水线模式(Pipeline)

A → B → C 串行处理。

async def pipeline(text):
    a_out = await agent_a.send_message(make_msg(text))
    b_out = await agent_b.send_message(make_msg(extract_text(a_out)))
    c_out = await agent_c.send_message(make_msg(extract_text(b_out)))
    return c_out

8.3 并行 + 聚合(Map-Reduce)

async def parallel_query(question):
    tasks = [
        agent_search.send_message(make_msg(question)),
        agent_kb.send_message(make_msg(question)),
        agent_db.send_message(make_msg(question)),
    ]
    results = await asyncio.gather(*tasks)
    return await agent_aggregator.send_message(
        make_msg("\n".join(extract_text(r) for r in results))
    )

8.4 协商模式(Negotiation)

通过 input-required 状态多轮往返。

async def negotiate(client, initial_msg):
    task = await client.send_message(initial_msg)
    while task.status.state == "input-required":
        clarification = await ask_user(task.status.message)
        task = await client.send_message(clarification, task_id=task.id)
    return task

九、流式与异步任务

9.1 SSE 流(默认)

POST /a2a
Accept: text/event-stream

{ "jsonrpc": "2.0", "method": "message/stream", ... }

返回:

event: status-update
data: {"taskId":"...","status":{"state":"working"},"final":false}

event: artifact-update
data: {"taskId":"...","artifact":{...}}

event: status-update
data: {"taskId":"...","status":{"state":"completed"},"final":true}

9.2 Webhook 推送(长任务)

await client.set_push_notification_config(
    task_id=task.id,
    config={
        "url": "https://my-app.com/webhook/a2a",
        "token": "shared-secret",
        "authentication": {"schemes": ["bearer"]},
    }
)

Server 在状态变化时主动 POST 到 webhook URL。

9.3 断线重连

async for ev in client.resubscribe(task_id="task-abc"):
    ...

服务端必须保留事件历史(受 stateTransitionHistory 能力位控制)。


十、安全与认证

10.1 认证方案

A2A 复用 OpenAPI Security Schemes:

方案用途
apiKeyAPI Key 鉴权(header/query/cookie)
http: bearerOAuth 2 / JWT Bearer
oauth2完整 OAuth 2.0 流程
openIdConnectOIDC
mTLS互信 TLS(服务端到服务端推荐)

10.2 OAuth 2.0 配置

{
  "securitySchemes": {
    "oauth2": {
      "type": "oauth2",
      "flows": {
        "clientCredentials": {
          "tokenUrl": "https://auth.example.com/token",
          "scopes": {
            "agent.read":  "查询任务",
            "agent.write": "创建任务"
          }
        }
      }
    }
  },
  "security": [{ "oauth2": ["agent.write"] }]
}

10.3 安全最佳实践

  • 默认全部 HTTPS,拒绝 HTTP(开发除外)
  • 校验对方 Agent Card 来源:防止 card 投毒
  • 沙箱执行不可信 agent 返回:返回内容可能含 prompt injection
  • 限制 webhook 出站:防 SSRF(白名单域名)
  • Token 定期轮换:尤其 Bearer 长生命周期
  • 签名验证:webhook 推送加 HMAC 签名头
def verify_webhook(req, secret):
    sig = req.headers.get("X-A2A-Signature")
    expected = hmac.new(secret.encode(), req.body, "sha256").hexdigest()
    if not hmac.compare_digest(sig, expected):
        raise PermissionError("invalid signature")

十一、与 MCP 的关系

┌───────────────────────────────────────────┐
│        Client Agent (LLM-driven)          │
│  ┌─────────────┐         ┌──────────────┐ │
│  │  MCP Tools  │         │  A2A Client  │ │
│  └─────────────┘         └──────────────┘ │
│         │                       │          │
└─────────┼───────────────────────┼─────────┘
          │ MCP                   │ A2A
          ▼                       ▼
   ┌────────────┐          ┌────────────┐
   │ Tool / DB  │          │  Other     │
   │ / FS       │          │  Agent     │
   └────────────┘          └────────────┘
MCPA2A
通信对象模型 ↔ 工具/资源Agent ↔ Agent
抽象tools / resources / promptstasks / messages / artifacts
状态通常无状态有状态(task 生命周期)
传输stdio / HTTP+SSEHTTP + JSON-RPC + SSE
典型用法LLM 调用本地工具跨组织/跨厂商 agent 协作

十二、生产部署

12.1 部署拓扑

                ┌──────────────┐
                │  API Gateway │ ← TLS 终止 / 限流
                └──────┬───────┘
                       │
          ┌────────────┼────────────┐
          │            │            │
   ┌──────▼─┐   ┌──────▼─┐   ┌─────▼──┐
   │ Agent A│   │ Agent B│   │ Agent C│ ← 多实例 + 负载均衡
   └────┬───┘   └────┬───┘   └───┬────┘
        └────────┬───┴───┬───────┘
                 │       │
            ┌────▼───┐  ┌▼────────┐
            │ Redis  │  │Postgres │ ← Task 持久化
            │(队列)  │  │(状态)   │
            └────────┘  └─────────┘

12.2 Task 持久化

生产环境务必将 Task 状态持久化,否则进程重启丢失:

class PostgresTaskStore:
    async def save(self, task: Task): ...
    async def load(self, task_id: str) -> Task: ...
    async def append_event(self, task_id, event): ...

server = A2AServer(
    agent_card=agent_card,
    executor=executor,
    task_store=PostgresTaskStore(dsn="postgresql://..."),
)

12.3 横向扩展

  • Stateless agent:无 task store 依赖时直接 K8s HPA
  • Stateful agent:用 Redis Streams 做事件总线,多实例消费
  • 粘性路由:同一 task 路由到同一实例,减少跨节点同步

12.4 Dockerfile 示例

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
HEALTHCHECK --interval=30s CMD curl -f http://localhost:8000/.well-known/agent.json || exit 1
CMD ["uvicorn", "main:server.app", "--host", "0.0.0.0", "--port", "8000"]

十三、可观测性

13.1 必备指标

指标说明
a2a_task_total{state}各状态任务数
a2a_task_duration_seconds任务耗时直方图
a2a_message_size_bytes消息大小
a2a_active_streams当前活跃 SSE 流
a2a_webhook_failures_totalwebhook 失败次数

13.2 OpenTelemetry 集成

from opentelemetry import trace
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor

FastAPIInstrumentor.instrument_app(server.app)
tracer = trace.get_tracer("a2a")

class InstrumentedExecutor(AgentExecutor):
    async def execute(self, ctx, bus):
        with tracer.start_as_current_span("a2a.execute") as span:
            span.set_attribute("a2a.task.id", ctx.task_id)
            ...

13.3 跨 Agent 链路追踪

A2A 推荐通过 traceparent HTTP header 透传 W3C Trace Context:

headers = {
    "Authorization": "Bearer ...",
    "traceparent": current_traceparent(),
}

十四、常见问题

14.1 Agent Card 拉不到

  • 确认 /.well-known/agent.json 路径未被网关拦截
  • CORS 头:跨域调用需 Access-Control-Allow-Origin
  • 检查 TLS 证书是否被对方信任

14.2 SSE 连接频繁断开

  • 网关默认超时(如 nginx proxy_read_timeout 60s)→ 调到 600s+
  • 中间代理不支持 SSE → 启用 webhook 模式
  • 客户端无心跳 → server 周期发送 comment 行(: keepalive\n\n

14.3 Task 状态丢失

  • 多实例部署但用了内存 task store → 切换 Redis/Postgres
  • 进程崩溃 → 用 systemd / K8s 自动拉起 + 持久化 store

14.4 消息体过大

  • 大文件用 file.uri 引用对象存储 URL,而非 file.bytes 内嵌
  • 上传带签名的 S3/OSS 临时 URL,agent 之间共享引用

14.5 跨语言 / 跨框架兼容性

A2A 是协议标准,不绑定 SDK。只要遵守 JSON-RPC + Agent Card 规范,Python agent 可与 Node/Java/Go agent 互通。验证工具:A2A Inspector


十五、完整示例

一个"研究 + 写作"双 agent 协作系统:

User → Coordinator Agent
            │
            ├── (research) → Research Agent → Web Search
            │
            └── (writing)  → Writer Agent

15.1 Research Agent(Python)

from a2a.server import A2AServer, AgentExecutor
from a2a.types import AgentCard, Skill, Message, TextPart, TaskState, TaskStatus

class ResearchExecutor(AgentExecutor):
    async def execute(self, ctx, bus):
        query = ctx.get_user_input()
        await bus.enqueue_event(TaskStatus(state=TaskState.working))
        sources = await web_search(query)
        summary = await summarize(sources)
        await bus.enqueue_event(TaskStatus(
            state=TaskState.completed,
            message=Message(role="agent", parts=[TextPart(text=summary)])
        ))

    async def cancel(self, ctx, bus):
        await bus.enqueue_event(TaskStatus(state=TaskState.canceled))

research_card = AgentCard(
    name="Research Agent",
    url="https://research.example.com/a2a",
    version="1.0.0",
    protocolVersion="0.2.5",
    capabilities={"streaming": True},
    defaultInputModes=["text/plain"],
    defaultOutputModes=["text/markdown"],
    skills=[Skill(id="research", name="网络研究", description="...", tags=["search"])],
)

15.2 Coordinator Agent(TypeScript)

import { A2AClient } from "@a2a-js/sdk";

const research = await A2AClient.fromCardUrl("https://research.example.com/.well-known/agent.json");
const writer   = await A2AClient.fromCardUrl("https://writer.example.com/.well-known/agent.json");

class CoordinatorExecutor {
  async execute(ctx, bus) {
    const topic = extractText(ctx.userMessage);

    bus.publish({ kind: "status-update", status: { state: "working",
      message: { role: "agent", parts: [{ kind: "text", text: "研究中..." }] }}, final: false });
    const r = await research.sendMessage({ role: "user",
      parts: [{ kind: "text", text: topic }], messageId: crypto.randomUUID() });

    bus.publish({ kind: "status-update", status: { state: "working",
      message: { role: "agent", parts: [{ kind: "text", text: "撰写中..." }] }}, final: false });
    const w = await writer.sendMessage({ role: "user",
      parts: [{ kind: "text", text: extractText(r) }], messageId: crypto.randomUUID() });

    bus.publish({
      kind: "artifact-update",
      artifact: { artifactId: crypto.randomUUID(), parts: w.artifacts[0].parts },
    });
    bus.publish({ kind: "status-update", status: { state: "completed" }, final: true });
  }
}

15.3 端到端测试

curl https://coordinator.example.com/a2a \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0", "id": "1",
    "method": "message/send",
    "params": {
      "message": {
        "role": "user",
        "parts": [{"kind": "text", "text": "写一篇关于量子计算商业化的文章"}],
        "messageId": "msg-1"
      }
    }
  }'

附录:协议字段速查

字段位置必填说明
protocolVersionAgentCardA2A 协议版本
capabilities.streamingAgentCard支持 SSE
capabilities.pushNotificationsAgentCard支持 webhook
skills[].idAgentCard能力唯一 ID
messageIdMessage消息 UUID
taskIdMessage/Event任务 UUID
contextIdMessage多轮上下文 ID
parts[].kindParttext/file/data

参考资源: