仓库地址:A2A MCP
本仓库演示了如何设置和使用 a2a-python SDK 来创建一个简单的服务器和客户端实现 a2a 协议,其中代理服务器由 mcp 实现。
概述
- A2A (Agent-to-Agent): 用于构建可互操作 AI 代理的协议和 SDK。
- 本示例: 展示如何运行基本的 A2A 服务器和客户端,交换消息并查看响应。
前置条件
- Python 3.13+
- uv(用于快速依赖管理和运行)
- OpenRouter 的 API 密钥(设置为
OPENROUTER_API_KEY
)
安装
-
克隆仓库:
git clone https://github.com/sing1ee/a2a-mcp-openrouter cd https://github.com/sing1ee/a2a-mcp-openrouter
-
安装依赖:
uv venv source .venv/bin/activate uv sync
-
设置环境变量:
export OPENROUTER_API_KEY=your-openrouter-api-key
或创建一个
.env
文件:OPENROUTER_API_KEY=your-openrouter-api-key
注意: 您可以从 https://openrouter.ai/ 获取您的 OpenRouter API 密钥
运行示例
1. 启动服务器
uv run --env-file .env a2a-server
- 服务器将在端口 9999 上启动。
验证代理卡片:
2. 运行客户端
在新终端中:
uv venv
source .venv/bin/activate
uv run --env-file .env a2a-client --question "What is A2A protocol?"
- 客户端将连接到服务器并发送请求。
3. 查看响应
- 客户端的响应将保存到 response.xml。
配置
系统使用以下配置:
- 模型: 通过 OpenRouter 使用
google/gemini-flash-1.5
- 基础 URL:
https://openrouter.ai/api/v1
文件结构
src/a2a_mcp_openrouter/server/
:服务器实现。src/a2a_mcp_openrouter/client/
:客户端实现。response.xml
:客户端的示例响应。
故障排除
- 缺少依赖: 确保您已安装
uv
。 - API 密钥错误: 确保
OPENROUTER_API_KEY
设置正确。 - 端口冲突: 确保端口 9999 空闲。
A2A vs MCP:协议相似性和统一方法
通过这个实现,我们发现 A2A (Agent-to-Agent) 和 MCP (Model Context Protocol) 具有显著的架构相似性。两个协议都遵循类似的发现、能力交换和执行模式。
统一实现模式
关键发现:A2A 和 MCP 都遵循相同的底层实现模式:
- 基于 HTTP 的通信:两者都使用 HTTP 进行通信(A2A 使用 REST API,MCP 使用服务器发送事件)
- 提示驱动设计:两者都依赖 LLM 提示来决定调用什么以及如何调用
- 发现机制:两者都提供发现可用能力的方法
- 结构化响应:两者都返回可以程序化处理的结构化数据
查看 mcp.py
实现,我们可以看到:
# 通过 HTTP 进行 MCP 工具发现
async with sse_client(url) as (read, write):
resources = await session.list_tools()
# 为 LLM 决策生成提示
return template.render(tools=resources.tools)
# 通过 HTTP 执行工具调用
return await session.call_tool(tool_name, arguments=arguments)
这在概念上与 A2A 代理调用模式相同 - 发现能力,使用 LLM 决定调用什么,然后执行调用。
A2A 作为通用接口
关键洞察:A2A 可以作为代理间通信和工具调用的统一接口,因为调用模式本质上是相同的:
- A2A → 代理:
客户端 → HTTP → 代理 → LLM 响应
- A2A → 工具:
客户端 → HTTP → 工具包装器 → MCP 工具响应
两种模式都使用:
- HTTP 通信
- 能力发现
- LLM 驱动的决策制定
- 结构化请求/响应格式
这种统一方法的好处
- 单一接口:客户端只需要理解一种调用模式
- 互操作性:在同一工作流中无缝混合代理和工具
- 一致的架构:不同能力类型使用相同的实现模式
- LLM 原生设计:两者都利用 LLM 推理进行智能能力选择
这表明 A2A 和 MCP 不是竞争协议,而是可以在单一接口范式下统一的互补模式。
系统架构和流程
下面是详细的序列图,显示了从客户端输入到最终响应的 A2A 协议的完整流程:
sequenceDiagram
participant User
participant Client as A2A Client
participant LLM_Client as OpenRouter LLM (Client)
participant Server as A2A Server
participant AgentExecutor as Agent Executor
participant Agent as Server Agent
participant LLM_Server as OpenRouter LLM (Server)
participant MCP as MCP Tool
User->>Client: 输入问题:"What is A2A protocol?"
Note over Client: 使用 agent_urls 初始化代理
Client->>Server: GET /agent-card - 发现可用代理
Server-->>Client: 返回具有能力的 AgentCard
Note over Client: 渲染代理提示模板
Client->>LLM_Client: 发送包含问题和可用代理的决策提示
LLM_Client-->>Client: 返回包含选定代理的 JSON
loop 对于每个选定的代理
Client->>Server: POST /send-message-streaming
Server->>AgentExecutor: execute(context, event_queue)
AgentExecutor->>Agent: stream(query)
Agent->>MCP: 获取可用工具
MCP-->>Agent: 返回工具定义
Note over Agent: 渲染工具提示模板
Agent->>LLM_Server: 发送包含问题和工具的决策提示
LLM_Server-->>Agent: 返回包含选定工具的 JSON
loop 对于每个选定的工具(最大迭代次数)
Agent->>MCP: 使用参数调用工具
MCP-->>Agent: 返回工具结果
Note over Agent: 更新 called_tools 历史
Agent->>LLM_Server: 发送包含工具结果的更新提示
LLM_Server-->>Agent: 返回下一个工具或最终答案
alt 需要更多工具
Note over Agent: 继续下一次迭代
else 任务完成
Note over Agent: 任务已完成
end
end
Agent-->>AgentExecutor: 产生流式事件
AgentExecutor-->>Server: 将事件转发到 event_queue
Server-->>Client: 通过 HTTP 流式传输响应块
Client->>Client: 从响应标签中提取答案
Note over Client: 添加到 agent_answers 列表
end
alt 需要最终合成
Client->>LLM_Client: 发送包含所有答案的合成提示
LLM_Client-->>Client: 返回最终合成答案
else 不需要合成
Note over Client: 使用现有答案
end
Client-->>User: 流式传输包含代理输出的最终响应
关键特性
- 代理发现:通过 A2A 协议自动发现可用代理
- LLM 驱动选择:使用 LLM 推理进行智能代理和工具选择
- MCP 集成:与 MCP 工具无缝集成以进行知识检索
- 流式管道:整个管道的实时流式响应
- 迭代处理:具有维护上下文的多迭代工具调用
流程描述
系统遵循以下主要阶段:
客户端阶段:用户输入问题 → 客户端发现代理 → LLM 选择相关代理
服务器阶段:服务器接收请求 → 代理发现工具 → LLM 选择工具 → 工具迭代执行
响应阶段:结果通过管道流回 → 客户端合成最终答案 → 用户接收响应
这种架构展示了 A2A 协议在创建可互操作的 AI 代理方面的强大功能,这些代理可以相互发现并协作,同时利用 MCP 工具访问外部知识源。