Spring AI 初步集成(2)-添加记忆

发布时间:2026/5/20 2:15:26

Spring AI 初步集成(2)-添加记忆 添加记忆大语言模型LLMs是无状态的这意味着它们不会保留关于先前交互的信息。当你希望在多次交互中保持上下文或状态时这可能会成为一个限制。为了解决这个问题Spring AI提供了保存上下文功能定义为Chat Memory允许你在与LLM的多次交互中存储和检索信息。但是在此之前我们需要理解Chat Memory并不等于Chat History。Chat Memory大型语言模型在整个对话过程中保留并用于保持语境感知的信息。Chat History整个对话历史包括用户与模型之间交换的所有消息通常用于审计或回顾。添加Chat MemorySpring AI会自动配置一个ChatMemory Bean我们可以在应用程序中直接使用。默认情况下它使用内存中的存储库InMemoryChatMemoryRepository来存储消息并使用MessageWindowChatMemory实现来管理对话历史。修改src/main/java/com/example/canaan/config/ai/ChatConfiguration.java文件在构建ChatClient的实例时添加Chat Memory配置package com.chestnut.canaan.config.ai; import jakarta.annotation.Resource; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor; import org.springframework.ai.chat.memory.ChatMemory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; Configuration public class ChatConfiguration { Resource private ChatMemory chatMemory; Bean public ChatClient chatClient(ChatClient.Builder builder) { return builder .defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build()) .defaultSystem(you are a friendly assistant!).build(); } }在这个配置中我们使用了MessageChatMemoryAdvisor它会将ChatMemory与ChatClient关联起来。这样每次调用ChatClient时都会自动使用Chat Memory。因为我们没有额外的配置所以默认使用InMemoryChatMemoryRepository来存储消息。InMemoryChatMemoryRepository会将消息存在ConcurrentHashMap中。每次使用chatClient的相关方法时Chat Memory会自动更新。测试效果:目前所有的请求都共用同一份Chat Memory这意味着不同的用户之间的Chat Memory是共享的。如果我们希望每个对话有独立的Chat Memory我们可以在每次对话时传入一个conversationId来区分不同的对话。修改src/main/java/com/example/canaan/service/AiService.java和src/main/java/com/example/canaan/service/impl/AiServiceImpl.java文件添加一个conversationId参数package com.chestnut.canaan.service; import reactor.core.publisher.Flux; public interface AiService { FluxString chat(String input,String conversationId); }package com.chestnut.canaan.service.impl; import com.chestnut.canaan.service.AiService; import jakarta.annotation.Resource; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.memory.ChatMemory; import org.springframework.stereotype.Service; import reactor.core.publisher.Flux; Service public class AiServiceImpl implements AiService { Resource private ChatClient chatClient; Override public FluxString chat(String input,String conversationId) { return chatClient.prompt() .advisors(it - it.param(ChatMemory.CONVERSATION_ID, conversationId)) .user(input).stream().content(); } }现在为了快速检测结果我们修改一下控制器src/main/java/com/example/canaan/controller/AiController.java使其支持传入conversationId参数package com.chestnut.canaan.controller; import com.chestnut.canaan.service.AiService; import jakarta.annotation.Resource; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Flux; RestController RequestMapping(/ai) public class AiController { Resource private AiService aiService; GetMapping(/chat) public FluxString chat(String input,String conversationId) { return aiService.chat(input,conversationId); } }现在我们可以通过访问/ai/chat?input问题conversationId对话ID来与模型进行交互。每个不同的conversationId将会有独立的Chat Memory。记忆持久化目前Chat Memory是存储在内存中的这意味着当应用程序重启时所有的Chat Memory都会丢失。为了持久化Chat Memory我们可以使用数据库或其他持久化存储。Spring AI提供了ChatMemoryRepository抽象来存储Chat Memory并提供了内置存储库及其使用方法。如有需要我们也可以实现自己的存储库。以下是几种内置存储库InMemoryChatMemoryRepository默认的内存存储库。JdbcChatMemoryRepository使用JDBC将消息存储在关系型数据库中。支持多种数据库开箱即用适用于需要持久存储Chat Memory的应用程序。CassandraChatMemoryRepository 使用Apache Cassandra来存储消息。适用于需要持久存储Chat Memory的应用程序尤其适用于对可用性、持久性、扩展性有要求以及需要利用生存时间TTL功能的场景。Neo4j ChatMemoryRepository使用Neo4j将Chat Memory作为节点和关系存储在属性图数据库中。适用于希望利用Neo4j的图功能来持久化Chat Memory的应用程序。使用JDBC存储Chat Memory我们将使用JDBC存储Chat Memory。数据库可以是MySQL、PostgreSQL等关系型数据库。以下是使用MySQL的步骤首先我们需要添加依赖项。在build.gradle文件的dependencies中添加以下依赖dependencies { // JDBC memory repository 核心依赖 implementation org.springframework.ai:spring-ai-starter-model-chat-memory-repository-jdbc // MySQL JDBC驱动 runtimeOnly com.mysql:mysql-connector-j }其次我们需要新建一个数据库名称随意我取名assists:CREATE DATABASE assists CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;配置数据库连接。在src/main/resources/application.yml文件中添加以下配置spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://${PERSONAL_SERVER_IP}:3306/assists username: ${DATABASE_USERNAME} password: ${DATABASE_PASSWORD} ai: chat: memory: repository: jdbc: platform: mariadb initialize-schema: always其中spring.datasource.*配置的是数据库相关信息spring.ai.chat.memory.repository.jdbc.platform使用mariadb而不是mysql,是因为默认的数据表初始化文件放在依赖包classpath:org/springframework/ai/chat/memory/repository/jdbc/schema-platform.sql位置但是我们可以看到在此目录下并不存在数据表初始化文件schema-mysql.sql因为mariadb兼容MySQL所以我们可以使用mariadb的初始化脚本。或者我们也可以通过spring.ai.chat.memory.repository.jdbc.schema手动指定脚本位置。默认情况下初始化存储Chat Memory表SPRING_AI_CHAT_MEMORY仅对嵌入式数据库H2、HSQL、Derby等生效所以我们需要使用spring.ai.chat.memory.repository.jdbc.initialize-schema来让初始化脚本对MySQL生效。因为Spring AI 会自动配置一个ChatMemory Bean所以我们不需要手动配置ChatMemory。Spring AI会根据spring.ai.chat.memory.repository.jdbc的配置来创建一个JdbcChatMemoryRepository实例,并以此为基础创建一个ChatMemory实例。并且由于有了jdbc配置InMemoryChatMemoryRepository将不会被创建。最后启动服务在数据库assists下面应该已经出现了数据表SPRING_AI_CHAT_MEMORY。重新调用接口/ai/chat?input问题conversationId对话ID你会发现Chat Memory已经被存储在数据库中了。每次调用接口时Chat Memory都会被更新。总结在本章中我们了解了如何为Spring AI应用程序添加Chat Memory。我们了解了Chat Memory的概念并通过配置ChatClient来启用Chat Memory功能。我们还知道了如何使用JDBC存储Chat Memory以便在应用程序重启后仍然对话仍然可用。通过这些步骤我们可以在多次交互中保持上下文或状态从而使应用程序更加智能和人性化。

相关新闻