☰
A2A协议从入门到实践:多智能体协作的标准通信指南
2026/9/30 12:07:23 网站建设 项目流程

最近总有朋友问我:"A2A协议到底是个啥?网上资料怎么全是英文?"说实话,我接触A2A协议也有一段时间了,从最初对着官方文档一头雾水,到现在能在项目里把多个Agent串起来干活,中间踩过的坑不算少。这个协议虽然挂着"小白友好"的旗号,但真要学起来,如果没找对路径,很容易被一堆术语劝退。

这篇文章就从一个学习者的角度,把我自己的学习路线、踩坑经验、以及动手实践的关键步骤都拆开揉碎讲一遍。我不会堆概念,只讲怎么从零开始把A2A协议跑起来,并真正理解它到底解决了什么问题。不管是刚入门的技术爱好者,还是已经在做Agent开发的工程师,按这条路线走,至少能省下一两个月瞎摸索的时间。

1. 堆概念之前,先搞懂A2A到底在解决什么问题

1.1 从一个"A"到多个"A":智能体协作的现实困境

如果你做过AI应用开发,应该能感受到一个趋势:2024年到2025年,行业里突然从"单机版智能体"转向了"多智能体协作"。单机版是什么概念?就是一个Agent自己调用工具、自己读文档、自己完成任务。但现实世界里,很多任务根本不是单一Agent能搞定的。举个例子,你让一个"旅行规划Agent"帮你安排出差,它需要查天气、订机票、订酒店、看日程冲突,这些能力可能分散在不同团队、不同系统里。如果让一个Agent全包,要么它的上下文窗口爆炸,要么它对于专业系统的调用权限不够。

这时候最自然的想法是:让擅长不同领域的Agent各干各的,互相通信。但问题来了,市面上Agent框架五花八门,Autogen、LangChain、CrewAI,你用你的我用我的,彼此之间怎么通信?总不能每个框架都写一套适配代码吧。A2A协议就是Google在2025年4月牵头搞的一个开放协议,目标非常朴素:让不同厂商、不同框架的Agent能够像人和人发邮件一样,标准、互通地完成协作。后来这个项目捐给了Linux基金会,成了真正的开放标准。

1.2 A2A和MCP的分工:别再把它们搞混了

几乎所有刚开始学A2A的人,第一个问题都是:"它和MCP有什么区别?"这种问题我回答过不下十次。你可以这么理解:MCP是"Agent访问工具"的协议,A2A是"Agent调用Agent"的协议。

我自己做的一个类比是:MCP像是给一个员工发了一堆工具箱,让他自己会用电钻、会拧螺丝;A2A则是让这个员工去和另一个员工对接协作,比如"你把墙刷了,我来装开关"。

从技术形态上看也是如此。MCP走的是Client-Server,一个Agent作为一个MCP客户端去连接工具服务器。A2A走的也是Client-Agent模式,但是对端是一个完整的智能体,而不是一个工具。这带来的复杂度完全不是一个量级的:工具是无状态的,执行完返回结果就行;Agent是有状态的,它可能要在对话中来回确认信息,任务执行过程也分阶段。这也是A2A协议里为什么会有Task状态机、Message轮次这种设计的原因。

搞清楚了这一层,你再看官方文档,就会觉得那些抽象概念突然有了落地的方向。学习A2A协议,拼的不是死记硬背接口,而是理解"为什么要这么设计"。

1.3 版本情况与学习资料的选择策略

还有一个比较坑的地方:A2A协议的版本更新速度非常快。我刚开始学的时候还是0.1.0版本,现在官方文档已经是0.2.x甚至更新的内容了。结构上其实变化不大,核心机制稳定,主要是一些字段细节和认证扩展。这里给你一个很实在的建议:别追最新的commit,直接盯住Linux基金会下的A2A项目文档,以稳定发布版本为准。遇到网上教程里说的接口和官方文档对不上,九成是版本问题。

2. 上手第一步:把核心概念压缩成"一听就懂"的版本

2.1 Agent Card:智能体的"简历"

学习A2A协议,第一个要认识的概念就是Agent Card。你完全可以把它理解为智能体挂在门口的名片或者简历。一个Agent如果想要被别人调用,首先要对外发布一个JSON格式的卡片,里面写清楚自己是谁、能干什么、怎么联系。通常访问路径放在根目录下,规则和很多网站的标准约定一样。

下面是一个很典型的Agent Card长什么样,我用一个小示例给你感受一下:

{ "name": "weather-agent", "description": "为其他智能体提供实时天气查询与预警服务", "url": "https://agent.example.com/", "protocolVersion": "0.2.0", "capabilities": { "streaming": true, "pushNotifications": false }, "skills": [ { "id": "weather_query", "name": "天气查询", "description": "输入所在城市名称,返回当天与未来三天的天气" } ] }

你看,这里的字段其实都不难:protocolVersion是协议版本,capabilities声明了能力(比如是否支持流式输出),skills列的是这个Agent具体会干的活。对于小白来说,只要理解了Agent Card的发布位置和字段作用,后续的一切调用都是从"找到简历"开始的。

2.2 核心对象:Task、Message、Part

接下来是A2A协议的数据模型,这部分是理解协议的关键。我当年被一堆英文术语绕晕了,后来画了一下关系,发现就三层:Task(任务)、Message(消息)、Part(内容片段)。

Task是整个协作的执行单元,比如"帮我查天气"就是一个Task。Task有状态机流转,一般是submitted -> working -> completed或者failed,当然也可能进入input-required状态,代表Agent需要更多的输入信息。

Message是在Task执行过程中传递的信息。每条Message有role,要么是user角色,要么是agent角色,它在Task的上下文里不能乱传,必须和Task绑定。

Part则是Message的组成片段。为什么有Part这个概念?因为一条消息里可能既有文字文本,又有文件图片,甚至是结构化的代码数据。Part分成几种类型,比如文本片段、文件片段、数据片段。

举个例子,你让一个报告助手Agent总结PDF,它的返回可能是:文字总结(TextPart)加一个输出PDF文件(FilePart)。如果这两样东西用传统的RPC语义去做,数据格式必须预先约定死,非常僵硬。A2A把消息内容用Part组织起来,协作双方便有了极大的灵活性。

2.3 传输方式与关键API:拆掉JSON-RPC这堵墙

看协议文档时,很多人会被JSON-RPC这个名词吓到。其实它没有多高深,就是一个基于JSON的远程调用规范,规定了"这次调用要执行什么方法、传什么参数、返回什么结果"。A2A建立在JSON-RPC之上,常用的方法也就那么几个:

  • message/task/send:向目标Agent发消息并创建任务。
  • message/task/get:按ID查询当前任务状态。
  • message/task/cancel:取消任务。
  • message/stream:以流式方式推送任务过程中的增量消息。

A2A支持普通同步调用,也支持流式调用。同步调用是"发出去然后等结果",流式则是在任务处理过程中,把中间的消息一条一条推给客户端。流式场景下,A2A底层用的是SSE(Server-Sent Events),一种基于HTTP的单向推送技术,服务端可以向客户端持续推送数据。搞懂这几类传输方式,你的学习进度其实已经过半了。

3. 动手!从零搭建一个能跑的最小A2A协作

3.1 别一上来就上框架:先手写一次HTTP调用

我之前走了条弯路,一开始就直接用官方SDK,结果被封装搞得很懵,出了错也不知道是协议问题还是SDK问题。后来我换了个思路:先用最原始的工具把A2A握手流程跑通,再回头看SDK就豁然开朗了。

第一步,我们先手动获取一个Agent Card。假设对方Agent的地址是https://remote-agent.example.com,它的Agent Card就放在https://remote-agent.example.com/.well-known/agent.json。用curl拉一下:

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

拿到这个JSON文件后,你会看到对方协议版本、通知方式、技能列表等。到这里,你就相当于拿到了一张"简历",知道了对方的能力边界和调用惯例。

3.2 发送一个最简单的任务请求

接着我们尝试发送第一个Task。A2A的端点通常就是Agent Card里的url字段。假设我们就要调起上面那个天气Agent,让它查询北京天气。一条最朴素的JSON-RPC请求长这样:

{ "jsonrpc": "2.0", "id": "1", "method": "message/task/send", "params": { "context": { "threadId": "my-thread-001" }, "message": { "role": "user", "parts": [ { "kind": "text", "text": "查一下北京明天的天气" } ] } } }

用curl把它发过去:

curl -s -X POST https://remote-agent.example.com/ \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":"1","method":"message/task/send","params":{"context":{"threadId":"my-thread-001"},"message":{"role":"user","parts":[{"kind":"text","text":"查一下北京明天的天气"}]}}}'

这步看起来简单,但意义重大——你已经在用标准的A2A协议和另一个Agent通信了。等返回结果,通常是一条带taskId和taskStatus的响应。拿到taskId,就代表任务状态被对方托管起来了,后续可以通过message/task/get反复查询进度。

3.3 选择主流框架跑一个完整Demo

手写完一次调用后,就可以接入官方SDK,跑一个端到端的Demo了。目前社区里对小白比较友好的SDK有Python版本的a2a-sdk,Google那边也把A2A集成到了Agent Development Kit(ADK)里。这一阶段,你最好在本地起两个服务:一个是Agent端,一个是客户端,让客户端通过A2A协议去调用Agent端。

一个最小的Agent端,核心逻辑其实就接一个回调,处理接收到的任务,返回结果:

from a2a.agent import Agent agent = Agent( name="echo-agent", description="回声助手,原样返回收到的消息", ) # 这个装饰器代表此方法会处理文本类请求 @agent.handler("text") def handle_text(text, context): # 业务逻辑:把用户内容原样返回 return f"你发送的消息是: {text}" if __name__ == "__main__": agent.serve(port=8080)

我建议你跑通这一步时,一定要做一件事:用抓包工具或者直接打印HTTP请求日志,对比自己手写的请求和SDK发出的请求有什么不同。这样你才会真正理解框架帮我们封装了什么,底层到底是怎么传输的。这比看十遍文档都管用。

跑通一次端到端之后,你会发现A2A其实没有想象中复杂。它就是一种约定,核心就是"找到对方简历""发JSON-RPC消息""轮询或流式获取结果"。

4. 小白最容易踩的五个坑:我帮你先踩过了

4.1 Agent Card的URL配置错误,导致一切调用失败

这是我见过的第一大类问题,连我自己都跳过。很多人会把Agent Card里的url字段填成Agent Card自身的JSON文件地址,比如某个很常见的错误写法。但实际上这个字段应该是Agent服务本身的API地址,也就是你发JSON-RPC请求的目标端点。如果填错了,客户端能拉到简历,但发送任务请求时就会打到不存在的路径上。

排查思路也简单:先手动curl一下卡片里的url,看返回是正常响应还是网页内容。如果访问之后返回HTML,那一定是配错了,这个地址不是API端点,而是某个欢迎页。

4.2 上下文轮次管理混乱,直接把Agent搞失忆

A2A和普通HTTP接口最大的不同,它是有上下文、有对话轮次的。很多小白一开始会犯一个错误:每发一条消息就开一个新的threadId,或者干脆不传threadId。结果就是,Agent根本记不住之前聊过什么,多轮对话断掉,最终出来的东西驴唇不对马嘴。

正确做法是:同一个多轮协作流程,从第一轮到最后结果出来,始终使用同一个threadId。用生活类比来说,这就像你给同一个客服专员打电话,每次都应该报同一个工单号,而不是每次都换号重开。当然,A2A协议里面Task和Message并不是我们理解的标准聊天对话,如果你需要做长期记忆,层次还要再往业务数据库里做一些扩展,这个话题后面进阶篇再说。

4.3 流式场景的"半截消息"问题:SSE读不完就断开

A2A支持流式任务结果,底层用SSE推送。我刚开始调试的时候,用requests库去读流式接口,读了一部分就连接断开了,当时以为是协议问题,后来查了才发现,是自己在客户端直接用了普通的POST请求去发message/stream方法。这就有个关键点:流式方法必须用支持SSE的HTTP客户端来调用,普通的requests.post会一直挂在那里等完整响应,而服务端早就开始推流了。

比较合适的方案是用httpx并开启流式读取,逐步解析服务端推送的事件。如果不想从底层实现,那就用官方SDK,它已经帮你处理好了。但目的还是要理解一件事:A2A的流式传输并不是一套自己发明的协议,它就是标准的SSE流,该换客户端就必须换。

4.4 把A2A当作普通RPC来设计,结果陷入死等

还有一个认识层面的大坑:不少开发者会把A2A调用的结果当作"一次性返回的JSON",等不到结果就认为服务出了问题。但A2A协议的一个核心哲理是:任务的生命周期是异步的。

调用方发起一个Task后,被调的Agent可能瞬间返回一个"taskStatus: submitted",然后这个任务就在后台执行了。如果你严格只做一个同步调用的设计,那么当任务处理时间变长、Agent需要向你确认信息时,你的程序会卡在等待里。更聪明的做法是:把每次调用都当作异步任务处理,通过状态轮询,或配合服务端主动通知(比如Webhook)来获得最终结果。提早把这个心态建立起来,你的架构不会在任务复杂化之后轰然倒塌。

4.5 官方文档中"迭代太快"的字段变动,别被迁移通知吓到

这个问题非常影响新手心态。A2A从0.1到0.2之间,部分字段被改名,比如capabilities的结构调整等,社区里的老教程可能会失效。我自己的处理办法是:锁定三个稳定参考——Linux基金会仓库里的协议文档、Google ADK对应版本的A2A实现、以及官方SDK源码。当教程和这些参考矛盾的时候,以参考为准,不用浪费时间在找"为什么教程不对"上面。

5. 进阶思考:从Demo走向生产级应用,还差哪些修炼

5.1 跨智能体的语义能力匹配

跑通了Demo,只是"学会语法";要让Agent真正在业务里干活,还得理解"怎么选Agent"。实际场景里,你面对的不是一个而是几十个Agent,这时候不能傻乎乎地拿一份Agent Card挨个试。比较有效的办法是维护一份本地Agent目录,定期拉取更新,并基于每个Agent的skills描述做向量检索匹配,让任务自动路由到最合适的Agent上。

我目前在做的一个内部项目就是这样:把公司内部的数据分析Agent、文案Agent、客服Agent都注册到目录里,上游任务进来后先做一次embedding匹配,选出top几的Agent候选,再由一个路由Agent最终裁决。这套系统起来之后,整个协作效率明显提升。

5.2 认证授权隔离:企业落地绕不过的坎

另一个生产级必聊的话题就是安全。A2A协议本身定义了标准的认证扩展,目前主流的方式还是基于OAuth 2.0体系,比较常见的流程是:客户端获取Agent Card的同时,可以从卡片中读取到对方的authentication信息,然后按OAuth流程换取access token,后续的每一个JSON-RPC请求都带上token。

如果你要把A2A引入企业环境,一定要尽早考虑权限隔离问题。比如同一个Agent,对不同部门返回的数据粒度可能不同;或者有些Agent只允许内网调用。这个在协议层面没有魔法,它就是一个HTTP服务,服务端该怎么鉴权就怎么鉴权。但有个细节值得注意:当Agent A去调用Agent B的时候,权限到底是以A的身份还是以最终用户的身份来算?这就引申出身份传播问题。A2A协议目前在鼓励这种跨Agent身份透传,但最终实现往往要结合你所在企业的身份网关来做。

5.3 人机协作闭环:别忘了还有人在任务环里

最后我想强调一点,A2A并不是把所有东西都做成纯机器对机器协作。协议的Task状态机里专门设计了input-required状态,也就是说,一个Agent在执行任务过程中可能需要向人类用户询问信息。比如一个订票Agent在安排行程时,不确定你是要靠窗还是过道,它会停在这个状态,把问题抛给用户,拿到答复后才继续执行。

我在设计业务时,往往会把人这个环节纳入流程考虑:人类作为特殊角色出现在协作链路里,既能兜底处理异常,又能提供更人性化的判断。这一点很多技术狂热者会忽略,但恰好是落地时的加分项。

回头看我的A2A学习路,最关键的转折不是看了某篇神文,而是坚持"手写一遍协议调用"和"锁定稳定版本文档"这两个笨方法。A2A协议本质上没那么复杂,它唯一复杂的地方,是和"分布式协作"这件事纠缠在一起。你只要不急着跳过原理,一步步把卡片、消息模型、任务状态、流式传输这四块地基打牢,后面的功能无论怎么演进,都不会把你甩下车。

如果你正在学A2A卡在某个环节,不妨回归到最笨的方法:打开终端,拉一次别人的Agent Card,发一条最简单的任务,看看返回包里到底有什么。协议这东西,跑通一次比看十篇解读都有用。等到你有了一定经验之后,再回头看看官方定义,相信也会有和我一样的感觉:原来每个设计都没那么玄乎,全是为了解决现实协作里的真问题。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询