Spring AI 聊天記憶功能實戰(一):從接口設計到生產實踐
在構建AI對話應用時,聊天記憶管理及存儲是實現連貫上下文交互的關鍵組件。而大模型(LLM)本質上是無狀態的,這意味著它們不會保留歷史交互信息。當需要跨多輪交互保持上下文時,這一特性會帶來局限。為此,Spring AI 提供了聊天記憶功能,支持在 LLM 交互過程中存儲和檢索上下文數據。
入門理解
Spring AI 框架通過模塊化設計提供了靈活的聊天記憶解決方案,其核心在于ChatMemoryRepository
與ChatMemory
的協同工作機制。
ChatMemoryRepository
接口提供了各種存儲方式實現的統一抽象,增加了聊天記憶功能的靈活性及擴展性,目前 Spring AI(1.0.0 版本)框架提供了基于 內存(默認)、JDBC、Cassandra、Neo4j 四種存儲方式的實現。
public interface ChatMemoryRepository {// 獲取所有會話IDList<String> findConversationIds();// 獲取指定會話ID的聊天消息List<Message> findByConversationId(String conversationId);// 存儲整個會話ID的歷史消息(替換式更新)void saveAll(String conversationId, List<Message> messages);// 清理指定會話ID中的聊天消息void deleteByConversationId(String conversationId);
}
ChatMemory
抽象層支持實現多種記憶類型以滿足不同場景需求。消息的底層存儲由 ChatMemoryRepository
處理,其唯一職責是存儲和檢索消息。ChatMemory
實現類可自主決定消息保留策略 —— 例如保留最近 N 條消息、按時間周期保留或基于 Token 總量限制保留。
public interface ChatMemory {// 從聊天記憶的上下文檢索會話IDString CONVERSATION_ID = "chat_memory_conversation_id";// 將聊天消息保存到指定會話ID的存儲中void add(String conversationId, List<Message> messages);// 獲取指定會話ID中的聊天消息List<Message> get(String conversationId);// 清理指定會話ID中的聊天消息void clear(String conversationId);
}
快速使用
Spring AI 自動配置 ChatMemory
Bean 供直接使用。默認采用內存存儲(InMemoryChatMemoryRepository
)及 MessageWindowChatMemory
實現管理會話歷史。若已配置其他 Repository(如 Cassandra / JDBC / Neo4j ),則自動切換至對應實現。
記憶類型:MessageWindowChatMemory
維護固定容量的消息窗口(默認 20 條)。當消息超限時,自動移除較早的對話消息(始終保留系統消息)。
// 自動注入
@Autowired
ChatMemory chatMemory;// 手動創建
MessageWindowChatMemory memory = MessageWindowChatMemory.builder().maxMessages(10).build();
記憶存儲:InMemoryChatMemoryRepository
內存存儲為默認的聊天記憶存儲實現。同樣地,Spring AI 提供了統一的自動配置,可直接自動注入使用。
// 自動注入
@Autowired
ChatMemoryRepository chatMemoryRepository;// 手動創建
ChatMemoryRepository repository = new InMemoryChatMemoryRepository();
自動配置在默認情況下,Spring AI 注入了如下 Bean 對象:
@Bean
ChatMemoryRepository chatMemoryRepository() {return new InMemoryChatMemoryRepository();
}@Bean
ChatMemory chatMemory(ChatMemoryRepository chatMemoryRepository) {return MessageWindowChatMemory.builder().chatMemoryRepository(chatMemoryRepository).build();
}
原理實現
聊天記憶存儲的實現主要依靠 ChatMemoryRepository
接口 及 ChatMemory
接口,它們的默認實現類分別為 InMemoryChatMemoryRepository
及 MessageWindowChatMemory
。
InMemoryChatMemoryRepository
實現類:
public final class InMemoryChatMemoryRepository implements ChatMemoryRepository {Map<String, List<Message>> chatMemoryStore = new ConcurrentHashMap<>();// 方法實現...
}
InMemoryChatMemoryRepository 使用并發安全的 ConcurrentHashMap 實現聊天記錄的增刪改操作,存儲實現依賴 Map 的 get、put、remove 操作。需要注意的是,這里 saveAll(寫入記錄)方法實現是替換舊數據的更新邏輯,若對應到外部存儲的寫入方式應該先刪除后插入數據,而限制聊天對話歷史長度的邏輯在 MessageWindowChatMemory 類實現。
MessageWindowChatMemory
實現類:
public final class MessageWindowChatMemory implements ChatMemory {private final ChatMemoryRepository chatMemoryRepository;private final int maxMessages;// 方法實現...private List<Message> process(List<Message> memoryMessages, List<Message> newMessages) {// 根據最大消息數處理消息窗口}
}
處理消息窗口容量的主要邏輯為:
- 識別新增的
SystemMessage
,當有新系統消息時,清除所有舊系統消息、所有的新SystemMessage
不受容量限制; - 保留非系統消息歷史+新增消息,按添加順序移除最早的非系統消息,確保 最終消息數 ==
maxMessages
、返回處理后的新消息;
消息窗口的聊天記憶管理與數據存儲交互的 UML 類圖 如下:
實戰案例
接下來我們使用MessageWindowChatMemory
+JdbcChatMemoryRepository
的方式實現一個AI聊天助手的功能。
JdbcChatMemoryRepository
是內置的 JDBC 實現,支持多種關系型數據庫,適用于需要持久化存儲聊天記憶的場景。JDBC 實現是基于 spring-jdbc 模塊,我們可通過 JdbcTemplate
來配置任一數據源。
1、導入模塊
首先,在 spring-boot 項目中添加以下依賴:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-model-openai</artifactId>
</dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-model-chat-memory-repository-jdbc</artifactId>
</dependency><dependency><groupId>org.postgresql</groupId><artifactId>postgresql</artifactId><scope>runtime</scope>
</dependency>
2、配置參數
新建 application.yml,添加配置 spring.ai
和JdbcTemplate
相關參數:
spring:application:name: AI Assistantai:openai:api-key: ${OPENAI_API_KEY:NONE}base-url: ${OPENAI_BASE_URL:NONE}chat:options:model: DeepSeek-V3completions-path: /v1/chat/completionschat:memory:repository:jdbc:initialize-schema: always # Always initializedatasource:url: jdbc:postgresql://localhost:5432/testusername: rootpassword: 123456driver-class-name: org.postgresql.Driver
3、創建 Bean 實例
Spring AI 為 JdbcChatMemoryRepository
提供了自動配置,可直接在應用中使用 (默認使用 hsqldb 嵌入式數據庫),也可手動創建 Bean 實例。
@Configuration
public class GeneralChatClientConfig {private final JdbcChatMemoryRepository jdbcChatMemoryRepository;public GeneralChatClientConfig(JdbcChatMemoryRepository jdbcChatMemoryRepository) {this.jdbcChatMemoryRepository = jdbcChatMemoryRepository;}@Bean(name = "messageWindowChatMemoryWithJdbc")public MessageWindowChatMemory messageWindowChatMemoryWithJdbc() {int maxMessages = 20;return MessageWindowChatMemory.builder().chatMemoryRepository(jdbcChatMemoryRepository) // default: new InMemoryChatMemoryRepository().maxMessages(maxMessages).build();}
}
目前 Spring AI 支持的數據庫與方言抽象層:
- PostgreSQL
- MySQL / MariaDB
- SQL Server
- HSQLDB
使用 JdbcChatMemoryRepositoryDialect.from(DataSource)
時可基于 JDBC URL 自動識別正確方言。通過實現 JdbcChatMemoryRepositoryDialect
接口可擴展其他數據庫方言支持。
4、聊天記憶客戶端
創建使用 ChatClient
API 時,可通過注入 ChatMemory
實現來維護跨多輪交互的會話上下文。
Spring AI 提供多種內置 Advisor,用于按需配置 ChatClient
的記憶行為。
MessageChatMemoryAdvisor
:通過指定ChatMemory
實現管理會話記憶。每次交互時從記憶庫檢索歷史消息,并將其作為消息集合注入提示詞。PromptChatMemoryAdvisor
:基于指定ChatMemory
實現管理會話記憶。每次交互時從記憶庫檢索歷史對話,并以純文本形式追加至系統(system)提示詞。VectorStoreChatMemoryAdvisor
:通過指定VectorStore
實現管理會話記憶。每次交互時從向量存儲檢索歷史對話,并以純文本形式追加至系統(system)消息。
例如,若需結合 MessageWindowChatMemory
與 PromptChatMemoryAdvisor
,可按如下方式配置:
@Bean(name = "deepseekV3ClientWithJdbc")public ChatClient deepseekV3ClientWithJdbc(@Value("${spring.ai.openai.base-url}") String baseUrl,@Value("${spring.ai.openai.chat.options.model}") String modelName,@Value("${spring.ai.openai.api-key}") String apiKey,@Qualifier("messageWindowChatMemoryWithJdbc") MessageWindowChatMemory messageWindowChatMemoryWithJdbc) {OpenAiApi build = OpenAiApi.builder().apiKey(apiKey).baseUrl(baseUrl).build();OpenAiChatModel openAiChatModel =OpenAiChatModel.builder().openAiApi(build).defaultOptions(OpenAiChatOptions.builder().model(modelName).build()).build();return ChatClient.builder(openAiChatModel).defaultAdvisors(PromptChatMemoryAdvisor.builder(messageWindowChatMemoryWithJdbc).build()).defaultAdvisors(new SimpleLoggerAdvisor()).build();}
調用 ChatClient
時,ChatMemoryAdvisor
將自動管理記憶存儲。系統會根據指定的會話 ID 從記憶庫檢索歷史對話。
我們新建一個 Controller ,注入配置好的 ChatClient,定義一個api實現大模型的 chat 調用,代碼如下:
@RestController
@RequestMapping("/ai/v3/chat/")
@Slf4j
public class GeneralChatController {private final ChatClient jdbcChatClient;public GeneralChatController(@Qualifier("deepseekV3ClientWithJdbc") ChatClient jdbcChatClient) {this.jdbcChatClient = jdbcChatClient;}@PostMapping(value = "/t1", produces = {MediaType.TEXT_EVENT_STREAM_VALUE})@ResponseBodypublic Object chatWithJdbc(@RequestBody String body) {JSONObject entries = JSONUtil.parseObj(body);String text = entries.getStr("text");Boolean stream = entries.getBool("stream", false);String conversationId = entries.getStr("conversationId");log.info("開始對話聊天,會話ID:{}", conversationId);var request = jdbcChatClient.prompt().system("你是樂觀小王,回答問題簡練精要。").advisors(advisor -> advisor.param(CONVERSATION_ID, conversationId)).user(text);try {log.info("開始生成回答,是否流式輸出:{}", stream);return stream ? request.stream().content() : request.call().content();} catch (Exception e) {log.error("對話聊天發生異常,會話ID:{}", conversationId, e);throw e;}}
}
5、測試AI聊天功能
通過上述的簡單配置和代碼編寫,我們已經實現了一個通用的帶有記憶功能的AI聊天助手。
接下來讓我們測試一下這個聊天助手的使用效果,設置幾條 USER 的提問內容,具體內容如下:
# Openai Chat API
### 我的名字叫小明,你叫什么名字?
### 我是誰?
### 我們之間的第一句問話是什么?
POST http://localhost:10001/ai/v3/chat/t1
Content-Type: application/json{
"text": "我的名字叫小明,你叫什么名字?",
"stream": false,
"conversationId": "bnA9f525-l7ae-5c66-ae21-vh53547c96cf"
}
聊天消息記錄會被存儲到 PostgreSQL 數據庫中,http順序請求后的大模型返回結果 如圖所示:
小總結
通過上述測試結果可以清晰看到,基于 Spring AI 搭建的聊天助手憑借聊天記憶存儲功能,能夠準確關聯上下文信息,針對連續提問給出符合對話邏輯的回答。無論是識別用戶身份,還是追溯對話起始內容,系統都能有效利用歷史消息,實現連貫且智能的交互體驗,充分利用聊天記憶存儲機制可以更好的維護對話上下文及提高模型回答的準確性。
目前 Spring AI (1.0.0 版本) 官方還沒有提供 Redis 的聊天記憶外部存儲實現,那么,下一篇文章我們將聚焦于 自定義 Redis 聊天記憶的外部存儲實現,通過 自定義一個外部存儲方式,自己實現一個聊天記憶存儲功能,來進一步提升聊天助手的擴展性與數據持久性,讓AI聊天助手在高并發、大規模對話場景中穩定運行。敬請期待接下來的深度技術解析!
文章案例項目代碼:spring-ai-model-chat-memory-repository-redis
- https://github.com/Cyanty/spring-ai-model-chat-memory-repository-redis
大數據