提示:如果不能访问 OpenAI,请点击 AiCode API 注册账号,通过代理访问。

PromptChatMemoryAdvisor 类用于管理对话历史(Chat Memory)的组件,它结合了 对话记忆(Chat Memory) 和 提示词工程(Prompt Engineering),帮助在多轮对话中维护上下文,并动态优化提示词(Prompt)。
其主要核心功能如下:
对话历史管理:自动保存用户与AI的交互消息,确保后续请求能携带上下文。支持限制记忆的容量,如只保留最近的N条消息。实际是通过内部的 ChatMemory 对象,以及 ChatMemory 对象内部的 ChatMemoryRepository 去完成保存操作。
动态提示词增强:在发送请求给 AI 模型前,自动将历史对话注入到当前提示词中(系统提示词),形成完整的上下文感知 Prompt。内部维护了一个默认的系统提示词模板,如下:
private static final PromptTemplate DEFAULT_SYSTEM_PROMPT_TEMPLATE = new PromptTemplate("""
{instructions}
Use the conversation memory from the MEMORY section to provide accurate answers.
---------------------
MEMORY:
{memory}
---------------------
""");与 ChatClient 集成:作为 ChatClient 的增强层,透明地处理上下文传递,无需手动拼接历史消息。使用时,简单配置到 defaultAdvisors() 方法中就可以了。
和其他 Advisor 一样,PromptChatMemoryAdvisor 没有提供公开的构造方法,它的构造方法是私有的,源码:
private PromptChatMemoryAdvisor(ChatMemory chatMemory, String defaultConversationId, int order, Scheduler scheduler,
PromptTemplate systemPromptTemplate) {
Assert.notNull(chatMemory, "chatMemory cannot be null");
Assert.hasText(defaultConversationId, "defaultConversationId cannot be null or empty");
Assert.notNull(scheduler, "scheduler cannot be null");
Assert.notNull(systemPromptTemplate, "systemPromptTemplate cannot be null");
this.chatMemory = chatMemory;
this.defaultConversationId = defaultConversationId;
this.order = order;
this.scheduler = scheduler;
this.systemPromptTemplate = systemPromptTemplate;
}如果要构建 PromptChatMemoryAdvisor 的实例,可以通过静态方法 builder(ChatMemory chatMemory),源码如下:
public static Builder builder(ChatMemory chatMemory) {
return new Builder(chatMemory);
}该方法返回的是 PromptChatMemoryAdvisor.Builder 类型的对象,是静态内部类。
PromptChatMemoryAdvisor.Builder 是 Spring AI 中用于构建 PromptChatMemoryAdvisor 的流式构建器,专门设计用于优化提示工程中的上下文管理。包含了多个配置成员:
public static final class Builder {
// 系统提示词模板
private PromptTemplate systemPromptTemplate = DEFAULT_SYSTEM_PROMPT_TEMPLATE;
// 会话ID
private String conversationId = ChatMemory.DEFAULT_CONVERSATION_ID;
// Advisor 序号
private int order = Advisor.DEFAULT_CHAT_MEMORY_PRECEDENCE_ORDER;
// 调度策略
private Scheduler scheduler = BaseAdvisor.DEFAULT_SCHEDULER;
// 保存会话记录实现
private ChatMemory chatMemory;
//...
}其中属性详细说明:
systemPromptTemplate 基础系统提示模板,定义系统级别的初始提示模板,控制如何将记忆注入到系统提示中。注意,还可包含变量,如 {conversation_id}。默认系统模板如下图:

conversationId 唯一会话 ID,必须保证唯一性才能正确隔离不同对话。注意,在生产环境建议使用组合ID,如 userId_sessionId。如果未设置该值时,可能导致记忆混淆。多个用户共用一个会话上下文,这不就乱套了吗。默认值为“default”。
order 控制当前 Advisor 执行顺序,数值越小优先级越高,越优先执行。
scheduler 控制异步处理线程,常用取值:
Schedulers.immediate() 同步执行(默认)
Schedulers.boundedElastic() 弹性线程池,推荐 IO 操作
Schedulers.parallel() 固定线程池,CPU 密集型
chatMemory 对话记忆存储实现,。常用实现如下图:

其中:
InMemoryChatMemoryRepository 基于内存的对话记忆存储实现,适用于开发测试环境或轻量级生产场景,提供零延迟的对话记忆访问。
JdbcChatMemoryRepository 基于 关系型数据库 的对话记忆存储实现,通过 JDBC 提供标准化的 SQL 数据库访问,支持主流关系型数据库如 MySQL、PostgreSQL、Oracle 等。
Neo4jChatMemoryRepository 为 Neo4j 图数据库设计的对话记忆存储实现,它利用图数据库的天然优势来高效存储和检索复杂的对话关系。
CassandraChatMemoryRepository 基于 Apache Cassandra 数据库的对话记忆存储实现,专为大规模、高并发的对话系统设计,利用 Cassandra 的分布式特性实现高性能的记忆存储与检索。
下面示例将通过 SimpleLoggerAdvisor 来观察 PromptChatMemoryAdvisor 对 AI 会话增强的请求信息,是否自动帮助我们将历史信息添加到会话中。
由于我们还是通过 MySQL 数据库来保存历史会话信息,配置可以参考“MessageChatMemoryAdvisor 对话历史管理”。
依赖项也参考“MessageChatMemoryAdvisor 对话历史管理”。
配置文件请参考“MessageChatMemoryAdvisor 对话历史管理”。
创建名为 AiConfig 的配置类,添加 PromptChatMemoryAdvisor 相关配置,以及自定义一个系统提示词模板,如下:
package com.hxstrive.springai.springai_openai.advisor_PromptChatMemoryAdvisor.config;
import org.springframework.ai.chat.client.advisor.PromptChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.ChatMemoryRepository;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.chat.memory.repository.jdbc.JdbcChatMemoryRepository;
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
/**
* AI配置
* @author Administrator
*/
@Configuration
public class AiConfig {
// 实际存储历史会话,这里通过数据库存储
@Bean
public ChatMemoryRepository chatMemoryRepository(DataSource dataSource) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
return JdbcChatMemoryRepository.builder().jdbcTemplate(jdbcTemplate).build();
}
// 回话记忆
@Bean
public ChatMemory chatMemory(ChatMemoryRepository chatMemoryRepository) {
return MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository) // 会话存储实现
.maxMessages(10) // 消息大小,10条,包含请求和响应,即仅仅保存5个对话数据
.build();
}
@Bean
public PromptChatMemoryAdvisor promptChatMemoryAdvisor(ChatMemory chatMemory) {
// 自定义系统提示模板
PromptTemplate promptTemplate = new PromptTemplate("""
{instructions}
请使用 “MEMORY” 部分中的对话记忆来提供准确答案。
---------------------
MEMORY:
{memory}
---------------------
""");
return PromptChatMemoryAdvisor.builder(chatMemory).systemPromptTemplate(promptTemplate).build();
}
// 添加日志 Advisor,要显示需要设置日志级别为 DEBUG
@Bean
public SimpleLoggerAdvisor simpleLoggerAdvisor() {
return new SimpleLoggerAdvisor();
}
}📢注意,上述配置的系统提示词模板中的 {instructions} 和 {memory} 占位符,Spring AI 会自动帮我们替换。我们还可以添加自定义的占位符,但需要使用 PromptTemplate 的 add(String name, Object value) 添加占位符具体的值。
创建名为 AIController 的 Controller,使用 @Autowired 将配置的 Advisor 注入进去,然后通过 ChatClient 的 defaultSystem() 方法进行配置,如下:
package com.hxstrive.springai.springai_openai.advisor_PromptChatMemoryAdvisor.controller;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.PromptChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AIController {
@Autowired
private ChatModel chatModel;
@Autowired
private PromptChatMemoryAdvisor promptChatMemoryAdvisor;
@Autowired
private SimpleLoggerAdvisor simpleLoggerAdvisor;
@GetMapping("/ai/simple")
public String completion(@RequestParam("userText") String userText) {
// 构建 RAG advisor 时需要完成 vectorStore 初始化
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultSystem("请使用中文进行回复")
.defaultAdvisors(
simpleLoggerAdvisor,
promptChatMemoryAdvisor
)
.build();
// conversationId 区分不同对话,定位对应的历史记录
String conversationId = "sessionId-20250705220950";
return chatClient.prompt()
// 运行时设置会话ID参数
.advisors(advisor -> {
advisor.param(ChatMemory.CONVERSATION_ID, conversationId);
})
.user(userText)
.call()
.content();
}
}启动应用程序,通过浏览器访问,问“成都大学是 211 吗?”,由于首次访问,你会发现打印的日志中“MEMORY”部分内容为空,如下图:


再次,问“是 985?”,此时日志中的“MEMORY”部分出现了上次对话的问题和答案。如下图:


而且,你发现了吗?“是 985?”我们没有说什么是 985,AI 根据上下文推断出你问的是“成都大学”是 985?。
提示:如果不能访问 OpenAI,请点击 AiCode API 注册账号,通过代理访问。