【AI】持久化聊天记忆(隔离对话)

引子

当我们需要模型支持上下文对话时,就必须要有对应的聊天记忆来进行支撑,对此,我们可以 将每次用户的提问和AI的回复存储在一个存储介质中,这个存储介质可以是MySQL、Redis等各种存储媒介,而我们这里使用的是MongoDB来进行存储,MongoDB具体安装方式请自行搜索安装(官网链接)

同时安装好可视化界面Compass并完成连接,效果如下:

在这里插入图片描述

完成上述步骤后,接下来就可以通过代码来完成聊天记忆的保存了。

1. 引入MongoDB

我们需要先将mongodb引入到项目中:

1.1 引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

1.2 配置远程连接

# 若库不存在后续在完成连接后也能自动创建
spring.data.mongodb.uri=mongodb://localhost:27017/chat_memory_test_db

2. 代码编写

2.1 创建实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
@Document("chat_messages") // 文档名称,如果mongodb没有这个文档将会自动创建
public class ChatMessages {

    // 唯一标识,映射到 MongoDB 文档的 _id  字段
    @Id
    private ObjectId messageId; 
	
    // 用来区分每个记忆,后续的操作都是通过操控memoryId来进行当前记忆的增删改查的
    private String memoryId;
	
    // 存储当前聊天记录列表的json字符串
    private String content;  
}

:如果想要根据用户来区分对话,可以自行添加上userId属性,并修改持久化类

2.2 创建持久化类

通过这个持久化类,我们能够对聊天记忆进行对应的crud:

@Component
public class MongoChatMemoryStore implements ChatMemoryStore {

   @Autowired
   private MongoTemplate mongoTemplate;

   @Override
   public List<ChatMessage> getMessages(Object memoryId) {
       Criteria criteria = Criteria.where("memoryId").is(memoryId);
       Query query = new Query(criteria);
       ChatMessages chatMessages = mongoTemplate.findOne(query, ChatMessages.class);
       if(chatMessages == null)
           return new LinkedList<>();
       return ChatMessageDeserializer.messagesFromJson(chatMessages.getContent());
   }

   @Override
   public void updateMessages(Object memoryId, List<ChatMessage> messages) {
       Criteria criteria = Criteria.where("memoryId").is(memoryId);
       Query query = new Query(criteria);

       Update update = new Update();
       update.set("content", ChatMessageSerializer.messagesToJson(messages));

       //根据query条件能查询出文档,则修改文档;否则新增文档
       mongoTemplate.upsert(query, update, ChatMessages.class) ;
   }

   @Override
   public void deleteMessages(Object memoryId) {
       Criteria criteria = Criteria.where("memoryId").is(memoryId);
       Query query = new Query(criteria) ;
       mongoTemplate.remove(query, ChatMessages.class);
   }
}

2.3 创建持久化配置

@Configuration
public class SeparateChatAssistantConfig {

    @Autowired
    private MongoChatMemoryStore mongoChatMemoryStore; 

    @Bean // 将这个方法加入IOC容器
   ChatMemoryProvider chatMemoryProvider() {
       return memoryId -> MessageWindowChatMemory.builder()
               .id(memoryId)
               .maxMessages(10) // 限制最大的记忆存储数
               .chatMemoryStore(mongoChatMemoryStore) // 指定持久化类(存储介质)
               .build();
   }
}

2.4 注入配置

使用@AiService注解中的chatMemoryProvider属性将持久化配置引入到对话中,这样我们只需进行对话就能自动完成持久化配置的调用了:

@AiService(
       wiringMode = EXPLICIT ,
       chatModel = "qwenChatModel",
       chatMemoryProvider = "chatMemoryProvider")
public interface SeparateChatAssistant {

   /**
    *  分离聊天记录
    *  @param  memoryId  聊天id
    *  @param  userMessage  用户消息
    *  @return
    */
   String chat(@MemoryId int memoryId, @UserMessage String userMessage);
}

:当AIService由多个组件如大模型、聊天记忆等组成的时候,我们就可以称它为 智能体

2.5 测试代码

@SpringBootTest
public class ChatMemoryTest {

    @Autowired
    private SeparateChatAssistant separateChatAssistant;

    @Test
    public void testChatMemory() {

        //调用service的接口
        String answer1 = separateChatAssistant.chat(1, "我是Gray");
        System.out.println(answer1);

        String answer2 = separateChatAssistant.chat(1, "我是谁");
        System.out.println(answer2);

        String answer3 = separateChatAssistant.chat(2, "我是谁");
        System.out.println(answer3);
    }
}

这里我们通过传入不同的memoryId来区分不同的聊天记忆,这样ai在获取上下文内容的时候就不会冲突调用了,执行结果如下:

在这里插入图片描述

可以看到不同的memoryId会有不同的记忆组区分,同时从mongodb中存储的内容也能直接看出区别:

在这里插入图片描述

在这里插入图片描述

可以看到,memoryId为1的内容与我们设置需要存储的内容一致,这样我们持久化聊天记忆就能实现隔离对话了!!

以上便是对持久化聊天记忆(隔离对话)的介绍与使用了,如果上述内容对大家有帮助的话请给一个三连关注吧💕( •̀ ω •́ )✧✨

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐