|
此版本仍在开发中,尚未被视为稳定版。为了获取最新的快照版本,请使用Spring AI 1.1.3! |
聊天记忆
大型语言模型(LLMs)是无状态的,这意味着它们不会保留关于先前交互的信息。当你希望在多次交互中保持上下文或状态时,这可能成为一个限制。为了解决这个问题,Spring AI提供了聊天记忆功能,允许你在与LLM的多次交互中存储和检索信息。
ChatMemory 抽象允许您实现多种类型的记忆存储以支持不同的使用场景。消息的底层存储由ChatMemoryRepository处理,其唯一职责是存储和检索消息。决定保留哪些消息以及何时移除它们则是由ChatMemory实现来决定的。策略示例可能包括保留最后N条消息、保留消息一定时间段,或保留消息直到达到某个Tokens限制。
在选择内存类型之前,理解聊天内存和聊天历史之间的区别是至关重要的。
-
聊天记忆. 大型语言模型在对话过程中保留并使用的,用以维持上下文意识的信息。
-
聊天记录. 包含用户与模型之间所有交换信息的完整对话历史。
ChatMemory 抽象设计用于管理聊天内存。它使您能够存储和检索与当前对话上下相关的消息。然而,它并不适合存储聊天历史记录。如果您需要维护所有交换消息的完整记录,应考虑使用不同方法,比如依靠Spring Data来高效存储和检索完整的聊天历史记录。
快速开始
Spring AI 会自动配置一个 ChatMemory bean,您可以在应用程序中直接使用。默认情况下,它使用内存存储库来存储消息 (InMemoryChatMemoryRepository) 和一个 MessageWindowChatMemory 实现来管理对话历史。如果已经配置了其他存储库(例如,Cassandra、JDBC 或 Neo4j),Spring AI 将使用那个存储库代替。
@Autowired
ChatMemory chatMemory;
以下各节将进一步介绍Spring AI中可用的不同内存类型和存储库。
内存存储
Spring AI 为存储聊天记忆提供了 ChatMemoryRepository 抽象。本节描述了 Spring AI 提供的内置存储库及其使用方法,但如有需要,您也可以实现自己的存储库。
内存中存储库
InMemoryChatMemoryRepository 使用 ConcurrentHashMap 在内存中存储消息。
默认情况下,如果没有配置其他仓库,Spring AI 会自动配置一个类型为 ChatMemoryRepository 的 InMemoryChatMemoryRepository bean,您可以在应用程序中直接使用它。
@Autowired
ChatMemoryRepository chatMemoryRepository;
如果希望手动创建InMemoryChatMemoryRepository,可以按照以下方式操作:
ChatMemoryRepository repository = new InMemoryChatMemoryRepository();
JdbcChat内存存储库
JdbcChatMemoryRepository 是一个内置实现,使用JDBC将消息存储在关系数据库中。它开箱即支持多种数据库,适用于需要持久化存储聊天记忆的应用程序。
消息按时间戳的升序(从旧到新)检索,这是LLM对话历史记录的预期格式。
首先,将以下依赖项添加到您的项目中:
-
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 提供了自动配置,您可以在应用程序中直接使用。
@Autowired
JdbcChatMemoryRepository chatMemoryRepository;
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository)
.maxMessages(10)
.build();
如果希望手动创建JdbcChatMemoryRepository,可以通过提供一个JdbcTemplate实例和一个JdbcChatMemoryRepositoryDialect来实现:
ChatMemoryRepository chatMemoryRepository = JdbcChatMemoryRepository.builder()
.jdbcTemplate(jdbcTemplate)
.dialect(new PostgresChatMemoryRepositoryDialect())
.build();
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository)
.maxMessages(10)
.build();
支持的数据库和方言抽象
Spring AI 通过方言抽象支持多种关系型数据库。开箱即支持以下数据库:
-
PostgreSQL
-
MySQL / MariaDB
-
SQL Server
-
HSQLDB
-
Oracle数据库
当使用 JdbcChatMemoryRepositoryDialect.from(DataSource) 时,可以从JDBC URL自动检测正确的方言。您可以通过实现 JdbcChatMemoryRepositoryDialect 接口来扩展对其他数据库的支持。
配置属性
属性 |
描述 |
默认值 |
|
控制何时初始化架构。值: |
|
|
要使用的架构脚本初始化的位置。支持 |
|
|
如果初始化脚本中使用了 @@platform@@ 占位符,应使用的平台。 |
auto-detected |
架构初始化
自动配置将在启动时自动创建SPRING_AI_CHAT_MEMORY表,使用针对您的数据库的特定于提供商的SQL脚本。默认情况下,架构初始化仅对嵌入式数据库(H2、HSQL、Derby等)运行。
您可以使用 spring.ai.chat.memory.repository.jdbc.initialize-schema 属性来控制模式初始化:
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.ai.chat.memory.repository.jdbc.schema=classpath:/custom/path/schema-mysql.sql
卡桑德拉聊天内存存储库
CassandraChatMemoryRepository 使用Apache Cassandra存储消息。它适用于需要持久化存储聊天记录的应用程序,特别是在需要高可用性、持久性、可扩展性以及利用时间存活期(TTL)功能的场景下。
CassandraChatMemoryRepository 具有时间序列模式,记录了所有过往的聊天窗口,对于管理和审计非常有价值。建议设置存活时间为某个值,例如三年。
消息按时间戳的升序(从旧到新)检索,这是LLM对话历史记录的预期格式。
要使用CassandraChatMemoryRepository首先,将依赖项添加到您的项目中:
-
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 提供了自动配置,您可以在应用程序中直接使用。
@Autowired
CassandraChatMemoryRepository chatMemoryRepository;
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository)
.maxMessages(10)
.build();
如果希望手动创建CassandraChatMemoryRepository,可以通过提供一个CassandraChatMemoryRepositoryConfig实例来实现:
ChatMemoryRepository chatMemoryRepository = CassandraChatMemoryRepository
.create(CassandraChatMemoryRepositoryConfig.builder().withCqlSession(cqlSession));
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository)
.maxMessages(10)
.build();
配置属性
属性 |
描述 |
默认值 |
|
要进行集群发现的主机(s) |
|
|
连接到Cassandra原生协议的端口 |
|
|
要连接的Cassandra数据中心 |
|
|
在Cassandra中写入消息的生存时间(TTL) |
|
|
Cassandra 键空间 |
|
|
Cassandra中消息的列名称 |
|
|
Cassandra 表 |
|
|
是否在启动时初始化数据库模式。 |
|
Neo4j 聊天记忆库实现
Neo4jChatMemoryRepository 是一个内置实现,使用Neo4j将聊天消息作为节点和关系存储在属性图数据库中。它适用于希望利用Neo4j的图功能来持久化聊天记忆的应用程序。
消息按升序的消息索引顺序(从旧到新)检索,这是LLM对话历史记录的预期格式。
首先,将以下依赖项添加到您的项目中:
-
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 提供了自动配置,您可以在应用程序中直接使用。
@Autowired
Neo4jChatMemoryRepository chatMemoryRepository;
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository)
.maxMessages(10)
.build();
如果希望手动创建Neo4jChatMemoryRepository,可以通过提供一个Neo4jDriver实例来实现:
ChatMemoryRepository chatMemoryRepository = Neo4jChatMemoryRepository.builder()
.driver(driver)
.build();
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository)
.maxMessages(10)
.build();
配置属性
属性 |
描述 |
默认值 |
|
存储对话会话的节点标签 |
|
|
存储消息的节点标签 |
|
|
存储工具调用(例如,在助手消息中)的节点标签 |
|
|
存储消息元数据的节点标签 |
|
|
存储工具响应的节点标签 |
|
|
与消息关联的媒体存储节点的标签 |
|
CosmosDB聊天内存存储库
CosmosDBChatMemoryRepository 是一个内置实现,使用Azure Cosmos DB NoSQL API来存储消息。它适用于需要全球分布、高度可扩展的文档数据库来持久化聊天记忆的应用程序。仓库使用会话ID作为分区键,以确保数据的有效分布和快速检索。
消息按时间戳的升序(从旧到新)检索,这是LLM对话历史记录的预期格式。
首先,将以下依赖项添加到您的项目中:
-
Maven
-
Gradle
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-chat-memory-repository-cosmos-db</artifactId>
</dependency>
dependencies {
implementation 'org.springframework.ai:spring-ai-starter-model-chat-memory-repository-cosmos-db'
}
Spring AI 为 CosmosDBChatMemoryRepository 提供了自动配置,您可以在应用程序中直接使用。
@Autowired
CosmosDBChatMemoryRepository chatMemoryRepository;
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository)
.maxMessages(10)
.build();
如果希望手动创建CosmosDBChatMemoryRepository,可以通过提供一个CosmosDBChatMemoryRepositoryConfig实例来实现:
ChatMemoryRepository chatMemoryRepository = CosmosDBChatMemoryRepository
.create(CosmosDBChatMemoryRepositoryConfig.builder()
.withCosmosClient(cosmosAsyncClient)
.withDatabaseName("chat-memory-db")
.withContainerName("conversations")
.build());
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository)
.maxMessages(10)
.build();
配置属性
属性 |
描述 |
默认值 |
|
Azure Cosmos DB 终端URI。自动配置所需。 |
|
|
Azure Cosmos DB的主密钥或辅助密钥。如果未提供,将使用Azure身份验证。 |
|
|
Cosmos DB客户端的连接模式( |
|
|
Cosmos DB数据库的名称。 |
|
|
Cosmos DB容器的名称。 |
|
|
容器的分区键路径。 |
|
MongoChat内存存储库
MongoChatMemoryRepository 是一个内置实现,使用MongoDB存储消息。它适用于需要灵活的、面向文档的数据库来持久化聊天记录的应用程序。
消息按时间戳的升序(从旧到新)检索,这是LLM对话历史记录所需的格式。这种排序方式在所有聊天记忆存储实现中保持一致。
首先,将以下依赖项添加到您的项目中:
-
Maven
-
Gradle
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-chat-memory-repository-mongodb</artifactId>
</dependency>
dependencies {
implementation 'org.springframework.ai:spring-ai-starter-model-chat-memory-repository-mongodb'
}
Spring AI 为 MongoChatMemoryRepository 提供了自动配置,您可以在应用程序中直接使用。
@Autowired
MongoChatMemoryRepository chatMemoryRepository;
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository)
.maxMessages(10)
.build();
如果希望手动创建MongoChatMemoryRepository,可以通过提供一个MongoTemplate实例来实现:
ChatMemoryRepository chatMemoryRepository = MongoChatMemoryRepository.builder()
.mongoTemplate(mongoTemplate)
.build();
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository)
.maxMessages(10)
.build();
配置属性
属性 |
描述 |
默认值 |
|
是否应在启动时自动创建或重新创建索引。注意:更改*TTL*值将删除TTL索引并重新创建它。 |
|
|
MongoDB中写入消息的生存时间(TTL),以秒为单位。如果不设置,消息将无限期存储。 |
|
集合初始化
自动配置将在启动时自动创建集合ai_chat_memory,如果它尚不存在的话。
聊天客户端中的内存
在使用ChatClient API时,您可以提供一个ChatMemory实现来跨多个交互维护会话上下文。
Spring AI 提供了一些内置的顾问,您可以根据需要使用它们来配置 ChatClient 的内存行为。
| 目前,在执行工具调用时与大型语言模型交换的中间消息并未存储在内存中。这是当前实现的一个限制,将在未来的版本中得到解决。如果您需要存储这些消息,请参考用户控制的工具执行指南。 |
-
MessageChatMemoryAdvisor. 此顾问使用提供的ChatMemory实现来管理对话记忆。在每次交互中,它从内存中检索对话历史,并将其作为消息集合包含在提示中。 -
PromptChatMemoryAdvisor. 此顾问使用所提供的ChatMemory实现来管理对话记忆。在每次交互中,它从内存中检索对话历史,并将其作为纯文本追加到系统提示中。 -
VectorStoreChatMemoryAdvisor. 此顾问使用所提供的VectorStore实现来管理对话记忆。在每次交互中,它从向量存储中检索对话历史,并将其作为纯文本附加到系统消息中。
例如,如果你想在MessageWindowChatMemory中使用MessageChatMemoryAdvisor,你可以这样配置:
ChatMemory chatMemory = MessageWindowChatMemory.builder().build();
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build())
.build();
在调用ChatClient时,内存将由MessageChatMemoryAdvisor自动管理。根据指定的会话ID,会话历史记录将从内存中检索:
String conversationId = "007";
chatClient.prompt()
.user("Do I have license to code?")
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, conversationId))
.call()
.content();
即时聊天内存顾问
自定义模板
数字PromptChatMemoryAdvisor使用默认模板增强系统消息,包含检索到的对话记忆。您可以通过.promptTemplate()构建器方法提供自定义的PromptTemplate对象来定制此行为。
提供的PromptTemplate在这里定制了顾问如何将检索到的内存与系统消息合并。这与在ChatClient本身上配置TemplateRenderer(使用.templateRenderer())不同,后者影响顾问运行前初始用户/系统提示内容的渲染。有关客户端级模板渲染的更多详细信息,请参见ChatClient 提示模板。 |
自定义的PromptTemplate可以使用任何TemplateRenderer实现(默认情况下,它使用基于StringTemplate引擎的StPromptTemplate)。关键要求是模板必须包含以下两个占位符:
-
一个
instructions占位符,用于接收原始系统消息。 -
一个
memory占位符,用于接收检索到的会话记忆。
向量存储聊天记忆顾问
自定义模板
数字VectorStoreChatMemoryAdvisor使用默认模板增强系统消息,包含检索到的对话记忆。您可以通过.promptTemplate()构建器方法提供自定义的PromptTemplate对象来定制此行为。
提供的PromptTemplate在这里定制了顾问如何将检索到的内存与系统消息合并。这与在ChatClient本身上配置TemplateRenderer(使用.templateRenderer())不同,后者影响顾问运行前初始用户/系统提示内容的渲染。有关客户端级模板渲染的更多详细信息,请参见ChatClient 提示模板。 |
自定义的PromptTemplate可以使用任何TemplateRenderer实现(默认情况下,它使用基于StringTemplate引擎的StPromptTemplate)。关键要求是模板必须包含以下两个占位符:
-
一个
instructions占位符,用于接收原始系统消息。 -
一个
long_term_memory占位符,用于接收检索到的会话记忆。
聊天模型中的内存
如果您直接处理的是ChatModel而不是ChatClient,您可以显式管理内存:
// 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"