当前位置: 首页 > java >正文

SpringBoot中使用MCP和通义千问来处理和分析数据

文章目录

  • 前言
  • 一、正文
    • 1.1 项目结构
    • 1.2 项目环境
    • 1.3 完整代码
      • 1.3.1 spring-mcp-demo的pom文件
      • 1.3.2 sse-server 的pom文件
      • 1.3.3 ChatRequest
      • 1.3.4 ChatResponse
      • 1.3.5 ChatClientConfig
      • 1.3.6 ServiceProviderConfig
      • 1.3.7 ChatController
      • 1.3.8 Student
      • 1.3.9 StudentManager
      • 1.3.10 StudentService
      • 1.3.11 StudentServiceImpl
      • 1.3.12 SseServerApplication
      • 1.3.13 application,yml
    • 1.4 调用聊天接口
      • 1.4.1 请求1
      • 1.4.2 请求2
      • 1.4.3 请求3
      • 1.4.4 请求4
      • 1.4.5 请求5

前言

近来,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 {@Autowiredprivate ToolCallbackProvider toolCallbackProvider;/*** 配置ChatClient,注册系统指令和工具函数*/@Beanpublic 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 {@Autowiredprivate StudentService studentService;@Beanpublic 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 {@Resourceprivate ChatClient chatClient;@PostMapping("/chatting")@SneakyThrowspublic 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 {@Resourceprivate 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-serverai:mcp:server:enabled: truetype: SYNC # 同步name: mcp-server # MCP服务器名称version: 0.0.1   # 服务器版本号dashscope:api-key: sk-xxxxx你自己在阿里那边申请的keychat: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地址:北京市朝阳区"
}
http://www.xdnf.cn/news/4238.html

相关文章:

  • 强啊!Oracle Database 23aiOracle Database 23ai:使用列别名进行分组排序!
  • 高光谱相机赋能烟叶分选:精准、高效与智能化的新突破
  • 美团后端开发一面
  • 第十五届蓝桥杯单片机国赛-串口解析
  • 前端封装框架依赖管理全攻略:构建轻量可维护的私有框架
  • 关于Java多态简单讲解
  • 【表设计】外键的取舍-分布式中逐渐消失的外键
  • 【firewall-cmd】--的作用以及使用方法
  • FlinkCDC采集MySQL8.4报错
  • 第六节:图像基本操作-像素级操作
  • Windows11下ESP-IDF开发环境搭建【基于Cursor/VS Code插件】
  • 【25软考网工】第五章(7)路由协议、静态与默认路由、路由协议分类
  • 代码随想录训练营第十八天| 150.逆波兰表达式求值 239.滑动窗口最大值 347.前k个高频元素
  • 了解一下OceanBase中的表分区
  • C++:实现线程池
  • 【Spring Boot 注解】@SpringBootApplication
  • 力扣-hot100 (矩阵置零)
  • C++命名空间
  • Windows11下通过Docker安装mysql8.0
  • FPGA----基于ZYNQ 7020实现petalinux文件持久化存储
  • Linux主机时间设置操作指南及时间异常影响
  • LeetCode 解题思路 45(Hot 100)
  • 科普文:丰田凯美瑞三代混动(THS II)技术解析
  • Golang领域Beego框架的中间件开发实战
  • 【Linux】用户与组管理
  • Fastjson 从多层级的JSON数据中获取特定字段的值
  • Transformer中的三种注意力机制
  • 开源模型应用落地-qwen模型小试-Qwen3-8B-推理加速-vLLM-结构化输出(三)
  • Copilot for PPT 可直接用模板创建品牌演示文稿
  • 【Python-Day 10】Python 循环控制流:while 循环详解与 for 循环对比