Skip to content

第4章 SpringAi 1.1 实现 MCP+A2A

4-1 以bom方式导入SpringAi Alibaba依赖

为什么使用SpringAiAlibaba,代替SpringAi

  1. SpringAi Alibaba 是基于 SpringAi
  2. SpringAiAlibaba在SpringAi的基础做了优化,
    • 更好集成国内模型:DeepSeek,Qwen3
    • 和阿里云百炼模型平台,有深度的集成
  3. SpringAi可以看作底层的Ai应用开发框架,SpringAi_Alibaba 倾向于Ai智能体(AiAgent)的开发框架
    • 智能体的编排工作流
    • 适配多个智能体协作场景
    • 和阿里云的智能体应用平台有深度集成
    • 提供了RAG知识库的解决方案
    • 提供了分布式的MCP的方案

依赖管理

xml
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <!--  bom依赖,起到的是版本的统一管理
        注意:bom依赖必须放在<dependencyManagement>标签内-->
        <spring-boot.version>3.2.4</spring-boot.version>
        <!-- 最低版本必须是>1.0.0-m6,因为从1.0.0-m6开始才集成MCP-->
        <spring-ai-alibaba.version>1.0.0.2</spring-ai-alibaba.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud.ai</groupId>
                <artifactId>spring-ai-alibaba-bom</artifactId>
                <version>${spring-ai-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

4-2导入MCP依赖

xml
<spring-ai.version>1.0.0</spring-ai.version>

<dependencyManagement>
  <dependencies>    
     <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-bom</artifactId>
        <version>${spring-ai.version}</version>
        <type>pom</type>
        <scope>import</scope>
       </dependency>
     </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-mcp</artifactId>
    </dependency>
</dependencies>

4-3 MCP能连接万物的原因:通信的分层设计

**MCP协议的引入背景与核心作用 **

  • 引入原因 大模型缺乏实时数据与用户私有数据访问能力,需通过第三方API或本地/云端存储获取数据。
  • 统一化需求 不同大模型调用外部工具的方式各异,亟需标准化中间层以屏蔽底层差异。
  • MCP协议定位 作为通用中间层,使任意大模型(如千问、DeepSeek、豆包)均可通过统一接口调用外部API或访问本地/云端数据。

**MCP协议的三层节点架构与会话建立流程 **

  • 三个核心节点
    • MCP host(大模型端)
    • MCP客户端
    • MCP服务端
  • 会话初始化流程
    • MCP host初始化MCP客户端 ;
    • MCP客户端向MCP服务端请求工具列表 ;
    • MCP服务端返回其支持的全部工具清单 ;
    • MCP host据此获知可用工具,完成三节点会话通信建立 。

工具调用完整执行逻辑

  • 用户请求示例 查询“深圳实时天气变化” 。
  • 调用链路
    • MCP host查工具列表,识别“墨迹天气API”工具 ;
    • MCP host指令MCP客户端调用该工具,并传入参数“深圳”;
    • MCP客户端将工具名与参数转发至MCP服务端 ;
    • MCP服务端执行工具调用,获取并返回实时气温数据 ;
    • MCP客户端将结果回传MCP host ;
    • MCP host经推理组织语言后交付用户 。
  • 执行主体明确性 工具实际执行仅发生在MCP服务端,大模型端仅需知晓工具名与参数,无需理解API业务逻辑 。

MCP协议的两大核心抽象层

  • 协议层:统一响应数据格式
    • 解决不同工具(墨迹天气API、高德地图API、Excel文件、数据库)返回数据格式不一致问题);
    • 在协议层约定标准化响应结构,确保MCP host可精确解析字段语义并提取所需数据 。
  • 传输层:自适应数据传输机制
    • 解决工具间传输方式异构问题:API调用使用HTTP,本地文件访问依赖进程间通信 );
    • 传输层自主选择机制:
      • MCP服务端→MCP客户端:HTTP(跨机)或本地进程(同机) ;
      • MCP客户端→MCP host:若同节点则用本地线程,若分节点则用HTTP ;
      • MCP服务端调用API时选HTTP,访问本地文件时选本地进程 。

**MCP协议的类比与整体价值 **

  • 通用插头类比 MCP如同USB接口,提供即插即用能力,使大模型可无缝连接任意外部系统 。
  • 双重保障机制
    • 协议层保障“数据语义统一”,无论来源是API、Excel或数据库,响应格式严格遵循约定 ;
    • 传输层保障“通信路径灵活”,自动适配HTTP、本地进程等传输机制,覆盖跨机、同机、云边等全场景

4-4 MCP的通信:SSE实时传输

本视频讲述了MCP协议为解决工具返回数据格式与传输机制不统一问题而设计的协议层与传输层架构,并重点解析了MCP三节点(Host、客户端、服务端)间通信所采用的SSE事件流协议及其相较于WebSocket的单向性、轻量性优势,同时说明了本地场景下进程/线程通信(STDIO)与远程HTTP调用的协同机制。

**MCP协议设计动因与双层架构 **

  • 工具异构性引发的两大问题
    • 不同工具返回数据格式不统一。
    • 不同工具数据传输机制不统一:第三方API使用HTTP协议,本地文件访问使用进程通信。
  • MCP双层通信架构
    • 协议层 :约定工具返回数据的统一格式。
    • 传输层 :使MCP协议能自主选择适配的数据传输机制。

**MCP传输层的双重自主选择能力 **

  • 第一重选择:服务端调用工具时的传输机制适配
    • 调用第三方API → 选用HTTP协议 。
    • 访问本地数据文件 → 选用线程通信 。
  • 第二重选择:三节点间通信的传输机制适配
    • MCP客户端与MCP服务端跨机器部署 → 可选HTTP或RPC协议。
    • MCP host(大模型端)与MCP客户端同机部署 → 选用本地进程通信。

传统HTTP通信的局限性分析

  • 请求-响应模型本质
    • 客户端发起请求 → 服务端响应 → 连接断开。
    • 服务端无法主动向客户端推送数据 。
  • DeepSeek网页端实证观察
    • 发送prompt后,响应内容以流式方式逐字返回(如打印机效果)。
    • Network面板中compression大小持续变化,表明服务端持续分批发送数据 。
    • 响应头Content-Type: text/event-stream明确标识为事件流(Event Stream)。

**WebSocket与SSE协议对比及SSE选型依据 **

  • WebSocket特性 建立长连接后,支持客户端→服务端请求与服务端→客户端推送双向通信 。
  • SSE(Server-Sent Events)特性
    • 建立长连接后,仅支持服务端→客户端单向推送 ;客户端无法在连接期间发起新请求,须待连接断开后方可重发 。
  • SSE被选为大模型通信协议的核心原因
    • 业务场景匹配性 :用户提问后,大模型分批返回结果;期间无需交互,仅需等待完整响应后再发起新prompt 。
    • 性能与资源效率 :SSE是轻量级协议,较WebSocket显著降低服务器资源消耗,适配高并发访问场景 。

MCP全链路通信机制总结

  • 页面前端 ↔ 大模型(MCP Host) 基于SSE事件流协议实现流式响应。
  • MCP Host ↔ MCP客户端 ↔ MCP服务端
    • 跨机器部署时 → 统一采用SSE协议,确保与前端通信模型一致 。
    • 同机部署时(MCP Host ↔ MCP客户端) → 采用进程间通信(STDIO)。
  • MCP服务端 ↔ 外部系统
    • 调用第三方API → 基于HTTP协议 。
    • 访问本地服务 → 基于线程通信(STDIO)。

4-5创建MCP工具

在父工程下创建mcp-server服务

java
/**
 * 天气工具的业务逻辑定义
 */
@Component
public class WeatherTool {

    /**
     * 疑问:
     * 1.大模型如何知道能够使用哪些工具
     * 2.大模型如何知道选择对应工具
     *
     * @Tool注解: 1。修饰的方法,告诉大模型,你能够使用这个方法
     * 2.@Tool的description属性非常重要,必须要写,
     * 大模型根据description的描述判断何时以及如何使用这个工具
     * @ToolParam注解: 定义方法的参数
     */
    @Tool(description = "获取指定城市的温度")
    public String getTemperature(@ToolParam String cityName) {
        return cityName + "温度值:20度";
    }

    @Tool(description = "获取指定城市的紫外线值")
    public String getUltraviolet(@ToolParam String cityName) {
        return cityName + "紫外线值:3";
    }
}

4-6将MCP工具注册到MCP服务

java
/**
 * 把MCP工具写入工具清单(在MCP服务端进行工具注册)
 */
@Configuration
@ComponentScan(basePackages = "mcp.server.tools")
public class ToolsRegister {

    /**
     * 将MCP工具写入工具清单
     *
     * @param weatherTool 天气工具
     * @return ToolCallbackProvider
     */
    @Bean
    public ToolCallbackProvider toolList(WeatherTool weatherTool) {

        /**
         * MethodToolCallbackProvider是实现了ToolCallbackProvider接口
         * MethodToolCallbackProvider通过Builder模式生成实例
         * Java对象实例生成的方式:
         * 1.New
         * 2.Builder模式
         */
        return MethodToolCallbackProvider.builder().toolObjects(weatherTool).build();
    }
}

4-7线程不会被卡住:WebFlux框架

SpringAi Alibaba文档 https://java2ai.com/

引入依赖

xml
<!--      基于SpringBoot的WebFluX 框架 实现MCP 服务端的 SSE 协议-->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-mcp-server-webflux</artifactId>
</dependency>
<!--      基于SpringBoot的WebMvc 框架 实现MCP 服务端的 SSE 协议-->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>
  • webflux 框架和 webmvc是 Spring 的核心通信框架。 SpringBoot 搭建HTTP服务器的时候,就已经自动配置了 webflux 框架 或者webmvc
  • webflux和webmvc 支持 SsE 协议
  • webmvc框架基于阻塞模型去处理请求:
    • 一个请求会单独用一个线程去处理这个请求
    • 这个线程在处理这个请求期间,是不能做其他的事情
  • webflux框架基于非阻塞模型去处理请求:
    • 用一个线程去处理多个请求
    • 这个线程在处理这个请求期间,是能做其他的事情
  • webflux框架在性能上 优于 webmvc框架

4-8Jmanus导入SpringAi自定义的MCP服务

mcp服务补充配置文件和启动方法,在sse配置mcp的地址时,JManus导入MCP服务器,如果是使用SSE协议,地址必须包含/sse/

yaml
server:
  port: 8081
spring:
  application:
    name: weather-mcp-server
  ai:
    mcp:
      server:
        # MCP服务器名称
        name: weather-mcp-server
        version: 0.0.1
        type: SYNC
#        MCP服务器的地址
#        JManus导入MCP服务器,如果是使用SSE协议,地址必须包含/sse/
        sse-message-endpoint: /mcp/sse/weather

JManus导入MCP服务器: Tools/MCP配置=> mcp名称/连接类型(sse)/URL

4-9 SpringAi Alibaba1.1 以bom方式导入依赖

SpringAi Alibaba1.1版本更新,包含文档,学习新的文档技术路线。项目相关的依赖更新,父工程更新:

xml
<properties>
    <!--  SpringAi Alibaba 的版本号      -->
    <spring-ai-alibaba.version>1.1.0.0-RC2</spring-ai-alibaba.version>
    <!--  SpringAi 的版本号      -->
    <spring-ai.version>1.1.0</spring-ai.version>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencyManagement>
    <dependencies>
    <!--   SpringAi Alibaba 的 bom 版本管理        -->
    <dependency>
        <groupId>com.alibaba.cloud.ai</groupId>
        <artifactId>spring-ai-alibaba-bom</artifactId>
        <version>${spring-ai-alibaba.version}</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>
    <!--   SpringAi 的 bom 版本管理         -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-bom</artifactId>
        <version>${spring-ai.version}</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>

<!--
SpringAi 1.0 版本需要导入MCP底层依赖 (Spring-ai-MCP) 才能支持MCP协议 MCP版本号是0.10
SpringAi 1.1 版本把MCP底层依赖整合进依赖包,不需要导入MCP底层依赖,就能直接支持MCP协议 MCP版本号是0.14
     -->
        <!-- Spring AI Alibaba Agent Framework -->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-agent-framework</artifactId>
        </dependency>
    </dependencies>

4-10 SpringAi 1.1 整合MCP

依赖更新

xml-dtd
<dependencies>
<!--
    MCP的4个通信方式:
    1. STDIO: 进程间的通信,MCP服务端和客户端处于同一个电脑
    2. SSE:流式通信
    3. Streamable-HTTP : 流式通信, SSE的升级版
    4. Stateless: 流式通信, 基于HTTP协议,无状态的通信
    SSE,Steamable-HTTP, Stateless都可以SpringBoot 的Webflux 框架进行处理
 -->
    <!--   基于SpringBoot 的Webflux 框架 实现MCP 服务端的 SSE 协议    -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
<!--
    SpringAi 1.1 基于注解(Annotations)开发MCP
    基于注解(Annotations) 引入依赖 MCP-Annotations 依赖包
    spring-ai-starter-mcp-server-webflux 这个依赖包自动引入 MCP-Annotations 依赖包
    spring-ai-starter-mcp-server-webflux 属于 SpringAi,
    不属于 SpringAi Alibaba,
    所以需要引入SpringAi
     -->
        <artifactId>spring-ai-starter-mcp-server-webflux</artifactId>
    </dependency>
</dependencies>

4-11SpringAi 1.1 A2A的3个核心组件

A2A通信协议:不同大模型直接的通信协议。

Google 提出的 A2A协议 用于不同大语言模型的Agent 之间进行通信

SpringAi alibaba 1.1 提供了实现A2A协议的Api 这里的A2A协议除了用于不同模型的Agent 之间进行通信, 也能用于同一个大语言模型,但位于不同节点(分布式)的Agent 之间的通信

*有3个核心组件 A2A Provider (服务提供): ReActAgent 注册中心 ( 阿里的Nacos 3.1 ) (服务注册 ) A2A Consumer ( 服务发现 ): A2aRemoteAgent

A2A协议的流程

  1. 服务提供者 将智能体卡片 存储在 注册中心
  2. 服务发现者 通过 AgentCardProvider 基于远程智能体name 获取 对应的智能体卡片
  3. 注册中心根据服务发现者所获取的智能体卡片,告诉远程Agent, 去执行服务发现者 所提供的任务

智能体卡片:

  1. name 远程智能体的name
  2. description 远程智能体的描述
  3. url 注册中心的地址
  4. version 远程智能体的版本
  5. capabilities 远程智能体的能力
  6. skills 远程智能体的专业领域技能

4-12 SpringAi 1.1 MCP注解:全新的MCP实现

MCP Server中更新。

依赖更新

  • SpringAi 1.1 基于注解(Annotations)开发MCP, 基于注解(Annotations) 引入依赖 MCP-Annotations 依赖包
  • spring-ai-starter-mcp-server-webflux 这个依赖包自动引入 MCP-Annotations 依赖包
  • spring-ai-starter-mcp-server-webflux 属于 SpringAi, 不属于 SpringAi Alibaba,所以需要引入SpringAi
xml
<dependencies>
<!--
    MCP的4个通信方式:
    1. STDIO: 进程间的通信,MCP服务端和客户端处于同一个电脑
    2. SSE:流式通信
    3. Streamable-HTTP : 流式通信, SSE的升级版
    4. Stateless: 流式通信, 基于HTTP协议,无状态的通信
    SSE,Steamable-HTTP, Stateless都可以SpringBoot 的Webflux 框架进行处理
 -->
    <!--   基于SpringBoot 的Webflux 框架 实现MCP 服务端的 SSE 协议    -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
<!--
    SpringAi 1.1 基于注解(Annotations)开发MCP
    基于注解(Annotations) 引入依赖 MCP-Annotations 依赖包
    spring-ai-starter-mcp-server-webflux 这个依赖包自动引入 MCP-Annotations 依赖包
    spring-ai-starter-mcp-server-webflux 属于 SpringAi,
    不属于 SpringAi Alibaba,
    所以需要引入SpringAi
     -->
        <artifactId>spring-ai-starter-mcp-server-webflux</artifactId>
    </dependency>
</dependencies>

WeatherTool更新

java
import io.modelcontextprotocol.server.McpSyncServerExchange;
import io.modelcontextprotocol.spec.McpSchema;
import org.springaicommunity.mcp.annotation.McpProgressToken;
import org.springaicommunity.mcp.annotation.McpTool;
import org.springaicommunity.mcp.annotation.McpToolParam;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Component;

/**
 * description: 天气工具的业务逻辑定义
 */
@Component
public class WeatherTool {
    /* **********************
     *
     * 疑问:
     * 1. 大模型如何知道能够使用哪些工具
     * 2. 大模型如何知道选择对应工具
     *
     * @MCPTool注解:
     *
     * 1. 修饰的方法,告诉大模型,你能够使用这个方法
     * 2. @MCPTool的description属性非常重要,必须要写,
     * 大模型根据description的描述判断何时以及如何使用这个工具
     *
     * @McpToolParam 注解:
     * 定义方法的参数
     *
     *
     * @McpProgressToken 注解:
     * 方法调用的进度
     * 只能是Sting,或者Int
     *
     * McpSyncServerExchange:
     * 将@McpProgressToken所产生的进度Token,
     * 写入到上下文,返回给客户端
     *
     * *********************/

    @McpTool(name = "Temperature",
            description = "获取指定城市当前时间的温度")
    public String getTemperature(
            @McpToolParam String cityName,
            @McpProgressToken String progressToken,
            McpSyncServerExchange exchange
    ) {
        //发送执行进度
        if(progressToken !=null) {
            exchange.progressNotification(
                    new McpSchema.ProgressNotification(
                            progressToken,
                            0.5,
                            1.0,
                            "正在执行中....")
            );
            exchange.progressNotification(
                    new McpSchema.ProgressNotification(
                            progressToken,
                            0.9,
                            1.0,
                            "准备返回数据" )
            );
        }
        return  cityName    + "温度值是30度";
    }
    @McpTool(description = "获取指定城市的紫外线值")
    public String getUltraviolet(@McpToolParam String cityName) {
        return cityName + "紫外线值:";
    }
}

配置修改

yaml
ai:
   mcp:
      server:
        # MCP服务器名称
        name: weather-mcp-server-springAi_1.1
        version: 0.0.1
        type: SYNC
        protocol: STREAMABLE
        annotation-scanner:
          enabled: true

4-13 SpringAi 1.1 A2A的服务注册

父工程依赖

xml
<properties>
    <!--  SpringAi Alibaba 的版本号      -->
    <spring-ai-alibaba.version>1.1.0.0-RC2</spring-ai-alibaba.version>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencyManagement>
    <dependencies>
        <!--   SpringAi Alibaba 的 bom 版本管理        -->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-bom</artifactId>
            <version>${spring-ai-alibaba.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <!-- Spring AI Alibaba Agent Framework -->
    <dependency>
        <groupId>com.alibaba.cloud.ai</groupId>
        <artifactId>spring-ai-alibaba-agent-framework</artifactId>
    </dependency>
    <!-- A2A Nacos 注册中心 -->
    <dependency>
        <groupId>com.alibaba.cloud.ai</groupId>
        <artifactId>spring-ai-alibaba-starter-a2a-nacos</artifactId>
    </dependency>
    <!--   阿里大模型平台 DashCope     -->
    <dependency>
        <groupId>com.alibaba.cloud.ai</groupId>
        <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
        <version>${spring-ai-alibaba.version}</version>
    </dependency>
    <!--   必须添加  spring-boot-starter-web   -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>3.5.8</version>
    </dependency>
</dependencies>

注册服务a2a-provider

Google 提出的 A2A协议 用于不同大语言模型的Agent 之间进行通信

SpringAi alibaba 1.1 提供了实现A2A协议的Api 这里的A2A协议除了用于不同模型的Agent 之间进行通信, 也能用于同一个大语言模型,但位于不同节点(分布式)的Agent 之间的通信

有3个核心组件 A2A Provider (服务提供): ReActAgent 注册中心 ( 阿里的Nacos 3.1 ) (服务注册 ) A2A Consumer ( 服务发现 ): A2aRemoteAgent

A2A协议的流程

  1. 服务提供者 将智能体卡片 存储在 注册中心
  2. 服务发现者 通过 AgentCardProvider 基于远程智能体name 获取 对应的智能体卡片
  3. 注册中心根据服务发现者所获取的智能体卡片,告诉远程Agent, 去执行服务发现者 所提供的任务

智能体卡片:

  1. name 远程智能体的name
  2. description 远程智能体的描述
  3. url 注册中心的地址
  4. version 远程智能体的版本
  5. capabilities 远程智能体的能力
  6. skills 远程智能体的专业领域技能

创建Tools工具tools/WeatherTool

java
/**
 * 天气工具
 */
@Component
public class WeatherTool {
    @Tool(description = "获取天气")
    public void getWeather(String city) {
        System.out.println("正在获取" + city + "天气信息...");
    }
}

创建智能体agents/AgentProviderConfig

java
/**
 * 创建智能体
 */
@Configuration
public class AgentProviderConfig {
    @Bean
    public ReactAgent agentProvider(
            //以参数形式注入ChatModel
            ChatModel chatModel,
            WeatherTool weatherTool) {
        /**
         * SpringAi Alibaba 1.1 版本
         * 通过 ReactAgent的工厂方法(builder) 创建Agent,
         * ReactAgent: 能够自主规划,自主决策,能够执行工具,有记忆能力,感知周边环境的智能体
         **/
        return ReactAgent.builder()
                .name("AgentProvider")
                .description("")
                //.model需要的参数是 ChatModel,
                //ChatModel是以参数的形式注入的,
                //在后面课程会详细讲解ChatModel
                .model(chatModel)
                //先注释Agent工具配置, 在后面课程会详细讲述
                //.tool(weatherTool)
                .build();
    }
}

配置文件applicatopn.yml

yaml
spring:
  application:
    name: xxx
  ai:
    dashscope:
      api-key: 你的ApiKey
      chat:
        options:
          model: qwen-max
    alibaba:
      a2a:
        nacos:
          server-addr: 127.0.0.1:8848
          username: nacos
          password: nacos
          registry:
            enabled: true
        server:
          version: 1.0.0
          card:
            # 智能体卡片的name 要和 Agent的name 一致
            name: AgentProvider
            description: "imooc智能体"
            version: "1.0.0"

4-14 SpringAi 1.1 A2A的服务发现

服务service

java
/**
 * description: A2A 远程Agent的发现服务类
 */
@Service
public class AgentConsumerService {

    //发现远程的A2A Agent
    public void getAgentProvider() throws GraphRunnerException {

        /* **********************
         *
         * 这里创建的Agent,
         * 并不是用于执行业务的,
         * 执行业务的是远程的Agent,
         *
         * 这里创建的Agent,
         * 用于发现相应的远程的Agent,并获取这个远程Agent
         *
         *
         * *********************/
        //获取远程Agent
        A2aRemoteAgent agentProvider =
                A2aRemoteAgent.builder()
                        //AgentCardProvider 通过 远程Agent的name 获取指定的远程智能体卡片
                        .name("AgentProvider")
                        .shareState(true)
                        .build();
        //运行远程的Agent
        Optional<OverAllState> res = agentProvider.invoke("提示词");
        /* **********************
         *
         *
         * OverAllState属于工作流的状态对象
         * 工作流每个节点的执行结果,多会更新到OverAllState对象里
         * OverAllState对象,在工作流的所有节点进行流动
         * 这样,工作流上一个节点,就可以把执行结果,传递到下一个节点
         * OverAllState是属于Key-Value
         *
         * *********************/
        //获取远程Agent执行完成任务之后的结果 (从OverAllState对象里获取回复)
        res.flatMap(state -> state.value("key"))
                .map(v->(String) v);
    }
}

消费

java
/**
 * description: 调用远程Agent的控制器
 */
@RestController
public class AgentConsumerController {

    @Autowired
    private AgentConsumerService serv;

    //把要调用的远程Agent的智能体卡片属性(name)告诉注册中心
    @GetMapping("/demo/a2a/consumer")
    public void getRemoteAgent() throws GraphRunnerException {
        serv.getAgentProvider();
    }
}

配置文件

yaml
spring:
  application:
    name: xx_a2a_consumer
  ai:
    dashscope:
      api-key: 你的ApiKey
      chat:
        options:
          model: qwen-max
    alibaba:
      a2a:
        nacos:
          server-addr: 127.0.0.1:8848
          discovery:
            enabled: true

4-15SpringAi 1.1 A2A的元数据AgentCard

javascript
@Service
public class AgentConsumerService {
    @Autowired
    @Qualifier("agentCardProvider")
    private AgentCardProvider agentCardProvider;

    //发现远程的A2A Agent
    public void getAgentProvider() throws GraphRunnerException {

        /* **********************
         *
         * 这里创建的Agent,
         * 并不是用于执行业务的,
         * 执行业务的是远程的Agent,
         *
         * 这里创建的Agent,
         * 用于发现相应的远程的Agent,并获取这个远程Agent
         *
         *
         * *********************/
        //获取远程Agent
        A2aRemoteAgent agentProvider =
                A2aRemoteAgent.builder()
                        //AgentCardProvider 通过 远程Agent的name 获取指定的远程智能体卡片
                        .name("AgentProvider")
                        //必须要填
                        .description("description")
                        //必须要填
                        .instruction("instruction")
                        //远程智能体的卡片(远程Agent的元数据, 名片)
                        //远程智能体的卡片,存储在注册中心
                        //服务消费者,是通过 AgentCardProvider 对象获取注册中心的智能体卡片
                        .agentCardProvider(agentCardProvider)
                        //必须要填
                        .shareState(true)
                        .build();
        //运行远程的Agent
        Optional<OverAllState> res = agentProvider.invoke("提示词");
        /* **********************
         *
         *
         * OverAllState属于工作流的状态对象
         * 工作流每个节点的执行结果,多会更新到OverAllState对象里
         * OverAllState对象,在工作流的所有节点进行流动
         * 这样,工作流上一个节点,就可以把执行结果,传递到下一个节点
         * OverAllState是属于Key-Value
         *
         * *********************/
        res.ifPresent(state -> {
            System.out.println("远程Agent被成功调用");
        });
        //获取远程Agent执行完成任务之后的结果 (从OverAllState对象里获取回复)
//        res.flatMap(state -> state.value("key"))
//                .map(v->(String) v);
//
    }
}

4-16测试SpringAi 1.1 实现的A2A协议

nacos下载

shell
# 下载
sudo docker pull nacos/nacos-server:v3.1.0
# 运行
sudo docker run --rm --name nacos -e MODE=standalone -e NACOS_AUTH_ENABLE=false -e NACOS_AUTH_TOKEN=MjM1ZmU4NjAxMzU1NTQyYWU0MTEyYWU4ZDg3YTZiNGUK -e NACOS_AUTH_IDENTITY_KEY=nacos -e NACOS_AUTH_IDENTITY_VALUE=nacos -p 8848:8848 -p 9848:9848 -p 8088:8080 nacos/nacos-server:v3.1.0

# 控制台页面:http://127.0.0.1:8088
# 控制台登录username: nacos
# 控制台登录password: nacos

# 说明
 8848:HTTP端口
 9848:RPC端口
 8088:控制台页面端口

启动,调用消费者的接口