Chat Memory

大型语言模型 (LLM) 是无状态的,这意味着它们不会保留以前交互的信息。当您希望在多次交互中保持上下文或状态时,这可能是一个限制。为了解决这个问题,Spring AI 提供了聊天记忆功能,允许您在与 LLM 的多次交互中存储和检索信息。

Large language models (LLMs) are stateless, meaning they do not retain information about previous interactions. This can be a limitation when you want to maintain context or state across multiple interactions. To address this, Spring AI provides chat memory features that allow you to store and retrieve information across multiple interactions with the LLM.

ChatMemory 抽象允许您实现各种类型的记忆以支持不同的用例。消息的底层存储由 ChatMemoryRepository 处理,其唯一职责是存储和检索消息。由 ChatMemory 实现来决定要保留哪些消息以及何时删除它们。策略示例可以包括保留最后 N 条消息、在一定时间段内保留消息,或将消息保留到一定令牌限制。

The ChatMemory abstraction allows you to implement various types of memory to support different use cases. The underlying storage of the messages is handled by the ChatMemoryRepository, whose sole responsibility is to store and retrieve messages. It’s up to the ChatMemory implementation to decide which messages to keep and when to remove them. Examples of strategies could include keeping the last N messages, keeping messages for a certain time period, or keeping messages up to a certain token limit.

在选择记忆类型之前,了解聊天记忆和聊天历史之间的区别至关重要。

Before choosing a memory type, it’s essential to understand the difference between chat memory and chat history.

  • Chat Memory 。大型语言模型保留并用于在整个对话中保持上下文意识的信息。

  • Chat Memory. The information that a large-language model retains and uses to maintain contextual awareness throughout a conversation.

  • Chat History 。完整的对话历史,包括用户和模型之间交换的所有消息。

  • Chat History. The entire conversation history, including all messages exchanged between the user and the model.

ChatMemory 抽象旨在管理 chat memory 。它允许您存储和检索与当前对话上下文相关的消息。但是,它不最适合存储 chat history 。如果您需要维护所有交换消息的完整记录,您应该考虑使用不同的方法,例如依赖 Spring Data 来高效存储和检索完整的聊天历史。

The ChatMemory abstraction is designed to manage the chat memory. It allows you to store and retrieve messages that are relevant to the current conversation context. However, it is not the best fit for storing the chat history. If you need to maintain a complete record of all the messages exchanged, you should consider using a different approach, such as relying on Spring Data for efficient storage and retrieval of the complete chat history.

Quick Start

Spring AI 自动配置一个 ChatMemory bean,您可以直接在应用程序中使用。默认情况下,它使用内存存储库来存储消息 ( InMemoryChatMemoryRepository ) 和 MessageWindowChatMemory 实现来管理对话历史。如果已配置不同的存储库(例如,Cassandra、JDBC 或 Neo4j),Spring AI 将使用该存储库。

Spring AI auto-configures a ChatMemory bean that you can use directly in your application. By default, it uses an in-memory repository to store messages (InMemoryChatMemoryRepository) and a MessageWindowChatMemory implementation to manage the conversation history. If a different repository is already configured (e.g., Cassandra, JDBC, or Neo4j), Spring AI will use that instead.

@Autowired
ChatMemory chatMemory;

以下部分将进一步描述 Spring AI 中可用的不同记忆类型和存储库。

The following sections will describe further the different memory types and repositories available in Spring AI.

Memory Types

ChatMemory 抽象允许您实现各种类型的记忆以适应不同的用例。记忆类型的选择可以显著影响应用程序的性能和行为。本节描述了 Spring AI 提供的内置记忆类型及其特性。

The ChatMemory abstraction allows you to implement various types of memory to suit different use cases. The choice of memory type can significantly impact the performance and behavior of your application. This section describes the built-in memory types provided by Spring AI and their characteristics.

Message Window Chat Memory

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

MessageWindowChatMemory maintains a window of messages up to a specified maximum size. When the number of messages exceeds the maximum, older messages are removed while preserving system messages. The default window size is 20 messages.

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

这是 Spring AI 用于自动配置 ChatMemory bean 的默认消息类型。

This is the default message type used by Spring AI to auto-configure a ChatMemory bean.

Memory Storage

Spring AI 提供了 ChatMemoryRepository 抽象用于存储聊天记忆。本节描述了 Spring AI 提供的内置存储库以及如何使用它们,但您也可以根据需要实现自己的存储库。

Spring AI offers the ChatMemoryRepository abstraction for storing chat memory. This section describes the built-in repositories provided by Spring AI and how to use them, but you can also implement your own repository if needed.

In-Memory Repository

InMemoryChatMemoryRepository 使用 ConcurrentHashMap 将消息存储在内存中。

InMemoryChatMemoryRepository stores messages in memory using a ConcurrentHashMap.

默认情况下,如果没有配置其他存储库,Spring AI 会自动配置一个类型为 InMemoryChatMemoryRepositoryChatMemoryRepository bean,您可以直接在应用程序中使用。

By default, if no other repository is already configured, Spring AI auto-configures a ChatMemoryRepository bean of type InMemoryChatMemoryRepository that you can use directly in your application.

@Autowired
ChatMemoryRepository chatMemoryRepository;

如果您更喜欢手动创建 InMemoryChatMemoryRepository ,可以按如下方式操作:

If you’d rather create the InMemoryChatMemoryRepository manually, you can do so as follows:

ChatMemoryRepository repository = new InMemoryChatMemoryRepository();

JdbcChatMemoryRepository

JdbcChatMemoryRepository 是一个内置实现,它使用 JDBC 将消息存储在关系数据库中。它开箱即用地支持多种数据库,适用于需要持久存储聊天记忆的应用程序。

JdbcChatMemoryRepository is a built-in implementation that uses JDBC to store messages in a relational database. It supports multiple databases out-of-the-box and is suitable for applications that require persistent storage of chat memory.

首先,将以下依赖项添加到您的项目中:

First, add the following dependency to your project:

  • Maven

  • Gradle

<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 AI provides auto-configuration for the JdbcChatMemoryRepository, that you can use directly in your application.

@Autowired
JdbcChatMemoryRepository chatMemoryRepository;

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

如果您更喜欢手动创建 JdbcChatMemoryRepository ,可以通过提供 JdbcTemplate 实例和 JdbcChatMemoryRepositoryDialect 来实现:

If you’d rather create the JdbcChatMemoryRepository manually, you can do so by providing a JdbcTemplate instance and a JdbcChatMemoryRepositoryDialect:

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

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

Supported Databases and Dialect Abstraction

Spring AI 通过方言抽象支持多种关系数据库。以下数据库开箱即用:

Spring AI supports multiple relational databases via a dialect abstraction. The following databases are supported out-of-the-box:

  • PostgreSQL

  • MySQL / MariaDB

  • SQL Server

  • HSQLDB

使用 JdbcChatMemoryRepositoryDialect.from(DataSource) 时,可以从 JDBC URL 自动检测正确的方言。您可以通过实现 JdbcChatMemoryRepositoryDialect 接口来扩展对其他数据库的支持。

The correct dialect can be auto-detected from the JDBC URL when using JdbcChatMemoryRepositoryDialect.from(DataSource). You can extend support for other databases by implementing the JdbcChatMemoryRepositoryDialect interface.

Configuration Properties

Property

Description

Default Value

spring.ai.chat.memory.repository.jdbc.initialize-schema

Controls when to initialize the schema. Values: embedded (default), always, never.

embedded

spring.ai.chat.memory.repository.jdbc.schema

Location of the schema script to use for initialization. Supports classpath: URLs and platform placeholders.

classpath:org/springframework/ai/chat/memory/repository/jdbc/schema-@@platform@@.sql

spring.ai.chat.memory.repository.jdbc.platform

Platform to use in initialization scripts if the @@platform@@ placeholder is used.

auto-detected

Schema Initialization

自动配置会在启动时自动创建 SPRING_AI_CHAT_MEMORY 表,使用特定于供应商的 SQL 脚本来创建数据库。默认情况下,模式初始化仅针对嵌入式数据库(H2、HSQL、Derby 等)运行。

The auto-configuration will automatically create the SPRING_AI_CHAT_MEMORY table on startup, using a vendor-specific SQL script for your database. By default, schema initialization runs only for embedded databases (H2, HSQL, Derby, etc.).

您可以使用 spring.ai.chat.memory.repository.jdbc.initialize-schema 属性控制模式初始化:

You can control schema initialization using the spring.ai.chat.memory.repository.jdbc.initialize-schema property:

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)

要覆盖模式脚本位置,请使用:

To override the schema script location, use:

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

Extending Dialects

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

To add support for a new database, implement the JdbcChatMemoryRepositoryDialect interface and provide SQL for selecting, inserting, and deleting messages. You can then pass your custom dialect to the repository builder.

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

CassandraChatMemoryRepository

CassandraChatMemoryRepository 使用 Apache Cassandra 存储消息。它适用于需要持久存储聊天记忆的应用程序,特别是在可用性、持久性、扩展性以及利用生存时间 (TTL) 功能方面。

CassandraChatMemoryRepository uses Apache Cassandra to store messages. It is suitable for applications that require persistent storage of chat memory, especially for availability, durability, scale, and when taking advantage of time-to-live (TTL) feature.

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

CassandraChatMemoryRepository has a time-series schema, keeping record of all past chat windows, valuable for governance and auditing. Setting time-to-live to some value, for example three years, is recommended.

要使用 CassandraChatMemoryRepository ,首先将依赖项添加到您的项目中:

To use CassandraChatMemoryRepository first, add the dependency to your project:

  • Maven

  • Gradle

<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 AI provides auto-configuration for the CassandraChatMemoryRepository that you can use directly in your application.

@Autowired
CassandraChatMemoryRepository chatMemoryRepository;

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

如果您更喜欢手动创建 CassandraChatMemoryRepository ,可以通过提供 CassandraChatMemoryRepositoryConfig 实例来创建:

If you’d rather create the CassandraChatMemoryRepository manually, you can do so by providing a CassandraChatMemoryRepositoryConfig instance:

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

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

Configuration Properties

Property

Description

Default Value

spring.cassandra.contactPoints

Host(s) to initiate cluster discovery

127.0.0.1

spring.cassandra.port

Cassandra native protocol port to connect to

9042

spring.cassandra.localDatacenter

Cassandra datacenter to connect to

datacenter1

spring.ai.chat.memory.cassandra.time-to-live

Time to live (TTL) for messages written in Cassandra

spring.ai.chat.memory.cassandra.keyspace

Cassandra keyspace

springframework

spring.ai.chat.memory.cassandra.messages-column

Cassandra column name for messages

springframework

spring.ai.chat.memory.cassandra.table

Cassandra table

ai_chat_memory

spring.ai.chat.memory.cassandra.initialize-schema

Whether to initialize the schema on startup.

true

Schema Initialization

自动配置将自动创建 ai_chat_memory 表。

The auto-configuration will automatically create the ai_chat_memory table.

您可以通过将属性 spring.ai.chat.memory.repository.cassandra.initialize-schema 设置为 false 来禁用模式初始化。

You can disable the schema initialization by setting the property spring.ai.chat.memory.repository.cassandra.initialize-schema to false.

Neo4j ChatMemoryRepository

Neo4jChatMemoryRepository 是一个内置实现,它使用 Neo4j 将聊天消息作为节点和关系存储在属性图数据库中。它适用于希望利用 Neo4j 图功能进行聊天记忆持久化的应用程序。

Neo4jChatMemoryRepository is a built-in implementation that uses Neo4j to store chat messages as nodes and relationships in a property graph database. It is suitable for applications that want to leverage Neo4j’s graph capabilities for chat memory persistence.

首先,将以下依赖项添加到您的项目中:

First, add the following dependency to your project:

  • Maven

  • Gradle

<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 AI provides auto-configuration for the Neo4jChatMemoryRepository, which you can use directly in your application.

@Autowired
Neo4jChatMemoryRepository chatMemoryRepository;

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

如果您更倾向于手动创建 Neo4jChatMemoryRepository ,可以通过提供一个 Neo4j Driver 实例来实现:

If you’d rather create the Neo4jChatMemoryRepository manually, you can do so by providing a Neo4j Driver instance:

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

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

Configuration Properties

Property

Description

Default Value

spring.ai.chat.memory.repository.neo4j.sessionLabel

The label for the nodes that store conversation sessions

Session

spring.ai.chat.memory.repository.neo4j.messageLabel

The label for the nodes that store messages

Message

spring.ai.chat.memory.repository.neo4j.toolCallLabel

The label for nodes that store tool calls (e.g. in Assistant Messages)

ToolCall

spring.ai.chat.memory.repository.neo4j.metadataLabel

The label for nodes that store message metadata

Metadata

spring.ai.chat.memory.repository.neo4j.toolResponseLabel

The label for the nodes that store tool responses

ToolResponse

spring.ai.chat.memory.repository.neo4j.mediaLabel

The label for the nodes that store media associated with a message

Media

Index Initialization

Neo4j 存储库将自动确保为对话 ID 和消息索引创建索引,以优化性能。如果您使用自定义标签,也将为这些标签创建索引。无需进行模式初始化,但您应确保您的 Neo4j 实例可供您的应用程序访问。

The Neo4j repository will automatically ensure that indexes are created for conversation IDs and message indices to optimize performance. If you use custom labels, indexes will be created for those labels as well. No schema initialization is required, but you should ensure your Neo4j instance is accessible to your application.

Memory in Chat Client

当使用 ChatClient API 时,您可以提供一个 ChatMemory 实现,以在多次交互中保持对话上下文。

When using the ChatClient API, you can provide a ChatMemory implementation to maintain conversation context across multiple interactions.

Spring AI 提供了一些内置的 Advisor,您可以根据需要使用它们来配置 ChatClient 的内存行为。

Spring AI provides a few built-in Advisors that you can use to configure the memory behavior of the ChatClient, based on your needs.

目前,执行工具调用时与大型语言模型交换的中间消息未存储在内存中。这是当前实现的一个限制,将在未来版本中解决。如果您需要存储这些消息,请参阅 User Controlled Tool Execution 的说明。

Currently, the intermediate messages exchanged with a large-language model when performing tool calls are not stored in the memory. This is a limitation of the current implementation and will be addressed in future releases. If you need to store these messages, refer to the instructions for the User Controlled Tool Execution.

  • MessageChatMemoryAdvisor 。此 Advisor 使用提供的 ChatMemory 实现管理对话内存。在每次交互中,它从内存中检索对话历史记录,并将其作为消息集合包含在提示中。

  • MessageChatMemoryAdvisor. This advisor manages the conversation memory using the provided ChatMemory implementation. On each interaction, it retrieves the conversation history from the memory and includes it in the prompt as a collection of messages.

  • PromptChatMemoryAdvisor 。此 Advisor 使用提供的 ChatMemory 实现管理对话内存。在每次交互中,它从内存中检索对话历史记录,并将其作为纯文本附加到系统提示中。

  • PromptChatMemoryAdvisor. This advisor manages the conversation memory using the provided ChatMemory implementation. On each interaction, it retrieves the conversation history from the memory and appends it to the system prompt as plain text.

  • VectorStoreChatMemoryAdvisor 。此 Advisor 使用提供的 VectorStore 实现管理对话内存。在每次交互中,它从向量存储中检索对话历史记录,并将其作为纯文本附加到系统消息中。

  • VectorStoreChatMemoryAdvisor. This advisor manages the conversation memory using the provided VectorStore implementation. On each interaction, it retrieves the conversation history from the vector store and appends it to the system message as plain text.

例如,如果您想将 MessageWindowChatMemoryMessageChatMemoryAdvisor 一起使用,可以按如下方式进行配置:

For example, if you want to use MessageWindowChatMemory with the MessageChatMemoryAdvisor, you can configure it as follows:

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

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

当对 ChatClient 进行调用时,内存将由 MessageChatMemoryAdvisor 自动管理。对话历史记录将根据指定的对话 ID 从内存中检索:

When performing a call to the ChatClient, the memory will be automatically managed by the MessageChatMemoryAdvisor. The conversation history will be retrieved from the memory based on the specified conversation ID:

String conversationId = "007";

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

PromptChatMemoryAdvisor

Custom Template

PromptChatMemoryAdvisor 使用默认模板通过检索到的对话内存来增强系统消息。您可以通过 .promptTemplate() 构建器方法提供自己的 PromptTemplate 对象来自定义此行为。

The PromptChatMemoryAdvisor uses a default template to augment the system message with the retrieved conversation memory. You can customize this behavior by providing your own PromptTemplate object via the .promptTemplate() builder method.

此处提供的 PromptTemplate 自定义了 Advisor 如何将检索到的内存与系统消息合并。这与在 ChatClient 本身(使用 .templateRenderer() )上配置 TemplateRenderer 不同,后者会影响 Advisor 运行 before 之前的初始用户/系统提示内容的渲染。有关客户端级别模板渲染的更多详细信息,请参阅 ChatClient Prompt Templates

The PromptTemplate provided here customizes how the advisor merges retrieved memory with the system message. This is distinct from configuring a TemplateRenderer on the ChatClient itself (using .templateRenderer()), which affects the rendering of the initial user/system prompt content before the advisor runs. See ChatClient Prompt Templates for more details on client-level template rendering.

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

The custom PromptTemplate can use any TemplateRenderer implementation (by default, it uses StPromptTemplate based on the StringTemplate engine). The important requirement is that the template must contain the following two placeholders:

  • * 一个 instructions 占位符,用于接收原始系统消息。

  • an instructions placeholder to receive the original system message.

  • * 一个 memory 占位符,用于接收检索到的对话记忆。

  • a memory placeholder to receive the retrieved conversation memory.

VectorStoreChatMemoryAdvisor

Custom Template

VectorStoreChatMemoryAdvisor 使用默认模板通过检索到的对话内存来增强系统消息。您可以通过 .promptTemplate() 构建器方法提供自己的 PromptTemplate 对象来自定义此行为。

The VectorStoreChatMemoryAdvisor uses a default template to augment the system message with the retrieved conversation memory. You can customize this behavior by providing your own PromptTemplate object via the .promptTemplate() builder method.

此处提供的 PromptTemplate 自定义了 Advisor 如何将检索到的内存与系统消息合并。这与在 ChatClient 本身(使用 .templateRenderer() )上配置 TemplateRenderer 不同,后者会影响 Advisor 运行 before 之前的初始用户/系统提示内容的渲染。有关客户端级别模板渲染的更多详细信息,请参阅 ChatClient Prompt Templates

The PromptTemplate provided here customizes how the advisor merges retrieved memory with the system message. This is distinct from configuring a TemplateRenderer on the ChatClient itself (using .templateRenderer()), which affects the rendering of the initial user/system prompt content before the advisor runs. See ChatClient Prompt Templates for more details on client-level template rendering.

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

The custom PromptTemplate can use any TemplateRenderer implementation (by default, it uses StPromptTemplate based on the StringTemplate engine). The important requirement is that the template must contain the following two placeholders:

  • * 一个 instructions 占位符,用于接收原始系统消息。

  • an instructions placeholder to receive the original system message.

  • * 一个 long_term_memory 占位符,用于接收检索到的对话记忆。

  • a long_term_memory placeholder to receive the retrieved conversation memory.

Memory in Chat Model

如果您直接使用 ChatModel 而不是 ChatClient ,您可以显式管理内存:

If you’re working directly with a ChatModel instead of a ChatClient, you can manage the memory explicitly:

// 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"