MCP与A2A协议深度解析:Agent时代的“TCP/IP“如何诞生

文章目录

引言

想象一下,1990年的互联网世界:每家公司都有自己的网络协议,IBM 的 SNA、Apple 的 AppleTalk、Novell 的 IPX......它们就像一群说着不同语言的人,谁也听不懂谁。直到 TCP/IP 协议一统天下,互联网才真正爆发。

2026年的 AI Agent 生态,正处于同样的十字路口。

一方面,大语言模型(LLM)的能力越来越强,但它们依然被困在对话框里------不能读文件、不能查数据库、不能调 API。另一方面,各种 Agent 框架(LangChain、AutoGen、CrewAI)遍地开花,但每个框架都定义了自己的一套工具调用和通信方式,就像一个又一个的语言孤岛。

这就是 MCP(Model Context Protocol)和 A2A(Agent-to-Agent)协议要解决的问题。MCP 定义了「模型如何使用工具」的标准,A2A 则定义了「Agent 之间如何通信」的标准。它们合在一起,正在成为 Agent 时代的 TCP/IP 协议栈。

本文将带你深入这两个协议的核心原理,从架构设计到代码实战,让你完整掌握 Agent 标准化的技术全貌。


一、核心概念:为什么Agent需要标准化协议

1.1 从"一个人干活"到"一群人协作"

在 Agent 发展的早期阶段,我们关注的是"如何让一个 LLM 更好地完成任务"------给它一个 prompt,它返回一个答案。这本质上是一个单Agent 系统,模型的边界就是 Agent 的边界。

但随着应用场景的复杂化,单 Agent 的局限日益明显:

首先是能力边界问题。一个再强大的模型也有知识盲区。你需要它查数据库,它做不到;你需要它调用搜索引擎,它做不到;你需要它读写文件,它还是做不到。模型需要"手和脚",而这些"手和脚"就是外部工具。

其次是协作效率问题。复杂任务往往需要多个专业角色协同完成。比如开发一个功能,需要产品经理理清需求、设计师出图、开发者写代码、测试工程师验证------这不是一个 Agent 能包揽的。

这就带来了两个核心需求:

  • 模型与工具的标准化:让任何模型都能以统一的方式调用任何工具
  • Agent 与 Agent 的标准化:让不同来源、不同框架的 Agent 能以统一的方式通信

1.2 协议标准化:从各自为政到通用语言

在没有标准协议之前,每个 Agent 框架都搞了自己的一套:

复制代码
LangChain  -> Tool 抽象类 + BaseTool 接口
AutoGen    -> 自定义的 Agent 消息传递机制
CrewAI     -> 基于角色的 Task 分发机制
OpenAI     -> Function Calling 格式
Anthropic  -> Tool Use 格式

这种碎片化带来了严重的问题。如果你用 LangChain 开发了一个 Agent,它很难和 AutoGen 开发的 Agent 通信。如果你为 OpenAI 模型写了一套工具,换成 Claude 就得重写。这就像每家公司都有自己的充电接口------直到 USB-C 出现。

MCP 和 A2A 要做的事情,就是这个"USB-C 时刻":

  • MCP(Model Context Protocol):由 Anthropic 提出,定义了 LLM 与外部工具/资源之间的标准通信协议。它解决的是"模型怎么用工具"的问题。
  • A2A(Agent-to-Agent):由 Google 提出,定义了 Agent 之间的标准通信协议。它解决的是"Agent 之间怎么对话"的问题。

两者的关系可以这样理解:

MCP 是「纵向协议」,连接模型层和工具层,解决深度问题------让模型能访问更多的工具和数据。

A2A 是「横向协议」,连接 Agent 层和 Agent 层,解决广度问题------让多个 Agent 能协同工作。


二、MCP协议:连接模型与工具的"USB接口"

2.1 MCP的设计哲学

MCP 的设计灵感来自于 LSP(Language Server Protocol)------编辑器领域的标准化协议。在 LSP 出现之前,每个编辑器都要为每种编程语言单独实现补全、跳转、诊断等功能,工作量是 M x N。LSP 出现后,语言社区只需实现一个 Language Server,所有支持 LSP 的编辑器都能用,工作量变成了 M + N。

MCP 在 AI 领域复制了这个思路:

复制代码
LSP 模式:  编辑器 <--> Language Server  <--> 语言编译器
MCP 模式:  LLM    <--> MCP Server      <--> 外部工具/数据

MCP 的核心设计原则有三条:

第一,客户端-服务器架构。 LLM 应用作为 MCP Client,工具/数据提供方作为 MCP Server。Client 和 Server 之间通过标准协议通信,Client 不需要知道 Server 的内部实现。

第二,传输层无关。 MCP 定义了协议的消息格式(基于 JSON-RPC 2.0),但不绑定特定的传输方式。你可以用标准输入输出(stdio)进行本地通信,也可以用 HTTP + SSE 进行远程通信。

第三,能力发现机制。 MCP Server 启动时会向 Client 声明自己提供哪些能力------包括工具(Tools)、资源(Resources)、提示模板(Prompts)。Client 可以动态发现并使用这些能力,不需要预先配置。

2.2 MCP架构详解

MCP 协议定义了三种核心能力类型:

  • Tools(工具) :模型可以调用的函数。比如 search_databasesend_emailcreate_file。每个工具声明了名称、描述和参数 schema(JSON Schema 格式),模型根据描述决定何时调用哪个工具。

  • Resources(资源):模型可以读取的数据。比如文件内容、数据库记录、API 响应。Resources 和 Tools 的区别在于------Tools 是"做事情",Resources 是"读东西"。

  • Prompts(提示模板):预定义的提示词模板。Server 可以提供适合自己工具的最佳 prompt 模板,帮助模型更好地使用这些工具。

图:MCP 协议工作流程------从用户请求到工具调用完成的完整链路

2.3 实战:搭建一个MCP Server

下面我们动手搭建一个完整的 MCP Server,提供两个工具:天气查询和计算器。使用 Python 和 MCP 官方 SDK。

python 复制代码
"""
MCP Server 实战示例
提供天气查询和计算器两个工具
演示 MCP 协议的完整实现流程

依赖安装:pip install mcp
"""

import asyncio
import json
from typing import Any

from mcp.server import Server, NotificationOptions
from mcp.server.models import InitializationCapabilities
from mcp.server.stdio import stdio_server
from mcp.types import (
    Tool,
    TextContent,
    ImageContent,
    EmbeddedResource,
)


# ====== 1. 创建 MCP Server 实例 ======

server = Server("my-first-mcp-server")


# ====== 2. 定义工具函数 ======

async def query_weather(city: str, date: str = "today") -> str:
    """
    查询天气(模拟实现)

    Args:
        city: 城市名称,如"北京"、"上海"
        date: 日期,默认为"today"

    Returns:
        天气信息字符串
    """
    # 实际项目中这里会调用天气 API
    weather_data = {
        "北京": {"today": "晴天,25C,湿度 45%", "tomorrow": "多云,22C,湿度 55%"},
        "上海": {"today": "小雨,28C,湿度 80%", "tomorrow": "阴天,26C,湿度 70%"},
        "深圳": {"today": "雷阵雨,32C,湿度 85%", "tomorrow": "多云,30C,湿度 75%"},
    }

    city_weather = weather_data.get(city, {})
    weather = city_weather.get(date, f"暂无 {city} 在 {date} 的天气数据")

    return f"[天气查询] {city} {date} 天气:{weather}"


async def calculator(expression: str) -> str:
    """
    安全计算器(模拟实现)

    Args:
        expression: 数学表达式,如 "2 + 3 * 4"

    Returns:
        计算结果字符串
    """
    # 实际项目中需要安全解析,这里简化为受限的 eval
    try:
        # 安全限制:只允许数字、运算符、空格和小数点
        allowed_chars = set("0123456789+-*/().% ")
        if not all(c in allowed_chars for c in expression):
            return "[错误] 表达式包含不支持的字符"

        result = eval(expression)
        return f"[计算结果] {expression} = {result}"
    except Exception as e:
        return f"[错误] 计算失败:{str(e)}"


# ====== 3. 注册工具列表 ======

@server.list_tools()
async def handle_list_tools() -> list[Tool]:
    """
    向 Client 声明本 Server 提供的所有工具

    Client 在连接初始化时会调用此方法获取工具列表,
    然后将其转换为模型的 Function Calling 格式
    """
    return [
        Tool(
            name="query_weather",
            description="查询指定城市的天气信息。支持查询今天和明天的天气。",
            inputSchema={
                "type": "object",
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "城市名称,如 北京、上海、深圳",
                    },
                    "date": {
                        "type": "string",
                        "description": "日期:today 或 tomorrow",
                        "default": "today",
                    },
                },
                "required": ["city"],
            },
        ),
        Tool(
            name="calculator",
            description="执行安全的数学计算。支持加减乘除和括号。",
            inputSchema={
                "type": "object",
                "properties": {
                    "expression": {
                        "type": "string",
                        "description": "数学表达式,如 2 + 3 * 4",
                    },
                },
                "required": ["expression"],
            },
        ),
    ]


# ====== 4. 处理工具调用 ======

@server.call_tool()
async def handle_call_tool(
    name: str, arguments: dict[str, Any]
) -> list[TextContent]:
    """
    处理来自 Client 的工具调用请求

    Args:
        name: 要调用的工具名称
        arguments: 工具参数

    Returns:
        工具执行结果
    """
    print(f"\n[工具调用] 收到请求:{name}")
    print(f"[参数] {json.dumps(arguments, ensure_ascii=False, indent=2)}")

    # 根据工具名称路由到对应的处理函数
    if name == "query_weather":
        city = arguments.get("city", "北京")
        date = arguments.get("date", "today")
        result = await query_weather(city, date)

    elif name == "calculator":
        expression = arguments.get("expression", "")
        result = await calculator(expression)

    else:
        result = f"[错误] 未知工具:{name}"

    print(f"[返回] {result}")

    return [TextContent(type="text", text=result)]


# ====== 5. 启动 Server ======

async def main():
    """
    启动 MCP Server

    使用 stdio 传输方式运行,可以通过以下方式测试:
    python mcp_server_demo.py
    """
    print("MCP Server 启动中...")
    print("传输方式:stdio")
    print("可用工具:query_weather, calculator")
    print("=" * 50)

    async with stdio_server() as (read_stream, write_stream):
        await server.run(
            read_stream,
            write_stream,
            InitializationCapabilities(
                sampling={},
                experimental={},
            ),
        )


if __name__ == "__main__":
    asyncio.run(main())

运行说明:

将以上代码保存为 mcp_server_demo.py,安装依赖后运行:

bash 复制代码
pip install mcp
python mcp_server_demo.py

这个 MCP Server 启动后,任何支持 MCP 协议的 Client(如 Claude Desktop、Continue、Cline 等)都可以连接它,动态发现 query_weathercalculator 两个工具并使用。

当你问 Claude "北京今天天气怎么样?"时,Claude 会:

  1. 发现 MCP Server 提供了 query_weather 工具
  2. 自动决定调用该工具,参数为 {"city": "北京", "date": "today"}
  3. 收到返回结果后,整合到回复中

整个过程不需要你手动配置,完全由协议自动完成。


三、A2A协议:Agent之间的"HTTP协议"

3.1 A2A的设计哲学

如果说 MCP 解决的是"模型如何用工具",那么 A2A 解决的就是"Agent 之间如何协同"。

在 Google 提出 A2A 之前,多 Agent 系统的通信方式五花八门。有的通过共享内存,有的通过消息队列,有的直接在代码里函数调用。这导致不同框架开发的 Agent 几乎无法互通。

A2A 的设计哲学可以总结为三点:

第一,去中心化。 没有中央调度器,每个 Agent 都是独立的节点,通过标准协议进行对等通信。这就像互联网------没有中央控制器,所有主机通过 TCP/IP 平等通信。

第二,能力自描述。 每个 Agent 通过 Agent Card(一个 JSON 文档)公开自己的能力、接口和支持的通信方式。其他 Agent 通过读取 Agent Card 来了解对方能做什么、怎么调用。

第三,任务驱动。 A2A 的核心抽象是 Task(任务)。Agent 之间通过发送 Task 来请求对方完成工作,通过 Task 的状态变更来追踪进度。

3.2 A2A通信模式

A2A 支持多种通信模式以适应不同场景:

复制代码
+---------------------------------------------+
|              A2A 通信模式                     |
+------------+------------+-------------------+
| 点对点      |  广播      |    订阅/发布       |
| (1:1)      | (1:N)      |    (Pub/Sub)      |
+------------+------------+-------------------+
| 请求-响应   | 通知所有    |  按主题筛选接收者   |
| 任务委托    | 状态同步    |  事件驱动架构      |
+------------+------------+-------------------+
  • 点对点模式:最常用。一个 Agent 向另一个 Agent 发送任务请求,等待完成通知。
  • 广播模式:一个 Agent 向所有在线 Agent 广播消息,适用于状态同步等场景。
  • 订阅/发布模式:Agent 按主题订阅消息,只接收自己关心的事件。

3.3 实战:实现A2A Agent通信

让我们实现一个完整的 A2A 多 Agent 系统,模拟一个软件开发团队:

python 复制代码
"""
A2A (Agent-to-Agent) 协议实战
模拟软件开发团队:产品经理 -> 架构师 -> 开发者 -> 测试工程师

演示 Agent 之间通过标准化的任务对象进行通信
"""

import json
import time
import uuid
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
from typing import Dict, List, Optional, Callable


# ====== 1. A2A 核心数据结构 ======

class TaskStatus(Enum):
    """A2A 任务状态枚举"""
    PENDING = "pending"          # 等待处理
    IN_PROGRESS = "in_progress"  # 处理中
    COMPLETED = "completed"      # 已完成
    FAILED = "failed"            # 失败
    CANCELLED = "cancelled"      # 已取消


class MessageType(Enum):
    """A2A 消息类型枚举"""
    TASK_REQUEST = "task_request"        # 任务请求
    TASK_RESULT = "task_result"          # 任务结果
    QUERY = "query"                      # 询问
    RESPONSE = "response"                # 回复
    BROADCAST = "broadcast"              # 广播
    STATUS_UPDATE = "status_update"      # 状态更新
    HEARTBEAT = "heartbeat"              # 心跳


@dataclass
class AgentCard:
    """
    Agent Card:Agent 的能力自描述文档

    这是 A2A 协议的核心概念------每个 Agent 通过 Agent Card
    公开自己的身份、能力和通信接口
    """
    agent_id: str
    name: str
    role: str
    description: str
    capabilities: List[str]           # 能力列表
    supported_message_types: List[MessageType]
    endpoint: str = ""                # 通信端点(实际项目中是 URL)
    version: str = "1.0.0"


@dataclass
class Task:
    """
    A2A Task:Agent 之间通信的核心抽象
    """
    task_id: str
    title: str
    description: str
    sender_id: str
    receiver_id: str
    status: TaskStatus = TaskStatus.PENDING
    context: Dict = field(default_factory=dict)  # 附加上下文信息
    result: Optional[str] = None
    created_at: str = field(default_factory=lambda: datetime.now().isoformat())
    completed_at: Optional[str] = None


@dataclass
class Message:
    """A2A 消息信封"""
    message_id: str
    msg_type: MessageType
    sender_id: str
    receiver_id: str
    content: Dict  # 消息体,包含 Task 或其他数据
    timestamp: str = field(default_factory=lambda: datetime.now().isoformat())


# ====== 2. A2A Agent 基类 ======

class A2AAgent:
    """
    A2A Agent 基类

    每个 Agent 拥有:
    - Agent Card:自我描述
    - 消息收件箱:接收其他 Agent 发来的消息
    - 能力路由表:记录已知的其他 Agent 的能力
    """

    def __init__(
        self,
        name: str,
        role: str,
        description: str,
        capabilities: List[str],
        llm_func: Optional[Callable] = None,
    ):
        self.agent_card = AgentCard(
            agent_id=str(uuid.uuid4())[:8],
            name=name,
            role=role,
            description=description,
            capabilities=capabilities,
            supported_message_types=[
                MessageType.TASK_REQUEST,
                MessageType.QUERY,
                MessageType.RESPONSE,
                MessageType.STATUS_UPDATE,
            ],
        )

        self.llm_func = llm_func
        self.inbox: List[Message] = []
        self.known_agents: Dict[str, AgentCard] = {}  # 已知的其他 Agent
        self.completed_tasks: List[Task] = []
        self.active_tasks: Dict[str, Task] = {}

    def register_agent(self, agent_card: AgentCard):
        """注册已知 Agent 的能力信息"""
        self.known_agents[agent_card.agent_id] = agent_card
        print(f"  [{self.agent_card.name}] 发现了 Agent: {agent_card.name} "
              f"({', '.join(agent_card.capabilities)})")

    def send_message(self, receiver: "A2AAgent", msg_type: MessageType,
                     content: Dict) -> Message:
        """发送消息到另一个 Agent"""
        message = Message(
            message_id=str(uuid.uuid4())[:8],
            msg_type=msg_type,
            sender_id=self.agent_card.agent_id,
            receiver_id=receiver.agent_card.agent_id,
            content=content,
        )
        receiver.receive_message(message)
        print(f"  [{self.agent_card.name}] -> [{receiver.agent_card.name}]: "
              f"{msg_type.value}")
        return message

    def receive_message(self, message: Message):
        """接收消息"""
        self.inbox.append(message)
        sender_name = self.known_agents.get(
            message.sender_id,
            AgentCard(agent_id=message.sender_id, name="Unknown", role="",
                      description="", capabilities=[], supported_message_types=[])
        ).name

        print(f"  [{self.agent_card.name}] <- [{sender_name}]: "
              f"{message.msg_type.value}")

        # 自动处理不同类型的消息
        self._handle_message(message)

    def create_task(self, receiver: "A2AAgent", title: str,
                    description: str, context: Dict = None) -> Task:
        """创建一个 A2A Task 并发送给目标 Agent"""
        task = Task(
            task_id=str(uuid.uuid4())[:8],
            title=title,
            description=description,
            sender_id=self.agent_card.agent_id,
            receiver_id=receiver.agent_card.agent_id,
            context=context or {},
        )
        self.active_tasks[task.task_id] = task

        # 通过 Task Request 消息发送任务
        self.send_message(
            receiver,
            MessageType.TASK_REQUEST,
            content={
                "task_id": task.task_id,
                "title": task.title,
                "description": task.description,
                "context": task.context,
            }
        )
        return task

    def _handle_message(self, message: Message):
        """
        处理收到的消息(子类可重写以实现自定义逻辑)

        这是 A2A Agent 的核心逻辑------根据消息类型做出不同的响应
        """
        if message.msg_type == MessageType.TASK_REQUEST:
            # 收到任务请求,开始执行
            task_data = message.content
            task = Task(
                task_id=task_data["task_id"],
                title=task_data["title"],
                description=task_data["description"],
                sender_id=message.sender_id,
                receiver_id=self.agent_card.agent_id,
                context=task_data.get("context", {}),
            )
            self._execute_task(task)

        elif message.msg_type == MessageType.QUERY:
            # 收到询问,根据自己的能力回答
            pass

    def _execute_task(self, task: Task):
        """执行任务(子类必须实现)"""
        raise NotImplementedError(
            f"{self.agent_card.name} 需要实现 _execute_task 方法"
        )

    def complete_task(self, task: Task, result: str, success: bool = True):
        """完成任务并通知发送方"""
        task.status = TaskStatus.COMPLETED if success else TaskStatus.FAILED
        task.result = result
        task.completed_at = datetime.now().isoformat()
        self.completed_tasks.append(task)

        print(f"  [完成] {self.agent_card.name} 完成任务: {task.title}")
        print(f"  结果: {result[:100]}...")


# ====== 3. 具体 Agent 实现 ======

class ProductManagerAgent(A2AAgent):
    """产品经理 Agent:负责需求分析"""

    def __init__(self, llm_func=None):
        super().__init__(
            name="产品经理-PM",
            role="product_manager",
            description="负责需求分析与任务分解",
            capabilities=["需求分析", "任务分解", "优先级排序"],
            llm_func=llm_func,
        )

    def analyze_requirement(self, requirement: str) -> Dict:
        """分析需求并生成开发任务"""
        print(f"\n[产品经理] 正在分析需求: {requirement}")

        # 实际项目中这里调用 LLM 进行需求分析
        analysis = {
            "原始需求": requirement,
            "需求拆解": [
                "1. 系统架构设计(架构师负责)",
                "2. 核心功能开发(开发者负责)",
                "3. 测试验证(测试工程师负责)",
            ],
            "验收标准": [
                "功能完整可用",
                "代码通过测试",
                "架构评审通过",
            ],
            "优先级": "P0",
        }

        print(f"[产品经理] 需求分析完成,拆解为 {len(analysis['需求拆解'])} 个子任务")
        return analysis


class ArchitectAgent(A2AAgent):
    """架构师 Agent:负责系统设计"""

    def __init__(self, llm_func=None):
        super().__init__(
            name="架构师-Architect",
            role="architect",
            description="负责系统架构设计和技术选型",
            capabilities=["系统设计", "技术选型", "架构评审"],
            llm_func=llm_func,
        )

    def design_architecture(self, requirement: str) -> str:
        """设计系统架构"""
        print(f"\n[架构师] 正在设计系统架构...")

        design = f"""
        ====== 系统架构设计文档 ======

        需求:{requirement}

        1. 整体架构:微服务 + 事件驱动
           - API Gateway: 统一入口,路由、限流、鉴权
           - Service Layer: 核心业务逻辑
           - Data Layer: MySQL 主库 + Redis 缓存
           - Message Queue: RabbitMQ 异步处理

        2. 技术选型:
           - 后端框架: FastAPI (Python)
           - 数据库: MySQL 8.0 + Redis 7.0
           - 消息队列: RabbitMQ
           - 容器化: Docker + Kubernetes

        3. 关键设计决策:
           - 采用 CQRS 模式分离读写
           - 使用 Saga 模式处理分布式事务
           - API 版本化策略: URL Path Versioning

        4. 非功能性需求:
           - QPS 目标: 10000+
           - 响应时间: P99 < 200ms
           - 可用性: 99.95%
        """

        print("[架构师] 架构设计完成")
        return design


class DeveloperAgent(A2AAgent):
    """开发者 Agent:负责编码实现"""

    def __init__(self, llm_func=None):
        super().__init__(
            name="开发者-Developer",
            role="developer",
            description="负责代码实现和单元测试",
            capabilities=["编码实现", "单元测试", "代码审查"],
            llm_func=llm_func,
        )

    def write_code(self, design: str) -> str:
        """根据设计文档编写代码"""
        print(f"\n[开发者] 正在根据架构设计编写代码...")

        code = '''
# ====== 根据架构设计生成的代码框架 ======

from fastapi import FastAPI, HTTPException, Depends
from pydantic import BaseModel
from typing import Optional, List
import redis
import pymysql
import pika
import json

# ---- API Gateway Layer ----

app = FastAPI(title="A2A Demo Service", version="1.0.0")


class CreateOrderRequest(BaseModel):
    """创建订单请求"""
    user_id: str
    product_id: str
    quantity: int
    price: float


class OrderResponse(BaseModel):
    """订单响应"""
    order_id: str
    status: str
    message: str


# ---- Service Layer ----

class OrderService:
    """订单服务(CQRS 模式)"""

    def __init__(self):
        self.redis_client = redis.Redis(
            host="localhost", port=6379, decode_responses=True
        )
        # 数据库连接在实际项目中通过连接池管理
        self.db_config = {
            "host": "localhost",
            "user": "root",
            "password": "",
            "database": "a2a_demo",
        }

    async def create_order(
        self, user_id: str, product_id: str, quantity: int, price: float
    ) -> OrderResponse:
        """创建订单 - Command 端(写操作)"""
        # 1. 检查库存(Redis 缓存)
        stock_key = f"stock:{product_id}"
        current_stock = self.redis_client.get(stock_key)

        if not current_stock or int(current_stock) < quantity:
            raise HTTPException(status_code=400, detail="库存不足")

        # 2. 扣减库存(Redis 原子操作)
        self.redis_client.decrby(stock_key, quantity)

        # 3. 发布订单创建事件(消息队列)
        connection = pika.BlockingConnection(
            pika.ConnectionParameters("localhost")
        )
        channel = connection.channel()
        channel.queue_declare(queue="order_events")

        event = {
            "event_type": "order_created",
            "user_id": user_id,
            "product_id": product_id,
            "quantity": quantity,
            "total_price": price * quantity,
        }
        channel.basic_publish(
            exchange="",
            routing_key="order_events",
            body=json.dumps(event),
        )
        connection.close()

        return OrderResponse(
            order_id=f"ORD-{user_id}-{product_id}",
            status="created",
            message="订单创建成功,已发送事件通知",
        )


# ---- API Routes ----

order_service = OrderService()


@app.post("/api/v1/orders", response_model=OrderResponse)
async def create_order(request: CreateOrderRequest):
    """创建订单 API"""
    return await order_service.create_order(
        user_id=request.user_id,
        product_id=request.product_id,
        quantity=request.quantity,
        price=request.price,
    )


@app.get("/api/v1/health")
async def health_check():
    """健康检查"""
    return {"status": "healthy", "service": "A2A Demo Service"}


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

        print(f"[开发者] 代码编写完成({len(code)} 字符)")
        return code


class TesterAgent(A2AAgent):
    """测试工程师 Agent:负责质量验证"""

    def __init__(self, llm_func=None):
        super().__init__(
            name="测试工程师-Tester",
            role="tester",
            description="负责测试用例编写和质量验证",
            capabilities=["功能测试", "性能测试", "回归测试"],
            llm_func=llm_func,
        )

    def write_tests(self, code: str) -> str:
        """编写测试用例"""
        print(f"\n[测试工程师] 正在编写测试用例...")

        tests = '''
# ====== 测试用例 ======

import pytest
from fastapi.testclient import TestClient
from main import app

client = TestClient(app)


class TestOrderAPI:
    """订单 API 测试套件"""

    def test_create_order_success(self):
        """测试正常创建订单"""
        response = client.post("/api/v1/orders", json={
            "user_id": "user_001",
            "product_id": "prod_001",
            "quantity": 2,
            "price": 99.99,
        })
        assert response.status_code == 200
        data = response.json()
        assert data["status"] == "created"
        assert "order_id" in data

    def test_create_order_insufficient_stock(self):
        """测试库存不足场景"""
        response = client.post("/api/v1/orders", json={
            "user_id": "user_001",
            "product_id": "prod_001",
            "quantity": 99999,
            "price": 99.99,
        })
        assert response.status_code == 400
        assert "库存不足" in response.json()["detail"]

    def test_health_check(self):
        """测试健康检查接口"""
        response = client.get("/api/v1/health")
        assert response.status_code == 200
        assert response.json()["status"] == "healthy"

    @pytest.mark.parametrize("quantity", [0, -1, -100])
    def test_invalid_quantity(self, quantity):
        """测试非法数量参数"""
        response = client.post("/api/v1/orders", json={
            "user_id": "user_001",
            "product_id": "prod_001",
            "quantity": quantity,
            "price": 99.99,
        })
        assert response.status_code in [400, 422]


class TestPerformanceBaseline:
    """性能基线测试"""

    @pytest.mark.benchmark(min_rounds=100)
    def test_create_order_performance(self, benchmark):
        """测试创建订单的性能基线"""
        response = benchmark(
            client.post,
            "/api/v1/orders",
            json={
                "user_id": "user_001",
                "product_id": "prod_001",
                "quantity": 1,
                "price": 99.99,
            }
        )
        assert response.status_code == 200


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
'''

        print(f"[测试工程师] 测试用例编写完成({len(tests)} 字符)")
        return tests


# ====== 4. A2A 工作流编排 ======

class A2AOrchestrator:
    """
    A2A 工作流编排器

    注意:这不是 A2A 协议的一部分,而是使用 A2A 协议的应用层代码。
    A2A 协议本身是去中心化的,没有中央调度器。
    这里只是为了演示而建立了一个工作流编排。
    """

    def __init__(self):
        # 创建团队
        self.pm = ProductManagerAgent()
        self.architect = ArchitectAgent()
        self.developer = DeveloperAgent()
        self.tester = TesterAgent()

        # 互相注册------在实际 A2A 系统中,这一步通过服务发现自动完成
        agents = [self.pm, self.architect, self.developer, self.tester]
        for a1 in agents:
            for a2 in agents:
                if a1 != a2:
                    a1.register_agent(a2.agent_card)

    def run_workflow(self, requirement: str):
        """
        运行完整的 A2A 协作工作流

        流程:PM 分析需求 -> 架构师设计 -> 开发者编码 -> 测试工程师验证
        """
        print("\n" + "=" * 60)
        print("A2A 多 Agent 协作工作流启动")
        print("=" * 60)

        # Phase 1: PM 分析需求
        print("\n【Phase 1/4】产品经理分析需求...")
        analysis = self.pm.analyze_requirement(requirement)

        # Phase 2: 架构师设计
        print("\n【Phase 2/4】架构师进行系统设计...")
        design = self.architect.design_architecture(requirement)

        # Phase 3: 开发者编码
        print("\n【Phase 3/4】开发者进行编码实现...")
        code = self.developer.write_code(design)

        # Phase 4: 测试工程师验证
        print("\n【Phase 4/4】测试工程师编写测试...")
        tests = self.tester.write_tests(code)

        # 输出完整交付物
        print("\n" + "=" * 60)
        print("A2A 协作完成!交付物清单:")
        print("=" * 60)
        print(f"[OK] 需求分析文档({len(str(analysis))} 字符)")
        print(f"[OK] 架构设计文档({len(design)} 字符)")
        print(f"[OK] 代码实现({len(code)} 字符)")
        print(f"[OK] 测试用例({len(tests)} 字符)")

        return {
            "analysis": analysis,
            "design": design,
            "code": code,
            "tests": tests,
        }


# ====== 5. 运行演示 ======

if __name__ == "__main__":
    orchestrator = A2AOrchestrator()

    result = orchestrator.run_workflow(
        requirement="构建一个支持高并发的订单处理系统"
    )

    print("\n" + "=" * 60)
    print("A2A 协作统计")
    print("=" * 60)
    print(f"参与 Agent 数量: 4")
    print(f"Agent 角色: PM / 架构师 / 开发者 / 测试工程师")
    print(f"通信协议: A2A (Agent-to-Agent)")
    print(f"通信模式: 流水线模式 (Pipeline)")
    print(f"交付物数量: 4 份")

四、MCP vs A2A:互补而非竞争

很多人第一次接触这两个协议时会问:"MCP 和 A2A 是什么关系?谁替代谁?"

答案是:它们解决的是不同维度的问题,是互补关系,不是竞争关系。

图:MCP(纵向连接模型与工具)vs A2A(横向连接 Agent 与 Agent)

用一个生活中的类比来理解:

MCP 是汽车的「车载接口」------它让汽车(LLM)能够连接各种外设:GPS(搜索)、行车记录仪(文件系统)、车载充电器(API)。标准化的接口意味着任何品牌的设备都能插上用。

A2A 是汽车的「V2V通信协议」------它让汽车之间能够互相通信:前车刹车了通知后车、路况信息共享、编队行驶协作。标准化的协议意味着不同品牌的汽车也能协同工作。

具体的技术差异对比如下:

维度 MCP (Model Context Protocol) A2A (Agent-to-Agent)
提出方 Anthropic Google
解决的问题 LLM 如何使用外部工具/数据 Agent 之间如何通信协作
架构模式 客户端-服务器(C/S) 对等网络(P2P)
通信方向 纵向:模型层 <-> 工具层 横向:Agent <-> Agent
消息格式 JSON-RPC 2.0 JSON(基于 HTTP/gRPC)
核心抽象 Tools / Resources / Prompts Agent Card / Task
发现机制 Server -> Client 声明能力 Agent Card 自描述
传输层 stdio / HTTP+SSE HTTP / gRPC
典型场景 一个 Agent 调用多个工具 多个 Agent 协同完成任务
类比 USB 接口(设备 <-> 外设) TCP/IP(计算机 <-> 计算机)

在实际项目中,两个协议通常会一起使用:

图:多 Agent 系统同时使用 MCP 和 A2A------每个 Agent 通过 MCP 调用工具,Agent 之间通过 A2A 协同

典型架构:

  • 每个 Agent 通过 MCP 连接自己需要的工具和数据源
  • Agent 之间通过 A2A 交换任务、同步状态、协同决策
  • MCP 让每个 Agent "更有能力",A2A 让 Agent 们 "更能协作"

五、最佳实践与总结

5.1 MCP 使用建议

  1. 工具粒度要适中。 不要设计一个"万能工具",也不要把每个小操作都做成独立工具。一个好的经验法则是:一个工具完成一个明确的功能。
  2. 工具描述要清晰。 模型靠描述来理解工具的用途,描述越清晰,调用越准确。建议使用「动词+名词」格式,如 search_documentssend_email
  3. 做好错误处理。 工具调用可能失败(网络超时、权限不足等),Server 端要返回有意义的错误信息,方便模型理解并重试。
  4. 注意安全边界。 MCP Server 实际执行文件操作、网络请求等,要做好权限控制和输入校验。

5.2 A2A 使用建议

  1. Agent 职责要单一。 每个 Agent 只做一件事,通过组合实现复杂功能。这既是软件工程的基本原则,也是 A2A 系统稳定运行的前提。
  2. Agent Card 要诚实。 不要夸大能力,准确描述自己能做什么、不能做什么。其他 Agent 依赖这些信息做决策。
  3. 任务要有超时机制。 Agent 可能卡住或崩溃,Task 必须有超时和重试策略。
  4. 从简单模式开始。 先用点对点通信,跑通了再加广播和订阅/发布。不要一开始就上复杂拓扑。

5.3 总结

  • MCP 是模型与工具之间的标准协议,解决"单 Agent 的能力边界"问题。它让任何 LLM 都能以统一的方式使用任何工具,类比 USB 接口。
  • A2A 是 Agent 与 Agent 之间的标准协议,解决"多 Agent 的协作效率"问题。它让不同框架、不同来源的 Agent 能无缝通信,类比 TCP/IP 协议。
  • 两者互补:MCP 做纵向打通(深度),A2A 做横向打通(广度),共同构成 Agent 时代的协议栈基石。
  • 趋势明确:2026 年是 Agent 协议标准化元年,MCP 生态已有数百个 Server 实现,A2A 被 Google、Salesforce 等大厂力推。早理解、早受益。

延伸阅读

相关推荐
dong__csdn1 小时前
websocket实现简单的单聊、群聊demo
网络·websocket·网络协议
ZFSS1 小时前
VS Code + Serp MCP:让 Copilot 实时上网查询
人工智能·ai·ai作画·copilot·ai编程·ai写作
装不满的克莱因瓶2 小时前
基于 Python 进行二维空间线性可分数据单/多层感知器实战
人工智能·python·深度学习·神经网络·ai·卷积
金融RPA机器人丨实在智能2 小时前
最终决定选择实在Agent的关键因素通常是什么?
人工智能·ai
酉鬼女又兒2 小时前
零基础入门计算机网络可靠传输:从基本概念到三大实现机制(停止 - 等待 / 回退 N 帧 / 选择重传)全解析
网络·网络协议·计算机网络·考研·职场和发展·计算机外设·求职招聘
土星云SaturnCloud2 小时前
边缘计算赋能烟草行业数字化转型
服务器·人工智能·ai·边缘计算
专注VB编程开发20年2 小时前
上位机监控接收数据(从站)-Modbus TCP 从机(Slave)模式多站点设计
网络·网络协议·tcp/ip
财经资讯数据_灵砚智能2 小时前
基于全球经济类多源新闻的NLP情感分析与数据可视化(夜间-次晨)2026年6月4日
人工智能·python·ai·信息可视化·自然语言处理·ai编程·灵砚智能
装不满的克莱因瓶2 小时前
深度学习优化:使用深层神经网络来解决复杂任务
人工智能·python·深度学习·神经网络·机器学习·ai