前阵子有知识星球成员私信,想要我介绍下 Google 发布的 A2A 是啥?
我在具体研究 A2A 之前,刷到过几个视频号的博主介绍 A2A时说 A2A 完全是多此一举,现有的 MCP(大模型上下文协议 )可以直接实现 agent 之间的标准化交互功能。
但初步测试下来发现,A2A并非这么简单。
这篇试图说清楚 A2A 的核心定义是啥, 其与 MCP 的主要区别,以及 A2A 官方 Demo 复现讲解。
以下,enjoy:
1、A2A 到底是啥
这部分内容主要从公开信息整理而来,但当涉猎即可,看不下去的 feel free 划到下一章节查看表格形式的与 MCP 核心特性对比。
根据 Google 的官方介绍,A2A (Agent-to-Agent) 是其和超过 50 家技术合作伙伴(如 Langchain, Salesforce, SAP 等)共同推出并支持的开放协议,核心目标是为 AI Agents 提供一个标准的通信方式,使它们能够:
1.1互相发现和识别
通过“Agent Card”(一种 JSON 格式的文件,包含 Agent 的 ID、名称、能力、版本、安全需求等信息),一个 Agent 可以找到并了解其他 Agent 的能力。
复制======= Agent Card ======== {"name":"Parse and Chat","description":"Parses a file and then chats with a user using the parsed content as context.","url":"http://localhost:10010/","version":"1.0.0","capabilities":{"streaming":true,"pushNotifications":true,"stateTransitionHistory":false},"defaultInputModes":["text","text/plain"],"defaultOutputModes":["text","text/plain"],"skills":[{"id":"parse_and_chat","name":"Parse and Chat","description":"Parses a file and then chats with a user using the parsed content as context.","tags":["parse","chat","file","llama_parse"],"examples":["What does this file talk about?"]}]} ========= starting a new task ========
这个被 ======= Agent Card ======== 包裹的 JSON 对象就是官方Demo中LlamaIndex Agent 的 Agent Card示例。里面包含了:
复制name: "Parse and Chat" description: Agent 功能描述 url: Agent 的访问地址 version: 版本号 capabilities: 支持的能力(流式、推送通知等) defaultInputModes / defaultOutputModes: 支持的默认输入输出格式 skills: Agent 拥有的技能列表,每个技能有 ID、名称、描述、标签和示例。
1.2安全地交换信息
协议设计考虑了安全性,确保 Agent 之间交互的可靠性。
复制{ "jsonrpc": "2.0", "id": 11, // 请求 ID "method": "tasks/send", // A2A 方法 "params": { // 方法参数 "id": "129", // 任务 ID "sessionId": "8f01f3d172cd4396a0e535ae8aec6687", // 会话 ID "acceptedOutputModes": [ "text" ], "message": { // 用户消息 "role": "user", "parts": [ // 消息内容部分 { "type": "text", "text": "How much is the exchange rate for 1 USD to INR?" } ] } } }
Input - 发送给 Agent 服务器的请求示例
复制// 第一个流式更新 (中间状态) data: {"jsonrpc":"2.0","id":12,"result":{"id":"131","status":{"state":"working","message":{"role":"agent","parts":[{"type":"text","text":"Looking up the exchange rates..."}]},"timestamp":"2025-04-02T16:59:34.578939"},"final":false}} // 第二个流式更新 (中间状态) data: {"jsonrpc":"2.0","id":12,"result":{"id":"131","status":{"state":"working","message":{"role":"agent","parts":[{"type":"text","text":"Processing the exchange rates.."}]},"timestamp":"2025-04-02T16:59:34.737052"},"final":false}} // 第三个流式更新 (推送结果片段) data: {"jsonrpc":"2.0","id":12,"result":{"id":"131","artifact":{"parts":[{"type":"text","text":"Based on the current exchange rate, 1 USD is equivalent to 0.77252 GBP. Therefore, 100 USD would be approximately 77.252 GBP."}],"index":0,"append":false}}} // 注意这里是 artifact // 第四个流式更新 (最终状态) data: {"jsonrpc":"2.0","id":12,"result":{"id":"131","status":{"state":"completed","timestamp":"2025-04-02T16:59:35.331844"},"final":true}}
流式通知示例
1.3协调行动
跨越不同的工具、服务和企业系统进行协作,完成更复杂的任务。
例如与LangGraph 货币兑换 Agent 交互时,这个 Agent 会调用外部的汇率 API 来获取实时汇率。
2、A2A 与 MCP 的核心区别所在
2.1主要特性对比
下面通过一个表格给各位简要的梳理下二者间的核心特性差别:
特性 | A2A | MCP |
核心目标 | 标准化 Agent 之间的通信和协作 | 标准化 Agent/应用与外部工具/数据源之间的上下文交互 |
交互层面 | Agent ↔ Agent (水平集成) | Agent/应用 ↔ 工具/数据源 (垂直集成) |
解决问题 | 如何让不同来源、不同框架的 Agent 互相发现、对话、委托任务、协调工作流? | 如何让一个 Agent/LLM 标准化、安全、高效地调用外部 API、访问数据库、获取实时数据等“工具”? |
通信内容 | 任务指令、状态更新、协作请求、结果工件、上下文共享、协商 | 传递给模型的结构化上下文、工具列表、工具调用请求、工具执行结果 |
设想类比 | Agent 之间的内部消息总线或协作框架 | AI 应用连接外部工具的“USB-C”接口 |
主要发起者 | Anthropic | |
典型场景 | 多 Agent 系统、复杂工作流自动化、跨平台协作 | 单个 Agent 需要调用多种外部工具、增强 LLM 的上下文理解和执行能力 |
简单来说:
MCP 关注的是 Agent 如何使用工具 (Agent-to-Tool/Context)。它让 Agent 更方便地连接和使用各种外部资源(如 API、数据库)。
A2A 关注的是 Agent 如何互相合作 (Agent-to-Agent)。它让不同的 Agent 能够像一个团队一样协同工作
2.2A2A 相对 MCP 是否画蛇添足
在给出这个问题答案之前,我们先来梳理下网上所谓的 MCP 实现 A2A 核心功能的主要逻辑所在。
MCP 如何实现 A2A 核心功能
封装 Agent B 为 API/Tool:
复制将 Agent B 的核心功能(例如,特定的 RAG 检索能力、数据分析能力、API 调用能力等)封装在一个或多个 API 端点后面。 例如,创建一个 REST API,其中 /queryKnowledgeBase 端点接收查询并返回 RAG 结果,/analyzeData 端点接收数据并返回分析报告。 这个 API 就成为了 Agent B 对外提供服务的接口。
为 API/Tool 创建 MCP 描述:
复制为 Agent B 的 API 创建一个符合 MCP 规范的描述文件(使用 OpenAPI Specification)。这个描述文件需要清晰地说明: 工具的名称和描述(告诉 Agent A 这是什么工具,能做什么)。 可用的函数/端点(如 /queryKnowledgeBase)。 每个函数所需的输入参数(名称、类型、描述、是否必需)。 函数预期的输出格式(结构化的数据模式)。 可能的认证或安全要求。
Agent A 通过 MCP 调用 Agent B:
复制Agent A(通常是一个基于 LLM 的 Agent)在其上下文中“看到”了 Agent B 这个工具及其描述。 当 Agent A 的 LLM 判断需要 Agent B 的能力来完成当前任务时,它会生成一个符合 MCP 规范的“工具调用”(Tool Call)请求。 这个请求包含了要调用的 Agent B 的函数名(如 /queryKnowledgeBase)以及所需的输入参数(如用户的查询)。 Agent A 的执行环境(或 MCP 处理器)接收到这个工具调用请求,实际调用 Agent B 的 API 端点。 Agent B 的 API 执行其内部逻辑(调用自己的 RAG 流程、分析数据等)。 Agent B 将执行结果按照 MCP 描述中定义的输出格式返回。 Agent A 的执行环境接收到结果,并将其格式化为“工具结果”(Tool Result),反馈给 Agent A 的 LLM。 Agent A 的 LLM 结合这个工具结果,继续处理任务或生成最终响应。
这种“MCP + Agent as Tool”的方式,实测确实可以实现基本的 Agent 任务委托和信息交换,尤其适用于相对简单、明确的请求-响应式交互。
注:这部分大家可以参考我之前的文章,使用 Dify 的自定义 Tool 功能模拟 MCP 实现 Agent 协作,这里就不做赘述。
Dify+RAGFLow:基于占位符的图片问答升级方案(最佳实践)
However,虽然可以将 Agent 视为 MCP 工具来实现部分 A2A 功能,但这更多是一种“模拟”,实际不能充分发挥多 Agent 系统协作的潜力,也缺乏 A2A 提供的标准化协作框架。
当然,选择哪种方式取决于各位具体应用场景的复杂度和对 Agent 间交互深度的要求。
3、A2A 官方 Demo 复现与讲解
光说不练假把式,我们来使用 A2A 的 Github 官方实例来给大家做一个具体的复现讲解。
建议感兴趣的一定要实际上手操作下,再结合下方的日志解析应该可以对 A2A 有更加完整的理解。
3.1官方示例的选择
复制git clone https://github.com/google/A2A.git
先把 A2A 的官方仓库下载到本地,我们可以发现官方提供了多个 demo(以 python 为例)供选择测试,这里先分析下其中主要几个 demo 的内容和差别。
Google ADK (google_adk)
内容: 模拟一个填写费用报销单的 Agent。
主要特性:
使用 Google 的 Agent Development Kit (ADK) 构建。
展示多轮交互:当用户提供的信息不完整时,Agent 会要求补充。
核心亮点: 演示如何通过 A2A 返回 Web 表单给客户端(或用户)填写,并在客户端提交表单后继续处理任务。
LangGraph (langgraph)
内容: 一个可以进行货币兑换查询的 Agent。
主要特性:
使用 LangGraph 框架和 ReAct 模式构建。
展示多轮交互:例如,询问需要兑换的目标货币。
核心亮点: 演示 Agent 如何使用外部工具(调用 Frankfurter API 获取汇率)以及如何通过 A2A 流式传输状态更新(例如,“正在查询汇率...”)。
CrewAI (crewai)
内容: 一个可以生成图像的 Agent。
主要特性:
使用 CrewAI 框架构建。
展示多轮交互。
核心亮点: 演示如何通过 A2A 发送图像数据作为任务结果。
LlamaIndex File Chat (llama_index_file_chat)
内容: 一个可以接收用户上传的文件,解析文件内容,然后根据文件内容与用户进行问答的 Agent。
主要特性:
使用 LlamaIndex Workflows 构建。
展示多轮交互:在同一会话中基于文件内容进行连续问答。
核心亮点: 演示通过 A2A 处理文件上传(用户将文件附加到请求中)、文件解析(使用 LlamaParse),以及流式传输状态更新和带引用的结果(回答中会标注信息来源是文件的哪部分)。
示例 | 主要功能 | 核心 A2A 特性展示 | 使用框架 | 相对复杂度 |
Google ADK | 费用报销 (模拟) | Web 表单交互 | Google ADK | 中等 |
LangGraph | 货币兑换 | 工具使用 (API 调用), 流式状态更新 | LangGraph | 较低 |
CrewAI | 图像生成 | 图像数据传输 | CrewAI | 中等 |
LlamaIndex File Chat | 文件问答 | 文件上传与解析, 流式更新, 引用 | LlamaIndex Workflows | 较高 |
经过初步测试,建议各位还是从 LangGraph (langgraph) 示例开始实践,理解了 LangGraph 示例后,可以再尝试其他示例,例如 ADK 示例来理解 Web 表单交互,或者 LlamaIndex 示例来理解文件处理。
3.2LangGraph 的配置
1. 导航至demo目录: ```bash cd samples/python/agents/langgraph ``` 2. 创建虚拟环境并配置Google_API_Key: ```bash echo "GOOGLE_API_KEY=your_api_key_here" > .env ``` 3. 运行agent服务器: ```bash # Basic run on default port 10000 uv run . # On custom host/port uv run . --host 0.0.0.0 --port 8080 ``` 4. 另起一个单独的终端, 运行A2A客户端: ```bash cd samples/python/hosts/cli uv run . ```
3.3测试目的与示例场景
测试目的
A2A 协议集成: 确保 Agent 可以正确地通过 A2A 协议接收任务请求 (tasks/send, tasks/sendSubscribe) 并返回符合协议规范的响应。
多轮对话能力: 测试 Agent 在信息不充分时,能否主动向用户请求额外信息(例如,只问了“1 美元换多少?”,Agent 会反问“换成哪种货币?”),并能利用后续用户提供的信息完成任务。
流式响应 (Streaming): 测试 Agent 在处理耗时任务时,能否通过 A2A 协议实时发送中间状态更新(例如,“正在查找汇率...”,“正在处理...”),而不是让客户端一直等待最终结果。
工具使用 (Tool Usage): 测试基于 ReAct 模式的 LangGraph Agent 能否在需要时正确调用外部工具(这里是 Frankfurter API)来获取实时汇率数据。
会话管理 (Conversational Memory): 测试 Agent 能否在同一会话 (sessionId) 的多次交互中保持上下文记忆。
示例场景
简单同步请求: 发送一个包含所有必要信息的请求,期望直接得到最终结果。
例子: "1 美元兑换多少印度卢比?" (How much is the exchange rate for 1 USD to INR?)
需要补充信息的多轮请求: 发送一个信息不完整的请求,测试 Agent 是否会要求补充信息,以及在收到补充信息后能否给出结果。
用户: "1 美元能换多少?" (How much is the exchange rate for 1 USD?)
Agent: "你想换成哪种货币?" (Which currency do you want to convert to? )
用户: "加元" (CAD)
Agent: (返回 1 美元兑换加元的汇率)
流式请求: 发送一个订阅任务的请求 (tasks/sendSubscribe),测试服务器是否会逐步推送状态更新和最终结果。
例子: "100 美元兑换多少英镑?" (How much is 100 USD in GBP?),期望收到类似 "正在查找汇率...", "正在处理...", 然后是最终结果的消息流。
针对一次提问 ("How much is 100 USD in GBP?"),客户端收到了三个以 stream event => 开头的独立消息。这就是流式输出的核心——服务器不是一次性返回最终结果,而是分多次推送信息。
3.4日志解析
客户端日志
samples/python/hosts/cli 目录下的日志,这是最直接展示 A2A 交互的地方。
发起请求: 当在 CLI 中输入问题(例如 "What is exchange rate between USD and GBP?"),CLI 工具会构建一个符合 A2A tasks/sendSubscribe 或 tasks/send 规范的 JSON RPC 请求,并通过 HTTP POST 发送给 Agent 服务器 (http://localhost:10000)。虽然日志没有显示发出的请求原文,但后续的响应证明了请求的发送 ( http://localhost:10000)。虽然日志没有显示发出的请求原文,但后续的响应证明了请求的发送 )。
接收响应 (流式事件): 日志中的 stream event => {...} 行就是 Agent 服务器按照 A2A 协议返回给 CLI 客户端的实时响应。这些 JSON 数据结构完全遵循 A2A 规范:
复制jsonrpc: "2.0": 表明使用 JSON RPC 协议。 id: 对应请求的 ID。 result.id: A2A 任务的 ID。 result.status.state: 显示任务状态,如 working (处理中), input-required (需要输入), completed (已完成)。这是 A2A 定义的标准状态。 result.status.message: 当状态是 working 或 input-required 时,这里包含 Agent 发来的中间消息或提问。 result.artifact: 当任务完成时,这里包含最终的结果。 final: false / true: 表明这个事件是否是该次请求的最终响应。false 代表后面还有更新,true 代表结束。
多轮交互体现: 当问 "How much is the exchange rate for 1 USD?" 时,收到的事件中 result.status.state 变为 input-required,并且 result.status.message 包含了 Agent 的提问 "What currency do you want to convert to?..."。随后再输入 "CAD",CLI 再次发送 A2A 请求,Agent 处理后返回最终结果。这清晰地展示了 A2A 对多轮对话的支持。
Agent 服务器日志
samples/python/agents/langgraph 目录下的日志,这份日志展示了 Agent 服务器内部处理 A2A 请求的过程。
接收请求: INFO: 127.0.0.1:xxxxx - "POST / HTTP/1.1" 200 OK 表明服务器收到了来自 CLI 客户端的 HTTP POST 请求 (这是承载 A2A 消息的方式)。
任务管理: INFO:common.server.task_manager:Upserting task ... 和 Getting task ... 显示服务器内部对 A2A 任务状态的管理。
调用外部工具: INFO:httpx:HTTP Request: GET https://api.frankfurter.app/ ( https://api.frankfurter.app/ )... 显示 Agent 为了回答问题,调用了外部的汇率 API。这是 Agent 内部逻辑的一部分,由 A2A 请求触发。
准备响应: 虽然日志没有直接显示服务器发送的 JSON 响应,但服务器的处理逻辑(调用 API、生成文本)最终会
构建成您在客户端日志中看到的 stream event 内容,然后发送回客户端。
Agent 发现: INFO: 127.0.0.1:xxxxx - "GET /.well-known/agent.json HTTP/1.1" 200 OK 是 CLI 客户端启动时,根据 A2A 规范去获取 Agent 能力描述文件的记录。
4、MCP 如何与 A2A 协同
注:这部分内容由 LLM 协助编写
一个复杂的企业 RAG 系统,不仅仅是一个单一的问答机器人,而是一个由多个专业 agents 组成的协作网络:
MCP 的角色(垂直整合 - Agent 与工具/数据):
核心 RAG Agent: 每个负责特定领域(如 HR、财务、产品技术文档)的 RAG Agent,内部会使用 MCP 来标准化地调用其核心工具:
复制连接并查询**向量数据库**以检索相关文档片段。 访问**结构化数据库**(如 SQL 数据库)以获取精确数据。 调用**内部 API**(例如,查询用户权限、获取实时库存状态)。 MCP 在这里确保了每个 RAG Agent 能够高效、可靠地利用其所需的底层数据源和功能 API,就像给 Agent 插上了标准化的“眼睛”和“手臂”去感知和操作数据。
**A2A 的角色(水平协作 - Agent 与 Agent):
用户交互与路由 Agent: 用户首先接触的是一个前端交互 Agent。该 Agent 理解用户意图后,利用 A2A 协议的发现机制找到最合适的下游专业 Agent。
任务委托与编排: 路由 Agent 通过 A2A 向选定的专业 RAG Agent(如 HR Agent 或 技术文档 Agent)提交一个标准的 Task。如果任务复杂,需要跨领域知识(例如,“查询新员工入职的技术设备配置流程和预算标准”),路由 Agent(或一个专门的编排 Agent)可以通过 A2A 协调技术文档 Agent 和财务 Agent,管理各自子任务的状态,最终汇总结果。A2A 的任务生命周期管理在此场景下至关重要。
多轮澄清与协作: 如果专业 RAG Agent 在处理任务时发现信息不足,可以通过 A2A 向路由 Agent(进而传递给用户)发送需要输入 (Needs Input) 的状态和澄清消息,进行多轮交互,而不是简单地失败或返回模糊答案。
主动知识更新与同步: 一个监控 Agent 可以监测外部信息源(如法规更新网站、内部知识库变更),发现重要更新后,通过 A2A 通知相关的 RAG Agent 进行知识库更新(如重新索引)或触发内容摘要任务。
5、写在最后
总结来说,与侧重于标准化 Agent/LLM 与外部工具/数据源交互的 MCP 相比,A2A 并非画蛇添足。虽然通过将 Agent 封装为 API 并使用 MCP 的“工具调用”模式,但缺乏 A2A 在任务生命周期管理、丰富消息传递、流式状态更新和标准化协作原语方面的深度和灵活性。
A2A 刚推出不久,在实际生产场景中具体可以发挥多大的作用还有待各位一起探索,我计划后续分享的项目实操案例中,会适当加入 A2A 的相关方法。Anyway,从实践中来,到实践中去。