1.基于memory对话记忆
SpringAI 基于 ChatMemory 实现对话的记忆,也就是上下⽂内容的存储、发送请求时候附带。 ChatMemory 表示聊天对话记忆的存储,它提供添加消息到对话、从对话中检索消息以及清除对话历 史的⽅法。
java
public interface ChatMemory {
default void add(String conversationId, Message message) {
this.add(conversationId, List.of(message));
}
// 添加消息到记忆
void add(String conversationId, List<Message> messages);
// 获取对话历史
List<Message> get(String conversationId, int lastN);
// 清除对话记忆
void clear(String conversationId);
}
Spring AI 提供了 ChatMemory 的实例⽤于存储聊天上下⽂,默认使⽤内存的⽅式进⾏实现,将对 话直接存储在内存中。
2.什么是会话 ID
SpringAI 中, conversationId 是⽤于标识和隔离不同对话会话的核⼼参数,通过该 ID 实现对 话上下⽂的持久化与连续性管理。它有如下的⼀些核⼼作⽤:
- 会话隔离:为每个对话分配唯⼀ ID ,确保不同会话的数据独⽴存储和读取。
- 上下⽂持久化:通过 ChatMemoryRepository 接⼝,将过滤后的消息(如⽤户输⼊、 AI 回 复)按 conversationId 存储,⽀持本地内存或 JDBC 数据库等存储⽅式。
3.具体实现(基于内存)
3.1. 书写 ChatMemoryConfig 配置类
java
@Configuration
public class ChatMemoryConfig {
@Bean("inMemoryChatMemory")
public ChatMemory chatMemory() {
return MessageWindowChatMemory.builder()
.chatMemoryRepository(new
InMemoryChatMemoryRepository()) // 对话记忆默认使⽤内存⽅式
.maxMessages(3) // 保存最近的三条历史记录
.build();
}
}
注意: 其实内存⽅式就是默认的⽅式,如果不⾃定义 ChatMemory 对象,默认的 ChatMemory 对象已经实现了内存记忆功能。 保存的历史记录⾄少三条,因为会保存多个⻆⾊信息。
3.2修改ChatClientConfig控制类
java
@Bean("openAiChatClient")
public ChatClient openAiChatClient(OpenAiChatModel openAiChatModel){
return ChatClient.builder(openAiChatModel).build();
}
@Bean("openAiChatClient2")
public ChatClient openAiChatClient2(OpenAiChatModel openAiChatModel){
return ChatClient.builder(openAiChatModel)
//引入chatMemory in
.defaultAdvisors(MessageChatMemoryAdvisor.builder(inMemoryChatMemory).build())
.build();
}
3.3控制层类
分别为入门版、提升版以及手撕版
java
//入门版写法
@GetMapping(value = "/stream",produces = "text/html;charset=utf-8")
public Flux<String> stream(@RequestParam("question") String question){
history+=question+"/n";
return openAiChatClient.prompt()
.user(history)
.stream().content();
}
//提升版
@GetMapping(value = "/history1",produces = "text/html;charset=utf-8")
public Flux<String> history1(@RequestParam("question") String question){
return openAiChatClient2.prompt()
.user(question)
.stream().content();
}
//手撕版
@GetMapping(value = "/history2",produces = "text/html;charset=utf-8")
public String history2(@RequestParam("question") String question,@RequestParam("id") String id){
//1.获取到原来的消息
List<Message> historyMessages=chatMemory.get(id);
log.info("历史记录:{}",historyMessages);
if (historyMessages==null || historyMessages.size()==0){
historyMessages =new ArrayList<>();
}
//2.将当用户的消息组装后存放到历史中
Message userMessage=new UserMessage(question);
historyMessages.add(userMessage);
chatMemory.add(id,historyMessages);
//3.获取到大模型的回答
Prompt prompt=new Prompt(historyMessages);
String result=openAiChatClient.prompt(prompt).call().content();
Message assistantMessage = new AssistantMessage(result);
//4.将大模型回答的消息存放到历史记录中
historyMessages.add(assistantMessage);
chatMemory.add(id,historyMessages);
//5.返回结果
return result;
}
4.基于JDBC实现
4.1引入依赖
XML
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-chat-memory-repository-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
4.2修改yml文件
XML
spring:
ai:
chat:
memory:
repository:
jdbc:
initialize-schema: always(第二次运行需修改为never)
schema: classpath:schema-mysql.sql
datasource:
password: 123456
username: root
url: jdbc:mysql://localhost:3306/sys
driver-class-name: com.mysql.cj.jdbc.Driver
4.3在resources目录下新建schema-mysql.sql
sql
CREATE TABLE IF NOT EXISTS SPRING_AI_CHAT_MEMORY
(
conversation_id VARCHAR(36) NOT NULL,
content TEXT NOT NULL,
type VARCHAR(10) NOT NULL,
`timestamp` TIMESTAMP NOT NULL,
CONSTRAINT TYPE_CHECK CHECK (type IN ('USER', 'ASSISTANT', 'SYSTEM', 'TOOL'))
);
会在yml文件所写的数据库中新建SPRING_AI_CHAT_MEMORY表,会将对话记录存到该表中
4.4写ChatMemoryConfig类
java
@Bean("jdbcMemoryChatMemory")
public ChatMemory jdbcChatMemory(JdbcChatMemoryRepository jdbcChatMemoryRepository) {
return MessageWindowChatMemory.builder()
.chatMemoryRepository(jdbcChatMemoryRepository)
.build();
}
4.5写ChatClientConfig类
java
@Bean("openAiChatClient3")
public ChatClient openAiChatClient3(OpenAiChatModel openAiChatModel) {
return ChatClient.builder(openAiChatModel)
// 引入chatMemory jdbc
.defaultAdvisors(MessageChatMemoryAdvisor.builder(jdbcMemoryChatMemory).build())
.build();
}
4.6写controller类
java
@GetMapping(value = "/history3", produces = "text/html;charset=utf-8")
public Flux<String> history3(@RequestParam("question") String question, @RequestParam("id") String id) {
return openAiChatClient3.prompt()
.advisors(a -> a.param("chat_memory_conversation_id", id))
.user(question)
.stream().content();
}
4.7编写启动类
java
package com.jiazhong.mingxing.ai.siliconflow.memory.glm;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AiSiliconflowMemoryGlmApplication {
public static void main(String[] args) {
SpringApplication.run(AiSiliconflowMemoryGlmApplication.class);
}
}
启动后在浏览器中写入具体路径即可实现。