Spring AI Alibaba + Nacos 构建 A2A 分布式智能体

一、Spring AI Alibaba

在本专栏上一篇文章中,介绍了 Python + AgentScope 完整实现 A2A 智能体服务的注册、集群部署、Nacos 服务发现与客户端负载调用能力,解决了多智能体框架不统一、智能体无法高效协同的问题。

过程如下图所示:

文章地址:

基于A2A + AgentScope + Nacos 构建分布式高可用异构 Agent 方案

但在企业真实落地场景中,绝大多数核心业务系统、微服务架构均基于 Java 技术栈构建。如果 AI 智能体仅能在 Python 侧独立运行,无法与 Java 业务体系打通,会形成新的技术孤岛,无法真正融入企业微服务生态。

因此本篇内容将聚焦Java生态上,基于 Spring AI Alibaba 快速搭建 Java 版 A2A 服务端与客户端,实现Java 智能体注册至 Nacos、并实现客户端远程调用。

Spring AI Alibaba 是阿里开源的 Spring AI 生态扩展,旨在帮助 Java 开发者更便捷地构建 AI 应用。在最新的版本中,Spring AI Alibaba 已经全面拥抱 A2A 协议,提供了开箱即用的 Starter 组件:

  • spring-ai-alibaba-starter-a2a-server :用于快速将 Agent 包装为标准的 A2A 服务端。
  • spring-ai-alibaba-starter-a2a-client :用于在 Spring 环境中作为客户端,发起 A2A 协议调用。
  • spring-ai-alibaba-starter-a2a-registry :深度集成 Nacos,实现 A2A AgentCard 的自动注册与发现。

这意味着,Java 开发者无需手动处理 A2A 协议底层的 JSON-RPC 转换和 HTTP 路由,只需通过简单的配置和注解,就能让 Spring Boot 微服务具备 Agent 互联能力。

核心技术栈版本延续上篇规范,保证前后实验兼容性:

  • Nacos:3.2.0(最低 3.0+ 支持 AI 注册中心能力)
  • Spring Boot:3.4.0
  • Spring AI Alibaba:1.0.0.4+
  • 模型服务:ModelScope Qwen3.5 系列开源模型

开始前请提前安装好 Nacos 服务, 安装过程可参考官方文档:

https://nacos.io/docs/latest/quickstart/quick-start/

二、A2A 服务端实现

首先,我们新建一个 Spring Boot 项目,将 Java 端的天气助手 Agent 封装为 A2A 服务并注册到 Nacos。

2.1 项目依赖

pom 引入 WebFlux、Spring AI Alibaba A2A Server、Registry 以及 OpenAI 模型依赖:

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.4.0</version>
        <relativePath/>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>a2a-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>a2a-demo</name>
    <description>a2a-demo</description>
    <properties>
        <java.version>17</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <!-- Spring AI Alibaba版本1.0.0.4及以上 -->
        <spring.ai.alibaba.version>1.0.0.4</spring.ai.alibaba.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- 引入A2A Server starter -->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter-a2a-server</artifactId>
            <version>${spring.ai.alibaba.version}</version>
        </dependency>

        <!-- 引入A2A Nacos 注册中心 -->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter-a2a-registry</artifactId>
            <version>${spring.ai.alibaba.version}</version>
        </dependency>

        <!-- 引入OpenAI -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-model-openai</artifactId>
            <version>1.0.1</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>17</source>
                    <target>17</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>com.example.a2ademo.A2aDemoApplication</mainClass>
                    <skip>true</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

2.2 配置文件

指定模型连接信息、Nacos 注册中心以及 Agent 元数据:

yml 复制代码
server:
  port: 8085

spring:
  application:
    name: a2a-server-example
  ai:
    openai:
      base-url: https://api-inference.modelscope.cn
      api-key: ms-xxx ## 替换为你的key
      chat:
        options:
          model: Qwen/Qwen3.5-35B-A3B

    alibaba:
      a2a:
        # 配置Nacos信息
        nacos:
          server-addr: ${NACOS_ADDRESS:localhost:8848}
          username: ${NACOS_USERNAME:nacos}
          password: ${NACOS_PASSWORD:123456}
        server:
          version: 1.0.1
          card:
            # 配置Agent URL
            url: http://localhost:8085/a2a

这里 a2a.server.card.url 非常关键,它定义了该 Agent 在 A2A 协议下暴露的地址。启动时,框架会自动构建 AgentCard 并注册至 Nacos 中。

2.3 构建测试工具

使用 @Tool 注解定义一个简单的天气伪工具,供智能体调用,以测试工具调用能力:

java 复制代码
@Component
public class WeatherTools {

    @Tool(description = "查看某个地区的最新天气情况")
    public String weather(String local) {
        if (StringUtils.isBlank(local)){
            return "参数:local 不可为空!";
        }
        return local + ",地区的最新天气为多云转晴,30-35摄氏度。";
    }

}

2.4 构建 ReactAgent 智能体

通过 ReactAgent 将大模型与工具整合构造智能体:

java 复制代码
@Configuration
public class RootAgentConfiguration {

    @Bean
    public List<ToolCallback> tools(WeatherTools tools) {
        return new ArrayList<ToolCallback>(List.of(ToolCallbacks.from(tools)));
    }

    @Bean
    @Primary
    public BaseAgent rootAgent(OpenAiChatModel chatModel, List<ToolCallback> tools) throws GraphStateException {
        return ReactAgent.builder()
                .name("xiaobichao")
                .description("小毕超天气助手")
                .model(chatModel)
                .instruction("你叫小毕超,是一个天气智能助手!")
                .inputKey("input")
                .tools(tools)
                .build();
    }
}

2.5 启动服务端

启动 Spring Boot 项目:

观察 Nacos 注册情况,可以看到名为 xiaobichao 的智能体已自动注册:

点进详情,可以看到注册的 URL 等信息,与配置一致:

至此,A2A 服务端已经就绪。它与上一篇用 AgentScope 编写的 Python 服务端在协议层面完全互通,可以被任意支持 A2A 的客户端调用。

三、A2A 客户端实现并调用测试

接下来我们创建一个新的 Spring Boot 客户端项目,通过 Nacos 发现刚才的 xiaobichao 服务,并进行流式调用。

3.1 项目依赖

客户端 pom 需要引入 spring-ai-alibaba-starter-a2a-client 和 spring-ai-alibaba-starter-a2a-registry:

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.4.0</version>
        <relativePath/>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>a2a-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>a2a-demo</name>
    <description>a2a-demo</description>
    <properties>
        <java.version>17</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <!-- Spring AI Alibaba版本1.0.0.4及以上 -->
        <spring.ai.alibaba.version>1.0.0.4</spring.ai.alibaba.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- 引入A2A Client starter -->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter-a2a-client</artifactId>
            <version>${spring.ai.alibaba.version}</version>
        </dependency>

        <!-- 引入A2A Nacos 注册中心 -->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter-a2a-registry</artifactId>
            <version>${spring.ai.alibaba.version}</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>17</source>
                    <target>17</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>com.example.a2ademo.A2aDemoApplication</mainClass>
                    <skip>true</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

3.2 配置文件

application.yml 只要指定 Nacos 地址:

yml 复制代码
server:
  port: 8086

spring:
  application:
    name: a2a-client-example
  ai:
    alibaba:
      a2a:
        nacos:
          # 开启从Nacos中自动发现Agent
          discovery:
            enabled: true
          server-addr: ${NACOS_ADDRESS:localhost:8848}
          username: ${NACOS_USERNAME:nacos}
          password: ${NACOS_PASSWORD:123456}

3.3 构建远程智能体代理

创建一个 A2aRemoteAgent,用于代理远程智能体。

java 复制代码
@Configuration
public class RootAgentConfiguration {

    @Bean
    public BaseAgent rootAgent(AgentCardProvider agentCardProvider) throws GraphStateException {
        return A2aRemoteAgent.builder()
                .agentCardProvider(agentCardProvider)
                .name("xiaobichao").description("小毕超天气智能助手").build();
    }
}

AgentCardProvider 会自动根据 name 从 Nacos 中查找对应的 AgentCard,并建立通信通道。整个过程开发者无需关心远程服务地址和协议细节。

3.4 构建测试接口

java 复制代码
@RestController
@RequestMapping("/")
public class TestController {

    private final BaseAgent rootAgent;

    public TestController(BaseAgent rootAgent) {
        this.rootAgent = rootAgent;
    }

    @GetMapping(value = "stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<ServerSentEvent<String>> stream(@RequestParam("question") String question)
            throws GraphStateException, GraphRunnerException {
        return rootAgent.stream(Map.of("input", List.of(new UserMessage(question))))
                .mapNotNull(output -> {
                    System.out.println("stream agent invoke : " + output.toString());
                    if (output.isSTART() || output.isEND()) {
                        return null;
                    }
                    if (output instanceof StreamingOutput) {
                        String chunk = ((StreamingOutput) output).chunk();
                        return ServerSentEvent.<String>builder()
                                .data(chunk)
                                .build();
                    }
                    return null;
                });
    }

}

启动服务:

3.5 远程调用测试