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

SpringAI实现保存聊天记录到redis中

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.dtcms.com/a/276279.html

相关文章:

  • Softmax回归(多类逻辑回归)原理及完整代码示例实现
  • 如何查询服务器的操作系统
  • 算法题(173):枚举排列
  • Arduino 无线通信实战:使用 RadioHead实现 315MHz 433M模块数据传输
  • MS Azure Eventhub 发送 AD log 到cribl
  • 学习笔记 Datewhale MCP Server Task2
  • 免费用Claude code薅羊毛
  • 【模板】最长公共子序列 详细解析
  • FastGPT革命:下一代语言模型的极速进化
  • 集训Demo1
  • 史上最全 MySQL 锁详解:从理论到实战,一篇搞定所有锁机制
  • 接口和抽象方法示例
  • C语言基础知识--联合体
  • Mybatis的一级缓存与二级缓存
  • 电网失真下单相锁相环存在的问题
  • STM32第二十一天定时器TIM
  • docker搭建 与镜像加速器
  • LeetCode经典题解:3、无重复字符的最长子串
  • 【Elasticsearch】post_filter
  • 【MATLAB代码】Chan方法解算TOA,用于三维目标的定位,锚点数量可自适应。订阅专栏后可查看完整代码
  • Windows环境下解决Matplotlib中文字体显示问题的详细指南
  • PyTorch神经网络实战:从零构建图像分类模型
  • linux----------------------线程同步与互斥(上)
  • 搭建MySQL读写分离
  • LiteFlow源码
  • Mamba架构的模型 (内容由deepseek辅助汇总)
  • 手把手教你 Aancond 的下载与 YOLOV13 部署(环境的创建及配置下载)以及使用方法,连草履虫都能学会的目标检测实验!
  • net.createServer详解
  • Python后端项目之:我为什么使用pdm+uv
  • 模拟注意力:少量参数放大 Attention 表征能力