|
最新快照版本请使用Spring AI 1.1.0! |
聊天记忆
大型语言模型(LLM)是无状态的,意味着它们不会保留之前互动的信息。当你需要在多次交互中保持上下文或状态时,这可能会成为一个限制。为此,Spring AI 提供了聊天内存功能,允许你在多次与 LLM 交互中存储和检索信息。
这聊天记忆抽象允许你实现多种类型的内存,以支持不同的使用场景。消息的底层存储由聊天记忆仓库,其唯一职责是存储和检索消息。这取决于聊天记忆实现以决定保留哪些消息以及何时删除它们。策略的例子包括保留最后N条消息、保留消息一定时间段,或将消息限制在某个Tokens限制内。
在选择内存类型之前,了解聊天记忆和聊天历史的区别至关重要。
-
聊天记忆。大语言模型保留并利用的信息,用于在整个对话过程中保持上下文意识。
-
聊天记录。完整的对话记录,包括用户与模特之间所有交换的信息。
这聊天记忆抽象旨在管理聊天记忆。它允许您存储和检索与当前对话上下文相关的消息。然而,它并非存储聊天历史的最佳选择。如果您需要完整记录所有交换的消息,应考虑采用其他方法,例如依赖 Spring Data 高效存储和检索完整聊天历史。
快速入门
Spring AI 会自动配置聊天记忆你可以直接在应用中使用BEAN。默认情况下,它使用内存存储库来存储消息(InMemoryChatMemoryRepository) 以及消息WindowChatMemory(记忆窗口聊天)实现以管理对话历史。如果已经配置了不同的仓库(例如 Cassandra、JDBC 或 Neo4j),Spring AI 会使用该仓库。
@Autowired
ChatMemory chatMemory;
以下章节将进一步介绍 Spring AI 中可用的不同内存类型和存储库。
存储
Spring AI 提供了聊天记忆仓库用于存储聊天内存的抽象。本节介绍了 Spring AI 提供的内置仓库及其使用方法,但如果需要,你也可以实现自己的仓库。
内存存储库
InMemoryChatMemoryRepository通过并发哈希图.
默认情况下,如果没有其他仓库已配置,Spring AI 会自动配置聊天记忆仓库类型豆InMemoryChatMemoryRepository你可以直接在申请中使用。
@Autowired
ChatMemoryRepository chatMemoryRepository;
如果你更愿意创建InMemoryChatMemoryRepository手动作时,你可以这样做:
ChatMemoryRepository repository = new InMemoryChatMemoryRepository();
JdbcChatMemoryRepository
JdbcChatMemoryRepository是一个内置实现,使用 JDBC 将消息存储在关系数据库中。它开箱即用支持多个数据库,适合需要持续存储聊天内存的应用。
首先,给你的项目添加以下依赖关系:
-
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手动作时,你可以通过提供Jdbc模板实例和JdbcChatMemoryRepository方言:
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
使用时,可以通过JDBC网址自动检测正确的方言JdbcChatMemoryRepositoryDialect.from(DataSource).你可以通过实现JdbcChatMemoryRepository方言接口。
配置属性
属性 |
描述 |
默认值 |
|
控制何时初始化模式。值: |
|
|
用于初始化的模式脚本位置。支持 |
|
|
如果使用@@platform@@占位符,该平台可用于初始化脚本。 |
自动检测 |
模式初始化
自动配置会自动创建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
CassandraChatMemoryRepository使用 Apache Cassandra 来存储消息。它适合需要持续存储聊天内存的应用,尤其是在可用性、耐用性、扩展性以及利用寿命时间(TTL)功能时。
CassandraChatMemoryRepository拥有时间序列模式,记录所有过去的聊天窗口,对治理和审计非常有价值。建议将生命时间设定为某个数值,例如三年。
使用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();
配置属性
属性 |
描述 |
默认值 |
|
主机启动集群发现 |
|
|
Cassandra 原生协议端口用于连接 |
|
|
Cassandra 数据中心连接 |
|
|
用Cassandra写成的消息的生存时间(TTL) |
|
|
Cassandra 密钥空间 |
|
|
Cassandra 列名用于消息 |
|
|
卡桑德拉表格 |
|
|
是否在启动时初始化模式。 |
|
Neo4j ChatMemoryRepository
Neo4jChatMemoryRepository是一个内置实现,利用 Neo4j 将聊天消息作为节点和关系存储在属性图数据库中。它适合希望利用 Neo4j 图功能实现聊天内存持久化的应用程序。
首先,给你的项目添加以下依赖关系:
-
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手动作时,你可以通过提供Neo4j来实现Drivers实例:
ChatMemoryRepository chatMemoryRepository = Neo4jChatMemoryRepository.builder()
.driver(driver)
.build();
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository)
.maxMessages(10)
.build();
配置属性
属性 |
描述 |
默认值 |
|
存储会话节点的标签 |
|
|
存储消息的节点标签 |
|
|
存储工具调用的节点标签(例如助理消息中) |
|
|
存储消息元数据的节点标签 |
|
|
存储工具响应节点的标签 |
|
|
存储与消息关联的媒体节点的标签 |
|
聊天客户端中的内存
使用 ChatClient API 时,你可以提供聊天记忆实现以在多次交互中保持对话上下文。
Spring AI 提供了一些内置的 Advisor,可以用来配置聊天客户端,根据你的需求。
| 目前,在执行工具调用时,与大型语言模型交换的中间消息不会存储在内存中。这是当前实现的一个局限,未来版本将加以解决。如果您需要存储这些消息,请参阅用户控制工具执行的说明。 |
-
消息聊天记忆顾问.该顾问通过提供的管理对话记忆聊天记忆实现。每次互动时,它会从内存中检索对话历史,并将其作为一组消息包含在提示中。 -
提示聊天记忆顾问.该顾问通过提供的管理对话记忆聊天记忆实现。每次交互时,它会从内存中检索对话历史,并以纯文本形式附加到系统提示中。 -
向量存储聊天记忆顾问.该顾问通过提供的管理对话记忆VectorStore实现。每次交互中,它从向量存储中获取对话历史,并将其作为明文附加到系统消息中。
例如,如果你想使用消息WindowChatMemory(记忆窗口聊天)其中消息聊天记忆顾问,你可以按以下方式配置:
ChatMemory chatMemory = MessageWindowChatMemory.builder().build();
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build())
.build();
在对聊天客户端,内存将由消息聊天记忆顾问.对话历史将根据指定的对话ID从内存中检索:
String conversationId = "007";
chatClient.prompt()
.user("Do I have license to code?")
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, conversationId))
.call()
.content();
提示聊天记忆顾问
自定义模板
这提示聊天记忆顾问使用默认模板来增强系统消息,并获取对话内存。你可以通过提供自己的行为来定制这种行为提示模板对象通过.promptTemplate()建造者方法。
这提示模板此处提供了顾问如何将检索的内存与系统消息合并的方式进行自定义。这与配置模板渲染器在聊天客户端本身(使用.templateRenderer()),这会影响在顾问运行前对初始用户/系统提示内容的渲染。有关客户端模板渲染的更多细节,请参见ChatClient提示模板。 |
习俗提示模板可以使用任何模板渲染器实现(默认情况下,它使用StPrompt模板基于StringTemplate引擎)。重要要求是模板必须包含以下两个占位符:
-
一
指示占位符以接收原始系统消息。 -
一个
存储占位符以接收检索到的对话内存。
向量存储聊天记忆顾问
自定义模板
这向量存储聊天记忆顾问使用默认模板来增强系统消息,并获取对话内存。你可以通过提供自己的行为来定制这种行为提示模板对象通过.promptTemplate()建造者方法。
这提示模板此处提供了顾问如何将检索的内存与系统消息合并的方式进行自定义。这与配置模板渲染器在聊天客户端本身(使用.templateRenderer()),这会影响在顾问运行前对初始用户/系统提示内容的渲染。有关客户端模板渲染的更多细节,请参见ChatClient提示模板。 |
习俗提示模板可以使用任何模板渲染器实现(默认情况下,它使用StPrompt模板基于StringTemplate引擎)。重要要求是模板必须包含以下两个占位符:
-
一
指示占位符以接收原始系统消息。 -
一个
long_term_memory占位符以接收检索到的对话内存。
聊天模型中的内存
如果你直接与聊天模型而不是聊天客户端,你可以显式地管理内存:
// 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"