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 指令可列出经过指定网络界面的数据包文件头,可以将网络中传送的数据包的 “头” 完全截获下来提供分析。它支持针对网络层、协…...
朱雀广告平台:技术架构深度解析与高性能广告解决方案构建
朱雀广告平台:技术架构深度解析与高性能广告解决方案构建 【免费下载链接】zhuque 开放源码的一站式广告平台,包含ssp/adx/dsp/dmp模块 项目地址: https://gitcode.com/gh_mirrors/zhu/zhuque 在数字广告技术快速演进的今天,广告平台面…...
FactoryBluePrints项目深度解析:戴森球计划终极工厂蓝图优化指南
FactoryBluePrints项目深度解析:戴森球计划终极工厂蓝图优化指南 【免费下载链接】FactoryBluePrints 游戏戴森球计划的**工厂**蓝图仓库 项目地址: https://gitcode.com/GitHub_Trending/fa/FactoryBluePrints FactoryBluePrints项目是戴森球计划游戏中最为…...
硬核教程:用Gemini境像站构建端到端自动化办公工作流,告别重复操作(国内免费镜像实测)
在日常办公中,大量的重复性操作——数据录入、日报生成、文件归档——占据了相当比例的时间。将这些任务串联成自动化工作流,能显著提升效率。目前国内用户无需特殊网络环境,通过聚合镜像站 RskAi(ai.jingxiang.me) 即…...
华硕笔记本性能优化终极指南:三步搞定轻量级控制神器GHelper
华硕笔记本性能优化终极指南:三步搞定轻量级控制神器GHelper 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, Vivobook, Zenbo…...
JMeter压测秒退的三大静默杀手:线程组、超时、监听器
1. 这不是JMeter“崩了”,而是它在用报错告诉你:配置里藏着三个沉默的杀手 刚跑完第一个JMeter压测脚本,线程组设了200个用户、持续5分钟,结果3秒后就自动停了——控制台只留下一行灰底白字的 INFO o.a.j.e.StandardJMeterEngine…...
从开发者反馈看taotoken api密钥管理与访问控制功能的实用性
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 从开发者反馈看taotoken api密钥管理与访问控制功能的实用性 在构建基于大模型的应用时,API密钥的管理与访问控制是保障…...
COMET:基于深度学习的翻译质量评估技术革命
COMET:基于深度学习的翻译质量评估技术革命 【免费下载链接】COMET A Neural Framework for MT Evaluation 项目地址: https://gitcode.com/gh_mirrors/com/COMET 在机器翻译技术快速发展的今天,翻译质量评估已成为连接技术研发与实际应用的关键…...
终极指南:如何用PHP轻松实现网页截图与PDF生成
终极指南:如何用PHP轻松实现网页截图与PDF生成 【免费下载链接】browsershot Convert HTML to an image, PDF or string 项目地址: https://gitcode.com/gh_mirrors/br/browsershot 你是否曾经遇到过这样的困境:需要在PHP应用中生成网页截图&…...
5个高效Adobe Illustrator脚本,让你的设计效率提升300%
5个高效Adobe Illustrator脚本,让你的设计效率提升300% 【免费下载链接】illustrator-scripts Adobe Illustrator scripts 项目地址: https://gitcode.com/gh_mirrors/il/illustrator-scripts 还在为Adobe Illustrator中的重复性设计任务烦恼吗?你…...
医疗可穿戴跨界创新:从连续监测到专业检测的硬件设计实践
1. 项目概述:当可穿戴设备“走出”身体这几年,医疗可穿戴设备已经不是什么新鲜词了。从最初只能计步的手环,到如今能监测心率、血氧、心电图甚至血糖趋势的智能手表,它们正变得越来越“贴身”,也越来越“懂”我们的身体…...
