面试官:如何实现大模型连续对话?

所有的大模型本身是不进行信息存储的,也不提供连续对话功能,所以想要实现连续对话功能需要开发者自己写代码才能实现。那怎么才能实现大模型的连续对话功能呢?

大模型连续对话功能不同的框架实现也是不同的,以行业使用最多的 Java AI 框架 Spring AI 和 Spring AI Alibaba 为例,给大家演示一下它们连续对话是如何实现的。

1.SpringAI连续对话实现

Spring AI 以 MySQL 数据库为例,我们来实现一下它的连续对话功能。

PS:我们只有先讲对话存储起来,才能实现连续对话功能,所以我们需要借助数据库存储来连续对话。

1.1 准备工作

1.创建表

CREATE TABLE chat_message (   id BIGINT AUTO_INCREMENT PRIMARY KEY,   conversation_id VARCHAR(255) NOT NULL,   role VARCHAR(50) NOT NULL,   context TEXT NOT NULL,   created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 

2.添加数据库和 MyBatisPlus 依赖:

<dependency>   <groupId>com.baomidou</groupId>   <artifactId>mybatis-plus-spring-boot3-starter</artifactId>   <version>3.5.11</version> </dependency>  <dependency>   <groupId>com.mysql</groupId>   <artifactId>mysql-connector-j</artifactId>   <scope>runtime</scope> </dependency> 

3.设置配置文件:

spring:   datasource:     url: jdbc:mysql://127.0.0.1:3306/testdb?characterEncoding=utf8     username: root     password: 12345678     driver-class-name: com.mysql.cj.jdbc.Driver # 配置打印 MyBatis 执行的 SQL mybatis-plus:   configuration:     log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 配置打印 MyBatis 执行的 SQL logging:   level:     com:       ai:         deepseek: debug 

4.编写实体类

import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Getter; import lombok.Setter;  import java.io.Serializable; import java.util.Date;  @Getter @Setter @TableName("chat_message") public class ChatMessageDO implements Serializable {      private static final long serialVersionUID = 1L;      @TableId(value = "id", type = IdType.AUTO)     private Long id;      private String conversationId;      private String role;      private String context;      private Date createdAt; } 

5.编写 Mapper:

import com.ai.chat.entity.ChatMessageDO; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper;  @Mapper public interface ChatMessageMapper extends BaseMapper<ChatMessageDO> { } 

1.2 自定义ChatMemory类

自定义的 ChatMemory 实现类,将对话记录存储到 MySQL:

import com.ai.deepseek.entity.ChatMessageDO; import com.ai.deepseek.mapper.ChatMessageMapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import org.springframework.ai.chat.memory.ChatMemory; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.UserMessage; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;  import java.util.List; import java.util.stream.Collectors;  @Component public class MySQLChatMemory implements ChatMemory {     @Autowired     private ChatMessageMapper repository;      @Override     public void add(String conversationId, Message message) {         ChatMessageDO entity = new ChatMessageDO();         entity.setConversationId(conversationId);         entity.setRole(message.getMessageType().name());         entity.setContext(message.getText());         repository.insert(entity);     }      @Override     public void add(String conversationId, List<Message> messages) {         messages.forEach(message -> add(conversationId, message));     }      @Override     public List<Message> get(String conversationId, int lastN) {         LambdaQueryWrapper<ChatMessageDO> queryWrapper = new LambdaQueryWrapper<>();         queryWrapper.eq(ChatMessageDO::getConversationId, conversationId);         // queryWrapper.orderByDesc(ChatMessageDO::getId);         return repository.selectList(queryWrapper)         .stream()         .limit(lastN)         .map(e -> new UserMessage(e.getContext()))         .collect(Collectors.toList());     }      @Override     public void clear(String conversationId) {         LambdaQueryWrapper<ChatMessageDO> queryWrapper = new LambdaQueryWrapper<>();         queryWrapper.eq(ChatMessageDO::getConversationId, conversationId);         repository.delete(queryWrapper);     } } 

1.3 代码调用

编写代码测试历史对话保存到 MySQL 的功能:

import com.ai.deepseek.component.MySQLChatMemory; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Flux;  @RestController @RequestMapping("/multi") public class MultiChatController {      @Autowired     private ChatClient chatClient;     @Autowired     private MySQLChatMemory chatMemory;      @RequestMapping("/chat")     public Flux<String> chat(@RequestParam("msg") String msg,                              @RequestParam(defaultValue = "default") String sessionId) {         // 添加MessageChatMemoryAdvisor,自动管理上下文         MessageChatMemoryAdvisor advisor =         new MessageChatMemoryAdvisor(chatMemory, sessionId, 10); // 保留最近5条历史         return chatClient.prompt()         .user(msg)         .advisors(advisor) // 关键:注入记忆管理         .stream()         .content();     } } 

以上程序执行结果如下:

面试官:如何实现大模型连续对话?

2.SpringAIAlibaba实现连续对话

Spring AI Alibaba 连续对话的实现就简单很多了,因为它内置了 MySQL 和 Redis 的连续对话存储方式,接下来以 Redis 为例演示 SAA 的连续对话实现,它的实现步骤如下:

  1. 添加依赖。
  2. 设置配置文件,配置 Redis 连接信息。
  3. 添加 Redis 配置类,注入 RedisChatMemoryRepository 对象。
  4. 配置 ChatClient 实现连续对话。

具体实现如下。

2.1 添加依赖

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

2.2 设置配置文件

设置配置文件,配置 Redis 连接信息:

spring:   ai:     memory:       redis:         host: localhost         port: 6379         timeout: 5000 

2.3 添加Redis配置类

添加 Redis 配置类,注入 RedisChatMemoryRepository 对象,实现 Redis 自定义存储器注入:

import com.alibaba.cloud.ai.memory.redis.RedisChatMemoryRepository; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;  @Configuration public class RedisMemoryConfig {      @Value("${spring.ai.memory.redis.host}")     private String redisHost;     @Value("${spring.ai.memory.redis.port}")     private int redisPort;     //    @Value("${spring.ai.memory.redis.password}")     //    private String redisPassword;     @Value("${spring.ai.memory.redis.timeout}")     private int redisTimeout;      @Bean     public RedisChatMemoryRepository redisChatMemoryRepository() {         return RedisChatMemoryRepository.builder()         .host(redisHost)         .port(redisPort)         // 若没有设置密码则注释该项         //           .password(redisPassword)         .timeout(redisTimeout)         .build();     } } 

2.4 配置ChatClient实现连续对话

import com.alibaba.cloud.ai.memory.redis.RedisChatMemoryRepository; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor; import org.springframework.ai.chat.memory.MessageWindowChatMemory; import org.springframework.ai.chat.model.ChatModel; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;  import static org.springframework.ai.chat.memory.ChatMemory.CONVERSATION_ID;  @RestController @RequestMapping("/redis") public class RedisMemoryController {      private final ChatClient chatClient;     private final int MAXMESSAGES = 10;     private final MessageWindowChatMemory messageWindowChatMemory;      public RedisMemoryController(ChatModel dashscopeChatModel,                                  RedisChatMemoryRepository redisChatMemoryRepository) {         this.messageWindowChatMemory = MessageWindowChatMemory.builder()         .chatMemoryRepository(redisChatMemoryRepository)         .maxMessages(MAXMESSAGES)         .build();          this.chatClient = ChatClient.builder(dashscopeChatModel)         .defaultAdvisors(             MessageChatMemoryAdvisor.builder(messageWindowChatMemory)             .build()         )         .build();     }      @GetMapping("/call")     public String call(String msg, String cid) {         return chatClient.prompt(msg)         .advisors(             a -> a.param(CONVERSATION_ID, cid)         )         .call().content();     } } 

小结

通过以上代码大家也可以看出来,使用 Spring AI 实现连续对话是比较复杂的,需要自己实现数据库增删改查的代码,并且重写 ChatMemory 才能实现连续对话功能;而 Spring AI Alibaba 因为内置了连续对话的多种实现(Redis 和其他数据库),所以只需要简单配置就可以实现了。

本文已收录到我的面试小站 www.javacn.site,其中包含的内容有:场景题、SpringAI、SpringAIAlibaba、并发编程、MySQL、Redis、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、JVM、设计模式、消息队列、AI常见面试题等。

发表评论

评论已关闭。

相关文章