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.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;將業務邏…