SpringAI学习笔记(三)会话记忆功能

文章目录

SpringAI学习笔记(三)会话记忆功能

三、会话记忆功能

大模型本身是不具备记忆能力的,要想让大模型记住之前聊天的内容,唯一的办法就是把之前聊天的内容与最新的提问一起发给大模型。这里我们就要用到发给大模型的第三个参数 assistant 了。

实现会话记忆功能需要三个必要元素:

1、定义会话存储方式: 将历史会话存储到某个地方,可以是数据库,内存等等。

2、配置会话记忆Advisor: 让Spring帮我们做大模型的会话记忆环绕增强。

3、添加会话id: 每个会话记忆的唯一id,可以是用户的id加用户打开的每个会话框的id。

下面,我们使用 SpringAI 框架自带的 MessageWindowChatMemory 做基本的演示,搭配 SpringAI 框架自带的内存会话管理仓库 InMemoryChatMemoryRepository 类。如果想用Redis、MongoDB、MySQL 等方式进行会话记忆存储跟获取的话,也可以手动实现 ChatMemory 接口 或者 ChatMemoryRepository 接口 来完成。

ChatMemory 接口定义如下

java 复制代码
public interface ChatMemory {
    String DEFAULT_CONVERSATION_ID = "default";
    String CONVERSATION_ID = "chat_memory_conversation_id";

    default void add(String conversationId, Message message) {
        Assert.hasText(conversationId, "conversationId cannot be null or empty");
        Assert.notNull(message, "message cannot be null");
        this.add(conversationId, List.of(message));
    }

    void add(String conversationId, List<Message> messages);

    List<Message> get(String conversationId);

    void clear(String conversationId);
}

从上面接口可以看到,三个接口其实也都是通过会话id的形式来管理会话记忆的。

ChatMemoryRepository 接口定义如下

java 复制代码
public interface ChatMemoryRepository {
    List<String> findConversationIds();

    List<Message> findByConversationId(String conversationId);

    void saveAll(String conversationId, List<Message> messages);

    void deleteByConversationId(String conversationId);
}

步骤一、定义会话存储方式

这里我们以SpringAI 框架自带的 MessageWindowChatMemory 搭配 InMemoryChatMemoryRepository 为例,在配置的Java文件中定义我们的 ChatMemory。

java 复制代码
    /**
     *  注入我们会话记忆管理仓库(使用内存做会话记忆)
     */
    @Bean
    public ChatMemoryRepository chatMemoryRepository(){
        return new InMemoryChatMemoryRepository();
    }
    
    /**
     * 
     * @param chatMemoryRepository  会话记忆仓库,上面我们已经注册了,使用内存做会话记忆
     * @return
     */
    @Bean
    public ChatMemory chatMemory(ChatMemoryRepository chatMemoryRepository) {
        return MessageWindowChatMemory.builder()
                .chatMemoryRepository(chatMemoryRepository)
                .maxMessages(30)    //自定义消息窗口大小
                .build() ;
    }

步骤二、配置会话记忆Advisor

java 复制代码
    //将我们本地模型通过配置直接交给Spring容器做管理,方便使用
    @Bean
    public ChatClient chatClient2Qwen(OpenAiChatModel chatModel, ChatMemory chatMemory){
        return ChatClient.builder(chatModel)
                .defaultSystem("你是一个傻白甜属性的AI助手,你的名字叫小七,请以小七的口吻来回答用户的问题")     //系统设定
                .defaultAdvisors(
                        new SimpleLoggerAdvisor(),                              //配置日志Advisor
                        MessageChatMemoryAdvisor.builder(chatMemory).build()    //配置会话记忆Advisor
                        )             
                .build();
    }

步骤三、添加会话id

java 复制代码
@RestController
@RequestMapping("/ai")
public class ChatController {

    @Resource
    private ChatClient chatClient;

    //流式响应
    @RequestMapping("/streamChat")
    public Flux<String> streamChat(String request, String chatId) {
        return chatClient.prompt()
                .user(request)
                .advisors(advisorSpec -> advisorSpec.param(ChatMemory.CONVERSATION_ID, chatId))
                .stream()
                .content();
    }

}

代码演示

假设我们定义会话的id为用户的id+会话窗口的编号,现在用户的id为1001,打开的会话窗口的编号为A,那么我们的chatId为1001A,我们提问:"假如有10个苹果,怎么平均分给5个人",千问给出的答案如下:

之后,我们使用同一个会话id,继续提问:"如果是分给3个人呢"

可以看到,这里千问是可以根据我们给出的上一个问题的信息做回答的。

但是如果我们现在修改chatId,假设还是用户1001,他打开了会话框B,此时,我们提问:"如果是分给4个人呢",千问就摸不着头脑了:

相关推荐
疯狂打码的少年6 小时前
【数据库技术】复习日:关系代数 + SQL + 规范化(整理对比表)
jvm·数据库·笔记·sql
维克兜率天6 小时前
【维克】特征归一化与标准化:为什么模型对数据的“尺度“很敏感?
人工智能·笔记·python·机器学习·量化
摇滚侠7 小时前
《SpringBoot 3:入门与应用实战》第 12 章 JDBC 与事务 使用 JdbcTemplate 阅读笔记 31
android·spring boot·笔记
举个栗子。7 小时前
Marin:开源基础模型研究与开发框架,从数据到模型全链路可复现
人工智能·ai·开源
是隼人7 小时前
buuctf-pwn mrctf2020_easy_equation(64位fmt)题解(学习过程持续更新)
c语言·学习·安全·pwn入门·ctf入门
undsky_7 小时前
【n8n教程】:Email Trigger IMAP节点,实现邮件自动化处理
人工智能·ai·aigc·ai编程
金字塔頂の蝸牛7 小时前
商务日语口语全手册(一)
笔记·日语·语言·外语
云卷云舒___________7 小时前
OpenAI内测GPT-6 Sol,Claude Fable 5.2泄密,GLM-5.3-CYBERSECURITY 攻防安全模型炸场 | 9月7日 AI日报
ai·openai·claude·anthropic·ai日报·gpt6·glm53
从零开始的嵌入式之旅7 小时前
day36
linux·c语言·经验分享·笔记·嵌入式硬件
liulilittle8 小时前
为什么需要回程闲置保护?
ai·llm·prompt·agent·tools·subagent·opencode