提示:如果不能访问 OpenAI,请点击 AiCode API 注册账号,通过代理访问。
在 Spring AI 1.0.0 中,InMemoryChatMemoryRepository 是 ChatMemoryRepository 接口的一个默认实现,用于在内存中存储聊天消息和检索聊天消息。它可以获取所有会话 ID、根据会话 ID 获取聊天消息、存储整个会话的历史消息以及清理指定会话 ID 中的聊天消息。
InMemoryChatMemoryRepository 存储库使用 ConcurrentHashMap 来存储消息,键为会话 ID(conversationId),值为该会话的消息列表(List<Message>)。这种结构保证了在多线程环境下的并发安全性,能够高效地进行消息的添加、查询和删除操作。
默认情况下,若未配置其他 Repository 实现,Spring AI 将自动配置 InMemoryChatMemoryRepository 类型的 ChatMemoryRepository Bean 供直接使用。
使用方式如下:
@Autowired ChatMemoryRepository chatMemoryRepository;
直接通过 @Autowired 注解将 InMemoryChatMemoryRepository 注入到程序中即可。
如果需要手动创建 InMemoryChatMemoryRepository,可以这样做:
ChatMemoryRepository repository = new InMemoryChatMemoryRepository();
查看源码是最直接了解 InMemoryChatMemoryRepository 底层实现原理的方式,源码如下:
package org.springframework.ai.chat.memory;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.ai.chat.messages.Message;
import org.springframework.util.Assert;
/**
* ChatMemoryRepository 接口的内存实现类,用于在内存中存储和管理聊天会话消息。
* 基于 ConcurrentHashMap 实现,支持多线程安全操作,适合开发测试或简单场景。
*/
public final class InMemoryChatMemoryRepository implements ChatMemoryRepository {
/**
* 底层存储结构,键为会话ID(conversationId),值为该会话的消息列表
* 使用 ConcurrentHashMap 保证多线程环境下的并发安全性
*/
Map<String, List<Message>> chatMemoryStore = new ConcurrentHashMap();
/**
* 默认构造方法,初始化内存存储结构
*/
public InMemoryChatMemoryRepository() {
}
/**
* 获取所有会话ID的列表
*
* @return 包含所有会话ID的 ArrayList,无会话时返回空列表
*/
public List<String> findConversationIds() {
return new ArrayList(this.chatMemoryStore.keySet());
}
/**
* 根据会话ID查询对应的消息列表
*
* @param conversationId 会话唯一标识,不可为null或空字符串
* @return 该会话的消息列表副本(避免外部修改内部存储),会话不存在时返回空列表
* @throws IllegalArgumentException 若 conversationId 为null或空
*/
public List<Message> findByConversationId(String conversationId) {
// 验证会话ID合法性
Assert.hasText(conversationId, "conversationId cannot be null or empty");
// 从存储中获取消息列表
List<Message> messages = (List)this.chatMemoryStore.get(conversationId);
// 若消息存在则返回副本,否则返回空列表
return (List)(messages != null ? new ArrayList(messages) : List.of());
}
/**
* 保存指定会话的消息列表(覆盖式保存)
*
* @param conversationId 会话唯一标识,不可为null或空字符串
* @param messages 待保存的消息列表,不可为null且不能包含null元素
* @throws IllegalArgumentException 若参数不满足合法性要求
*/
public void saveAll(String conversationId, List<Message> messages) {
// 验证会话ID和消息列表合法性
Assert.hasText(conversationId, "conversationId cannot be null or empty");
Assert.notNull(messages, "messages cannot be null");
Assert.noNullElements(messages, "messages cannot contain null elements");
// 将消息列表存入存储结构(覆盖原有值)
this.chatMemoryStore.put(conversationId, messages);
}
/**
* 根据会话ID删除对应的所有消息
*
* @param conversationId 会话唯一标识,不可为null或空字符串
* @throws IllegalArgumentException 若 conversationId 为null或空
*/
public void deleteByConversationId(String conversationId) {
// 验证会话ID合法性
Assert.hasText(conversationId, "conversationId cannot be null or empty");
// 从存储中移除该会话的消息
this.chatMemoryStore.remove(conversationId);
}
}下面通过一个简单的例子来使用 InMemoryChatMemoryRepository,通过 InMemoryChatMemoryRepository 实现记忆存储。代码如下:
package com.hxstrive.springai.springai_openai.chatMemoryRepository.chatMemoryRepository1;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.ChatMemoryRepository;
import org.springframework.ai.chat.memory.InMemoryChatMemoryRepository;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RestController;
@RestController
@SpringBootApplication
public class SpringAiDemoApplication implements CommandLineRunner {
@Autowired
private ChatModel chatModel;
private static ChatMemory chatMemory;
static {
// 创建 ChatMemory 实现
ChatMemoryRepository chatMemoryRepository = new InMemoryChatMemoryRepository();
chatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository) // 使用InMemoryChatMemoryRepository作为存储仓库
.maxMessages(20) // 最多保存20条消息
.build();
}
public static void main(String[] args) {
SpringApplication.run(SpringAiDemoApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
StringBuilder builder = new StringBuilder();
// 唯一会话ID,同一个会话上下文中保持一致
String sessionId = "USER-251017100313";
String question = "四川大学是985吗?";
String ai = chat(sessionId, question);
builder.append(String.format("用户问题:%s\n", question));
builder.append(String.format("机器回复:%s\n", ai));
question = "是211吗?";
ai = chat(sessionId, question);
builder.append(String.format("用户问题:%s\n", question));
builder.append(String.format("机器回复:%s\n", ai));
System.out.println(builder.toString());
}
private String chat(String sessionId, String question) {
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultSystem("你是AI助手小粒,所有回复均使用中文。")
.defaultAdvisors(
new SimpleLoggerAdvisor() // 输出聊天日志
).build();
// 1. 将用户输入添加到记忆
UserMessage userMessage = new UserMessage(question);
chatMemory.add(sessionId, userMessage);
// 2. 获取记忆中的所有消息(上下文),传递给 AI 模型
ChatClient.CallResponseSpec responseSpec = chatClient.prompt().messages(chatMemory.get(sessionId)).call();
// 3. 将 AI 回复添加到记忆,更新上下文
AssistantMessage assistantMessage = responseSpec.chatResponse().getResult().getOutput();
chatMemory.add(sessionId, assistantMessage);
// 4. 返回 AI 回复内容
return assistantMessage.getText();
}
}配置可以参考 Spring AI 快速聊天示例,运行上述示例输出如下:
用户问题:四川大学是985吗? 机器回复:是的,四川大学是“985工程”大学之一。 用户问题:是211吗? 机器回复:是的,四川大学同时也是“211工程”大学之一。
通过一问一答,可以看出是具备记忆功能的。否则,问 AI“是211吗?”时,它怎么知道我问的是四川大学。
下面是打断点查看 InMemoryChatMemoryRepository 内部数据的截图:

更多信息,请读者自行尝试。
提示:如果不能访问 OpenAI,请点击 AiCode API 注册账号,通过代理访问。