d3y1头像
关注

分布式Agent架构:A2A + Nacos + gRPC

分布式 Agent 架构:A2A + Nacos + gRPC 工业级落地方案

本文先把 A2A、Nacos、gRPC 的职责边界切开,再用一张分层架构图、一条完整调用链路和一个最小落地实现,把“注册、发现、协商、调用、下线”五个环节讲透。


一、先说明一个前提:A2A 并不天然依赖 Nacos

A2A 是面向 Agent 间语义协作的应用层协议,标准化定义了 Agent Card 能力描述、任务状态机、消息交互与安全校验。它本身不负责网络实例的存活检测、动态扩缩容和流量分发。

也就是说,A2A 原生只需要两端各自暴露一个 Agent Card 地址,调用方静态拉取 Card 后就能完成能力协商和任务委派。对 Demo、单机、或者 3 个以内固定 Agent 的部署来说,硬编码端点地址完全够用,不需要注册中心。

引入 Nacos 的原因只有一个:生产环境里的 Agent 是动态集群,不是固定端点。

当 Agent 需要扩缩容、实例会宕机、存在多版本灰度时,如果继续写死 IP,会出现三类问题:

  • 新增或下线 Agent 都要改调用方配置并重启;
  • 故障实例无法被及时剔除,调用方继续把请求发给死节点;
  • 不同 Agent 的能力、资源、版本无法通过标签筛选。

因此,工业级组合的核心取舍是:

部署规模技术选型核心优势代价与局限
单机 / 3 个以内固定 Agent纯 A2A 静态部署极简、零中间件、运维成本低不能扩缩容、无法自动容错、配置需重启生效
分布式 Agent 集群A2A + gRPC + Nacos动态扩缩容、自动容错、负载均衡、配置热更新增加中间件运维成本,架构复杂度小幅提升

一句话:A2A 管“能做什么”,Nacos 管“谁在线、在哪、属于哪个分组”,gRPC 管“消息怎么快速送过去”。


二、三件技术各自的职责边界

先分别看清三件技术的边界,后面才不会把“能力发现”和“服务发现”混为一谈。

1. A2A:业务语义协作层

A2A 是面向 Agent 间协作的标准化协议,核心是“这个 Agent 能做什么”。它的能力集中在:

  • Agent Card 能力自描述:能力、输入参数、鉴权规则、接口规范;
  • 任务状态机:提交、执行、需要输入、完成、失败等状态流转;
  • 消息与产物模型:统一封装任务、消息和结果;
  • JWS 签名防篡改、OAuth2.1 PKCE 鉴权;
  • SSE 流式推送、Webhook 异步回调;
  • 原生平等支持 gRPC、JSON-RPC 2.0、HTTP + JSON 三种传输绑定。

A2A 不做网络实例治理。它并不关心这个 Agent 的 IP 是什么、端口通不通、是否扩缩容了,这些是治理层的事。

2. Nacos:实例治理与配置中心

Nacos 是云原生服务注册发现与配置中心,核心能力有四项:

  • 服务注册发现;
  • 心跳健康检查;
  • 客户端负载均衡;
  • 动态配置推送。

它只识别服务的 IP、端口和自定义键值标签,不具备业务语义解析能力。所以 Nacos 能做“粗筛选”,做不了“这个 Agent 到底能不能承接当前任务”的语义判断。

3. gRPC:高性能传输层

gRPC 基于 Protobuf 静态契约、HTTP/2 多路复用和二进制序列化,适合毫秒级短链路、内部模块之间的高频通信。它不提供标准化的任务生命周期管理,也不内置业务鉴权和语义化能力描述。

三者不是替代关系,而是分层互补:

对比维度gRPCA2A v1.0
协议层级底层传输 + 接口调用框架标准化智能体协作协议,原生绑定三类传输
核心模型单次函数 / 流式接口调用完整 Task 任务状态机
数据契约Protobuf 二进制静态编译校验标准化数据模型,支持 JWS 密码学校验
能力发现暴露接口方法签名,无业务语义/.well-known/agent-card.json 语义自描述
长任务支持仅基础流式连接,无任务状态管理原生支持暂停、撤销、人工校验、断线续跑
跨栈兼容性差,强依赖 IDL 文件对齐极强,平等支持三类主流传输协议
安全能力仅基础 TLS,业务自行鉴权原生 TLS + OAuth2.1 PKCE + JWS 签名

在完整通信体系里,分工还可以再放大一步:

  • MCP 负责 Agent 内部工具调用;
  • gRPC 负责内部模块高频短事务通信;
  • A2A 负责跨 Agent 长周期任务委派;
  • Nacos 负责底层实例治理。

三、结合的本质:平行解耦,不是上下级嵌套

A2A + Nacos 结合的真正价值,不是把 Nacos 嵌进 A2A 协议里,而是把业务语义与工程治理平行拆开。

Nacos 基础设施层(与传输链路平行)

gRPC 传输层

A2A 语义协作层

Agent Card 能力自描述

版本协商 / 任务编排

JWS 安全校验 / SSE / Webhook

HTTP/2 多路复用

Protobuf 二进制序列化

实例注册发现

心跳健康检查

客户端负载均衡

配置热更新

这张图里最需要记住的是方向:

  • A2A 的语义消息最终要借助 gRPC 传输层落地;
  • Nacos 并不位于 gRPC 下方作为底层依赖,而是与传输链路并行的独立基础设施。

因此把 Nacos 替换成 K8s Service 或 Consul,A2A 的业务协作逻辑一行都不用改。架构韧性就来自这种平行关系。

用一个通俗类比:

  • Nacos 是“人事管理平台”,负责在岗人员及其标签;
  • A2A 是“岗位技能说明书”,负责定义每个角色的能力边界;
  • gRPC 是“内部电话线”,负责服务间通信的连接与调用。

四、完整调用链路:注册、粗筛、精筛、调用、下线

一个 Agent 从上线到被调用的完整生命周期,可以拆成五个环节。

Agent Card / well-known 接口调用方 AgentNacos 治理层Agent 服务实例Agent Card / well-known 接口调用方 AgentNacos 治理层Agent 服务实例1. 注册 IP / 端口 / 标签,持续上报健康2. 按标签拉取健康实例列表3. 访问 /.well-known/agent-card.json返回 Agent Card,完成版本协商与能力校验4. 通过 gRPC 发起 A2A 任务调用任务状态 / 流式结果 / Artifact5. 正常关闭时主动注销;异常时由健康检查剔除

环节 1:注册

Agent 服务基于 gRPC 对外提供 A2A 接口。服务启动后,向 Nacos 注册当前 gRPC 实例的 IP、端口,并挂载简短标签,例如 agent_type=finance、resource=gpu、version=v2。

这里有一条关键边界:Nacos 元数据只放简短标签,完整 Agent Card 不存入 Nacos。 Agent Card JSON 由 Agent 实例自身托管,通过标准 /.well-known/agent-card.json 地址暴露。

环节 2:粗筛

调用方先访问 Nacos,按命名空间、标签和健康状态做键值匹配,得到候选实例列表,再通过本地负载均衡选中一个实例端点。

这一步只回答“哪些实例还活着、属于哪个类别”,不做语义理解。

环节 3:精筛

调用方拿到端点后,访问目标 Agent 的 well-known 接口拉取 Agent Card,完成 A2A 版本协商和能力校验,确认目标实例确实具备承接当前任务的能力。

这一步才是 A2A 规范定义的真正能力发现。

环节 4:调用

校验通过后,调用方通过 gRPC 通道发送 A2A 消息,完成 Agent 间任务交互。任务可能是长周期异步的,结果通过 SSE 推送、Webhook 回调或最终 Artifact 返回。

环节 5:下线与故障

Agent 正常关闭时主动注销实例;进程异常崩溃时,健康检查失效,Nacos 自动剔除该实例。调用方在本地定期刷新实例列表,避免继续向故障节点发请求。

注册解决“知道谁在”,调用解决“确认谁能干”。整条链路把“找人、验岗、派活”标准化,集群规模再大也不会乱。


五、最小落地实现

下面用一段 Python 伪代码串起“注册、粗筛、精筛、调用”四个核心动作。重点是看每一层的职责,而不是 SDK 的准确 API。

NACOS_SERVER = "127.0.0.1:8848"
SERVICE_NAME = "a2a-agent-grpc-service"
AGENT_CARD_PATH = "/.well-known/agent-card.json"


class NacosAgentRegistry:
    """Agent 服务实例注册与配置托管。"""

    def __init__(self, agent_ip, agent_port, agent_type):
        self.client = nacos_sdk.NacosClient(NACOS_SERVER)
        self.ip = agent_ip
        self.port = agent_port
        self.metadata = {
            "agent_type": agent_type,
            "env": "prod",
        }

    def register_service(self):
        self.client.add_instance(
            SERVICE_NAME,
            self.ip,
            self.port,
            metadata=self.metadata,
        )

    def get_a2a_config(self):
        # 拉取 A2A 超时、重试、鉴权等全局配置,支持热更新
        return self.client.get_config("a2a-agent-config", "default")


class A2AAgentDiscovery:
    """Nacos 粗筛 + A2A Agent Card 精筛。"""

    def get_matched_agent(self, agent_type):
        instances = self.get_healthy_instances(agent_type)
        for instance in instances:
            card = requests.get(
                f"http://{instance.ip}:{instance.port}{AGENT_CARD_PATH}"
            ).json()
            if self.check_task_capability(card):
                return instance
        return None

    def get_healthy_instances(self, agent_type):
        return nacos_sdk.get_instance_list(
            SERVICE_NAME,
            metadata={"agent_type": agent_type},
        )

    def check_task_capability(self, agent_card):
        # A2A 语义能力匹配校验
        return "finance_task" in agent_card["capabilities"]


class A2AGrpcClient:
    """gRPC 承载 A2A 标准化任务调用。"""

    def invoke_a2a_task(self, instance, task_params):
        channel = grpc.insecure_channel(f"{instance.ip}:{instance.port}")
        stub = channel.unary_unary("/A2AGrpcService/InvokeTask")
        return stub(task_params)


if __name__ == "__main__":
    registry = NacosAgentRegistry("127.0.0.1", "50051", "finance")
    registry.register_service()

    discovery = A2AAgentDiscovery()
    target = discovery.get_matched_agent("finance")
    if target:
        A2AGrpcClient().invoke_a2a_task(
            target,
            {"task": "bill_check"},
        )

如果技术栈基于 Spring Cloud 生态,团队已经熟悉 Nacos,那么这套组合的引入成本很低,可以复用现有运维体系。


六、双层能力筛选:Nacos 找得到人,A2A 认得清活

这套架构最巧妙的点,在于“网络层粗筛 + 业务层精筛”的双层接力。

存活且标签匹配

环境不符 / 标签不一致 / 已下线

协议兼容且能力匹配

技能不匹配 / 版本不兼容

原始任务请求

Nacos 网络层粗筛
命名空间 / 标签 / 健康状态

A2A 业务层精筛
版本协商 / Agent Card 能力校验

直接拒绝

gRPC 发起 A2A 调用

拒绝无效调用

第一层 Nacos 只按命名空间、元数据标签和健康状态做键值匹配,把明显不符的实例挡在门外。但它有个天生短板:只认识 IP、端口和标签,无法解析 Agent 的业务语义。

第二层 A2A 先做协议版本协商,再比对 Agent Card 中声明的语义能力,确认目标 Agent 确实具备执行该任务所需的全部能力。

两层合力,能挡住两类高频无效调用:

  • 网络可达,但技能不匹配;
  • 网络可达,但协议版本不兼容。

这既减轻了 Nacos 的语义负担,又补上了纯注册中心缺失的业务智能。


七、流程简述

明确前提:A2A 协议本身不依赖 Nacos,原生依靠 Agent Card 做能力描述和能力发现。两个 Agent 写死端点加 Agent Card 就能完成对接,小规模固定部署不需要注册中心。我们引入 Nacos,不是替 A2A 做协议级发现,而是解决分布式 Agent 集群的动态实例治理问题。

架构三层隔离:Nacos 负责实例治理,gRPC 负责传输,A2A 负责业务 Agent 交互。Nacos 与 A2A 之间没有协议层绑定,耦合由业务代码封装完成。

完整流程:Agent 启动后基于 gRPC 暴露 A2A 接口,把 IP、端口和简短标签注册到 Nacos;调用方先从 Nacos 拉取健康实例列表,做客户端负载均衡;再访问目标实例的 /.well-known/agent-card.json,完成 A2A 版本协商和能力校验;校验通过后通过 gRPC 发起 A2A 任务调用。正常关闭时主动注销,异常崩溃由健康检查自动剔除。

边界上,Nacos 只放简短标签,完整 Agent Card 仍由实例自己托管;Nacos 的健康检查只能确认网络层存活,所以我们还会补充 A2A 应用层探针;如果只有两三个固定 Agent,我们会直接用静态 Agent Card,不上 Nacos,避免过度设计。


八、选型边界与容易踩的坑

最后补几个生产里真正会踩到的点。

只有 2 到 3 个固定 Agent,不要硬上 Nacos。 静态配置 well-known 地址,拉取 Agent Card 通信即可,否则只是把简单问题复杂化。

Nacos 元数据只放简短标签,不放完整 Agent Card。 元数据膨胀会让注册中心承担本不属于它的语义负载,也容易产生数据不一致。

Nacos 的健康检查不等于 A2A 业务可用。 Nacos 只能判断端口连通性或网络层存活,无法确认 A2A 业务逻辑是否正常,需要额外实现应用层探针。

Nacos 标签是键值精确匹配,不具备语义理解。 上层 Agent 调度网关拿到标签列表后,要再结合 Agent Card 的完整能力描述做语义路由,Nacos 本身不参与语义路由。

配置托管要覆盖 A2A 的关键参数。 超时时间、重试策略、鉴权密钥、Agent Card 缓存策略都应放入 Nacos 配置中心,通过动态推送实现零重启变更。

传输层不要越界。 内部高频短事务继续用 gRPC,跨 Agent 长周期任务用 A2A,工具调用交给 MCP。不要把长任务状态机硬塞进 gRPC,也不要把内部工具调用协议套到跨 Agent 协作上。


九、小结

A2A + Nacos + gRPC 不是“三个名词的拼接”,而是一次清晰的分层解耦:

  • A2A 定义服务间协作的能力边界和行为契约,管“能做什么”;
  • Nacos 负责服务实例的注册、发现、健康状态和元数据治理,管“谁在线、在哪、属于哪个分组”;
  • gRPC 以 HTTP/2 和 Protobuf 提供低延迟二进制传输,负责把语义消息快速送达。

把这一层关系想清楚,再沿着“注册 → 粗筛 → 精筛 → 调用 → 下线”把流程梳理完整,最后注意“小规模用纯 A2A、大规模才引入 Nacos”。

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/IOIO_/article/details/166848081

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--