redis相关准备

添加依赖

我利用redission来实现

<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.37.0</version>
</dependency>

添加配置文件

spring:redis:database: 5host: 127.0.0.1port: 6379password: 1234

创建RedisProperties文件

@Data
@Component
@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {private String host;private int port;private String password;private int database;
}

创建redissionConfig配置文件

@Configuration
@RequiredArgsConstructor
public class RedisConfig {private final RedisProperties redisProperties;@Beanpublic RedissonClient redissonClient(){Config config = new Config();config.useSingleServer().setAddress("redis://" +  redisProperties.getHost() + ":" + redisProperties.getPort()).setDatabase(redisProperties.getDatabase()).setPassword(redisProperties.getPassword());config.setCodec(new StringCodec(StandardCharsets.UTF_8));return Redisson.create(config);}
}

创建RedissionUtil工具类

package com.sde.util;import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.jackson.JacksonProperties;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.StreamSupport;@Component
public class RedissonUtil {private static RedissonClient redissonClient;@Autowiredpublic void setRedissonClient(RedissonClient client) {redissonClient = client;}/*** 设置数据的过期时间* @param key 要设置的键* @param seconds 过期时间(秒)*/public static boolean expire(String key, long seconds) {return redissonClient.getKeys().expire(key, seconds, TimeUnit.SECONDS);}/*** 设置数据的过期时间* @param key 要设置的键* @param duration 时长* @param unit 时间单位* @return*/public static boolean expire(String key, long duration, TimeUnit unit) {return redissonClient.getKeys().expire(key, duration, unit);}/*** 将字符串添加到 Redis List 的尾部** @param key Redis 键* @param value 要添加的值*/public static void addToList(String key, String value) {RList<String> list = redissonClient.getList(key);list.add(value);}/*** 获取列表* @param key* @return*/public static RList<String> getList(String key) {return redissonClient.getList(key);}/*** 获取 RList 对象,用于后续操作如 trim、remove 等*/public static RList<String> getRList(String key) {return redissonClient.getList(key);}/*** 删除数据* @param key 要删除的键* @return*/public static boolean remove(final String key) {return redissonClient.getKeys().delete(key) >= 0;}/*** 检查键是否存在* @param key 键* @return 是否存在*/public static boolean exists(String key) {RBucket<String> bucket = redissonClient.getBucket(key);return bucket.isExists();}}

SpringAI相关准备

不用阿里云的maven仓库,用默认的maven中央仓库。

版本控制

    <properties><java.version>21</java.version><spring-ai.version>1.0.0-SNAPSHOT</spring-ai.version></properties>

    <dependencyManagement><dependencies><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-bom</artifactId><version>${spring-ai.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>

添加依赖

        <dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-model-openai</artifactId></dependency>

因为我对接的阿里云百炼平台

添加配置

spring:ai:openai:base-url: https://dashscope.aliyuncs.com/compatible-mode/api-key: ${ALIYUN_AK}chat:options:model: qwen-max

我的api-key 存储在我环境变量中

编写代码

创建保存到redis中的实体

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class StoredMessage implements Serializable {@JSONField(ordinal = 0)private String role;@JSONField(ordinal = 1)private String content;public static StoredMessage from(Message message) {return new StoredMessage(message.getMessageType().name(), message.getText());}public Message toMessage() {return switch (role) {case "USER" -> new UserMessage(content);case "ASSISTANT" -> new AssistantMessage(content);default -> new SystemMessage(content);};}
}

创建RedisChatMemory

@Component
public class RedisChatMemory implements ChatMemory {// redis key 的前缀private static final String CHAT_MEMORY_KEY = "chat:conversationid:";private static final long TTL_MILLIS = 2 * 24 * 60 * 60 * 1000; // 2天private final int maxMessage;public RedisChatMemory() {this(10); // 默认保留 10 条消息}public RedisChatMemory(int maxMessages) {this.maxMessage = maxMessages;}@Overridepublic void add(String conversationId, Message message) {String key = getKey(conversationId);StoredMessage storedMessage = StoredMessage.from(message);String json = toJson(storedMessage);RedissonUtil.addToList(key, json);trimMessages(key);//刷新过期时间为2天RedissonUtil.expire(key, TTL_MILLIS, TimeUnit.MILLISECONDS);}@Overridepublic void add(String conversationId, List<Message> messages) {messages.forEach(message -> add(conversationId, message));}@Overridepublic List<Message> get(String conversationId) {String key = getKey(conversationId);//检查key是否存在if (!RedissonUtil.exists(key)) {return Collections.emptyList();}//获取所有 json字符串格式的消息List<String> messages = RedissonUtil.getList(key);//转换成 Message 列表return messages.stream().map(this::fromJson).filter(Objects::nonNull).map(StoredMessage::toMessage).toList();}@Overridepublic void clear(String conversationId) {String key = getKey(conversationId);RedissonUtil.remove(key);}/*** 构建redis的key* @param conversationId* @return*/private String getKey(String conversationId){return CHAT_MEMORY_KEY + conversationId;}/*** 将消息转换为 JSON 字符串*/private String toJson(StoredMessage msg) {SerializeConfig config = new SerializeConfig();return JSON.toJSONString(msg,config, SerializerFeature.SortField);}/*** 将 JSON 字符串转换为 StoredMessage 对象*/private StoredMessage fromJson(String json) {return JSON.parseObject(json, StoredMessage.class);}/*** 控制消息数量,保留最近 maxMessages 条*/private void trimMessages(String key) {RList<String> list = RedissonUtil.getRList(key);if (list.size() > maxMessage) {int toRemove = list.size() - maxMessage;for (int i = 0; i < toRemove; i++) {list.remove(0);}}}}

创建Controller

@Slf4j
@RestController
@RequestMapping("/memory")
public class ChatMemoryController {private final ChatClient chatClient;public ChatMemoryController(ChatModel qwen) {this.chatClient = ChatClient.builder(qwen).build();}@Autowiredprivate RedisChatMemory redisChatMemory;@GetMapping("/redis")public Flux<String> redis(String question, String conversationId){MessageChatMemoryAdvisor advisor = MessageChatMemoryAdvisor.builder(redisChatMemory).conversationId(conversationId).order(5).build();return chatClient.prompt().system("你是我的学习助手名字叫小菜包").user(question).advisors(advisor).stream().content();}
}

测试

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/88697.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/88697.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/88697.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity中使用EzySlice实现模型切割与UV控制完全指南

引言 在Unity中实现3D模型的动态切割是一个常见的需求&#xff0c;无论是用于游戏特效、建筑可视化还是医疗模拟。本文将全面介绍如何使用EzySlice插件实现高效的模型切割&#xff0c;并深入探讨如何通过Shader Graph精确控制切割面的UV映射。 第一部分&#xff1a;EzySlice基…

【c++学习记录】状态模式,实现一个登陆功能

状态模式建议为对象的所有可能状态新建一个类&#xff0c; 然后将所有状态的对应行为抽取到这些类中。 原始对象被称为上下文 &#xff08;context&#xff09;&#xff0c; 它并不会自行实现所有行为&#xff0c; 而是会保存一个指向表示当前状态的状态对象的引用&#xff0c;…

Docker 搭建 Harbor 私有仓库

1 部署 Harbor 注意&#xff1a;docker、docker-compose、Harbor的版本是否适配&#xff0c;这里使用的版本如下表&#xff1a; Docker版本Docker Compose版本Harbor版本v19.09.8v1.29.2v2.8.2 1.1 安装 docker-compose # 下载 docker-compose 1.29.2 版本 curl -L "h…

C++类模板继承部分知识及测试代码

目录 0.前言 1.类模板基本使用 2.类模板继承 2.1类模板继承过程中的模板参数 情况1&#xff1a;父类非模板&#xff0c;子类为模板 情况2&#xff1a;父类模板&#xff0c;子类为非模板 情况3&#xff1a;父类模板&#xff0c;子类为模板 3.STL中的模板类分析 3.1STL中…

Laravel + Python 图片水印系统:实现与调试指南

前言 本系统通过 Laravel 作为前端框架接收用户上传的图片&#xff0c;调用 Python 脚本处理水印添加&#xff0c;最终返回处理后的图片。这种架构充分利用了 Laravel 的便捷性和 Python 图像处理库的强大功能。 一、Python 水印处理脚本 from PIL import Image, ImageEnhance …

【速通RAG实战:企业应用】25、从数智化场景看RAG:是临时方案,还是终局架构?

引言&#xff1a;RAG为何成为数智化场景的"必争之地"&#xff1f; 当ChatGPT在2023年掀起生成式AI浪潮时&#xff0c;一个矛盾逐渐凸显&#xff1a;大语言模型&#xff08;LLM&#xff09;能生成流畅文本&#xff0c;却常陷入"幻觉"&#xff08;虚构事实&a…

[Python] -实用技巧篇1-用一行Python代码搞定日常任务

在日常开发或数据处理过程中,我们常常为了一些简单的小任务写出数行代码。但实际上,Python 提供了大量强大且简洁的语法糖和标准库工具,让你用“一行代码”轻松搞定复杂操作。 本文将通过多个典型场景展示如何用“一行 Python 代码”高效完成常见任务。 一、文件操作:快速…

单细胞入门(1)——介绍

一、单细胞转录组测序流程介绍 单细胞测序能够探索复杂组织中单个细胞的不同生物学特性&#xff0c;帮助我们认识细胞与细胞之间的差异。这些检测方法有助于研究细胞谱系、细胞功能、细胞分化、细胞增殖和细胞应答&#xff0c;提升我们对复杂生物系统的理解&#xff0c;包括肿…

数据结构与算法之美:跳表

Hello大家好&#xff01;很高兴我们又见面啦&#xff01;给生活添点passion&#xff0c;开始今天的编程之路&#xff01; 我的博客&#xff1a;<但凡. 我的专栏&#xff1a;《编程之路》、《数据结构与算法之美》、《题海拾贝》、《C修炼之路》 欢迎点赞&#xff0c;关注&am…

从0设计一个短链接服务:如何实现尽可能短、可变长的短网址系统?

从 0 设计一个短链接服务&#xff1a;如何实现尽可能短、可变长的短网址系统&#xff1f; 在日常生活中&#xff0c;我们经常在短信、微博、广告营销中看到“短链接”&#xff0c;如&#xff1a; https://t.cn/EXaQ4xY https://bit.ly/3Yp9zJk相比冗长复杂的原始 URL&#xff0…

Microsoft Word 中 .doc 和 .docx 的区别

Microsoft Word 中 .doc 和 .docx 的区别 解释 Microsoft Word 中 .doc 和 .docx 文件格式的区别。这些格式都是 Word 处理文档的标准&#xff0c;但它们在结构、兼容性和功能上存在显著差异。下面我将详细说明。 1. 基本定义 .doc&#xff1a;这是 Microsoft Word 的旧格式&am…

Springboot aop面向切面编程

aop:面向切面编程&#xff0c;理解在一个流程中插入一个切面&#xff0c;这样切面方法会在指定位置执行能无影响的在某些方法前或者后插入一些动作springboot使用1.引入依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>sprin…

手机识别数据集,2628张原始图片,支持yolo,coco json,pasical voc xml等格式的标注

本文提供手机识别数据集&#xff0c;2628张原始图片&#xff0c;支持yolo&#xff0c;coco json,pasical voc xml等格式的标注的数据集下载&#xff0c;下载地址在文末手机识别数据集简介手机识别数据集通常用于训练和评估机器学习模型&#xff0c;以识别不同手机品牌、型号或功…

ollama - sqlcoder模型:面向提示词编程(根据用户信息生成sql语句并执行返回结果)

https://ollama.ac.cn/library/sqlcoderhttps://blog.csdn.net/hzether/article/details/143816042import ollama import sqlite3 import json from contextlib import closingdef generate_and_execute_sql(question: str, db_path: str) -> dict:# 1. 生成 SQL 查询语句pr…

C语言,结构体指针案例

案例一&#xff1a; #include <stdio.h> #include <stdbool.h> #include <string.h> // 添加string.h头文件用于strcpy //结构体指针//方式 1 : 先定义结构体 struct Dog {char *name;int age;char weight; };//方式 1 : char *get_dog_info(struct Dog do…

Vue 3 中父子组件双向绑定的 4 种方式

&#x1f501; Vue 3 中父子组件双向绑定的 4 种方式 整理不易&#xff0c;点赞 收藏 关注&#xff0c;助你组件通信不再混乱&#xff01;✅ 场景说明 父组件希望将某个值传递给子组件&#xff0c;同时希望子组件能够修改这个值&#xff08;实现“绑定 反向更新”&#xff0…

阻有形,容无声——STA 签核之RC Corner

RC corner&#xff0c;RC指的是gate跟network的寄生参数&#xff0c;寄生参数抽取工具&#xff08;比如Starrc&#xff09;根据电路的物理信息&#xff0c;抽取出电路的电阻电容值&#xff0c;再以寄生参数文件&#xff08;Spef&#xff09;输入给STA工具&#xff08;PT&#x…

多代理系统(multi-agent)框架深度解析:架构、特性与未来

在人工智能技术迭代的浪潮中&#xff0c;多代理系统&#xff08;Multi-Agent System&#xff09;正从实验室走向产业应用的核心舞台。这一技术范式的崛起源于三大驱动力&#xff1a;大模型能力的指数级提升、复杂任务分解的需求爆发&#xff0c;以及传统单体智能架构的局限性日…

【Redis】黑马点评笔记:使用redis解决各种分布式/并发问题

1、系统架构2、基于session登录用户的 session 是由服务器&#xff08;如 Tomcat&#xff09;自动管理和维护的&#xff0c;每个用户在访问 Web 应用时都会拥有一个独立的 session 对象。这个对象是通过浏览器和服务器之间的 HTTP 协议自动绑定的。1. 如何区分不同用户的 Sessi…

Javaweb- 11 MVC架构模式

MVC&#xff08;Model View Controller&#xff09; 是软件工程中一种软件架构模式&#xff0c;它把软件系统分为模型&#xff0c;视图&#xff0c;控制器&#xff0c;三个基本部分。用一种业务逻辑&#xff0c;数据&#xff0c;界面显示分离的方法组织代码&#xff0c;将业务逻…