【SAA】SpringAI Alibaba学习笔记(三):ChatModel对话记忆存储和持久化

一、对话记忆是什么?

本质上用户使用AI模型的本质是与AI模型进行对话,而“大模型对话记忆”,指的是LLM在与用户进行交互式的对话中,能够追踪、理解并利用先前对话上下文的能力。这种能力可以使得大模型不仅能够响应即时的输入请求,还能基于之前交流内容能够在对话中记住先前的对话内容,并根据这些信息进行后续的响应。这种记忆机制让模型能够在对话中持续跟踪和理解用户的意图和上下文,从而实现更自然和连贯的对话

如果不实现对话记忆持久化,如果电脑一重启,就什么都没有了


二、记忆类型

这里我们只是分成两种类型:内存存储和持久化存储。

  • 内存存储:被对话记忆存储到内存中,通常用于开发和测试简单的内存存储。
  • 持久化存储:跟之前开发一样,把数据存储到数据库中,类似将结构化数据存储到结构化数据库Mysql。而大模型对话记忆可以存储到RedisStack、PostgreSQL、MongoDB等数据库。

三、实现持久化存储

我们这里使用的是RedisStack来进行对话持久化。

1. 导入依赖

 <!--spring-ai-alibaba memory-redis-->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter-memory-redis</artifactId>
        </dependency>
        <!--jedis-->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>

2. 配置application.properties

server.port=8008

# 设置响应的字符编码
server.servlet.encoding.charset=utf-8
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true

spring.application.name=SAA-08Persistent

# ====SpringAIAlibaba Config=============
spring.ai.dashscope.api-key=${aliQwen-api}


# ==========redis config ===============
spring.data.redis.host=localhost
spring.data.redis.port=6379
spring.data.redis.database=0
spring.data.redis.connect-timeout=3
spring.data.redis.timeout=2

3. 配置RedisMemoryConfig类

我们需要在RedisMemoryConfig类中把RedisMemoryRepository给配置好。

@Configuration
public class RedisMemoryConfig
{
    @Value("${spring.data.redis.host}")  //从application.properties中读取信息
    private String host;
    @Value("${spring.data.redis.port}")
    private int port;

    @Bean
    public RedisChatMemoryRepository redisChatMemoryRepository()
    {
        return RedisChatMemoryRepository.builder()
                    .host(host)  //设置主机名
                    .port(port)  //设置端口
                .build();
    }
}

4. 配置大语言模型配置类

MessageWindowChatMemory:消息窗口聊天记忆。它维护一个消息窗口,可以指定最大存储对话记忆的大小,当消息超过最大值,就会删除比较旧的信息,同时保留系统信息。默认的存储的大小为20条信息。但是这种方式使用的是内存存储,也就是说只要关机后,信息就都没了。

因此,我们可以实现自己的ChatMemoryRepository

@Bean(name = "deepseekChatClient")
    public ChatClient deepSeekChatCilent(@Qualifier(value = "deepseek") ChatModel deepseek, RedisChatMemoryRepository redisChatMemoryRepository) {

        MessageWindowChatMemory windowChatMemory = MessageWindowChatMemory.builder()
                .chatMemoryRepository(redisChatMemoryRepository)
                .maxMessages(10)
                .build();
        return ChatClient.builder(deepseek)
                .defaultOptions(ChatOptions.builder()
                        .model(DEEPSEEK_MODEL)
                        .build())
                .defaultAdvisors(MessageChatMemoryAdvisor.builder(windowChatMemory).build())
                .build();
    }

Advisors(顾问)

这是ChatClient的一个关键特性,采用拦截器链的设计模式,允许通过注入检索数据和

ChatMemory(对话历史)来修改传入的Prompt。

MessageChatMemoryAdvisor使用提供的实现来管理对话内存。在每次交互中,它都会从内存中检索对话历史记录,并将其作为信息集合包含在提示中。


5. Controller实现

@RestController
public class ChatMemory4RedisController
{
    @Resource(name = "qwenChatClient")
    private ChatClient qwenChatClient;

    @GetMapping("/chatmemory/chat")
    public String chat(String msg, String userId)
    {
        return qwenChatClient.prompt(msg).advisors(new Consumer<ChatClient.AdvisorSpec>()
        {
            @Override
            public void accept(ChatClient.AdvisorSpec advisorSpec)
            {
                advisorSpec.param(CONVERSATION_ID, userId);  //根据对话ID从内存中检索对话历史记录。
            }
        }).call().content();
}

可以做一下优化,使用Lambda表达式进行实现:

@GetMapping("/chatmemory/chat")
    public String chat(String msg, String userId) {
        return deepseekChatClient.prompt(msg)
                .advisors(advisorSpec -> advisorSpec.param(CONVERSATION_ID,userId))
                .call().content();
    }

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值