Spring AI 2.0:Memory 一、简介大模型是没有记忆的Spring AI提供了聊天记录的持久化织入器Spring AI 提供了多种持久化方式支持内存默认InMemoryChatMemoryRepository、Redis、MongoDB、ES、其它数据库等。二、ChatMemory所谓记忆就是将历史之前的所有提示出和大模型返回的结果都作为下次的输入。ChatMemorychatMemoryMessageWindowChatMemory.builder().build();StringconversationIdxs001;// 当前对话唯一标识// 第一次对话将请求和响应添加到chatMemory中UserMessageuserMessage1newUserMessage(我叫张三);chatMemory.add(conversationId,userMessage1);ChatResponseresponse1chatModel.call(newPrompt(chatMemory.get(conversationId)));chatMemory.add(conversationId,response1.getResult().getOutput());// 第二次对话UserMessageuserMessage2newUserMessage(我是谁);chatMemory.add(conversationId,userMessage2);ChatResponseresponse2chatModel.call(newPrompt(chatMemory.get(conversationId)));chatMemory.add(conversationId,response2.getResult().getOutput());System.out.println(response2.getResult().getOutput().getText());// 删除会话chatMemory.clear(conversationId);InMemoryChatMemoryRepository默认存到MapString, ListMessage chatMemoryStore new ConcurrentHashMap();中Map的key表示conversationId用于区分用户的sessionIdconversationId如果没有听默认为default当数据多的时候会出现内存溢出OOM只适合简单Demo一下。MessageWindowChatMemory每个大模型的上下文长度都是有最大限制的窗口式会话内存保存对话历史可以设置最大消息条数默认20超过就丢弃最早消息。RedisChatMemoryRepositoryRedis相比Jdbc会更快。适合存储最近n条数据。propertiesjedis.version5.2.0/jedis.version/properties!-- Spring AI Alibaba Redis聊天记忆starter --dependencygroupIdcom.alibaba.cloud.ai/groupIdartifactIdspring-ai-alibaba-starter-memory-redis/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactIdexclusionsexclusiongroupIdio.lettuce/groupIdartifactIdlettuce-core/artifactId/exclusion/exclusions/dependency!-- Jedis Redis客户端 --dependencygroupIdredis.clients/groupIdartifactIdjedis/artifactIdversion${jedis.version}/version/dependencyspring:ai:memory:redis:host:127.0.0.1port:6379password:timeout:2000# key前缀redis里面的key spring:ai:memory:{sessionId}key-prefix:spring:ai:memoryBeanChatMemorychatMemory(RedisChatMemoryRepositoryredisChatMemoryRepository){returnMessageWindowChatMemory.builder().maxMessages(10)// 窗口大小保留最近10条消息.chatMemoryRepository(redisChatMemoryRepository).build();}JdbcChatMemoryRepositorydependencygroupIdorg.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/dependencyspring:datasource:url:jdbc:mysql://127.0.0.1:3306/ai_chat?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghaiusername:rootpassword:你的密码driver-class-name:com.mysql.cj.jdbc.Driver默认使用schema‑mysql.sql会创建该表。CREATETABLEIFNOTEXISTSSPRING_AI_CHAT_MEMORY(conversation_idVARCHAR(36)NOTNULL,contentTEXTNOTNULL,typeVARCHAR(10)NOTNULL,timestampTIMESTAMPNOTNULL,CONSTRAINTSPRING_AI_CHAT_MEMORY_TYPE_CHECKCHECK(typeIN(USER,ASSISTANT,SYSTEM,TOOL)));CREATEINDEXIFNOTEXISTSSPRING_AI_CHAT_MEMORY_CONVERSATION_ID_TIMESTAMP_IDXONSPRING_AI_CHAT_MEMORY(conversation_id,timestamp);MongoDBChatMemoryRepositoryspring-ai 和 spirng-ai-alibaba 都有提供对应实现原生 Spring‑AI官方!-- SpringAI官方Mongo ChatMemory Repository --dependencygroupIdorg.springframework.ai/groupIdartifactIdspring-ai-starter-model-chat-memory-repository-mongodb/artifactId/dependency!-- 必须引入spring‑data‑mongodb --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-mongodb/artifactId/dependency// 自动注入starter会自动配置MongoChatMemoryRepositoryAutowiredprivateMongoChatMemoryRepositoryrepository;BeanpublicChatMemorychatMemory(){returnMessageWindowChatMemory.builder().chatMemoryRepository(repository).maxMessages(10)//滑动窗口保留最近N条消息.build();}spring:data:mongodb:uri:mongodb://127.0.0.1:27017/spring_ai_chatai:chat:memory:repository:mongo:create-indices:true#启动自动建索引ttl:2592000#消息过期时间单位秒0代表永不过期Spring‑AI‑AlibabadependencygroupIdcom.alibaba.cloud.ai/groupIdartifactIdspring-ai-alibaba-starter-memory-mongodb/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-mongodb/artifactId/dependencyBeanpublicChatClientchatClient(ChatModelchatModel,ChatMemorychatMemory){returnChatClient.builder(chatModel).defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build()).build();}StringconvIdgetConversationId(sessionId);// userId _ sessionIdchatClient.prompt().user(你的问题).advisors(spec-spec.param(MessageChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY,convId).param(MessageChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY,10)).call();ElasticsearchChatMemoryRepository!-- spring‑ai‑alibaba ES chat memory 官方starter --dependencygroupIdcom.alibaba.cloud.ai/groupIdartifactIdspring-ai-alibaba-starter-memory-elasticsearch/artifactIdversion1.0.0.2/version/dependency!-- Spring Data Elasticsearch 底层驱动 --dependencygroupIdorg.springframework.data/groupIdartifactIdspring-data-elasticsearch/artifactId/dependencyspring:elasticsearch:uris:http://127.0.0.1:9200#username: elastic#password: xxxai:chat:memory:repository:elasticsearch:index-name:spring-ai-alibaba-chat-memory# ES索引名称自动创建BeanpublicChatMemorychatMemory(ChatMemoryRepositorychatMemoryRepository){returnMessageWindowChatMemory.builder().maxMessages(10).chatMemoryRepository(chatMemoryRepository).build();}BeanpublicRedisChatMemoryRepositorychatMemoryRepository(RedisTemplateString,ObjectredisTemplate){returnRedisChatMemoryRepository.builder().redisTemplate(redisTemplate).build();}BeanChatMemorychatMemory(JdbcChatMemoryRepositorychatMemoryRepository){returnMessageWindowChatMemory.builder().maxMessages(10).chatMemoryRepository(chatMemoryRepository).build();}/** * 直接注入alibaba官方ES ChatMemoryRepository自动读取yml配置 */BeanpublicChatMemorychatMemory(ElasticsearchChatMemoryRepositoryesChatMemoryRepository){returnMessageWindowChatMemory.builder().chatMemoryRepository(esChatMemoryRepository).maxMessages(20)//内存窗口上限ES中完整保存全部历史消息.build();}三、代码DataBuilderNoArgsConstructorAllArgsConstructorpublicclassChatDTO{/** * 用户的问题 */privateStringquestion;/** * 会话id */privateStringsessionId;}ConfigurationpublicclassSpringAiConfig{BeanpublicChatClientchatClient(DeepSeekChatModeldeepSeekChatModelChatMemorychatMemory){returnChatClient.builder(deepSeekChatModel).defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build()).build();}}RestControllerpublicclassSpringAIController{AutowiredprivateChatClientchatClient;GetMapping(value/chat,producesMediaType.TEXT_EVENT_STREAM_VALUE)publicFluxStringchat(RequestParam(chatDto)ChatDTOchatDto){FluxStringcontentchatClient.prompt().user(chatDto.getMessage())// 消息持久化需要一个conversationId这里的值一般是前端传的seesionId.advasors(a-a.param(ChatMemory.CONVERSATION_ID,chatDto.getSessionId())).stream().content().withConcat(Flux.just([complete]));// 自定义一个结束标记前端解析到就不会再请求表示本轮会话全部结束returncontent;}GetMapping(/history)publicListMessagegetHistory(RequestParamStringsid){returnchatMemory.get(sid);}GetMapping(/clear)publicvoidclear(RequestParamStringsid){chatMemory.clear(sid);}}先告诉大模型我叫什么。再问大模型我叫什么四、AI多层次记忆架构模仿人类记忆整体分为近期记忆、中期记忆、长期记忆三层正好对应Spring AI里面不同组件。1. 近期记忆Short‑term保留上下文窗口最近N轮对话每轮对话结束立刻存储对应ChatMemory实现MessageWindowChatMemory底层存储Redis/MySQLJdbcChatMemoryRepository / RedisChatMemoryRepository特点直接放在prompt上下文传给大模型有窗口上限maxMessages例如10条超过就丢弃最早消息只能记住最近几轮老对话直接被裁剪掉。局限会话轮次一多早期历史会丢失。2. 中期记忆Middle‑termRAG向量检索历史对话解决“近期记忆窗口不够”的痛点流程每轮对话结束后异步把本轮对话文本转向量存入向量数据库。推理阶段用户提问时把用户问题向量化去向量库检索相似的旧对话把检索出来的历史拼入prompt。特点不受LLM上下文窗口限制可以检索很久之前对话缺点是相似度召回不一定能命中真正需要的内容存储向量数据库Milvus、DashScope向量库等。对比近期记忆是全部塞进prompt中期记忆是检索挑选一部分塞进prompt。3. 长期记忆Long‑term提炼固化关键事实、用户偏好不是原始聊天记录是高度摘要信息。不存完整对话只存结构化要点比如用户年龄、喜好、习惯、重要事实。两种实现方案方式① 定时批处理定时任务每日/每周批量读取该用户全部对话调用LLM做总结提取关键信息、用户偏好写入数据库作为长期记忆优点计算集中、成本低适合大量用户缺点不能实时感知用户刚说的新信息有延迟。方式② 关键点实时处理写入触发器每一轮对话额外调用一次LLM识别当前消息是否包含关键信息用户个人信息、偏好、永久性设置如果识别到立刻提取、更新长期记忆库优点实时生效说完立刻记住缺点每轮多一次LLM调用增加token开销。三层在请求链路中的执行顺序用户提问从长期记忆读出用户关键偏好放到System Prompt用用户问题去向量库检索中期记忆历史相关对话片段加入prompt取出近期记忆最近N轮完整对话拼入消息列表合并全部内容发给大模型模型返回结果写回保存本轮对话到近期记忆异步写入向量库中期记忆触发长期记忆更新逻辑批处理/实时触发器。三者对比总结记忆层级存储内容存储介质SpringAI对应组件近期记忆原始最近N轮消息Redis/MySQLChatMemory、MessageWindowChatMemory中期记忆全部历史对话向量向量数据库RAG向量检索长期记忆结构化摘要、用户偏好MySQL/Redis自己开发SpringAI无内置组件重点Spring AI只原生提供近期记忆中期记忆靠RAG长期记忆需要自己开发没有现成starter。落地选型建议简单对话机器人只用近期记忆Redis ChatMemory够用需要记住几千轮历史加中期记忆RAG向量库需要记住用户永久偏好记住用户姓名、喜好再实现一层长期记忆。