SpringAi-MCP技术

1.定义

  1. 定义一个工具
  2. 把工具注册进去

MCP ,全称是 Model Context Protocol (模型上下⽂协议),是⼀种标准化协议,使 AI 模型能 够以结构化的⽅式与外部⼯具和资源进⾏交互。该协议⽀持多种传输机制,以在不同环境中提供灵活 性。可以把它想象成⼀个让 AI 模型更顺畅⼯作的桥梁和助⼿。

2.快速入门(获取当前时间)

2.1导包

XML 复制代码
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-model-openai</artifactId>
        </dependency>
    </dependencies>

2.2配置yml文件

复制代码
server:
  port: 8007
spring:
  application:
    name: ai-siliconflow-mcp-glm
  ai:
    openai:
      base-url: https://api.siliconflow.cn
      api-key: sk-rlpneielwjrtbzwghvmtnkrfzsqoorkclubnimumojlptvqz
      chat:
        options:
          model: "zai-org/GLM-4.6"
          temperature: 0.7

2.3写config类

java 复制代码
@Configuration
public class ChatClientConfig {
    @Resource
    private OpenAiChatModel openAiChatModel;
    @Bean("openAiChatClient")
    public ChatClient openAiChatClient(WeatherJiaService weatherJiaService, AmapSrvice amapSrvice){
        return ChatClient.builder(openAiChatModel)
                .build();
    }
}

2.4写工具类service

java 复制代码
package com.jiazhong.mingxing.ai.siliconflow.mcp.glm.service;

import org.springframework.stereotype.Service;

@Service
public interface NowDateToolService {
    String getNowDate();

}

2.5写工具类的具体实现类

java 复制代码
@Slf4j
@Service
public class NowDateToolServiceImpl implements NowDateToolService {
    //@Tool(description = "获取到系统的当前时间")
    public String getNowDate() {
        log.info("开始调用获取当前时间的工具......");
        SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
        return simpleDateFormat.format(new Date());
    }
}

2.6在config类中注册tool工具

java 复制代码
@Configuration
public class ChatClientConfig {
    @Resource
    private OpenAiChatModel openAiChatModel;
    @Resource
    private NowDateToolService nowDateToolService;
    @Bean("openAiChatClient")
    public ChatClient openAiChatClient(WeatherJiaService weatherJiaService, AmapSrvice amapSrvice){
        return ChatClient.builder(openAiChatModel)
                .defaultTools(nowDateToolService)
                .build();
    }
}

2.7写ccontroller类

java 复制代码
@GetMapping(value = "/stream",produces = "text/html;charset=utf-8")
    public Flux<String> stream(@RequestParam("question") String question){
        return openAiChatClient.prompt()
                .user(question)
                .stream().content();
    }

2.8配置启动类

并在浏览器中问关于时间的问题,会给出系统时间

3.采取行动

在前⾯的示例中,我们使⽤了⼀个⼯具来确定当前⽇期和时间。在这个例⼦中,我们将定义第⼆个⼯ 具,⽤于在特定时间设置警报。⽬标是从现在开始设置10分钟的警报,因此我们需要为模型提供这两 种⼯具来完成这项任务。 我们将把新⼯具添加到与以前相同的 DateTimeToolsService 类中。新⼯具将采⽤⼀个参数,即 ISO-8601 格式的时间。然后,该⼯具将向控制台打印⼀条消息,指示已在给定时间内设置报警。与 之前⼀样,该⼯具被定义为⼀个⽤ @tool 注释的⽅法,我们还使⽤它来提供详细的描述,以帮助模 型理解何时以及如何使⽤该⼯具。

java 复制代码
@Tool(description = "设置一个时间报警器")
    public void setAlarm(@ToolParam(description = "当前系统时间") String time){
        log.info("时间是:{}",time);
        LocalDateTime localDateTime=LocalDateTime.parse(time);
        log.info("转换后的时间:{}",localDateTime);
    }

4.方法即工具

4.1声明式

您可以通过使⽤ @tool 对⽅法进⾏注释,将其转化为⼯具。

如上述入门案例所示。

@Tool 注释允许您提供有关⼯具的关键信息:

  • name :工具具的名称。如果没有提供,将使⽤⽅法名称。 AI 模型在调⽤⼯具时使⽤此名称来 标识⼯具。因此,不允许在同⼀类中有两个同名⼯具。对于特定的聊天请求,该名称在模型可 ⽤的所有⼯具中必须是唯⼀的。(可以不写)
  • description :⼯具的描述,模型可以使⽤它来了解何时以及如何调⽤⼯具。如果没有提 供,⽅法名称将⽤作⼯具描述。然⽽,强烈建议提供详细的描述,因为这对于模型理解⼯具的 ⽬的以及如何使⽤它⾄关重要。如果不能提供⼀个好的描述,可能会导致模型在应该使⽤的时 候不使⽤⼯具,或者使⽤不当。(要写)
  • returnDirect :⼯具结果是应该直接返回给客户端还是传递回模型。
  • resultConverter : ToolCallResultConverter 实现,⽤于将⼯具调⽤的结果转换为 String 对象,以发送回 AI 模型。

SpringAI 将⾃动为 @Tool 注释⽅法的输⼊参数⽣成 JSON 模式。模型使⽤模式来了解如何调⽤⼯ 具和准备⼯具请求。 @ToolParam 注释可⽤于提供有关输⼊参数的其他信息,例如描述参数是必需的 还是可选的。默认情况下,所有输⼊参数都被认为是必需的。

4.2编程式

4.2.1在controller中

java 复制代码
 @GetMapping(value = "/stream2",produces = "text/html;charset=utf-8")
    public Flux<String> stream2(@RequestParam("question") String question){
        //获取到了指定的方法
        Method method = ReflectionUtils.findMethod(NowDateToolService.class,
                "getNowDate");
        //开始创建工具
        ToolDefinition toolDefinition = ToolDefinitions.builder(method)
                .description("获取⽤户时区中的当前时间")
                .name("getCurrentDateTime2")
                .build();
        //开始注册工具
        MethodToolCallback methodToolCallback = MethodToolCallback.builder()
                .toolDefinition(toolDefinition)
                .toolMethod(method)
                .toolObject(nowDateToolService) // 必须是DateTimeToolsService类的实例
                .build();

        return openAiChatClient.prompt()
                .toolCallbacks(methodToolCallback)
                .user(question)
                .stream().content();
    }

删掉serviceImp中的@Tool注解即可实现。

5.函数即工具

SpringAI 提供了从函数中指定⼯具的内置⽀持,可以使⽤ FunctionToolCallback 实现进⾏编 程,也可以在运⾏时动态解析 @Bean 。

5.1函数工具的回调

案例--查看城市天气(假的)

5.1.1bean包下写Weather类

定义两个实体类

java 复制代码
package com.jiazhong.mingxing.ai.siliconflow.mcp.glm.bean;

public class Weather {
    //城市
    public record WeatherRequest(String city){

    }
    //气温
    public record WeatherResponse(double weather){}
}

5.1.2service包

java 复制代码
package com.jiazhong.mingxing.ai.siliconflow.mcp.glm.service;

import com.jiazhong.mingxing.ai.siliconflow.mcp.glm.bean.Weather;
import org.springframework.stereotype.Service;

import java.util.function.Function;

@Service
public interface WeatherJiaService extends Function<Weather.WeatherRequest,Weather.WeatherResponse> {
}

5.1.3impl类

java 复制代码
package com.jiazhong.mingxing.ai.siliconflow.mcp.glm.service.impl;

import com.jiazhong.mingxing.ai.siliconflow.mcp.glm.bean.Weather;
import com.jiazhong.mingxing.ai.siliconflow.mcp.glm.service.WeatherJiaService;
import org.springframework.stereotype.Service;

@Service
public class WeatherJiaServiceImpl implements WeatherJiaService {
    @Override
    //因为WeatherRequest是内部类,在Weather类中,所以要使用Weather.WeatherRequest
    public Weather.WeatherResponse apply(Weather.WeatherRequest weatherRequest) {
        if ("西安".equals(weatherRequest.city())){
            return new Weather.WeatherResponse(30.1);
        }else if ("宝鸡".equals(weatherRequest.city())){
            return new Weather.WeatherResponse(25.4);
        }else if ("漠河".equals(weatherRequest.city())){
            return new Weather.WeatherResponse(-27.9);
        }
        return new Weather.WeatherResponse(15);
    }
}

5.1.4controller类(局部写法)

java 复制代码
@GetMapping(value = "stream3",produces = "text/html;charset=utf-8")
    public Flux<String> stream3(@RequestParam("question") String question){
        FunctionToolCallback<Weather.WeatherRequest,Weather.WeatherResponse> toolCallback=
                FunctionToolCallback.builder("weatherJiaServiceImpl",weatherJiaService)
                        .description("获取到指定位置的天气").inputType(Weather.WeatherRequest.class).build();
        return openAiChatClient.prompt()
                .toolCallbacks(toolCallback)
                .user(question)
                .stream().content();
    }

5.1.5config类(全局写法)

java 复制代码
@Bean("openAiChatClient")
    public ChatClient openAiChatClient(WeatherJiaService weatherJiaService, AmapSrvice amapSrvice){
        FunctionToolCallback<Weather.WeatherRequest,Weather.WeatherResponse> toolCallback
                =FunctionToolCallback.builder("weatherJiaServiceImpl",weatherJiaService)
                .description("获取到执行位置的天气").inputType(Weather.WeatherRequest.class).build();
        return ChatClient.builder(openAiChatModel)
                .defaultTools(weatherJiaService)
                /*.defaultToolNames("currentWeather","currentDressing")*/
                .defaultTools(toolCallback)
                .build();
    }

5.2@Bean 动态规范

5.2.1新建ToolConfig类

java 复制代码
package com.jiazhong.mingxing.ai.siliconflow.mcp.glm.config;

import com.jiazhong.mingxing.ai.siliconflow.mcp.glm.bean.Weather;
import com.jiazhong.mingxing.ai.siliconflow.mcp.glm.service.DressingService;
import com.jiazhong.mingxing.ai.siliconflow.mcp.glm.service.WeatherJiaService;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.function.Function;

@Configuration
public class ToolConfig {
    @Resource
    private WeatherJiaService weatherJiaService;
    @Resource
    private DressingService dressingService;

    @Bean("currentWeather")
    public Function<Weather.WeatherRequest,Weather.WeatherResponse> weather(){
        return weatherJiaService;
    }
    @Bean("currentDressing")
    public Function<Weather.WeatherResponse,String> dressing(){
        return dressingService;
    }
}

5.2.2写ChatClientController

java 复制代码
 @Bean("openAiChatClient")
    public ChatClient openAiChatClient(WeatherJiaService weatherJiaService, AmapSrvice amapSrvice){
        /*FunctionToolCallback<Weather.WeatherRequest,Weather.WeatherResponse> toolCallback
                =FunctionToolCallback.builder("weatherJiaServiceImpl",weatherJiaService)
                .description("获取到执行位置的天气").inputType(Weather.WeatherRequest.class).build();*/
        return ChatClient.builder(openAiChatModel)
                /*.defaultTools(currentWeather)*/
                .defaultToolNames("currentWeather")
               /* .defaultTools(amapSrvice)*/
                .build();
    }
相关推荐
咩咩啃树皮15 分钟前
第40篇:Vue3组件化开发精讲——组件拆分、复用、父子通信、工程化架构
java·前端·架构
鱟鲥鳚1 小时前
Spring Boot 集成 LangChain4j:从模型调用到 Tool Calling(Demo版)
java·spring boot
大模型码小白2 小时前
【Python零基础教程】继承、多态与魔法函数:面向对象编程三大核心特性详解
java·大数据·开发语言·人工智能·python·ai编程
腾渊信息科技公司3 小时前
Spring Boot对接MES实战:视觉检测数据自动同步方案
java·人工智能·spring boot·后端·计算机视觉·ai·软件需求
爱笑的源码基地4 小时前
高并发 Redis 缓存门诊HIS系统源码,含财务统计药房进销存
java·程序·门诊系统·诊所系统·云诊所源码
wuqingshun3141594 小时前
TCP超时重传机制是为了解决什么问题?
java
hhzz6 小时前
Tiger AI Platform平台中增加人脸识别功能
图像处理·人工智能·算法·计算机视觉·大模型
莫逸风6 小时前
【AgentScope 2.0】 0. 学习指南
java·llm·agent·agentscope
z123456789867 小时前
2026最新两款AI编程工具深度对比实测
java·数据库·ai编程
yaoxin5211238 小时前
470. Java 反射 - Member 接口与 AccessFlag
java·开发语言·python