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();
    }
相关推荐
铁蛋AI编程实战3 小时前
通义千问 3.5 Turbo GGUF 量化版本地部署教程:4G 显存即可运行,数据永不泄露
java·人工智能·python
晚霞的不甘3 小时前
CANN 编译器深度解析:UB、L1 与 Global Memory 的协同调度机制
java·后端·spring·架构·音视频
SunnyDays10113 小时前
使用 Java 冻结 Excel 行和列:完整指南
java·冻结excel行和列
摇滚侠3 小时前
在 SpringBoot 项目中,开发工具使用 IDEA,.idea 目录下的文件需要提交吗
java·spring boot·intellij-idea
云姜.3 小时前
java多态
java·开发语言·c++
李堇3 小时前
android滚动列表VerticalRollingTextView
android·java
泉-java4 小时前
第56条:为所有导出的API元素编写文档注释 《Effective Java》
java·开发语言
csdn_life184 小时前
openclaw mcporter 操作 chome 在 window10/linux chrome-devtools-mcp
chrome·mcp·openclaw
zfoo-framework4 小时前
帧同步和状态同步
java
charlotte102410244 小时前
高并发:关于在等待学校教务系统选课时的碎碎念
java·运维·网络