大模型聊天内容持久化开发步骤--解决两个痛点:持久化媒介(RedisChatMemoryRepository),消息对话窗口,聊天记录上限以及顾问(MessageChatMemoryAdvisor)
总结:
上下文要能连贯起来,需要有持久化的媒介,然后要有消息对话窗口聊天记忆(消息窗口的上限),顾问Adviser加强
一、解决持久化媒介(采用RedisChatMemoryRepository)
1.新建子模块Module
SAA-08Persistent
2..大模型的聊天内容要写入redis,要新增两个依赖
spring-ai-alibaba-starter-memory-redis是阿里巴巴和Reids整合的依赖
为什么不用RedisTemplate,而是用Jedis?
jedis依赖是因为阿里巴巴AI整合的框架就是jedis连接池
<!--spring-ai-alibaba memory-redis-->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-memory-redis</artifactId>
</dependency>
<!--jedis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
完整的pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.atguigu.study</groupId>
<artifactId>SpringAIAlibaba-atguiguV1</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>SAA-08Persistent</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--spring-ai-alibaba dashscope-->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
</dependency>
<!--spring-ai-alibaba memory-redis-->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-memory-redis</artifactId>
</dependency>
<!--jedis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.38</version>
</dependency>
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.22</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
<source>21</source>
<target>21</target>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
3.改yml文件
server.port=8008
# ?????????
server.servlet.encoding.charset=utf-8
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true
spring.application.name=SAA-08Persistent
# ====SpringAIAlibaba Config=============
spring.ai.dashscope.api-key=${aliQwen-api}
# ==========redis config ===============
spring.data.redis.host=localhost
spring.data.redis.port=6379
spring.data.redis.database=0
spring.data.redis.connect-timeout=3
spring.data.redis.timeout=2
spring.data.redis.password=123456
4.前置知识:步骤一
1.实现SpringAI框架规定的ChatMemoryRepository接口
Spring AI官网:Introduction :: Spring AI Referencehttps://docs.spring.io/spring-ai/reference/index.html
SpringAIAlibaba实现了SpringAI的ChatMemory
2.接口ChatMemoryRepository
这个接口两个实现类:
InMemoryChatMemoryRepository和RedisChatMemoryRepository
InMemoryChatMemoryRepository是保存在内存中的,是SpringAI的核心框架
RedisChatMemoryRepository是阿里巴巴的,用于保存到Redis中
3.RedisChatMemoryRepository源码
4.编码新建RedisMemoryConfig配置类
package com.atguigu.study.config;
import com.alibaba.cloud.ai.memory.redis.RedisChatMemoryRepository;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author NoFear
* @version 1.0
* @description: TODO
* @date 2025/10/5 13:54
*/
@Configuration
public class RedisMemoryConfig {
@Value("${spring.data.redis.host}")
private String host;
@Value("${spring.data.redis.port}")
private int port;
@Value("${spring.data.redis.password}")
private String password;
@Bean
public RedisChatMemoryRepository redisChatMemoryRepository() {
return RedisChatMemoryRepository.builder()
.host(host)
.port(port)
.password(password)
.build();
}
}
二、消息对话窗口,聊天记录上限
三、顾问(Advisors)MessageChatMemoryAdvisor
顾问对ChatMemory做了功能增强
1.可以将记录保存到Redis
2.消息窗口最多可以保存一百条
3.要以顾问增强器的方式打入到接口调用里面,告诉接口增加了新的功能
聊天客户端中的内存
使用 ChatClient API 时,您可以提供一种实现来维护多个交互的对话上下文。ChatMemory
Spring AI 提供了一些内置的 Advisor,您可以使用它们根据需要配置 的内存行为。ChatClient
目前,在执行工具调用时与大语言模型交换的中间消息不会存储在内存中。这是当前实现的限制,将在将来的版本中解决。如果需要存储这些消息,请参阅用户控制工具执行的说明。 |
-
MessageChatMemoryAdvisor
.此顾问使用提供的实现来管理对话内存。在每次交互中,它都会从内存中检索对话历史记录,并将其作为消息集合包含在提示中。ChatMemory
-
PromptChatMemoryAdvisor
.此顾问使用提供的实现来管理对话内存。在每次交互时,它都会从内存中检索对话历史记录,并将其作为纯文本附加到系统提示中。ChatMemory
-
VectorStoreChatMemoryAdvisor
.此顾问使用提供的实现来管理对话内存。在每次交互时,它都会从矢量存储中检索对话历史记录,并将其作为纯文本追加到系统消息中。VectorStore
例如,如果要与 一起使用,可以按如下方式配置:MessageWindowChatMemory
MessageChatMemoryAdvisor
<span style="color:#191e1e"><span style="background-color:#ffffff"><code class="language-java">ChatMemory chatMemory = MessageWindowChatMemory.builder().build();
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build())
.build();</code></span></span>
当执行对 的调用时,内存将由 自动管理。将根据指定的对话 ID 从内存中检索对话历史记录:ChatClient
MessageChatMemoryAdvisor
<span style="color:#191e1e"><span style="background-color:#ffffff"><code class="language-java">String conversationId = <span style="color:#032f62">"007"</span>;
chatClient.prompt()
.user(<span style="color:#032f62">"Do I have license to code?"</span>)
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, conversationId))
.call()
.content();</code></span></span>
advisors(a -> a.param(ChatMemory.CONVERSATION_ID, conversationId))
可以把对话的内容存入到Redis,且每个消息窗口里面保存**条(可以为20条)
从而使得大模型功能更加强大
之前只是通过提示词与大模型进行对话
而现在不但可以和大模型对话,还可以通过Adviser的配置,将消息保存到Redis同时设置上限是20条,从而使得大模型更加智能
在原有的ChatClient中增加了顾问增强器,增强了功能,可以最多保存10条聊天记录,将对话上下文的记录保存到Redis
@Bean(name = "deepseekChatClient")
public ChatClient deepseekChatClient(@Qualifier("deepseek")ChatModel deepseek, RedisChatMemoryRepository redisChatMemoryRepository){
MessageWindowChatMemory windowChatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(redisChatMemoryRepository)
.maxMessages(10)
.build();
return ChatClient.builder(deepseek)
.defaultAdvisors(MessageChatMemoryAdvisor.builder(windowChatMemory).build())
.defaultOptions(ChatOptions.builder().model(DEEPSEEK_MODEL).build())
.build();
}
@Bean(name = "qwenChatClient")
public ChatClient qwenChatClient(@Qualifier("qwen")ChatModel qwen, RedisChatMemoryRepository redisChatMemoryRepository){
MessageWindowChatMemory windowChatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(redisChatMemoryRepository)
.maxMessages(10)
.build();
return ChatClient.builder(qwen)
.defaultOptions(ChatOptions.builder().model(QWEN_MODEL).build())
.defaultAdvisors(MessageChatMemoryAdvisor.builder(windowChatMemory).build())
.build();
}
四、Controller层的编写和调用
也就是这样写代码,这个用户的聊天记录会自动保存到Redis中,无需手动编程,非常的方便,并且下次调用,如果Reids中的10条满了,还可以自动替换最早的信息并保存最新的消息,Redis中保存的Key是CONVERSATION_ID(RedisChatMemoryRepository中的常量,之前注册一个ChatClient时注入了这个属性) + 用户id,value是list类型的保存大模型回复的消息
package com.atguigu.study.controller;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.function.Consumer;
import static org.springframework.ai.chat.memory.ChatMemory.CONVERSATION_ID;
/**
* @author NoFear
* @version 1.0
* @description: TODO
* @date 2025/10/5 15:07
*/
@RestController
public class ChatMemoryRedisController {
@Resource(name = "qwenChatClient")
private ChatClient qwenChatClient;
/* @GetMapping("/chatmemory/chat")
public String chat(String msg, String userId){
return qwenChatClient.prompt(msg)
.advisors(new Consumer<ChatClient.AdvisorSpec>() {
@Override
public void accept(ChatClient.AdvisorSpec advisorSpec) {
advisorSpec.param(CONVERSATION_ID, userId);
}
})
.call()
.content();
}*/
@GetMapping("/chatmemory/chat")
public String chat(String msg, String userId){
return qwenChatClient.prompt(msg)
.advisors(advisorSpec -> advisorSpec.param(CONVERSATION_ID, userId))
.call()
.content();
}
}
.advisors(advisorSpec -> advisorSpec.param(CONVERSATION_ID, userId))CONVERSATION_ID(RedisChatMemoryRepository.java中的常量
private static final String DEFAULT_KEY_PREFIX = "spring_ai_alibaba_chat_memory:";)和userId共同组成了Redis中的key,value是用户提问的消息内容,是一个list集合
测试:http://localhost:8008/chatmemory/chat?msg=2加5等于多少&userId=7
更多推荐
所有评论(0)