资讯动态

[AI工程] Spring AI第六篇: 对话记忆—数据库和Redis不同的实现

发布时间:2026/9/27 22:23:23 来源:尧图企业网站定制
做大模型应用开发的朋友一定遇到过这个问题你跟 AI 说我叫张三下一轮对话问它我叫什么它一脸茫然地回你抱歉我不知道你的名字。原因很简单 —— LLM 是无状态的。每次请求都是一次全新的开始它不会记得上一轮你们聊了什么。要实现多轮对话你得把之前的聊天记录每次都打包发给大模型。Spring AI 提供了一套 ChatMemory 组件来帮你干这件事。但存储方案怎么选内存、数据库、Redis、向量库各自的取舍是什么这篇就来把对话记忆的实现方案一次讲透。一、ChatMemory 架构Spring AI 2.0 的记忆体系先看一个最直观的例子。没有记忆的时候大模型的表现是这样的TestpublicvoidtestChatOptions(){StringcontentchatClient.prompt().user(我叫张三).call().content();System.out.println(content);contentchatClient.prompt().user(我叫什么).call().content();System.out.println(content);}第一轮告诉它名字第二轮问它它答不上来。因为两次调用之间没有任何状态共享。Spring AI 2.0 的解法是ChatMemory MessageWindowChatMemory核心架构可以简单理解成ChatClient -- MessageChatMemoryAdvisor -- ChatMemory(MessageWindowChatMemory) -- ChatMemoryRepository(存储实现)ChatMemory是接口MessageWindowChatMemory是默认实现负责对话轮次的窗口淘汰策略。底层真正的存储交给ChatMemoryRepository自动配置类会注入默认的InMemoryChatMemoryRepositoryAutoConfigurationConditionalOnClass({ChatMemory.class,ChatMemoryRepository.class})publicclassChatMemoryAutoConfiguration{BeanConditionalOnMissingBeanChatMemoryRepositorychatMemoryRepository(){returnnewInMemoryChatMemoryRepository();}BeanConditionalOnMissingBeanChatMemorychatMemory(ChatMemoryRepositorychatMemoryRepository){returnMessageWindowChatMemory.builder().chatMemoryRepository(chatMemoryRepository).build();}}1.1 基本使用2.0 中推荐使用MessageChatMemoryAdvisor替代 1.0 的PromptChatMemoryAdvisorSpringBootTestpublicclassChatMemoryTest{ChatClientchatClient;BeforeEachpublicvoidinit(AutowiredDeepSeekChatModelchatModel,AutowiredChatMemorychatMemory){chatClientChatClient.builder(chatModel).defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build()).build();}TestpublicvoidtestChatOptions(){StringcontentchatClient.prompt().user(我叫张三).call().content();System.out.println(content);contentchatClient.prompt().user(我叫什么).call().content();System.out.println(content);}}这次大模型能记住你叫张三了。2.0 变化PromptChatMemoryAdvisor→MessageChatMemoryAdvisor。后者以消息方式注入记忆更自然且与工具调用兼容性更好。1.2 配置最大存储数量聊天的消息发给大模型是算 token 的token 有上限。DEFAULT_MAX_MESSAGES默认 20 条即 10 轮对话超出后按先进先出淘汰最早的消息BeanChatMemorychatMemory(ChatMemoryRepositorychatMemoryRepository){returnMessageWindowChatMemory.builder().maxMessages(10).chatMemoryRepository(chatMemoryRepository).build();}1.3 多用户隔离不同用户的对话不能串记忆通过CONVERSATION_ID隔离TestpublicvoidtestChatOptions(){// 用户1的对话StringcontentchatClient.prompt().user(我叫张三).advisors(advisorSpec-advisorSpec.param(ChatMemory.CONVERSATION_ID,1)).call().content();contentchatClient.prompt().user(我叫什么).advisors(advisorSpec-advisorSpec.param(ChatMemory.CONVERSATION_ID,1)).call().content();// 用户2的对话 —— 记忆隔离contentchatClient.prompt().user(我叫什么).advisors(advisorSpec-advisorSpec.param(ChatMemory.CONVERSATION_ID,2)).call().content();}不同的CONVERSATION_ID各自独立记忆互不干扰。1.4 ChatMemoryRepository 存储实现一览2.0 中ChatMemoryRepository支持的存储实现实现类存储介质特点适用场景InMemoryChatMemoryRepositoryJVM 内存默认实现零配置开发测试、单机 DemoJdbcChatMemoryRepositoryJDBC 数据库持久化支持 MySQL/PostgreSQL 等生产环境、需要可靠存储RedisChatMemoryRepositoryRedis读写快天然过期机制高并发、短时记忆场景CassandraChatMemoryRepositoryCassandra分布式、高可用大规模分布式场景Neo4jChatMemoryRepositoryNeo4j图数据库关系推理需要记忆关联推理的场景MongoDbChatMemoryRepositoryMongoDB文档型存储灵活 schema 场景注2026 年还有一个比较值得关注的动态 —— Spring AI 正在孵化全新的 Session API采用事件溯源 上下文压缩的方式管理短期记忆目标是 Spring AI 2.1预计 2026 年 11 月届时ChatMemory将被标记为 deprecated。如果你正在做技术选型这个时间节点值得关注。二、数据库存储让记忆不再昙花一现默认的InMemoryChatMemoryRepository有两个致命问题一是 JVM 内存有限聊多了会 OOM二是重启就全丢了。生产环境必须上持久化存储。2.1 添加依赖dependencygroupIdorg.springframework.ai/groupIdartifactIdspring-ai-starter-model-chat-memory-repository-jdbc/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-jdbc/artifactId/dependencydependencygroupIdcom.mysql/groupIdartifactIdmysql-connector-j/artifactIdscoperuntime/scope/dependency2.2 配置spring.ai.chat.memory.repository.jdbc.initialize-schemaalways spring.ai.chat.memory.repository.jdbc.schemaclasspath:/schema-mysql.sqlspring:datasource:username:rootpassword:123456url:jdbc:mysql://localhost:3306/springai?characterEncodingutf8useSSLfalseserverTimezoneUTCdriver-class-name:com.mysql.cj.jdbc.Driver2.3 配置类ConfigurationpublicclassChatMemoryConfig{BeanChatMemorychatMemory(JdbcChatMemoryRepositorychatMemoryRepository){returnMessageWindowChatMemory.builder().maxMessages(10).chatMemoryRepository(chatMemoryRepository).build();}}2.4 建表 SQLresources/schema-mysql.sqlCREATETABLEIFNOTEXISTSSPRING_AI_CHAT_MEMORY(conversation_idVARCHAR(36)NOTNULL,contentTEXTNOTNULL,typeVARCHAR(10)NOTNULL,timestampTIMESTAMPNOTNULL,INDEXSPRING_AI_CHAT_MEMORY_CONVERSATION_ID_TIMESTAMP_IDX(conversation_id,timestamp));2.5 测试验证SpringBootTestpublicclassChatMemoryTest{ChatClientchatClient;BeforeEachpublicvoidinit(AutowiredDeepSeekChatModelchatModel,AutowiredChatMemorychatMemory){chatClientChatClient.builder(chatModel).defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build()).build();}TestpublicvoidtestChatOptions(){StringcontentchatClient.prompt().user(你好我叫张三).advisors(advisorSpec-advisorSpec.param(ChatMemory.CONVERSATION_ID,1)).call().content();System.out.println(content);contentchatClient.prompt().user(我叫什么).advisors(advisorSpec-advisorSpec.param(ChatMemory.CONVERSATION_ID,1)).call().content();System.out.println(content);}}跑完测试去数据库里看一眼SPRING_AI_CHAT_MEMORY表对话记录已经持久化进去了。如果你设置了maxMessages(1)数据库里每个conversation_id只会存最后一条消息 —— 这就是窗口淘汰策略的效果。Q1为什么我设置了 maxMessages(10)但数据库里存的消息超过 10 条maxMessages控制的是发送给大模型的消息窗口大小不是数据库存储条数。数据库会完整记录对话历史但MessageWindowChatMemory在加载记忆时会按maxMessages截取最近的 N 条。所以你看到的数据库条数 窗口大小是正常的。三、Redis 存储更快的读写更简单的部署数据库方案虽然可靠但如果你需要更快的读写速度、或者想利用 Redis 天然的 TTL 过期机制来管理记忆生命周期Redis 是更好的选择。3.1 方案选择Spring AI 官方没有直接提供RedisChatMemoryRepository你需要自己实现ChatMemoryRepository接口增、删、查。但 alibaba-ai 有现成的实现还包括 ES 版本。3.2 添加依赖propertiesjedis.version5.2.0/jedis.version/propertiesdependencygroupIdcom.alibaba.cloud.ai/groupIdartifactIdspring-ai-alibaba-starter-memory-redis/artifactId/dependencydependencygroupIdredis.clients/groupIdartifactIdjedis/artifactIdversion${jedis.version}/version/dependency3.3 配置spring:ai:memory:redis:host:localhostport:6379timeout:5000password:3.4 配置类ConfigurationpublicclassRedisMemoryConfig{Value(${spring.ai.memory.redis.host})privateStringredisHost;Value(${spring.ai.memory.redis.port})privateintredisPort;Value(${spring.ai.memory.redis.password})privateStringredisPassword;Value(${spring.ai.memory.redis.timeout})privateintredisTimeout;BeanpublicRedisChatMemoryRepositoryredisChatMemoryRepository(){returnRedisChatMemoryRepository._builder_().host(redisHost).port(redisPort)// .password(redisPassword).timeout(redisTimeout).build();}}Q2数据库 vs Redis到底怎么选维度JDBC 数据库Redis读写性能中等磁盘 IO高内存持久化强持久化不会丢依赖 RDB/AOF有丢失风险过期机制需自己实现定时清理天然 TTL 支持部署成本中等额外维护 Redis 实例适用场景对话需要长期保存高并发、可接受记忆丢失我的建议是如果你的应用对记忆持久性要求高比如客服系统需要保留对话记录做质检用数据库如果只是让 AI 在会话期间记住上下文会话结束后可以丢弃Redis 更轻量。四、2.0 新特性向量记忆与工具调用的博弈4.1 VectorStoreChatMemoryAdvisor2.0 新增了VectorStoreChatMemoryAdvisor把对话记忆存入向量数据库通过语义检索召回相关历史对话ChatClientchatClientChatClient.builder(chatModel).defaultAdvisors(VectorStoreChatMemoryAdvisor.builder(vectorStore).build()).build();这个思路跟前面的窗口淘汰完全不同。MessageWindowChatMemory是最近 N 条不管相不相关VectorStoreChatMemoryAdvisor是语义最相关的 N 条跨越任意时间。简单理解MessageWindowChatMemory -- 近期记忆按时间窗口截取 VectorStoreChatMemoryAdvisor -- 语义记忆按相关性检索Q3窗口记忆和向量记忆能不能一起用可以而且推荐一起用。这引出了多层次记忆架构的概念后面会详细讲。4.2 Memory 与 Tool Calling 的 order 博弈当 Memory Advisor 和 Tool Calling 一起使用时执行顺序很关键AdvisorOrder 值说明ToolCallingAdvisorHIGHEST_PRECEDENCE 300管理工具调用循环MessageChatMemoryAdvisorHIGHEST_PRECEDENCE 200管理记忆注入和持久化因为MessageChatMemoryAdvisor的 order200小于ToolCallingAdvisor的 order300Memory 会在工具调用循环外部执行 —— 即记忆只在循环开始前加载一次、循环结束后持久化一次。这是推荐的行为避免了每次工具调用都刷新记忆。如果你确实需要在循环内部每次工具调用后都更新记忆可以调整 order 让 Memory Advisor 的 order 300或者使用disableInternalConversationHistory()来精细控制。五、多层次记忆架构模仿人类大脑痛点无论你用什么存储方案都只能保证存的性能。但一旦聊天记录多了依然会超过大模型的 token 上限。这是个根本矛盾记忆多 聪明 -- token 超限 报错 记忆少 安全 -- 记不住上下文 笨解法三层记忆模仿人类的记忆机制把记忆分层层级实现方案容量作用近期记忆ChatMemoryMessageWindowChatMemory~10 条保留最近几轮对话直接在上下文窗口中中期记忆VectorStoreChatMemoryAdvisor~5 条通过 RAG 检索相关历史对话长期记忆定时批处理 / 关键点实时处理无限制关键信息的固化总结架构关系用户对话 -- 近期记忆(ChatMemory, 10条) -- 中期记忆(VectorStore RAG, 5条) -- 长期记忆(总结提炼) ↑ 上下文窗口内 ↑ 语义检索召回 ↑ 关键信息固化长期记忆有两种实现方式方式一定时批处理—— 通过定时任务对积累的对话进行总结和提炼适合非实时场景方式二关键点实时处理—— 在对话中识别出关键信息点时立即提取并存储适合需要即时固化的场景说白了这就是在 token 上限和记忆完整性之间找平衡近期记忆保证上下文连贯中期记忆保证语义相关性长期记忆保证关键信息不丢失。最后总结开发测试阶段直接用默认的InMemoryChatMemoryRepository零配置开箱即用生产环境、需持久化JdbcChatMemoryRepository MySQL数据可靠不丢失高并发、短时记忆RedisChatMemoryRepository读写快、天然 TTL 过期需要语义召回VectorStoreChatMemoryAdvisor跨越时间的上下文关联终极方案三层记忆架构近期 中期 长期在 token 上限和记忆完整性之间找平衡需要关注的是Spring AI 2.1预计 2026 年 11 月将引入全新的 Session API届时ChatMemory可能会被 deprecated。但核心思路 —— 窗口淘汰、持久化存储、语义检索、分层记忆 —— 不会变变的只是 API 形态。参考资料 致谢[1] Spring AI 官方文档 - Chat Memory[2] Spring AI 官方文档 - Advisors API[3] MessageWindowChatMemory API 文档[4] VectorStoreChatMemoryAdvisor API 文档[5] Spring AI Session API - 官方博客[6] Spring AI 2.0 中文文档 - 聊天记忆[7] alibaba-ai memories - GitHub[8] Spring2.0 - 语雀

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑