☰
A2A协议解析:多Agent协作的架构选型与核心挑战
2026/10/15 11:49:11 网站建设 项目流程

Agent 协作这件事,过去一年被讨论得很多,但真正落到架构层面,很多团队还是停留在“把几个 Agent 串起来跑通”的阶段。A2A 这个概念一出来,不少人第一反应是“又一个协议标准”,第二反应是“跟我现在的多 Agent 编排有什么区别”。我一开始也是这个反应,直到自己动手把一套内部工具链从单 Agent 拆成多 Agent 协作,踩了一圈坑之后,才慢慢理解 A2A 想解决的其实不是“怎么让 Agent 互相调用”这么浅的问题,而是“当 Agent 数量变多、归属方变多、运行环境变多之后,协作这件事怎么才能不塌”。

这篇上篇,我想先把问题本身讲清楚:A2A 到底在解决什么,它和常见的编排框架、函数调用、消息队列之间的边界在哪,以及在真正做架构选型之前,你需要先想明白哪几件事。下篇我会再展开具体的落地形态和选型对比。整篇内容基于我自己做过的几个模拟项目,涉及的公司、项目、人物都是代称,重点在思路和踩坑经验。

1. 先把问题定义清楚:A2A 不是“多 Agent 框架”

1.1 从单 Agent 到多 Agent,痛点到底在哪

单 Agent 的时候,事情其实很简单。一个模型,一套工具,一个循环,输入进来,规划、调用、返回。你甚至不需要什么架构,一个 while 循环加几个 if 就能跑。问题出现在什么时候?出现在你发现一个 Agent 干不完所有事,或者干得不够好,于是你开始拆。

拆的第一种方式是按能力拆:一个负责检索,一个负责计算,一个负责写。第二种是按角色拆:一个规划者,一个执行者,一个审核者。第三种是按领域拆:客服 Agent、订单 Agent、风控 Agent。拆完之后你会发现,原本一个进程内的事情,现在变成了多个进程、多个服务、甚至多个团队之间的事情。

这时候痛点就来了。第一个痛点是通信:Agent 之间怎么传消息,传什么格式,谁负责序列化。第二个痛点是发现:A Agent 怎么知道 B Agent 存在,B 的能力是什么,怎么调用。第三个痛点是边界:A 和 B 属于不同团队,甚至不同公司,凭什么信任对方。第四个痛点是状态:一个任务跨了三个 Agent,中间状态谁维护,失败了怎么回滚。

我做过一个模拟项目,内部叫“文档处理流水线”,一开始是单 Agent 做摘要加分类。后来拆成三个:一个抽取,一个摘要,一个打标。拆完第一周就出问题——抽取 Agent 改了输出字段名,摘要 Agent 没同步,整条链路静默失败,日志里什么都看不出来。这就是典型的“拆了但没定义协作契约”。

1.2 A2A 想解决的核心矛盾

A2A 这个词,字面是 Agent to Agent。但它真正想解决的矛盾,我理解是三个层面的“异构”:

  • 能力异构:不同 Agent 由不同模型驱动,能力边界不一样,有的擅长推理,有的擅长工具调用。
  • 归属异构:不同 Agent 属于不同团队、不同系统,甚至不同组织,有自己的部署和生命周期。
  • 运行异构:不同 Agent 跑在不同环境,有的在本地,有的在云端,有的同步,有的异步。

传统的做法是写死调用关系,A 直接 import B 的 SDK。这在同团队、同语言、同部署环境下没问题。但一旦跨了归属,这套就崩了。你不可能让外部团队的 Agent 直接 import 你的内部类。

A2A 的思路是:把 Agent 之间的交互抽象成一种协议级的能力交换。每个 Agent 对外暴露一张“能力名片”,里面写清楚我是谁、我能做什么、我怎么被调用、我需要什么输入、我产出什么输出。调用方不需要知道对方内部怎么实现,只需要按名片上的约定发请求。

这听起来很像微服务里的服务发现加 API 契约。没错,本质上就是把微服务那套思路搬到了 Agent 世界。但 Agent 比微服务多了一层不确定性:微服务的接口是确定的,Agent 的输出是概率性的。所以 A2A 还要额外解决“不确定输出下怎么保证协作可靠”这个问题。

提示:如果你现在的多 Agent 系统还在同一个代码仓库、同一个进程里,A2A 对你来说大概率是过度设计。先把手头的编排做扎实,等到真的出现跨团队、跨环境协作需求,再考虑协议层。

1.3 一个容易混淆的点:A2A 和函数调用

很多人会把 A2A 和模型的 function calling 混为一谈。这两者完全不是一个层次的东西。

Function calling 解决的是“模型怎么调用一个具体函数”,它是模型和工具之间的接口。A2A 解决的是“Agent 怎么调用另一个 Agent”,它是 Agent 和 Agent 之间的接口。一个 Agent 内部可以用 function calling 调工具,对外用 A2A 暴露能力,这两件事可以同时存在,互不冲突。

打个比方:function calling 像是你用手去拿杯子,A2A 像是你让同事帮你拿杯子。前者是身体协调,后者是人际协作。你不可能用“手怎么拿杯子”的方法去解决“怎么让同事帮你拿杯子”。

我在早期就犯过这个错,试图用 function calling 的 schema 去描述 Agent 之间的调用,结果发现根本不够用。因为 function calling 描述的是无状态的一次调用,而 Agent 之间的协作往往是有状态、多轮、可中断的。这个认知转变花了我不少时间。

2. 协作模式拆解:从“能跑”到“跑得稳”

2.1 三种基础协作拓扑

在讨论 A2A 之前,先要把协作的拓扑结构理清楚。我总结下来,实际项目里最常见的是三种:

拓扑结构适用场景主要问题
链式A→B→C 顺序执行流水线式任务,步骤明确单点失败,链路长
星型中心调度,多个执行任务分发,能力聚合中心瓶颈,调度复杂
网状任意 Agent 互相调用复杂协商,动态协作状态难追踪,调试困难

链式最简单,也最容易落地。我那个文档处理流水线就是链式。星型适合“一个大脑多个手脚”的场景,比如一个规划 Agent 调度多个执行 Agent。网状最难,但最接近 A2A 想描述的终极形态——任意 Agent 之间可以按需协作。

实际项目里,纯网状很少见,更多是混合。比如外层星型,内层链式。选型的时候不要一上来就追求网状,那是给自己找麻烦。

2.2 同步、异步与流式:通信模式的取舍

通信模式的选择,直接决定了你的架构复杂度。

同步调用最好理解,A 发请求,等 B 返回,再继续。实现简单,但有个致命问题:如果 B 是个 Agent,它的响应时间可能是几秒到几十秒,同步等待会把 A 的上下文窗口和超时预算全部吃掉。

异步调用是 A 发请求,不等,B 处理完再通知。这解决了等待问题,但引入了状态管理。A 怎么知道 B 处理完了?靠回调、靠轮询、靠消息队列。每一种都有额外的工程成本。

流式是折中方案,B 边处理边把中间结果推给 A。这在 Agent 场景里特别有用,因为 Agent 的推理过程本身就是渐进的,流式能让 A 提前感知 B 的进展,甚至中途干预。

我实测下来的经验是:短任务用同步,长任务用异步,需要中途干预的用流式。不要为了“先进”而全部上异步,异步的状态管理成本会把你拖垮。我见过一个团队,所有 Agent 调用都走消息队列,结果调试一个简单问题要翻三个服务的日志,最后又改回同步。

2.3 状态管理:协作里最容易被低估的部分

状态管理是 Agent 协作里最不性感、但最要命的部分。一个任务跨多个 Agent,中间状态放哪?

常见做法有三种:

  • 调用方持有:A 维护整个任务的状态,B 是无状态的。简单,但 A 的负担重,且 A 崩溃就全丢。
  • 共享存储:状态放 Redis 或数据库,所有 Agent 读写。灵活,但并发控制和一致性是难题。
  • 每个 Agent 自持:每个 Agent 管自己的状态,通过消息传递衔接。解耦好,但全局状态难追踪。

我踩过的坑是:一开始用调用方持有,跑得好好的,后来加了个重试机制,发现重试时状态对不上,因为 B 其实已经执行了但 A 没收到响应。这就是典型的“至少一次”语义问题。后来改成共享存储加幂等键,才稳定下来。

注意:只要你的协作链路里存在重试、超时、中断,就必须考虑幂等。Agent 的副作用(比如写文件、发消息)一定要有幂等保护,否则重试就是灾难。

3. 架构选型前必须想明白的四件事

3.1 你的 Agent 边界划在哪

边界划分是架构选型的第一步,也是最容易拍脑袋的一步。很多人按“功能”划,比如检索一个 Agent、生成一个 Agent。但功能边界不等于协作边界。

我建议按变更频率和归属方来划。变更频率高的放一起,变更频率低的独立出去。归属方不同的必须分开,因为跨归属的协作才是 A2A 真正要解决的场景。

举个例子,一个模拟项目里,我们把“意图识别”和“槽位填充”放在一个 Agent 里,因为它们总是一起变。但“知识检索”独立出去,因为它对接的是另一个团队维护的知识库,变更节奏完全不同。这样划完之后,协作链路清晰了很多。

3.2 能力描述用什么粒度

A2A 的核心是能力交换,那能力描述写多细?太粗,调用方不知道怎么用;太细,维护成本爆炸。

我的经验是:按“一个完整的业务动作”来描述。比如“查询订单状态”是一个能力,“查询订单”加“解析状态码”加“格式化输出”就是三个能力,太细了。调用方关心的是“我能让你干什么”,不是“你内部怎么干”。

能力描述里至少要包含:能力名称、输入 schema、输出 schema、调用方式、错误码、限流策略。这几项缺一个,调用方就得猜,一猜就出错。

3.3 信任和权限怎么设计

跨归属协作必然涉及信任问题。A 凭什么相信 B 返回的结果?B 凭什么接受 A 的请求?

信任分两层:身份信任和内容信任。身份信任靠认证机制,比如令牌、证书。内容信任靠校验机制,比如输出格式校验、结果合理性检查。

权限设计上,我倾向于最小权限加显式授权。每个 Agent 默认只能访问自己的资源,要访问别人的必须显式申请。这在早期会显得麻烦,但等到 Agent 数量上来了,你会发现这是唯一能管住局面的方式。

3.4 失败和降级策略

Agent 协作的失败模式比普通服务多得多。除了常规的网络失败、超时,还有:Agent 返回了格式不对的结果、Agent 陷入了循环、Agent 的能力被误用。

降级策略要提前设计。比如 B 不可用时,A 是重试、是走备用路径、还是直接返回部分结果?这些决策不能等到线上出问题再想。

我一般会要求每个协作节点都定义三件事:超时时间、重试策略、降级方案。这三件事写清楚了,线上出问题的时候才不至于手忙脚乱。

4. 常见误区与排查思路

4.1 把 A2A 当成万能解

最常见的误区,就是觉得 A2A 能解决所有多 Agent 问题。实际上,如果你的 Agent 都在一个团队、一个仓库、一个部署单元里,用普通的函数调用加编排框架就够了,上 A2A 只会增加复杂度。

A2A 的价值在跨边界。没有跨边界需求,就没有 A2A 的用武之地。我见过一个团队,内部三个 Agent 硬要上协议层,结果调试成本翻了三倍,收益几乎为零。

4.2 忽视可观测性

Agent 协作链路一长,出问题的时候你根本不知道是哪一环。可观测性不是可选项,是必选项。

至少要有的:每个 Agent 的调用日志、每次协作的 trace id、关键节点的耗时和状态。trace id 尤其重要,它能把跨 Agent 的调用串起来。没有 trace id,你就是在黑盒里调试。

4.3 排查速查表

现象可能原因排查方向
链路静默失败字段名不一致检查能力描述的 schema
重复执行缺少幂等检查重试逻辑和幂等键
响应超时同步等待过长改异步或流式
状态错乱并发写共享状态加锁或改状态归属
调试困难缺 trace id补全可观测性

这张表是我自己踩坑总结的,实际排查时按这个顺序过一遍,大部分问题都能定位。

5. 上篇小结与下篇预告

写到这里,A2A 要解决的问题基本讲清楚了:它解决的是异构 Agent 之间的协作契约问题,核心在能力交换、边界划分和信任设计。它不是多 Agent 框架的替代品,而是跨边界协作的补充层。

下篇我会展开具体的落地形态,包括能力描述的具体写法、通信协议的选择、以及几种典型架构的对比。如果你现在正在做多 Agent 系统,建议先把这篇里的四个问题想明白,再动手选型。选型错了,后面全是返工。

我个人在实际操作中的体会是:Agent 协作的难点从来不在“怎么连”,而在“连上之后怎么不出事”。把失败模式、状态管理、可观测性这三件事想透,比选什么协议重要得多。

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

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

立即咨询