Spring AI 聊天记忆功能实战(一):从接口设计到生产实践

Spring AI 聊天记忆功能实战(一):从接口设计到生产实践

在构建AI对话应用时,聊天记忆管理及存储是实现连贯上下文交互的关键组件。而大模型(LLM)本质上是无状态的,这意味着它们不会保留历史交互信息。当需要跨多轮交互保持上下文时,这一特性会带来局限。为此,Spring AI 提供了聊天记忆功能,支持在 LLM 交互过程中存储和检索上下文数据。

入门理解

Spring AI 框架通过模块化设计提供了灵活的聊天记忆解决方案,其核心在于ChatMemoryRepositoryChatMemory的协同工作机制。

ChatMemoryRepository 接口提供了各种存储方式实现的统一抽象,增加了聊天记忆功能的灵活性及扩展性,目前 Spring AI(1.0.0 版本)框架提供了基于 内存(默认)、JDBC、Cassandra、Neo4j 四种存储方式的实现。

java 复制代码
public interface ChatMemoryRepository {
    // 获取所有会话ID
	List<String> findConversationIds();
    // 获取指定会话ID的聊天消息
	List<Message> findByConversationId(String conversationId);
	// 存储整个会话ID的历史消息(替换式更新)
	void saveAll(String conversationId, List<Message> messages);
    // 清理指定会话ID中的聊天消息
	void deleteByConversationId(String conversationId);
}

ChatMemory 抽象层支持实现多种记忆类型以满足不同场景需求。消息的底层存储由 ChatMemoryRepository 处理,其唯一职责是存储和检索消息。ChatMemory 实现类可自主决定消息保留策略 ------ 例如保留最近 N 条消息、按时间周期保留或基于 Token 总量限制保留。

java 复制代码
public interface ChatMemory {
	// 从聊天记忆的上下文检索会话ID
	String CONVERSATION_ID = "chat_memory_conversation_id";
	// 将聊天消息保存到指定会话ID的存储中
	void add(String conversationId, List<Message> messages);
	// 获取指定会话ID中的聊天消息
	List<Message> get(String conversationId);
	// 清理指定会话ID中的聊天消息
	void clear(String conversationId);
}

快速使用

Spring AI 自动配置 ChatMemory Bean 供直接使用。默认采用内存存储(InMemoryChatMemoryRepository)及 MessageWindowChatMemory 实现管理会话历史。若已配置其他 Repository(如 Cassandra / JDBC / Neo4j ),则自动切换至对应实现。

记忆类型:MessageWindowChatMemory 维护固定容量的消息窗口(默认 20 条)。当消息超限时,自动移除较早的对话消息(始终保留系统消息)。

java 复制代码
// 自动注入
@Autowired
ChatMemory chatMemory;

// 手动创建
MessageWindowChatMemory memory = MessageWindowChatMemory.builder()
    .maxMessages(10)
    .build();

记忆存储:InMemoryChatMemoryRepository 内存存储为默认的聊天记忆存储实现。同样地,Spring AI 提供了统一的自动配置,可直接自动注入使用。

java 复制代码
// 自动注入
@Autowired
ChatMemoryRepository chatMemoryRepository;

// 手动创建
ChatMemoryRepository repository = new InMemoryChatMemoryRepository();

自动配置在默认情况下,Spring AI 注入了如下 Bean 对象:

java 复制代码
@Bean
ChatMemoryRepository chatMemoryRepository() {
    return new InMemoryChatMemoryRepository();
}

@Bean
ChatMemory chatMemory(ChatMemoryRepository chatMemoryRepository) {
    return MessageWindowChatMemory.builder().chatMemoryRepository(chatMemoryRepository).build();
}

原理实现

聊天记忆存储的实现主要依靠 ChatMemoryRepository 接口 及 ChatMemory 接口,它们的默认实现类分别为 InMemoryChatMemoryRepositoryMessageWindowChatMemory

InMemoryChatMemoryRepository实现类:

java 复制代码
public final class InMemoryChatMemoryRepository implements ChatMemoryRepository {
    Map<String, List<Message>> chatMemoryStore = new ConcurrentHashMap<>();
    // 方法实现...
}

InMemoryChatMemoryRepository 使用并发安全的 ConcurrentHashMap 实现聊天记录的增删改操作,存储实现依赖 Map 的 get、put、remove 操作。需要注意的是,这里 saveAll(写入记录)方法实现是替换旧数据的更新逻辑,若对应到外部存储的写入方式应该先删除后插入数据,而限制聊天对话历史长度的逻辑在 MessageWindowChatMemory 类实现。

MessageWindowChatMemory 实现类:

java 复制代码
public final class MessageWindowChatMemory implements ChatMemory {
    private final ChatMemoryRepository chatMemoryRepository;
    private final int maxMessages;
    // 方法实现...

    private List<Message> process(List<Message> memoryMessages, List<Message> newMessages) {
        // 根据最大消息数处理消息窗口
    }
}

处理消息窗口容量的主要逻辑为:

  • 识别新增的SystemMessage,当有新系统消息时,清除所有旧系统消息、所有的新SystemMessage不受容量限制;
  • 保留非系统消息历史+新增消息,按添加顺序移除最早的非系统消息,确保 最终消息数 == maxMessages、返回处理后的新消息;

消息窗口的聊天记忆管理与数据存储交互的 UML 类图 如下:

classDiagram class ChatMemory { <> +add(String, List~Message~) +get(String) List~Message~ +clear(String) } class MessageWindowChatMemory { -chatMemoryRepository: ChatMemoryRepository -maxMessages: int -process(List~Message~ memoryMessages, List~Message~ newMessages) List~Message~ } class ChatMemoryRepository { <> +findConversationIds() List~Message~ +findByConversationId(String) List~Message~ +saveAll(String, List~Message~) +deleteByConversationId(String) } ChatMemory <|.. MessageWindowChatMemory MessageWindowChatMemory --> ChatMemoryRepository

实战案例

接下来我们使用MessageWindowChatMemory+JdbcChatMemoryRepository的方式实现一个AI聊天助手的功能。

JdbcChatMemoryRepository 是内置的 JDBC 实现,支持多种关系型数据库,适用于需要持久化存储聊天记忆的场景。JDBC 实现是基于 spring-jdbc 模块,我们可通过 JdbcTemplate 来配置任一数据源。

1、导入模块

首先,在 spring-boot 项目中添加以下依赖:

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-chat-memory-repository-jdbc</artifactId>
</dependency>

<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <scope>runtime</scope>
</dependency>

2、配置参数

新建 application.yml,添加配置 spring.aiJdbcTemplate 相关参数:

yaml 复制代码
spring:
  application:
    name: AI Assistant
  ai:
    openai:
      api-key: ${OPENAI_API_KEY:NONE}
      base-url: ${OPENAI_BASE_URL:NONE}
      chat:
        options:
          model: DeepSeek-V3
        completions-path: /v1/chat/completions
    chat:
      memory:
        repository:
          jdbc:
            initialize-schema: always # Always initialize
  datasource:
    url: jdbc:postgresql://localhost:5432/test
    username: root
    password: 123456
    driver-class-name: org.postgresql.Driver

3、创建 Bean 实例

Spring AI 为 JdbcChatMemoryRepository 提供了自动配置,可直接在应用中使用 (默认使用 hsqldb 嵌入式数据库),也可手动创建 Bean 实例。

java 复制代码
@Configuration
public class GeneralChatClientConfig {

    private final JdbcChatMemoryRepository jdbcChatMemoryRepository;

    public GeneralChatClientConfig(JdbcChatMemoryRepository jdbcChatMemoryRepository) {
        this.jdbcChatMemoryRepository = jdbcChatMemoryRepository;
    }

    @Bean(name = "messageWindowChatMemoryWithJdbc")
    public MessageWindowChatMemory messageWindowChatMemoryWithJdbc() {
        int maxMessages = 20;
        return MessageWindowChatMemory.builder()
                .chatMemoryRepository(jdbcChatMemoryRepository) // default: new InMemoryChatMemoryRepository()
                .maxMessages(maxMessages)
                .build();
    }
}

目前 Spring AI 支持的数据库与方言抽象层:

  • PostgreSQL
  • MySQL / MariaDB
  • SQL Server
  • HSQLDB

使用 JdbcChatMemoryRepositoryDialect.from(DataSource) 时可基于 JDBC URL 自动识别正确方言。通过实现 JdbcChatMemoryRepositoryDialect 接口可扩展其他数据库方言支持。

4、聊天记忆客户端

创建使用 ChatClient API 时,可通过注入 ChatMemory 实现来维护跨多轮交互的会话上下文。

Spring AI 提供多种内置 Advisor,用于按需配置 ChatClient 的记忆行为。

  • MessageChatMemoryAdvisor:通过指定 ChatMemory 实现管理会话记忆。每次交互时从记忆库检索历史消息,并将其作为消息集合注入提示词。
  • PromptChatMemoryAdvisor:基于指定 ChatMemory 实现管理会话记忆。每次交互时从记忆库检索历史对话,并以纯文本形式追加至系统(system)提示词。
  • VectorStoreChatMemoryAdvisor:通过指定 VectorStore 实现管理会话记忆。每次交互时从向量存储检索历史对话,并以纯文本形式追加至系统(system)消息。

例如,若需结合 MessageWindowChatMemoryPromptChatMemoryAdvisor,可按如下方式配置:

java 复制代码
    @Bean(name = "deepseekV3ClientWithJdbc")
    public ChatClient deepseekV3ClientWithJdbc(
            @Value("${spring.ai.openai.base-url}") String baseUrl,
            @Value("${spring.ai.openai.chat.options.model}") String modelName,
            @Value("${spring.ai.openai.api-key}") String apiKey,
            @Qualifier("messageWindowChatMemoryWithJdbc") MessageWindowChatMemory messageWindowChatMemoryWithJdbc) {

        OpenAiApi build = OpenAiApi.builder().apiKey(apiKey).baseUrl(baseUrl).build();

        OpenAiChatModel openAiChatModel =
                OpenAiChatModel.builder()
                        .openAiApi(build)
                        .defaultOptions(OpenAiChatOptions.builder().model(modelName).build())
                        .build();

        return ChatClient.builder(openAiChatModel)
                .defaultAdvisors(PromptChatMemoryAdvisor.builder(messageWindowChatMemoryWithJdbc).build())
                .defaultAdvisors(new SimpleLoggerAdvisor())
                .build();
    }

调用 ChatClient 时,ChatMemoryAdvisor 将自动管理记忆存储。系统会根据指定的会话 ID 从记忆库检索历史对话。

我们新建一个 Controller ,注入配置好的 ChatClient,定义一个api实现大模型的 chat 调用,代码如下:

java 复制代码
@RestController
@RequestMapping("/ai/v3/chat/")
@Slf4j
public class GeneralChatController {

    private final ChatClient jdbcChatClient;

    public GeneralChatController(@Qualifier("deepseekV3ClientWithJdbc") ChatClient jdbcChatClient) {
        this.jdbcChatClient = jdbcChatClient;
    }

    @PostMapping(value = "/t1", produces = {MediaType.TEXT_EVENT_STREAM_VALUE})
    @ResponseBody
    public Object chatWithJdbc(@RequestBody String body) {
        JSONObject entries = JSONUtil.parseObj(body);
        String text = entries.getStr("text");
        Boolean stream = entries.getBool("stream", false);
        String conversationId = entries.getStr("conversationId");

        log.info("开始对话聊天,会话ID:{}", conversationId);
        var request = jdbcChatClient
                        .prompt()
                        .system("你是乐观小王,回答问题简练精要。")
                        .advisors(advisor -> advisor.param(CONVERSATION_ID, conversationId))
                        .user(text);

        try {
            log.info("开始生成回答,是否流式输出:{}", stream);
            return stream ? request.stream().content() : request.call().content();
        } catch (Exception e) {
            log.error("对话聊天发生异常,会话ID:{}", conversationId, e);
            throw e;
        }
    }
}

5、测试AI聊天功能

通过上述的简单配置和代码编写,我们已经实现了一个通用的带有记忆功能的AI聊天助手。

接下来让我们测试一下这个聊天助手的使用效果,设置几条 USER 的提问内容,具体内容如下:

http 复制代码
# Openai Chat API
### 我的名字叫小明,你叫什么名字?
### 我是谁?
### 我们之间的第一句问话是什么?
POST http://localhost:10001/ai/v3/chat/t1
Content-Type: application/json

{
"text": "我的名字叫小明,你叫什么名字?",
"stream": false,
"conversationId": "bnA9f525-l7ae-5c66-ae21-vh53547c96cf"
}

聊天消息记录会被存储到 PostgreSQL 数据库中,http顺序请求后的大模型返回结果 如图所示:

小总结

通过上述测试结果可以清晰看到,基于 Spring AI 搭建的聊天助手凭借聊天记忆存储功能,能够准确关联上下文信息,针对连续提问给出符合对话逻辑的回答。无论是识别用户身份,还是追溯对话起始内容,系统都能有效利用历史消息,实现连贯且智能的交互体验,充分利用聊天记忆存储机制可以更好的维护对话上下文及提高模型回答的准确性。

目前 Spring AI (1.0.0 版本) 官方还没有提供 Redis 的聊天记忆外部存储实现,那么,下一篇文章我们将聚焦于 自定义 Redis 聊天记忆的外部存储实现,通过 自定义一个外部存储方式,自己实现一个聊天记忆存储功能,来进一步提升聊天助手的扩展性与数据持久性,让AI聊天助手在高并发、大规模对话场景中稳定运行。敬请期待接下来的深度技术解析!

文章案例项目代码:spring-ai-model-chat-memory-repository-redis

相关推荐
麓殇⊙5 分钟前
操作系统期末复习--操作系统初识以及进程与线程
java·大数据·数据库
大师兄带你刨AI37 分钟前
「AI大数据」| 《华为:面向智能制造的工业大模型标准化研究报告》
大数据·人工智能
Elastic 中国社区官方博客1 小时前
使用 Elasticsearch 提升 Copilot 能力
大数据·数据库·elasticsearch·搜索引擎·全文检索·copilot·mcp
F36_9_1 小时前
如何高效实现公司文件管理
大数据·数据库·人工智能
武子康3 小时前
大数据-16-Hive HiveServer2 HS2 允许客户端远程执行HiveHQL HCatalog
大数据·后端·apache hive
白总Server4 小时前
Web 架构之 GraphQL 与 REST API 对比与选型
java·大数据·前端·javascript·后端·架构·graphql
IT技术范4 小时前
2025商旅平台排行:国内主流商旅平台解析
大数据·人工智能
天氰色等烟雨4 小时前
Spring AI 聊天记忆功能实战(二):自定义 Redis 聊天记忆外部存储实现
大数据
安心联-车辆监控管理系统4 小时前
渣土车辆定位与监管:科技赋能城市建筑垃圾管理
大数据·人工智能·科技