SpringBoot中使用MCP和通义千问来处理和分析数据-入门,查寻和基本的分析

前言

近来,AI大模型的应用在各种场景下出尽了风头,那么不爱学习的java程序员,不是一个好程序员。这里我学习并简单使用了SpringBoot 和 MCP ,大模型使用通义千问。

MCP(Model Context Protocol,模型上下文协议)是一种用于大语言模型(LLM)与外部环境交互的标准化协议。它主要用于管理模型的上下文信息,使AI模型能够在多步骤、有状态的交互中保持上下文连贯。

相比传统API每次请求独立处理的方式,MCP通过统一的协议支持更高效、复杂的交互流程,提升了AI应用的智能性和实用性。

本文将以最基础的【学生查询功能】来搭配MCP 和 通义千问,实现智能对话功能。
另外,顺便标记了一个【创建学生】的功能,也可以使用自然语言来触发。

一、正文

1.1 项目结构

项目父模块是一个pom打包方式的模块,主要管理依赖和版本。另外配置了spring未发布的jar仓库地址。

核心代码在【sse-server】模块中。起初项目是想做成sse连接对话式的,后来做成了同步。所以这里的项目名也懒的改了。(SSE 的方式以后再说,后续如果再写一版,我会补充进来)

在这里插入图片描述
PS:这里以 manager 层作为 DAO 层,做数据访问,使用内存数据进行模拟数据库。

1.2 项目环境

项目采用 java 21 + springboot 3.4.2 版本来进行开发,没有前端页面。没有数据库,只提供一个对话接口。

内部整合了 通义千问。需要在阿里的申请页面进行申请,有免费的token。这个是申请页面:https://help.aliyun.com/zh/model-studio/get-api-key

1.3 完整代码

1.3.1 spring-mcp-demo的pom文件

<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.mcp</groupId>
  <artifactId>spring-mcp-demo</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>pom</packaging>

  <name>spring-mcp-demo</name>
  <url>http://maven.apache.org</url>
  <modules>
    <module>sse-server</module>
  </modules>

  <properties>
    <java.version>21</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <repositories>
    <repository>
      <id>spring-milestones</id>
      <name>Spring Milestones</name>
      <url>https://repo.spring.io/milestone</url>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
    <repository>
      <id>spring-snapshots</id>
      <name>Spring Snapshots</name>
      <url>https://repo.spring.io/snapshot</url>
      <releases>
        <enabled>false</enabled>
      </releases>
    </repository>
    <repository>
      <id>maven2</id>
      <name>maven2</name>
      <url>https://repo1.maven.org/maven2/</url>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
    <repository>
      <name>Central Portal Snapshots</name>
      <id>central-portal-snapshots</id>
      <url>https://central.sonatype.com/repository/maven-snapshots/</url>
      <releases>
        <enabled>false</enabled>
      </releases>
      <snapshots>
        <enabled>true</enabled>
      </snapshots>
    </repository>
  </repositories>

  <dependencyManagement>
    <dependencies>
      <!-- MCP 服务器支持 - WebMVC版本 -->
      <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-mcp-server-webmvc-spring-boot-starter</artifactId>
        <version>1.0.0-M6</version>
      </dependency>

      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>3.4.2</version>
      </dependency>

      <dependency>
        <groupId>com.alibaba.cloud.ai</groupId>
        <artifactId>spring-ai-alibaba-starter</artifactId>
        <version>1.0.0-M6.1</version>
      </dependency>
    </dependencies>

  </dependencyManagement>
</project>

这里需要额外注意一点,如果下载包有问题,需要在 maven 的 setting 配置文件中调整镜像配置:

<mirror>  
    <id>alimaven</id>  
    <name>aliyun maven</name>  
    <url>https://maven.aliyun.com/repository/public</url> 
    <!-- 表示除了spring-milestones、maven2其它都走阿里云镜像  --> 
    <mirrorOf>*,!spring-milestones,!maven2</mirrorOf>  
</mirror>

1.3.2 sse-server 的pom文件

<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.mcp</groupId>
        <artifactId>spring-mcp-demo</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>sse-server</artifactId>
    <packaging>jar</packaging>

    <name>sse-server</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.34</version>
            <optional>true</optional>
        </dependency>

        <!--        mcp-mvc的starter-->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-mcp-server-webmvc-spring-boot-starter</artifactId>
        </dependency>
        <!--        阿里ai的starter-->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>3.4.2</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <inherited>true</inherited>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <parameters>true</parameters>
                    <showWarnings>true</showWarnings>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>


1.3.3 ChatRequest

package org.mcp.beans;

import lombok.Data;

/**
 * 聊天请求体
 */
@Data
public class ChatRequest {
    /**
     * 用户消息内容,不能为空
     */
    private String message;
}


1.3.4 ChatResponse

package org.mcp.beans;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 聊天响应
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ChatResponse {
    /**
     * 响应内容
     */
    private String content;
}

1.3.5 ChatClientConfig

package org.mcp.config;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 聊天对话配置
 */
@Configuration
public class ChatClientConfig {

    @Autowired
    private ToolCallbackProvider toolCallbackProvider;

    /**
     * 配置ChatClient,注册系统指令和工具函数
     */
    @Bean
    public ChatClient chatClient(ChatClient.Builder builder){
        return builder
                .defaultSystem("你是一个学生管理助手,可以帮助用户查询学生信息。" +
                        "你可以根据学生名字模糊查询学生,根据性别查学生信息,查询全部学生信息,并做出一些基本的统计"+
                        "回复时,请使用简洁友好的语言,并将学生信息整理为易读的格式。")
                // 注册工具方法
                .defaultTools(toolCallbackProvider)
                .build();
    }
}

1.3.6 ServiceProviderConfig

package org.mcp.config;

import org.mcp.service.StudentService;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 服务提供者配置
 */
@Configuration
public class ServiceProviderConfig {

    @Autowired
    private StudentService studentService;
    
    @Bean
    public ToolCallbackProvider serverTools() {
        return MethodToolCallbackProvider.builder()
                // 可以注册多个服务
                .toolObjects(studentService)
                .build();
    }
}

1.3.7 ChatController

package org.mcp.controller;

import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import org.mcp.beans.ChatRequest;
import org.mcp.beans.ChatResponse;
import org.springframework.ai.chat.client.ChatClient;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;


@RestController
@RequestMapping("/api/chat")
public class ChatController {

    @Resource
    private ChatClient chatClient;


    @PostMapping("/chatting")
    @SneakyThrows
    public ResponseEntity<ChatResponse> chatting(@RequestBody ChatRequest request) {

        String userMessage = request.getMessage();

        // 调用聊天
        String content = chatClient.prompt()
                .user(userMessage)
                .call()
                .content();

        return ResponseEntity.ok(new ChatResponse(content));
    }
}

1.3.8 Student

package org.mcp.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {

    private String name;

    private int age;

    private String sex;

    private String className;

    private String phone;

    private String email;

    private String address;
}

1.3.9 StudentManager

package org.mcp.manager;

import org.mcp.entity.Student;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component
public class StudentManager {

    private static final List<Student> STUDENTS = new ArrayList<>();
    static {
        init();
    }
    private static void init() {
        // 初始化学生数据
        STUDENTS.add(new Student("张三", 18, "男", "1班", "12345678901", "12345678901@qq.com", "北京"));
        STUDENTS.add(new Student("李四", 19, "女", "2班", "12345678902", "12345678902@qq.com", "上海"));
        STUDENTS.add(new Student("王五", 20, "男", "3班", "12345678903", "12345678903@qq.com", "广州"));
        STUDENTS.add(new Student("赵六", 21, "女", "4班", "12345678904", "12345678904@qq.com", "深圳"));
        STUDENTS.add(new Student("孙七", 22, "男", "5班", "12345678905", "12345678905@qq.com", "杭州"));
        STUDENTS.add(new Student("钱八", 23, "女", "6班", "12345678906", "12345678906@qq.com", "南京"));
        STUDENTS.add(new Student("李九", 24, "男", "7班", "12345678907", "12345678907@qq.com", "西安"));
    }


    public List<Student> findStudentByName(String name) {
        List<Student> result = new ArrayList<>();
        for (Student student : STUDENTS) {
            if (student.getName().contains(name)) {
                result.add(student);
            }
        }

        return result;
    }

    public List<Student> findStudentBySex(String sex) {
        List<Student> result = new ArrayList<>();
        for (Student student : STUDENTS) {
            if (student.getSex().equals(sex)) {
                result.add(student);
            }
        }
        return result;
    }

    public List<Student> findAllStudents() {
        return STUDENTS;
    }

    public void createStudent(Student student) {
        STUDENTS.add(student);
    }
}


1.3.10 StudentService

提供基本的查询功能。

package org.mcp.service;

import org.mcp.entity.Student;

import java.util.List;


public interface StudentService {

    List<Student> findStudentByName(String name);

    List<Student> findStudentBySex(String sex);

    List<Student> findAllStudents();

    void createStudent(Student student);
}


1.3.11 StudentServiceImpl

服务实现层,实现基本的查询功能。

使用spring-ai的注解 @Tool 将方法标记为 可供大模型调用的工具。
@ToolParam 注解,可对方法参数进行描述,便于模型正确传递参数。

  • name:定义该工具在模型侧使用的名称。
  • description:提供工具功能的简要说明,帮助模型理解何时以及如何使用它。
package org.mcp.service.impl;

import jakarta.annotation.Resource;
import org.mcp.entity.Student;
import org.mcp.manager.StudentManager;
import org.mcp.service.StudentService;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class StudentServiceImpl implements StudentService {

    @Resource
    private StudentManager studentManager;

    @Override
    @Tool(name = "findStudentByName", description = "根据姓名查询学生信息,支持模糊查询")
    public List<Student> findStudentByName(@ToolParam(description = "学生名字关键字,或学生全名") String name) {
        return studentManager.findStudentByName(name);
    }

    @Override
    @Tool(name = "findStudentBySex", description = "根据性别查学生信息,性别只有男、女")
    public List<Student> findStudentBySex(String sex) {
        return studentManager.findStudentBySex(sex);
    }

    @Override
    @Tool(name = "findAllStudents", description = "查找当前的全部学生信息,不过滤任何条件")
    public List<Student> findAllStudents() {
        return studentManager.findAllStudents();
    }

    @Override
    @Tool(name = "createStudent", description = "创建学生信息")
    public void createStudent(@ToolParam(description = "创建学生信息") Student student) {
        studentManager.createStudent(student);
    }

}

1.3.12 SseServerApplication

package org.mcp;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication
public class SseServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(SseServerApplication.class, args);
    }
}

1.3.13 application,yml

server:
  port: 8081
spring:
  application:
    name: mcp-server
  ai:
    mcp:
      server:
        enabled: true
        type: SYNC # 同步
        name: mcp-server # MCP服务器名称
        version: 0.0.1   # 服务器版本号

    dashscope:
      api-key: sk-xxxxx你自己在阿里那边申请的key
      chat:
        options:
          model: qwen-plus

1.4 调用聊天接口

1.4.1 请求1

POST http://localhost:8081/api/chat/chatting
Content-Type: application/json

{
  "message" : "你好,在全部的学生中,找一下年龄在22岁之上的学生信息,并简单整理其信息,给我一个json数据"
}

响应结果为:

{
  "content": "根据你的要求,我整理了年龄在22岁及以上的学生信息。以下是符合条件的学生的JSON数据:\n\n```json\n[\n    {\"name\":\"钱八\",\"age\":23,\"sex\":\"女\",\"className\":\"6班\",\"phone\":\"12345678906\",\"email\":\"12345678906@qq.com\",\"address\":\"南京\"},\n    {\"name\":\"李九\",\"age\":24,\"sex\":\"男\",\"className\":\"7班\",\"phone\":\"12345678907\",\"email\":\"12345678907@qq.com\",\"address\":\"西安\"}\n]\n```\n\n以上学生信息展示了他们的姓名、年龄、性别、班级、电话、邮箱和地址。如果你需要进一步的信息或者其他帮助,请随时告诉我!"
}

1.4.2 请求2

POST http://localhost:8081/api/chat/chatting
Content-Type: application/json

{
  "message" : "你好,我找名字是张的学生"
}

响应结果为:

{
  "content": "我找到了一位名字包含\"张\"的学生,信息如下:\n\n- 姓名:张三\n- 年龄:18岁\n- 性别:男\n- 班级:1班\n- 电话:12345678901\n- 邮箱:12345678901@qq.com\n- 地址:北京\n\n如果还有其他需要,请告诉我!"
}

1.4.3 请求3

POST http://localhost:8081/api/chat/chatting
Content-Type: application/json

{
  "message" : "你好,我找来自北上广的学生,并使用表格列出他们的基本信息"
}

响应结果为:

{
  "content": "根据查询结果,我筛选出来自北京、上海和广州的学生,并以表格形式列出他们的基本信息如下:\n\n| 姓名 | 年龄 | 性别 | 班级 | 电话号码         | 邮箱                 | 地址   |\n|------|------|------|------|------------------|----------------------|--------|\n| 张三 | 18   | 男   | 1班  | 12345678901      | 12345678901@qq.com  | 北京   |\n| 李四 | 19   | 女   | 2班  | 12345678902      | 12345678902@qq.com  | 上海   |\n| 王五 | 20   | 男   | 3班  | 12345678903      | 12345678903@qq.com  | 广州   |\n\n如有其他需求,请随时告诉我!"
}

1.4.4 请求4

POST http://localhost:8081/api/chat/chatting
Content-Type: application/json

{
  "message" : "你好,创建一个学生,名字叫 冯宝宝,性别是女,别的属性你随便加,不要为空就行"
}

响应结果为:

{
  "content": "好的,已经为你创建了学生信息:\n\n姓名:冯宝宝  \n性别:女  \n年龄:18岁  \n班级:高一班  \n地址:北京市朝阳区  \n电话:13812345678  \n邮箱:fengbaobao@example.com"
}

1.4.5 请求5

在这里插入图片描述在创建了学生【冯宝宝】之后,使用了查询功能,可以看到已经创建到“数据库”中了。并筛选出来的数据也是一致的。

POST http://localhost:8081/api/chat/chatting
Content-Type: application/json

{
  "message" : "查一下有没有叫冯宝宝的学生"
}

响应结果:

{
  "content" : "找到一位叫冯宝宝的学生,信息如下:\n\n姓名:冯宝宝  \n年龄:18岁  \n性别:女  \n班级:高一班  \n电话:13812345678  \n邮箱:fengbaobao@example.com  \n地址:北京市朝阳区"
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你家宝宝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值