news 2026/10/6 8:56:44

深入A2A协议:破解多智能体协作标准化难题

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
深入A2A协议:破解多智能体协作标准化难题

你有没有遇到过这种情况:公司里同时有客服AI、数据分析AI、工单处理AI,每个单拎出来都能干活,但想让它们互相配合,比如客服AI把用户诉求转给工单AI去处理,却只能靠你在中间写胶水代码。我在做多智能体项目时,这个问题被放大得特别明显。直到我认真研究了Google开源的A2A协议,才意识到agent之间协作这件事,本不该这么痛苦。

A2A协议(Agent-to-Agent)是Google于2025年4月发布的开放协议,专门解决AI代理之间的发现、通信和协作问题。和其他把agent接入工具的协议不同,A2A把每个agent都当成可对话的实体,让它能向另一个agent发送任务、接收结果、追问细节。下面我从原理层面拆解A2A的工作方式,适合准备做多agent协作但不想被厂商绑定的开发者,也适合想搞懂agent间通信底层逻辑的技术决策者。

1. 聊天机器人之间为什么还需要一套协议

现在做单个功能Agent已经不难。难的是让多个Agent像团队一样一起工作。举个真实的例子:我用AI做了个日程管理助手,它能读取邮件、识别用户“周五下午开评审会”的意图,然后创建日历事件。这没问题。但我想让另一个Agent去联系参会人、预订会议室,问题就来了——两个Agent都是我自己开发的,我可以让它们直接调用同一个数据库、共享同一个内存表,等于我在它们之间拉了根私线。

1.1 多Agent协作的真实困境

私线一多,就变成了蜘蛛网。假设有三个Agent(A、B、C)需要两两协作,至少得写三条私线;再加一个D,连线变成六条;五个Agent就是十条。每条私线的接口风格、参数语义、错误处理都不同,维护成本指数级上升。更隐蔽的问题是语义不一致:A发一个“query_inventory”,B理解为“库存查询”,C却理解成“库存的单价查询”。没有公共规范,就只能靠人肉对齐。

我当时还试过用企业内部的消息队列(比如Kafka)来做Agent通信。能解决一部分问题,但消息队列本质上是“发布-订阅”模型,Agent之间的对话更像“请求-响应”:我需要向Agent X发起一个任务,等待它的反馈,甚至中途打断它。消息队列的异步拓扑天然不适合这种交互。所以A2A协议出来的时候,我第一反应是:终于有人把“Agent之间的协作语言”标准化了。

1.2 A2A协议想解决的三件事

A2A的官方定位,说起来特别朴素:让不同厂商、不同技术栈的Agent能在一起工作,且不需要提前知道对方的内部实现。拆开看,它主要解决三个问题。

第一是发现。一个Agent怎么知道另一个Agent存在?知道后怎么知道它“会做什么”?A2A用一张标准化的Agent Card对外描述自己的身份和能力,并通过HTTP端点暴露出来,相当于每个Agent在网上挂了一张“电子名片”。

第二是交互。Agent之间不是“调接口”的关系,而是“派活+协作”的关系。A2A定义了Task、Message、Artifact这些通用概念,让Agent能发送任务、接收中间状态、追问细节、取消任务。这套交互模型比单纯的API调用更贴近人类的沟通习惯。

第三是安全与集成。A2A支持OAuth 2.0等主流认证方式,并且定义了在企业环境里如何控权、怎么做审计。这一点对商业化落地很重要——不然你连一个公司内部的Agent都不敢往外放。

顺便补充一个时间线:2025年4月Google发布A2A后,6月就把它捐给了Linux基金会,成立A2A工作组来继续演进。也就是说它现在不是Google自家的私有协议,而是一个社区驱动的开放标准。对做技术选型的人来说,这一点比协议本身还重要——你不会想为一家公司的私有方案投入两年架构。

2. Agent Card:A2A世界的“自我介绍”与角色模型

要理解A2A,我建议先看Agent Card,因为它最直观。它相当于Agent在互联网上的公开资料页,别的Agent拿到这张卡,就能判断“我要不要跟它合作、怎么跟它合作”。

2.1 一张标准化的Agent名片

Agent Card本身是一个JSON文档,放在Agent服务的根路径或者已知路径下,比如/.well-known/agent.json。它最少要包含这些信息:

{ "name": "CalendarAgent", "description": "负责日程管理、会议安排的智能助手", "url": "https://agent.example.com/", "version": "1.0.0", "capabilities": { "streaming": true, "pushNotifications": false }, "security": { "schemes": [ { "type": "oauth2", "description": "使用OAuth 2.0授权码模式" } ] }, "skills": [ { "id": "create_event", "name": "创建日程", "description": "根据用户自然语言创建日历事件" }, { "id": "query_meeting_room", "name": "查询会议室", "description": "检查指定时间点哪些会议室可用" } ] }

注意capabilities字段不是“我能做什么”,而是“我在通信方式上有什么能力”。比如开启了streaming,说明这个Agent支持流式响应,客户端可以先收到零碎结果再拼装;开启了pushNotifications,说明它能主动往你注册的回调地址推任务状态。这两个开关直接决定了客户端用哪种交互方式。

skills列表才是“我会做什么”。里面每一项有一个id和description。客户端拿到这张卡,会先看description,再看具体skill的description,判断任务能不能交给它。这有点像你打开某家公司的官网,先看主营介绍,再看业务条线。

我在自己的项目里测试过,Agent Card对不确定性的贡献很大:以前多个Agent协作时,对方到底能力边界在哪全凭猜,现在有了标准卡,至少可以自动做“能力筛选”。当然,它不能解决“Agent吹牛”的问题——卡上说会修图,实际接过来可能只是滤镜,这是另一个层面的事。

2.2 既分Client/Server,又彼此对等

A2A协议里其实引入了client和server的说法:主动发起协作的Agent是client,接收任务的Agent是server。但这里要特别强调一点:这不是传统意义上的“调用方-被调用方”的不平等关系。因为每个Agent都可以既当client又当server。

比如一个复杂的跨国协作场景:上海公司的金融分析Agent需要新加坡公司的数据Agent给一份财报摘要。前者发起任务,是client;后者接收任务,是server。但如果数据Agent中途发现需要更进一步的信息,比如需要分析Agent确认某个指标的口径,它也可以反过来发起一个任务,角色就互换了。

所以A2A的模式在协议层面是对等的,不像REST API那样严格区分“服务提供者”和“服务消费者”。这种对等性,让A2A更像两个同事之间来回商量,而不是主从指令。我见过有人把A2A理解成“Agent的远程过程调用”,其实不准确——RPC关心的是“执行一个函数”,A2A关心的是“完成一项任务”,后者天然包含了上下文、中间反馈、多轮澄清这些过程。

2.3 传输协议的选择:JSON-RPC 2.0与HTTPS

A2A没有发明新的传输协议,而是直接复用HTTP和JSON-RPC 2.0。这一点我特别欣赏,因为这意味着任何语言、任何框架都能接入,只要你能处理HTTP请求和JSON。

具体来说,Agent必须暴露一个HTTP端点,接受JSON-RPC 2.0格式的方法调用。核心方法大概有这些:

方法作用
initialize建立连接前,客户端用它确认对方的基本信息和协议版本
message向Agent发送一条Message,用于无状态或者对话式的交互
tasks/send下发一个任务,返回任务结果或任务ID
tasks/get根据任务ID查询当前状态
tasks/cancel取消一个正在执行或等待中任务
tasks/resubscribe重新订阅某个任务的状态变更

用JSON-RPC而不是自定义协议,还有个附带好处:生态成熟,很多语言都有现成SDK,不需要自己造轮子。传输层用HTTPS,既保证了基本加密,又为身份认证留下了扩展空间。安全性上A2A没有自己做一套,而是复用OAuth 2.0这些企业里已经跑通的方案——老老实实站在巨人的肩膀上。

3. 任务生命周期:A2A协作的核心状态机

如果你只记一点A2A的知识,我建议记住Task(任务)这个概念。它是A2A里最核心的抽象,理解了任务生命周期,就理解了整个协议的运转方式。

3.1 Task是协作的“经办单”

你可以把Task想象成公司里的“经办单”:一个任务进来,有一个编号,有负责人,有当前状态。无论任务被分给谁,这个编号全程不变,双方靠它对齐进度。

A2A定义了Task的几个状态:

状态含义
submitted任务已提交,对方已收到,尚未开始处理
working任务正在执行中
input-required需要更多信息,等待发起方补充
completed任务成功完成
failed任务执行失败
canceled任务被发起方取消
awaiting-execution任务已排队,但还没轮到自己执行(如果目标Agent有并发控制)

状态流转的直观路径是submitted -> working -> completed,失败则走working -> failed,需要补充信息时走input-required,这时候client可以再发一条带补充信息的请求,让它回到working。

这里有个设计上的细节:input-required很重要,但很多Agent框架都忽略它。我在自己项目里发现,大部分Agent协作失败,不是因为技术问题,而是因为对方需要澄清用户意图,但发起方直接当成死任务挂了。A2A把“追问”显式建模成状态,等于是在协议层面承认了“Agent之间可以对话,而不只是递交”。

3.2 Message、Part与Artifact的关系

Task之外,A2A还有几个容易混淆的概念:Message、Part和Artifact。

Message是Agent之间往来的具体内容,可以类比微信里的一条消息。每条Message由若干个Part组成,Part可以是一段文本、一张图片、一份PDF文件,甚至是一段结构化JSON。这个设计的好处很直接:一条任务请求里,既要写“请分析这份财报”,又要附上财报PDF,文本在Part1,文件在Part2,一起放进Message。

Artifact则完全不同,它是Task执行过程中产生的结果“物”。比如分析Agent完成财报解读,产出一份“财报解读报告”,这就是Artifact。区别在于:Message是沟通过程中的对话内容,Artifact是协作成果的产出物。所以Task最终会关联一个或多个Artifact,而Message只是过程中的数据交换载体。

我把这几个概念用一个例子串起来:我是主Agent,向某个报表Agent发了一个Task,内容为“生成第一季度销售汇总”。这条请求是一个Message,其中Part1是指令文本,Part2是原始销售数据文件。报表Agent开始工作,期间发回一条Message说“原始文件中包含缺失值,是否用均值补全”,这是Message,不是Artifact。我回复“可以,并标注缺项”,它继续运行,最终返回一个Excel文件,这个Excel才是Artifact。

3.3 同步、轮询、推送与SSE:四种交互姿势

A2A在设计上很聪明的一点,是它不强迫所有Agent用同一种交互方式,而是提供了四种模式,通信双方根据能力协商选择。

先说同步。所谓同步,是指调用方发出tasks/send后,对方在同一个HTTP响应里直接返回最终结果。这种方式适合短任务,比如“把英文翻译成中文”,几秒内能出结果,没必要搞异步。

但现实里很多Agent任务耗时长,比如“爬取100个网页并生成摘要”。这时同步等待会让客户端长时间挂起,于是一般用异步:tasks/send先返回任务ID和当前状态(比如submitted),客户端隔一段时间再调用tasks/get查询进度。这就是轮询。

轮询虽然实现简单,但效率不高,频繁查空转还浪费HTTP请求。所以A2A支持推送:如果server的Agent Card里声明了pushNotifications: true,client可以提供一个回调URL,server在任务状态变化时主动POST一个状态更新过去。屋里有人说这像webhook,确实就是同一个思路。

第四种是流式输出,对应的是streaming能力。服务端通过SSE(Server-Sent Events)向客户端持续推送中间结果。比如一个AI创作Agent开始写文章,你可以看到它一个字一个字往外蹦,而不是等整篇生成完才一次性返回。对用户体感来说,流式输出明显比“干等5秒然后一次性弹出一大篇”友好得多。

我在实际项目里的建议是:短任务直接同步,长任务优先让server开SSE流式,不具备条件就退化为轮询。推送通知适合内部系统间协作,因为需要双方都有公网回调能力,本地开发环境下配置起来会比较麻烦。

4. A2A与MCP的分工:一个管队友,一个管工具

聊A2A的人,几乎一定会聊到MCP。因为这两个协议听起来都跟Agent生态有关,而且名字都带“C/P”,容易混。我在社区的问答里也见过不少“是不是有了MCP就不需要A2A了”的问题。我的回答是:它们解决的不是同一个问题,非但不冲突,反而应该配合使用。

4.1 MCP解决的是Agent到工具的最后一公里

MCP(Model Context Protocol)最初由Anthropic提出,后来Google、OpenAI等也陆续加入生态。它要解决的问题是:怎么让LLM统一地调用外部工具和数据源。

没有MCP之前,你要让AI的行为依赖一个数据库查询,得专门给它写一个工具函数,让模型自己决定何时调用。每个工具一套写法,每接一个新数据源就要写新代码。MCP把这些“AI与外部世界交互”的动作标准化了:模型通过MCP client,去连接一个个MCP server,每个server封装了一组工具或数据资源。

可以粗暴地理解:MCP解决的是“Agent如何拿到信息和执行动作”,它让Agent有了用工具的双手。A2A解决的是“Agent如何和别的Agent合作”,它让Agent有了能对话的队友。一个是纵向的“Agent-工具”通道,一个是横向的“Agent-Agent”通道。

4.2 A2A解决的是Agent到Agent的横向协作

A2A的设计场景,是两个独立Agent之间的协作。它们可能运行在不同公司、不同云厂商、不同技术栈上,不可能共享内部数据模型。A2A为这种场景定义了一套大家都认的“商务沟通规则”:你投递任务,我反馈进度,产出Artifact,中间还可以追问。

MCP继承不了这种职责。你可以想象,如果A2A只提供工具调用,那就意味着每个Agent都要知道“另一个Agent有哪些内部方法”。这正好违反了解耦原则,而且一旦另一个Agent内部改了方法名,所有协作方一起挂。有了A2A的任务级抽象,协作双方只需要知道“对方能完成什么任务”以及“输入输出格式是什么”,不需要理解对方内部架构。

所以,一个Agent内部可以用MCP去访问数据库、文档、API;对外则用A2A跟另一个Agent互通。两层协议管的事情不同,不存在谁取代谁。

4.3 实际项目中的组合架构

我在自己搭的一个多Agent系统里,就是这样组合的。以“用户让客服Agent预约会议室”为例,完整链路是:

  1. 用户对客服Agent说:“帮我预约周五下午的会议室。”
  2. 客服Agent先用MCP调用会议室查询工具,拿到可用会议室列表。
  3. 客服Agent发现涉及跨团队的日程同步,于是用A2A向日历Agent发一个Task,内容为“创建会议室预约事件,参会人包括市场部四人”。
  4. 日历Agent内部通过MCP调用企业的日历API,创建事件。
  5. 日历Agent通过A2A返回任务状态和最终的日历event作为Artifact。
  6. 客服Agent拿到结果后,用MCP调用邮件工具通知参会人。

整个过程里,A2A管的是客服Agent和日历Agent之间的横向协作,MCP管的是各自内部的纵向工具调用。两层各司其职,逻辑很清晰。对这种组合架构,我的体会是:不要试图让一个Agent直接调用另一个Agent的MCP工具,否则耦合会非常深,一旦对方内部工具升级,你的调用就废了。通过A2A的任务边界,把耦合切断在“任务”这一层,是最稳的。

5. 动手把一个Agent暴露成A2A服务:流程与踩坑

原理讲完,说点实操。如果你想把自己手头的Agent接入A2A生态,最直接的做法是写一个A2AServer适配层。下面是我验证过的最小路径和几个值得注意的坑。

5.1 最小实现需要准备哪些东西

实现一个能被其他Agent调用的A2A服务,从最小规模看,你只需要做三件事:一份Agent Card、一个接收JSON-RPC请求的HTTP端点、一套任务状态管理逻辑。

Agent Card可以直接放在Agent服务的根目录下,路径固定为/.well-known/agent.json。HTTP端点负责路由各个JSON-RPC方法,最核心的是tasks/send、tasks/get、message。任务状态管理则是在服务端维护一张任务表,记录每个任务ID对应的状态、输入Message、输出Artifact。

用官方社区提供的A2ASDK来搭的话,代码骨架大致是这样(不同版本API可能会有微调,核心流程是一样的):

from a2a.sdk import A2AServer, A2AServerConfig from a2a.types import Task, Message, TaskState def handle_send_task(task): # 保存任务,返回 task_id 和状态 ... server = A2AServer( config=A2AServerConfig( host="0.0.0.0", port=8080, agent_card_path="./agent.json" ), task_handler=handle_send_task ) server.run()

写这段代码不是为了让你照抄,而是想说明:接入A2A时,大部分协议细节都被SDK封装掉了,你需要关心的只是两件事——把Agent的能力如实写进Agent Card,以及提供一个将Task映射到你实际业务逻辑的handler。

如果你的Agent已经有了HTTP服务(比如一个FastAPI应用),也不一定要引入新SDK,最原始的方式是自己实现那几个JSON-RPC方法,本质上就是解析POST请求体里的method和params,然后返回对应结果。SDK只是帮你把反序列化、协议细节、错误码统一处理了。

5.2 最简单的验证方法:先给Agent发一条任务

接入完成后,验证客户端是否能发现和调用,可以用两条命令。

先用curl看Agent Card是否正常返回:

curl https://your-agent.example.com/.well-known/agent.json

如果能看到完整的JSON文档,说明发现机制没问题。然后用A2A client模拟另一个Agent发送任务:

curl -X POST https://your-agent.example.com/ \ -H 'Content-Type: application/json' \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "tasks/send", "params": { "task": { "message": [ { "role": "user", "parts": [ {"text": "帮我生成一份季度销售简报"} ] } ] } } }'

如果配置得当,你会收到一个包含taskId的响应,后续可以轮询tasks/get来查看状态,直到出现completed并且携带Artifact。这一步跑通,意味着一个最小A2A协作闭环已经建立。

我强烈建议,在做多Agent编排之前,先单独把每个Agent用这种方式验证一遍。因为多Agent链路一旦出现问题,排查成本是叠加的:你先要知道A到底有没有把任务发给B,B有没有正确处理,C有没有收到结果。单点验证能先消灭一半的变量。

5.3 我在集成A2A时踩过的几个坑

坑一:Agent Card里的capabilities声明和实际行为不一致。最常见的是我声明了streaming: true,但后端的SSE实现只发了最终结果,没发中间事件。客户端在复杂场景下会认为连接异常,直接报错。反过来,如果声明支持pushNotifications却没有实现回调推送,对方等待推送更新就会一直卡着。所以,Agent Card上的能力声明一定要和实际行为对齐,宁可保守,不要夸大。

坑二:任务状态机的分支处理不完整。很多初版实现只处理了working -> completed这条happy path,遇到需要澄清的场景就直接返回failed了。这其实是把责任推给了发起方。对方收到failed根本不知道是哪里失败,也没法继续沟通。要真正发挥A2A的价值,至少在业务可能出现歧义的地方,实现input-required状态,并返回一个“需要补充哪些信息”的说明Message。

坑三:异步长任务的超时和幂等。如果你用轮询方式,client侧一定要实现合理的退避策略,不要每秒猛打tasks/get。server侧要为同一任务的重复请求做幂等处理,尤其当task ID由client生成时,避免同一个任务被重复执行两次。我遇到过隔壁团队任务并发控制没做好,同一份报告被Agent自动生成三遍,时间和费用都浪费了。

坑四:本地开发环境的webhook回环。pushNotifications依赖server主动回调client,本地开发时如果两端都在自己的笔记本电脑上,回调URL会变成类似http://localhost:9000/callback的地址,对方根本访问不到。遇到这种场景,要么用内网穿透工具把本地回调地址暴露出去,要么直接退回轮询模式。对于只想在本地验证协议逻辑的团队,轮询是最省事的选择。

整体来说,A2A从协议设计上并不复杂,复杂的是真实业务里的状态混乱和安全边界。但有了标准状态机和Agent Card,至少不同团队不用再为“你们家Agent的创建任务接口传什么参数”开半天对齐会议了。

最后分享一个我自己的体会:A2A目前还在快速演进期,官方工作组每个季度都在更新规范,所以不要急着把所有Agent都重构成A2A。先挑出一两个跨团队的协作场景试点,跑通全链路和异常处理,积累经验后再铺开,比一口气全量接入要稳得多。如果你正在做多Agent系统,我建议你现在就把Agent Card的能力清单整理出来——这一步无论将来用不用A2A,都会让你的系统边界清晰很多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/6 8:56:41

无模型自适应控制MFAC六个MATLAB仿真案例详解

做控制的同学应该都有这种经历:拿到一个非线性强、耦合严重、甚至带时滞的对象,PID调到心累,模型辨识又建不准,辛辛苦苦整定的参数换一个工况就全线崩溃。我当年做课题的时候也被这个问题卡了很久,后来接触到MFAC&…

作者头像 李华
网站建设 2026/10/6 8:56:40

pgvector+PostgreSQL构建RAG知识库实战指南

如果你手头已经跑着一套 PostgreSQL,又想做语义搜索、搭一个 RAG 知识库,但不想为了向量检索再引三套中间件,那 pgvector 几乎是绕不开的选择。它是 PostgreSQL 官方的向量检索扩展,直接把 embedding 存进数据库,用 SQ…

作者头像 李华
网站建设 2026/10/6 8:56:40

剑侠情缘源码技术拆解:地图编辑器与老RPG架构解析

说实话,看到【180609】剑侠情缘_整套源码地图编辑器(单机学习例子)这个打包名的时候,我第一反应是有点感慨。这类资源在老玩家的硬盘里其实很常见,一个压缩包把代码、工具、资源一股脑塞进去,标注成“学习例子”。但真正能静下心来…

作者头像 李华
网站建设 2026/10/6 8:56:07

云和恩墨与YashanDB联手:国产数据库一体机的技术落地与选型指南

这消息刚在圈子里传开时,我手机上的DBA群就热闹了一阵。有人问云和恩墨和YashanDB搭伙做国产数据库一体机,到底图什么;也有人在讨论这种组合和过去那些“服务器厂商贴个数据库标签”的一体机有什么区别。我的第一反应倒不是参数和跑分&#x…

作者头像 李华
网站建设 2026/10/6 8:54:50

区域地下水位预测实战:GCN-LSTM 多井时空建模与避坑指南

简介:这份资源面向环境科学专业学生、水务工程技术人员及相关领域研究人员,提供一套融合图卷积网络与长短期记忆网络的区域级多井地下水位时空预测方案,用于解决多井空间分布差异大、水位关联性强条件下的同步预测难题。压缩包内共1个PDF文件…

作者头像 李华
网站建设 2026/10/6 8:54:00

openGauss 2025前瞻:AI原生、存储过程与生态迁移的破局之路

1. 数智时代的数据库"分水岭":为什么所有人都在等这场发布 数据库选型这件事,我最近半年被问到最多的一个问题是:openGauss到底能不能扛核心系统?问的人里有做金融的、做政务的、做能源的,也有互联网公司想省…

作者头像 李华