> 自媒体 > (AI)人工智能 > Spring AI[05]:聊天记忆(Chat Memory)—让 AI 记住上下文
Spring AI[05]:聊天记忆(Chat Memory)—让 AI 记住上下文
来源:kaiwill
2025-11-12 11:39:34
92
管理

CREATE TABLE IF NOT EXISTS SPRING_AI_CHAT_MEMORY ( `conversation_id` VARCHAR(36) NOT NULL, `content` TEXT NOT NULL, `type` ENUM('USER', 'ASSISTANT', 'SYSTEM', 'TOOL') NOT NULL, `timestamp` TIMESTAMP NOT NULL, INDEX `SPRING_AI_CHAT_MEMORY_CONVERSATION_ID_TIMESTAMP_IDX` (`conversation_id`, `timestamp`));

字段

类型

说明

conversation_id

VARCHAR

会话 ID(如用户 ID)

type

ENUM

类型:USER,ASSISTANT,SYSTEM,TOOL

content

TEXT

消息内容

timestamp

TIMESTAMP

创建时间

此时只需要在数据库中执行这个脚本即可。

还有一种方式就是在配置文件中,指定schema在项目启动的时候,让它自动创建。

spring: ai: chat: memory: repository: jdbc: initialize-schema: always # 自动建表 schema: classpath:org/springframework/ai/chat/memory/repository/jdbc/schema-mysql.sql

这里我们采用手动创建的方式。

5.5 Advisor核心机制

有了记忆窗口和记忆存储,还需要将这些存储起来的记忆作为 Prompt消息发送给大模型,所以Spring AI 创建了 Advisor机制。

真正让 AI 在每次调用时自动携带上下文 的关键组件是 **Advisor** —— 它是 Spring AI 中用于增强 Prompt 的核心设计模式。

5.5.1 什么是Advisor? 它解决了什么问题?

通俗理解:AI 对话的“上下文注入器”

你可以把 Advisor 想象成一个“智能助手”,它在你每次向 AI 发送请求前,自动帮你做几件事:

“这个用户之前聊过什么?”“要不要把之前的对话加到这次请求里?”“怎么组织这些信息才最有效?”

Advisor 就是负责这些逻辑的组件。它会在 ChatClient 发送请求前,自动修改 Prompt,加入必要的上下文信息。

5.5.2 BaseChatMemoryAdvisor

BaseChatMemoryAdvisor这个聊天记忆的 Advisor 接口,这个接口其实是 Advisor的子接口,它有两个实现类MessageChatMemoryAdvisor和 PromptChatMemoryAdvisor. 下面的类图中省略了 Advisor接口

MessageChatMemoryAdvisor:以消息形式注入上下文。这是最直观的记忆方式 —— 将历史对话作为 消息列表 注入,LLM 会看到完整的对话历史,自然能记住上下文。

[用户输入] → [Advisor 查找历史消息] → [构造完整消息链] → [发送给 LLM]例如:[ {"role": "user", "content": "我叫小明"}, {"role": "assistant", "content": "你好,小明!"}, {"role": "user", "content": "我昨天去了北京"}]PromptChatMemoryAdvisor:以系统提示词形式注入。这种方式不把历史作为“消息”,而是将其拼接到 系统提示词(System Prompt) 中。

系统提示:你是我的助手。以下是我们的对话历史:"用户:我叫小明""AI:你好,小明!"---当前问题:我昨天去了北京5.6 实战:构建一个支持多种记忆策略的聊天系统

本小节将构建一个多种记忆的聊天系统。本次将使用MySQL 数据库来存储历史聊天记录,所以需要按照 5.4 小节的描述,引入依赖和配置,以及创建数据库表.

5.6.1 记忆存储仓库。

本次使用的是spring-ai-starter-model-chat-memory-repository-jdbc,前面提到,org.springframework.ai.model.chat.memory.repository.jdbc.autoconfigure.JdbcChatMemoryRepositoryAutoConfiguration自动配置中已经配置了bean:

public class JdbcChatMemoryRepositoryAutoConfiguration { ... @Bean @ConditionalOnMissingBean JdbcChatMemoryRepository jdbcChatMemoryRepository(JdbcTemplate jdbcTemplate, DataSource dataSource) { JdbcChatMemoryRepositoryDialect dialect = JdbcChatMemoryRepositoryDialect.from(dataSource); return JdbcChatMemoryRepository.builder().jdbcTemplate(jdbcTemplate).dialect(dialect).build(); } ...}5.6.2 记忆

ChatMemory自动配置类 org.springframework.ai.model.chat.memory.autoconfigure.ChatMemoryAutoConfiguration配置了 ChatMemory 这个Bean,我们可以自己写一个配置,让ChatMemory这个Bean使用 JdbcChatMemoryRepository

// chapter05/src/main/java/com/kaifamiao/chapter05/configuration/ChatMemoryConfiguration.javapublic class ChatMemoryConfiguration { // 让ChatMemory 使用 JdbcChatMemoryRepository @Bean ChatMemory chatMemory(JdbcChatMemoryRepository chatMemoryRepository) { return MessageWindowChatMemory.builder().chatMemoryRepository(chatMemoryRepository).build(); }}5.6.3 记忆advisor

创建一个Controller,在Controller中创建 advisor, 并配置到 chatClient中:

// chapter05/src/main/java/com/kaifamiao/chapter05/MemoryController.java@RestControllerpublic class MemoryController { private final ChatClient chatClient; @Autowired public MemoryController(ChatClient.Builder chatClientBuilder , ChatMemory chatMemory) { // 通过不同角色Message方式传递聊天记忆 Advisor chatMemoryAdvisor = MessageChatMemoryAdvisor.builder(chatMemory).build(); // 通过提示词的方式传递聊天记忆 //Advisor promptChatMemoryAdvisor = MessageChatMemoryAdvisor.builder(chatMemory).build(); this.chatClient = chatClientBuilder // 通过Advisors设置聊天记忆 .defaultAdvisors(chatMemoryAdvisor) .build(); } /** * @param question 问题 * @param conversationId 聊天记忆的id */ // http://localhost:8080/chat/memory?question=我是小明,为我推荐10部周星驰的电影&conversationId=1001 @GetMapping(value = "/chat/memory", produces = "text/html;charset=UTF-8") public Flux memory(@RequestParam(value = "question", required = true) String question , @RequestParam(value = "conversationId", required = true) Integer conversationId) { return this.chatClient.prompt() .user(question) // conversationId 很重要,多次提问时,请确保conversationId一致。这与 WEB应用中的session概念一致。 .advisors(a -> a.param(ChatMemory.CONVERSATION_ID, conversationId)) .stream() .content(); }}5.6.4 启动测试验证

开始测试之前,先检查数据库SPRING_AI_CHAT_MEMORY表中的数据,此时是空的。启动服务:

第一次请求

GET http://localhost:8080/chat/memory?question=我是小明,为我推荐10部周星驰的电影&conversationId=1001AI 输出:你好,小明!周星驰是华语影坛最具影响力的喜剧演员和导演之一,他的电影融合无厘头幽默、深刻情感与社会讽刺,深受观众喜爱。.....祝你观影愉快,笑口常开,小明!

现在查看数据库,数据库中已经存储了发送给AI的问题和AI回答的内容:

源代码地址:https://github.com/kaiwill/kaifamiao

0
点赞
赏礼
赏钱
0
收藏
免责声明:本文仅代表作者个人观点,与本站无关。其原创性以及文中陈述文字和内容未经本网证实,对本文以及其中全部或者 部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。 凡本网注明 “来源:XXX(非本站)”的作品,均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对 其真实性负责。 如因作品内容、版权和其它问题需要同本网联系的,请在一周内进行,以便我们及时处理。 QQ:617470285 邮箱:617470285@qq.com
相关文章
《飞驰人生》片尾为何谢王思聪?不止借车库,千万跑车全是真家伙..
提起《飞驰人生》,不少人都记得片尾字幕里王思聪的名字,却鲜少有人知道..
中国古代的顶级“超跑”,如今全球仅剩六千匹!汗血宝马是啥样?..
在历史的长河中,骏马总是与英雄、战争和传奇紧密相连,而对于我们中国人..
法拉利296 Challenge Stradale路试曝光:赛道版公路跑车即将到来..
【网通社快报】法拉利被拍到正在测试一款重度伪装的原型车,外观酷似赛道..
10款你应该现在就入手的跑车,趁它们还没成为经典款!..
整备质量马力扭矩布局2195磅138马力126磅英尺中置引擎,后轮驱动MR-S 是..
消息称保时捷下月推911 GT3 Cabriolet敞篷跑车:折叠软顶..
IT之家 2 月 24 日消息,汽车媒体 thesupercarblog 于 2 月 22 日发布博..
新能源汽车出海2.0:从“卖车”到“建生态”
文 | 惊蛰研究所,作者|芒种2007年,华语女子团体S.H.E的一首《中国话》..
汽车能“乘火车”返乡了!订单火爆→
今年春运,“12306托运汽车订单火爆”的话题冲上热搜。汽车“坐”着火车..
湖北造飞行汽车来了!单价或50万元以内,市民可以像开汽车一样开“飞车”..
极目新闻记者 黄忠 陈倩 杨绍杭 王俐燃 刘中灿像车,又像飞机,能垂直起..
紧急召回!近30万辆汽车,吉林车主快自查!
国家市场监督管理总局网站2月9日发布上海蔚来汽车有限公司的汽车召回信息..
关于作者
搞印刷的黄先..(普通会员)
文章
1937
关注
0
粉丝
1
点击领取今天的签到奖励!
签到排行

成员 网址收录40418 企业收录2986 印章生成263660 电子证书1157 电子名片68 自媒体103523

0
0
分享
请选择要切换的马甲:

个人中心

每日签到

我的消息

内容搜索