此版本仍在开发中,尚不被认为是稳定的。对于最新的快照版本,请使用 Spring AI 1.0.1spring-doc.cadn.net.cn

聊天记忆

大型语言模型 (LLM) 是无状态的,这意味着它们不会保留有关先前交互的信息。当您想要在多个交互中维护上下文或状态时,这可能是一个限制。为了解决这个问题,Spring AI 提供了聊天内存功能,允许您在与 LLM 的多次交互中存储和检索信息。spring-doc.cadn.net.cn

ChatMemory抽象允许您实现各种类型的内存来支持不同的用例。消息的底层存储由ChatMemoryRepository,其唯一职责是存储和检索消息。这取决于ChatMemory实现来决定要保留哪些消息以及何时删除它们。策略的示例可能包括保留最后 N 条消息、将消息保留一段时间或将消息保持在某个Tokens限制内。spring-doc.cadn.net.cn

在选择记忆类型之前,有必要了解聊天记忆和聊天记录之间的区别。spring-doc.cadn.net.cn

  • 聊天记忆。大型语言模型保留并用于在整个对话中保持上下文感知的信息。spring-doc.cadn.net.cn

  • 聊天记录。整个对话历史记录,包括用户和模型之间交换的所有消息。spring-doc.cadn.net.cn

ChatMemory抽象旨在管理聊天记忆。它允许您存储和检索与当前对话上下文相关的消息。但是,它并不是存储聊天记录的最佳选择。如果您需要维护所有交换消息的完整记录,则应考虑使用不同的方法,例如依靠 Spring Data 来高效存储和检索完整的聊天历史记录。spring-doc.cadn.net.cn

快速入门

Spring AI 自动配置ChatMemory可以直接在应用程序中使用的 bean。默认情况下,它使用内存存储库来存储消息(InMemoryChatMemoryRepository) 和MessageWindowChatMemory实现来管理对话历史记录。如果已经配置了不同的存储库(例如,Cassandra、JDBC 或 Neo4j),Spring AI 将改用它。spring-doc.cadn.net.cn

@Autowired
ChatMemory chatMemory;

以下部分将进一步描述 Spring AI 中可用的不同内存类型和存储库。spring-doc.cadn.net.cn

内存类型

ChatMemory抽象允许您实现各种类型的内存以适应不同的用例。内存类型的选择会显着影响应用程序的性能和行为。本节介绍Spring AI提供的内置内存类型及其特点。spring-doc.cadn.net.cn

消息窗口聊天记忆

MessageWindowChatMemory维护一个消息窗口,最多可达指定的最大大小。当消息数超过最大值时,将删除较旧的消息,同时保留系统消息。默认窗口大小为 20 条消息。spring-doc.cadn.net.cn

MessageWindowChatMemory memory = MessageWindowChatMemory.builder()
    .maxMessages(10)
    .build();

这是 Spring AI 用来自动配置ChatMemory豆。spring-doc.cadn.net.cn

内存存储

Spring AI 提供ChatMemoryRepository用于存储聊天记忆的抽象。本节介绍 Spring AI 提供的内置仓库以及如何使用它们,但如果需要,您也可以实现自己的仓库。spring-doc.cadn.net.cn

内存存储库

InMemoryChatMemoryRepository使用ConcurrentHashMap.spring-doc.cadn.net.cn

默认情况下,如果尚未配置其他存储库,Spring AI 会自动配置ChatMemoryRepository类型InMemoryChatMemoryRepository您可以直接在应用程序中使用。spring-doc.cadn.net.cn

@Autowired
ChatMemoryRepository chatMemoryRepository;

如果您更愿意创建InMemoryChatMemoryRepository手动,您可以按如下方式执行此作:spring-doc.cadn.net.cn

ChatMemoryRepository repository = new InMemoryChatMemoryRepository();

JdbcChatMemory存储库

JdbcChatMemoryRepository是一个内置实现,它使用 JDBC 将消息存储在关系数据库中。它支持开箱即用的多个数据库,适用于需要持久存储聊天内存的应用程序。spring-doc.cadn.net.cn

首先,将以下依赖项添加到项目中:spring-doc.cadn.net.cn

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-chat-memory-repository-jdbc</artifactId>
</dependency>
dependencies {
    implementation 'org.springframework.ai:spring-ai-starter-model-chat-memory-repository-jdbc'
}

Spring AI 为JdbcChatMemoryRepository,您可以直接在应用程序中使用。spring-doc.cadn.net.cn

@Autowired
JdbcChatMemoryRepository chatMemoryRepository;

ChatMemory chatMemory = MessageWindowChatMemory.builder()
    .chatMemoryRepository(chatMemoryRepository)
    .maxMessages(10)
    .build();

如果您更愿意创建JdbcChatMemoryRepository手动,您可以通过提供JdbcTemplate实例和JdbcChatMemoryRepositoryDialect:spring-doc.cadn.net.cn

ChatMemoryRepository chatMemoryRepository = JdbcChatMemoryRepository.builder()
    .jdbcTemplate(jdbcTemplate)
    .dialect(new PostgresChatMemoryRepositoryDialect())
    .build();

ChatMemory chatMemory = MessageWindowChatMemory.builder()
    .chatMemoryRepository(chatMemoryRepository)
    .maxMessages(10)
    .build();

支持的数据库和方言抽象

Spring AI 通过方言抽象支持多个关系数据库。以下数据库是现成支持的:spring-doc.cadn.net.cn

使用 JDBC URL 时,可以自动检测到正确的方言JdbcChatMemoryRepositoryDialect.from(DataSource).您可以通过实现JdbcChatMemoryRepositoryDialect接口。spring-doc.cadn.net.cn

配置属性

属性spring-doc.cadn.net.cn

描述spring-doc.cadn.net.cn

默认值spring-doc.cadn.net.cn

spring.ai.chat.memory.repository.jdbc.initialize-schemaspring-doc.cadn.net.cn

控制何时初始化架构。值:embedded(默认),always,never.spring-doc.cadn.net.cn

embeddedspring-doc.cadn.net.cn

spring.ai.chat.memory.repository.jdbc.schemaspring-doc.cadn.net.cn

用于初始化的架构脚本的位置。支持classpath:URL 和平台占位符。spring-doc.cadn.net.cn

classpath:org/springframework/ai/chat/memory/repository/jdbc/schema-@@platform@@.sqlspring-doc.cadn.net.cn

spring.ai.chat.memory.repository.jdbc.platformspring-doc.cadn.net.cn

如果使用@@platform@@占位符,则在初始化脚本中使用的平台。spring-doc.cadn.net.cn

自动检测spring-doc.cadn.net.cn

模式初始化

自动配置将自动创建SPRING_AI_CHAT_MEMORY表,使用特定于提供商的数据库 SQL 脚本。默认情况下,模式初始化仅针对嵌入式数据库(H2、HSQL、Derby 等)运行。spring-doc.cadn.net.cn

您可以使用spring.ai.chat.memory.repository.jdbc.initialize-schema财产:spring-doc.cadn.net.cn

spring.ai.chat.memory.repository.jdbc.initialize-schema=embedded # Only for embedded DBs (default)
spring.ai.chat.memory.repository.jdbc.initialize-schema=always   # Always initialize
spring.ai.chat.memory.repository.jdbc.initialize-schema=never    # Never initialize (useful with Flyway/Liquibase)

要覆盖架构脚本位置,请使用:spring-doc.cadn.net.cn

spring.ai.chat.memory.repository.jdbc.schema=classpath:/custom/path/schema-mysql.sql

扩展方言

要添加对新数据库的支持,请实现JdbcChatMemoryRepositoryDialect接口,并提供用于选择、插入和删除消息的 SQL。然后,您可以将自定义方言传递给存储库构建器。spring-doc.cadn.net.cn

ChatMemoryRepository chatMemoryRepository = JdbcChatMemoryRepository.builder()
    .jdbcTemplate(jdbcTemplate)
    .dialect(new MyCustomDbDialect())
    .build();

CassandraChatMemory存储库

CassandraChatMemoryRepository使用 Apache Cassandra 来存储消息。它适用于需要持久存储聊天内存的应用程序,特别是可用性、持久性、规模以及利用生存时间 (TTL) 功能时。spring-doc.cadn.net.cn

CassandraChatMemoryRepository具有时间序列模式,记录所有过去的聊天窗口,对治理和审计很有价值。建议将生存时间设置为某个值,例如三年。spring-doc.cadn.net.cn

使用CassandraChatMemoryRepository首先,将依赖项添加到您的项目中:spring-doc.cadn.net.cn

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-chat-memory-repository-cassandra</artifactId>
</dependency>
dependencies {
    implementation 'org.springframework.ai:spring-ai-starter-model-chat-memory-repository-cassandra'
}

Spring AI 为CassandraChatMemoryRepository您可以直接在应用程序中使用。spring-doc.cadn.net.cn

@Autowired
CassandraChatMemoryRepository chatMemoryRepository;

ChatMemory chatMemory = MessageWindowChatMemory.builder()
    .chatMemoryRepository(chatMemoryRepository)
    .maxMessages(10)
    .build();

如果您更愿意创建CassandraChatMemoryRepository手动,您可以通过提供CassandraChatMemoryRepositoryConfig实例:spring-doc.cadn.net.cn

ChatMemoryRepository chatMemoryRepository = CassandraChatMemoryRepository
    .create(CassandraChatMemoryConfig.builder().withCqlSession(cqlSession));

ChatMemory chatMemory = MessageWindowChatMemory.builder()
    .chatMemoryRepository(chatMemoryRepository)
    .maxMessages(10)
    .build();

配置属性

属性spring-doc.cadn.net.cn

描述spring-doc.cadn.net.cn

默认值spring-doc.cadn.net.cn

spring.cassandra.contactPointsspring-doc.cadn.net.cn

用于启动集群发现的主机spring-doc.cadn.net.cn

127.0.0.1spring-doc.cadn.net.cn

spring.cassandra.portspring-doc.cadn.net.cn

要连接的 Cassandra 本机协议端口spring-doc.cadn.net.cn

9042spring-doc.cadn.net.cn

spring.cassandra.localDatacenterspring-doc.cadn.net.cn

要连接到的 Cassandra 数据中心spring-doc.cadn.net.cn

datacenter1spring-doc.cadn.net.cn

spring.ai.chat.memory.cassandra.time-to-livespring-doc.cadn.net.cn

使用 Cassandra 编写的消息的生存时间 (TTL)spring-doc.cadn.net.cn

spring.ai.chat.memory.cassandra.keyspacespring-doc.cadn.net.cn

Cassandra 键空间spring-doc.cadn.net.cn

springframeworkspring-doc.cadn.net.cn

spring.ai.chat.memory.cassandra.messages-columnspring-doc.cadn.net.cn

消息的 Cassandra 列名spring-doc.cadn.net.cn

springframeworkspring-doc.cadn.net.cn

spring.ai.chat.memory.cassandra.tablespring-doc.cadn.net.cn

Cassandra 桌子spring-doc.cadn.net.cn

ai_chat_memoryspring-doc.cadn.net.cn

spring.ai.chat.memory.cassandra.initialize-schemaspring-doc.cadn.net.cn

是否在启动时初始化架构。spring-doc.cadn.net.cn

truespring-doc.cadn.net.cn

模式初始化

自动配置将自动创建ai_chat_memory桌子。spring-doc.cadn.net.cn

您可以通过设置属性来禁用架构初始化spring.ai.chat.memory.repository.cassandra.initialize-schemafalse.spring-doc.cadn.net.cn

Neo4j 聊天内存存储库

Neo4jChatMemoryRepository是一个内置实现,它使用 Neo4j 将聊天消息作为节点和关系存储在属性图数据库中。它适用于希望利用 Neo4j 的图形功能实现聊天内存持久性的应用程序。spring-doc.cadn.net.cn

首先,将以下依赖项添加到项目中:spring-doc.cadn.net.cn

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-chat-memory-repository-neo4j</artifactId>
</dependency>
dependencies {
    implementation 'org.springframework.ai:spring-ai-starter-model-chat-memory-repository-neo4j'
}

Spring AI 为Neo4jChatMemoryRepository,您可以直接在应用程序中使用。spring-doc.cadn.net.cn

@Autowired
Neo4jChatMemoryRepository chatMemoryRepository;

ChatMemory chatMemory = MessageWindowChatMemory.builder()
    .chatMemoryRepository(chatMemoryRepository)
    .maxMessages(10)
    .build();

如果您更愿意创建Neo4jChatMemoryRepository手动,您可以通过提供 Neo4j 来做到这一点Driver实例:spring-doc.cadn.net.cn

ChatMemoryRepository chatMemoryRepository = Neo4jChatMemoryRepository.builder()
    .driver(driver)
    .build();

ChatMemory chatMemory = MessageWindowChatMemory.builder()
    .chatMemoryRepository(chatMemoryRepository)
    .maxMessages(10)
    .build();

配置属性

属性spring-doc.cadn.net.cn

描述spring-doc.cadn.net.cn

默认值spring-doc.cadn.net.cn

spring.ai.chat.memory.repository.neo4j.sessionLabelspring-doc.cadn.net.cn

存储对话会话的节点的标签spring-doc.cadn.net.cn

Sessionspring-doc.cadn.net.cn

spring.ai.chat.memory.repository.neo4j.messageLabelspring-doc.cadn.net.cn

存储消息的节点的标签spring-doc.cadn.net.cn

Messagespring-doc.cadn.net.cn

spring.ai.chat.memory.repository.neo4j.toolCallLabelspring-doc.cadn.net.cn

存储工具调用的节点的标签(例如,在助手消息中)spring-doc.cadn.net.cn

ToolCallspring-doc.cadn.net.cn

spring.ai.chat.memory.repository.neo4j.metadataLabelspring-doc.cadn.net.cn

存储消息元数据的节点的标签spring-doc.cadn.net.cn

Metadataspring-doc.cadn.net.cn

spring.ai.chat.memory.repository.neo4j.toolResponseLabelspring-doc.cadn.net.cn

存储工具响应的节点的标签spring-doc.cadn.net.cn

ToolResponsespring-doc.cadn.net.cn

spring.ai.chat.memory.repository.neo4j.mediaLabelspring-doc.cadn.net.cn

存储与邮件关联的媒体的节点的标签spring-doc.cadn.net.cn

Mediaspring-doc.cadn.net.cn

索引初始化

Neo4j 存储库将自动确保为对话 ID 和消息索引创建索引以优化性能。如果使用自定义标签,也会为这些标签创建索引。不需要初始化模式,但您应该确保您的应用程序可以访问您的 Neo4j 实例。spring-doc.cadn.net.cn

聊天客户端中的内存

使用 ChatClient API 时,您可以提供ChatMemory实现以在多个交互中维护对话上下文。spring-doc.cadn.net.cn

Spring AI 提供了一些内置的 Advisor,您可以使用它们来配置ChatClient,根据您的需要。spring-doc.cadn.net.cn

目前,在执行工具调用时与大语言模型交换的中间消息不会存储在内存中。这是当前实现的限制,将在将来的版本中解决。如果需要存储这些消息,请参阅用户控制工具执行的说明。
  • MessageChatMemoryAdvisor.此顾问使用提供的ChatMemory实现。在每次交互中,它都会从内存中检索对话历史记录,并将其作为消息集合包含在提示中。spring-doc.cadn.net.cn

  • PromptChatMemoryAdvisor.此顾问使用提供的ChatMemory实现。在每次交互时,它都会从内存中检索对话历史记录,并将其作为纯文本附加到系统提示中。spring-doc.cadn.net.cn

  • VectorStoreChatMemoryAdvisor.此顾问使用提供的VectorStore实现。在每次交互时,它都会从矢量存储中检索对话历史记录,并将其作为纯文本追加到系统消息中。spring-doc.cadn.net.cn

例如,如果要使用MessageWindowChatMemory使用MessageChatMemoryAdvisor,您可以按如下方式进行配置:spring-doc.cadn.net.cn

ChatMemory chatMemory = MessageWindowChatMemory.builder().build();

ChatClient chatClient = ChatClient.builder(chatModel)
    .defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build())
    .build();

执行对ChatClient,内存将由MessageChatMemoryAdvisor.将根据指定的对话 ID 从内存中检索对话历史记录:spring-doc.cadn.net.cn

String conversationId = "007";

chatClient.prompt()
    .user("Do I have license to code?")
    .advisors(a -> a.param(ChatMemory.CONVERSATION_ID, conversationId))
    .call()
    .content();

PromptChat记忆顾问

自定义模板

PromptChatMemoryAdvisor使用默认模板使用检索到的会话内存来扩充系统消息。您可以通过提供自己的行为来自定义此行为PromptTemplate对象通过.promptTemplate()builder 方法。spring-doc.cadn.net.cn

PromptTemplate此处提供自定义顾问程序将检索到的内存与系统消息合并的方式。这不同于配置TemplateRendererChatClient本身(使用.templateRenderer()),这会影响顾问运行初始用户/系统提示内容的呈现。有关客户端级模板渲染的更多详细信息,请参阅 ChatClient 提示模板。

自定义PromptTemplate可以使用任何TemplateRenderer实现(默认情况下,它使用StPromptTemplate基于 StringTemplate 引擎)。重要的要求是模板必须包含以下两个占位符:spring-doc.cadn.net.cn

VectorStoreChatMemoryAdvisor

自定义模板

VectorStoreChatMemoryAdvisor使用默认模板使用检索到的会话内存来扩充系统消息。您可以通过提供自己的行为来自定义此行为PromptTemplate对象通过.promptTemplate()builder 方法。spring-doc.cadn.net.cn

PromptTemplate此处提供自定义顾问程序将检索到的内存与系统消息合并的方式。这不同于配置TemplateRendererChatClient本身(使用.templateRenderer()),这会影响顾问运行初始用户/系统提示内容的呈现。有关客户端级模板渲染的更多详细信息,请参阅 ChatClient 提示模板。

自定义PromptTemplate可以使用任何TemplateRenderer实现(默认情况下,它使用StPromptTemplate基于 StringTemplate 引擎)。重要的要求是模板必须包含以下两个占位符:spring-doc.cadn.net.cn

聊天模型中的内存

如果您直接使用ChatModel而不是ChatClient,您可以显式管理内存:spring-doc.cadn.net.cn

// Create a memory instance
ChatMemory chatMemory = MessageWindowChatMemory.builder().build();
String conversationId = "007";

// First interaction
UserMessage userMessage1 = new UserMessage("My name is James Bond");
chatMemory.add(conversationId, userMessage1);
ChatResponse response1 = chatModel.call(new Prompt(chatMemory.get(conversationId)));
chatMemory.add(conversationId, response1.getResult().getOutput());

// Second interaction
UserMessage userMessage2 = new UserMessage("What is my name?");
chatMemory.add(conversationId, userMessage2);
ChatResponse response2 = chatModel.call(new Prompt(chatMemory.get(conversationId)));
chatMemory.add(conversationId, response2.getResult().getOutput());

// The response will contain "James Bond"