SpringAi整合大模型(进阶版)
进阶版是在基础的对话版之上进行新增功能。
如果还没弄出基础版的,请参考
https://blog.csdn.net/weixin_54925172/article/details/144143523?sharetype=blogdetail&sharerId=144143523&sharerefer=PC&sharesource=weixin_54925172&spm=1011.2480.3001.8118
一,进阶版需要实现的功能
- 给AI进行功能预设
- 记忆对话,能自动联系上下文语境
- 结合业务,通过对话操作系统业务
简单解释一下
给AI进行功能预设
比如当客户发送特定消息时,ai需要做出什么回应
或者
让ai充当淘宝客服之类的角色
记忆对话,能自动联系上下文语境
同一时间多个用户访问时,分别可以对应多个用户,不会混淆上下文语境。
比如用户A说了自己是A,用户B说了自己是B,那么A在问自己是谁时,AI能准确回答出用户是A,而不会混淆说A是B。
结合业务,通过对话操作系统业务
类似于现在的手机助手,叫声“小艺,帮我买杯霸王别姬的奶茶”。小艺就会自动下单购买奶茶。
二,代码编写
首先整合一下上次的样例代码,做一下简单的调整。
简单调整上次的代码
controller
package org.example.springaidemo.controller;import org.example.springaidemo.impl.SimpleControllerImpl;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;@RestController
public class SimpleController {private final SimpleControllerImpl simpleControllerimpl;@Autowiredpublic SimpleController(OpenAiChatModel openAiChatModel, SimpleControllerImpl simpleControllerimpl) {this.simpleControllerimpl = simpleControllerimpl;}@GetMapping("/ai/generate")public String generate(@RequestParam(value = "message", defaultValue = "讲个笑话") String message) {return simpleControllerimpl.generate(message);}@GetMapping("/ai/generateStream")public Flux<String> generateStream(@RequestParam(value = "message", defaultValue = "讲个笑话") String message) {return simpleControllerimpl.generateStream(message);}}
impl
package org.example.springaidemo.impl;import org.springframework.ai.chat.client.ChatClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;@Service
public class SimpleControllerImpl {private final ChatClient client;@Autowiredpublic SimpleControllerImpl(ChatClient.Builder clientBuilder) {this.client = clientBuilder.build();}public String generate(String msg) {return this.client.prompt().user(msg).call().content();}public Flux<String> generateStream(String msg) {return this.client.prompt().user(msg).stream().content();}
}
测试

给AI进行功能预设
修改我们的impl类
package org.example.springaidemo.impl;import org.springframework.ai.chat.client.ChatClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;@Service
public class SimpleControllerImpl {private final ChatClient client;@Autowiredpublic SimpleControllerImpl(ChatClient.Builder clientBuilder) {this.client = clientBuilder.defaultSystem("""你是一家名叫“Rojer”的淘宝客服。当用户语句中包含“退款”时,你需要回复“不好意思,本店不支持7天无理由退款”""").build();}public String generate(String msg) {return this.client.prompt().user(msg).call().content();}public Flux<String> generateStream(String msg) {return this.client.prompt().user(msg).stream().content();}
}
这里需要注意,大模型是经过特定训练后的,它无法做出一些本身禁止于大模型的回复,
比如说污言秽语,比如说民族纠纷,比如说反人类语言。
这个时候,我们再进行一些简单测试

记忆对话,能自动联系上下文语境
这里有两个方面
- 需要开启ai的记忆功能
- 需要对不同用户进行分别的处理
别的不多说,都在代码中,注释中
impl
package org.example.springaidemo.impl;import org.example.springaidemo.config.MychatMemory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.PromptChatMemoryAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;/*** SimpleControllerImpl 是一个服务类,用于处理基于 AI 的对话。* 它利用 Spring AI Chat 框架,通过会话 ID(token)管理不同用户的上下文和对话。*/
@Service
public class SimpleControllerImpl {// AI 对话客户端实例private final ChatClient client;// 自定义的对话存储实现,用于保存用户会话上下文private final MychatMemory mychatMemory;/*** 构造方法,初始化 ChatClient 和自定义的对话存储。** @param clientBuilder 用于构建 ChatClient 的构建器* @param mychatMemory 自定义的对话存储实现*/@Autowiredpublic SimpleControllerImpl(ChatClient.Builder clientBuilder, MychatMemory mychatMemory) {this.mychatMemory = mychatMemory;// 初始化 ChatClient,并设置默认系统提示和对话存储this.client = clientBuilder.defaultSystem("""你是一家名叫“Rojer”的淘宝客服。当用户语句中包含“退款”时,你需要回复“不好意思,本店不支持7天无理由退款”""").defaultAdvisors(new PromptChatMemoryAdvisor(mychatMemory)).build();}/*** 生成基于用户消息和会话 token 的 AI 回复。** @param msg 用户输入的消息* @param token 表示会话唯一标识,用于区分不同用户的上下文* @return AI 的回复内容*/public String generate(String msg, String token) {return this.client.prompt().user(msg) // 用户的输入.advisors(adv -> adv// 设置检索的上下文记录条数.param(AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100)// 指定会话唯一标识,用于区分不同的用户对话.param(AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY, token)).call() // 调用 AI 服务,生成回复.content(); // 获取生成的文本内容}/*** 以流式方式生成基于用户消息和会话 token 的 AI 回复。* 适用于需要逐步接收回复内容的场景,例如聊天应用中的实时响应。** @param msg 用户输入的消息* @param token 表示会话唯一标识,用于区分不同用户的上下文* @return Flux<String> 流式的回复内容*/public Flux<String> generateStream(String msg, String token) {return this.client.prompt().user(msg) // 用户的输入.advisors(adv -> adv// 设置检索的上下文记录条数.param(AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100)// 指定会话唯一标识,用于区分不同的用户对话.param(AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY, token)).stream() // 以流式模式调用 AI 服务.content(); // 获取生成的文本流内容}
}
自定义的chatMemory
package org.example.springaidemo.config;import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.messages.Message;
import org.springframework.stereotype.Component;import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;@Component
public class MychatMemory implements ChatMemory {Map<String, List<Message>> conversationHistory = new ConcurrentHashMap<>();@Overridepublic void add(String conversationId, List<Message> messages) {this.conversationHistory.computeIfAbsent(conversationId, id -> Collections.synchronizedList(new ArrayList<>())).addAll(messages);}@Overridepublic void add(String conversationId, Message message) {this.conversationHistory.computeIfAbsent(conversationId, id -> Collections.synchronizedList(new ArrayList<>())).add(message);}@Overridepublic List<Message> get(String conversationId, int lastN) {List<Message> allMessages = conversationHistory.get(conversationId);if (allMessages == null || allMessages.isEmpty()) {return List.of(); // 如果没有历史记录,返回空列表}// 计算获取的起始位置int start = Math.max(0, allMessages.size() - lastN);return new ArrayList<>(allMessages.subList(start, allMessages.size())); // 返回一个新列表,避免外部修改}@Overridepublic void clear(String conversationId) {conversationHistory.remove(conversationId); // 移除该会话的历史记录}
}
看看 实际对话是否有分别存储到自定义的chatMemory中



这里可以看出已经按照我的需求将两条不同的会话进行分别处理了。
这里可以根据自己的需要,使用标准的token,或者直接使用sessionID都可以。
结合业务,通过对话操作系统业务
这里需要用到springAI提供的fuction方法
详细都在注释 中
SimpleFunction
package org.example.springaidemo.config;import org.example.springaidemo.impl.SimpleControllerImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Description;import java.util.function.Function;/*** SimpleFunction 是一个 Spring 配置类,定义了应用中使用的函数 Bean。* 主要用于暴露基于 Lambda 表达式的业务逻辑函数。*/
@Configuration
public class SimpleFunction {// 引用业务逻辑实现类 SimpleControllerImplprivate final SimpleControllerImpl simpleImpl;/*** 构造方法,注入 SimpleControllerImpl 实例。** @param simpleImpl SimpleControllerImpl 的实例*/@Autowiredpublic SimpleFunction(SimpleControllerImpl simpleImpl) {this.simpleImpl = simpleImpl;}/*** 内部静态记录类,用于封装输入参数。* 在这里,PriceAll 用于传递商品的数量。** @param count 商品的数量*/public record PriceAll(int count){}/*** 定义一个 Function 类型的 Bean,用于计算总价格。** @return 一个函数,接收 PriceAll 类型的输入,返回计算结果(总价格)的字符串表示*/@Bean@Description("获取总价格")public Function<PriceAll, String> getPrice(){return priceCount -> {// 从输入中获取商品数量,并调用业务逻辑计算总价格Double pricedAll = simpleImpl.priceAll(priceCount.count);// 返回总价格的字符串表示return pricedAll.toString();};}
}
修改我们的Impl
package org.example.springaidemo.impl;import org.example.springaidemo.config.MychatMemory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.PromptChatMemoryAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Description;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;/*** SimpleControllerImpl 是一个服务类,用于处理基于 AI 的对话。* 它利用 Spring AI Chat 框架,通过会话 ID(token)管理不同用户的上下文和对话。*/
@Service
public class SimpleControllerImpl {// AI 对话客户端实例private final ChatClient client;// 自定义的对话存储实现,用于保存用户会话上下文private final MychatMemory mychatMemory;/*** 构造方法,初始化 ChatClient 和自定义的对话存储。** @param clientBuilder 用于构建 ChatClient 的构建器* @param mychatMemory 自定义的对话存储实现*/@Autowiredpublic SimpleControllerImpl(ChatClient.Builder clientBuilder, MychatMemory mychatMemory) {this.mychatMemory = mychatMemory;// 初始化 ChatClient,并设置默认系统提示和对话存储this.client = clientBuilder.defaultSystem("""你是一家名叫“Rojer”的淘宝客服。当用户语句中包含“退款”时,你需要回复“不好意思,本店不支持7天无理由退款”""").defaultAdvisors(new PromptChatMemoryAdvisor(mychatMemory)).build();}/*** 生成基于用户消息和会话 token 的 AI 回复。** @param msg 用户输入的消息* @param token 表示会话唯一标识,用于区分不同用户的上下文* @return AI 的回复内容*/public String generate(String msg, String token) {return this.client.prompt().user(msg) // 用户的输入.advisors(adv -> adv// 设置检索的上下文记录条数.param(AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100)// 指定会话唯一标识,用于区分不同的用户对话.param(AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY, token)).call() // 调用 AI 服务,生成回复.content(); // 获取生成的文本内容}/*** 以流式方式生成基于用户消息和会话 token 的 AI 回复。* 适用于需要逐步接收回复内容的场景,例如聊天应用中的实时响应。** @param msg 用户输入的消息* @param token 表示会话唯一标识,用于区分不同用户的上下文* @return Flux<String> 流式的回复内容*/public Flux<String> generateStream(String msg, String token) {return this.client.prompt().user(msg) // 用户的输入.advisors(adv -> adv// 设置检索的上下文记录条数.param(AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100)// 指定会话唯一标识,用于区分不同的用户对话.param(AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY, token)).functions("getPrice")// 指定需要调用的功能.stream() // 以流式模式调用 AI 服务.content(); // 获取生成的文本流内容}public Double priceAll(int count) {double price = 3.25;double re = price * count;System.out.println("打印这条内容,代表已经执行了priceAll该方法。");return re;}
}
看看测试结果


以上,后面还会出AI的进一步详细且方便的使用。欢迎各位大佬持续关注
相关文章:
SpringAi整合大模型(进阶版)
进阶版是在基础的对话版之上进行新增功能。 如果还没弄出基础版的,请参考 https://blog.csdn.net/weixin_54925172/article/details/144143523?sharetypeblogdetail&sharerId144143523&sharereferPC&sharesourceweixin_54925172&spm1011.2480.30…...
为什么爱用低秩矩阵
目录 为什么爱用低秩矩阵 一、定义与性质 二、区别与例子 为什么爱用低秩矩阵 我们更多地提及低秩分解而非满秩分解,主要是因为低秩分解在数据压缩、噪声去除、模型简化和特征提取等方面具有显著的优势。而满秩分解虽然能够保持数据的完整性,但在实际应用中的场景较为有限…...
React 自定义钩子:useOnlineStatus
我们今天的重点是 “useOnlineStatus” 钩子,这是 React 自定义钩子集合中众多精心制作的钩子之一。 Github 的:https://github.com/sergeyleschev/react-custom-hooks import { useState } from "react" import useEventListener from &quo…...
uniapp 小程序 监听全局路由跳转 获取路由参数
uniapp 小程序 监听全局路由跳转 获取路由参数 app.vue中 api文档 onLaunch: function(options) {let that this;let event [navigateTo, redirectTo, switchTab, navigateBack];event.forEach(item > {uni.addInterceptor(item, { //监听跳转//监听跳转success(e) {tha…...
12.02 深度学习-卷积
# 卷积 是用于图像处理 能够保存图像的一些特征 卷积层 如果用全连接神经网络处理图像 计算价格太大了 图像也被转为线性的对象导致失去了图像的空间特征 只有在卷积神经网络cnn的最后一层使用全连接神经网络 # 图像处理的三大任务 # 目标检测 对图像中的目标进行框出来 # 图…...
MySQL 主从同步一致性详解
MySQL主从同步是一种数据复制技术,它允许数据从一个数据库服务器(主服务器)自动同步到一个或多个数据库服务器(从服务器)。这种技术主要用于实现读写分离、提升数据库性能、容灾恢复以及数据冗余备份等目的。下面将详细…...
Spring源码导入idea时gradle构建慢问题
当我们将spring源码导入到idea进行构建的时候,spring采用的是gradle进行构建,默认下注在依赖是从https://repo.maven.apache.org会特别慢,需要改为国内的镜像地址会加快速度。 将项目中build.gradle配置进行调整: repositories …...
Dockerfile 安装echarts插件给java提供服务
java调用echarts插件,生成图片保存到磁盘然后插入到pptx中报表。 Dockerfile文件内容: #基础镜像,如果本地仓库没有,会从远程仓库拉取 openjdk:8 FROM docker.io/centos:centos7 #暴露端口 EXPOSE 9311 # 避免centos 日志输出 …...
Springboot小知识(1):启动类与配置
一、启动类(引导类) 在通常情况下,你创建的Spring应用项目都会为你自动生成一个启动类,它是这个应用的起点。 在Spring Boot中,引导类(也称为启动类,通常是main方法所在的类)是整个…...
[CISCN 2019华东南]Web11
[CISCN 2019华东南]Web11 给了两个链接但是都无法访问 这里我们直接抓包试一下 我们插入X-Forwarded-For:127.0.0.1 发现可以修改了右上角的IP地址,从而可以进行注入 {$smarty.version} 查看版本号 if标签执行PHP命令 {if phpinfo()}{/if} 查看协议 {if system(…...
Cypress内存溢出奔溃问题汇总
内存溢出报错信息 <--- Last few GCs ---> [196:0xe58001bc000] 683925 ms: Scavenge 1870.7 (1969.9) -> 1865.6 (1969.9) MB, 6.07 / 0.00 ms (average mu 0.359, current mu 0.444) task; [196:0xe58001bc000] 683999 ms: Scavenge 1872.4 (1969.9) -> 1867.1…...
树莓派4B--OpenCV安装踩坑
报错: Source directory: /tmp/pip-install-pv7l9r25/opencv-python_08fdf5a130a5429f89b0e0eaab39a329 Working directory: /tmp/pip-install-pv7l9r25/opencv-python_08fdf5a130a5429f89b0e0eaab39a329/_skbuild/linux-armv7l-3.7/cmake-build Please check the i…...
电子电气架构 --- 面向服务的汽车诊断架构
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所有人的看法和评价都是暂时的,只有自己的经历是伴随一生的,几乎所有的担忧和畏惧,都是来源于自己的想象,只有你真的去做了,才会发现有多快乐。…...
Pytest --capture 参数详解:如何控制测试执行过程中的输出行为
--capture 选项用于控制测试用例执行过程中标准输出(stdout)和标准错误输出(stderr)的捕获行为。 --capture 的选项值: fd(默认) 捕获文件描述符级别的输出(stdout 和 stderr&#x…...
IS-IS的原理
IS-IS的基本概念: 概述: IS-IS,中间系统到中间系统,是ISO国际标准化组织为它的无连接网络协议设计的一种动态路由协议 IS-IS支持CLNP网络和IP网络,采用数据链路层封装,区别于ospf只支持IP网络࿰…...
C++(4个类型转换)
1. C语言中的类型转换 1. 隐式 类型转换: 具有相近的类型才能进行互相转换,如:int,char,double都表示数值。 2. 强制类型转换:能隐式类型转换就能强制类型转换,隐式类型之间的转换类型强相关,强制类型转换…...
Ubuntu20.04安装NVIDIA显卡驱动
Ubuntu20.04安装NVIDIA显卡驱动 参考资料:https://blog.csdn.net/weixin_39244242/article/details/136282614?fromshareblogdetail&sharetypeblogdetail&sharerId136282614&sharereferPC&sharesourceqq_37397652&sharefromfrom_link 成功配置…...
速盾:介绍一下高防cdn的缓存响应事什么功能?
高防CDN(Content Delivery Network)是一种基于分布式缓存技术的网络加速服务,能够提供强大的缓存响应功能。它的缓存响应功能主要包括缓存加速和智能缓存两个方面。 首先,高防CDN的缓存加速功能是指通过在全球范围内部署大量的缓…...
Nuclei-快速漏洞扫描器
Nuclei-快速漏洞扫描器 声明 学习内容来自 B 站UP主泷羽sec,如涉及侵权马上删除文章。 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负。 ✍Ἷ…...
linux网络抓包工具
linux网络抓包工具 一、tcpdump1.1 基本用法1.2 龙芯平台实例操作 二、wireshark2.1 主要功能2.2 龙芯平台实例操作 一、tcpdump tcpdump 指令可列出经过指定网络界面的数据包文件头,可以将网络中传送的数据包的 “头” 完全截获下来提供分析。它支持针对网络层、协…...
低功耗电源开关电路设计与MCU控制实现
1. 经典电源开关电路设计与分析1.1 系统架构概述该电源开关电路采用三级晶体管控制架构,实现以下核心功能:低功耗待机模式(静态电流<10μA)按键触发启动机制MCU控制的自锁功能软件可控的电源关断系统工作电压为9V输入ÿ…...
Linux内核数据结构与算法深度解析
Linux内核中常用的数据结构和算法分析 1. 链表数据结构实现与应用 1.1 链表基础结构 链表是Linux内核中使用最广泛的数据结构之一,它解决了数组不能动态扩展的缺陷。链表元素可以动态创建、插入和删除,且不需要占用连续内存空间。每个链表节点由两部分…...
小型电动助力播种机【设计说明书+CAD图纸+solidworks三维+STEP+IGS】
小型电动助力播种机是针对传统播种作业效率低、劳动强度大的问题设计的农业机械装置,其核心作用在于通过电动助力系统优化播种流程,实现均匀播种与精准控制。该装置采用模块化设计理念,将动力传输、播种控制与行走机构集成于一体,…...
别再手动调API了!用Dify+FastAPI+阿里云OSS,5分钟搭建一个自动化的文生视频服务
从零构建AI视频生成流水线:DifyFastAPIOSS全链路自动化实战 在内容创作领域,视频制作正经历着从手工剪辑到AI生成的范式转移。传统视频制作需要专业软件、复杂操作和大量时间投入,而现代AI技术已经能够通过自然语言描述直接生成高质量视频片段…...
Win32下用libigl+GLFW3渲染3D模型的完整配置指南(附常见错误排查)
Win32下用libiglGLFW3渲染3D模型的完整配置指南(附常见错误排查) 在Windows平台进行3D图形开发时,libigl与GLFW3的组合为开发者提供了强大的工具集。libigl作为一个轻量级的C几何处理库,与GLFW3这一跨平台的OpenGL窗口管理库结合…...
联想M920x黑苹果终极指南:从零构建完美macOS系统
联想M920x黑苹果终极指南:从零构建完美macOS系统 【免费下载链接】M920x-Hackintosh-EFI Hackintosh Opencore EFIs for M920x 项目地址: https://gitcode.com/gh_mirrors/m9/M920x-Hackintosh-EFI 你是否想让联想M920x这款紧凑型主机运行macOS系统ÿ…...
开源风扇控制工具FanControl全攻略:从问题诊断到散热方案优化
开源风扇控制工具FanControl全攻略:从问题诊断到散热方案优化 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode.com/GitHub_Tren…...
5个维度掌握wechat-api:从入门到生产的微信机器人开发指南
5个维度掌握wechat-api:从入门到生产的微信机器人开发指南 【免费下载链接】wechat-api 🗯 wechat-api by java7. 项目地址: https://gitcode.com/gh_mirrors/we/wechat-api 核心价值:企业为什么需要微信机器人? 在数字化…...
零基础快速上手:免费开源H5编辑器h5maker完全指南
零基础快速上手:免费开源H5编辑器h5maker完全指南 【免费下载链接】h5maker h5编辑器类似maka、易企秀 账号/密码:admin 项目地址: https://gitcode.com/gh_mirrors/h5/h5maker 想要轻松制作专业级H5页面却苦于技术门槛?h5maker作为一…...
避开这5个坑!用HipSTR分析NGS数据时最容易出错的STR检测问题
避开这5个坑!用HipSTR分析NGS数据时最容易出错的STR检测问题 STR检测在二代测序数据分析中扮演着关键角色,但实际操作中常会遇到各种"坑"。本文将结合实战经验,剖析使用HipSTR进行STR检测时最容易出错的五个关键环节,帮…...
