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();
    }
相关推荐
@老蝴2 小时前
MySQL数据库 - 事务
java·数据库·mysql
木井巳2 小时前
【Java】深入理解Java语言的重要概念
java·开发语言
yangminlei2 小时前
MyBatis插件开发-实现SQL执行耗时监控
java·开发语言·tomcat
what丶k2 小时前
Java连接人大金仓数据库(KingbaseES)全指南:从环境搭建到实战优化
java·开发语言·数据库
沛沛老爹2 小时前
从Web到AI:多模态Agent Skills开发实战——JavaScript+Python全栈赋能视觉/语音能力
java·开发语言·javascript·人工智能·python·安全架构
0x532 小时前
JAVA|智能仿真并发项目-进程与线程
java·开发语言·jvm
xiaolyuh1232 小时前
Spring Boot 深度解析
java·spring boot·后端
黎雁·泠崖2 小时前
Java静态方法:用法+工具类设计+ArrayUtil实战
java·开发语言
Java后端的Ai之路2 小时前
【AI大模型开发】-RAG多模态详解(通俗易懂)
人工智能·大模型·rag多模态