找回密码
 立即注册
首页 业界区 业界 面试官:如何实现大模型连续对话?

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

湛恶 5 小时前
所有的大模型本身是不进行信息存储的,也不提供连续对话功能,所以想要实现连续对话功能需要开发者自己写代码才能实现。那怎么才能实现大模型的连续对话功能呢?
大模型连续对话功能不同的框架实现也是不同的,以行业使用最多的 Java AI 框架 Spring AI 和 Spring AI Alibaba 为例,给大家演示一下它们连续对话是如何实现的。
1.SpringAI连续对话实现

Spring AI 以 MySQL 数据库为例,我们来实现一下它的连续对话功能。
PS:我们只有先讲对话存储起来,才能实现连续对话功能,所以我们需要借助数据库存储来连续对话。
1.1 准备工作

1.创建表
  1. CREATE TABLE chat_message (
  2.   id BIGINT AUTO_INCREMENT PRIMARY KEY,
  3.   conversation_id VARCHAR(255) NOT NULL,
  4.   role VARCHAR(50) NOT NULL,
  5.   context TEXT NOT NULL,
  6.   created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  7. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
复制代码
2.添加数据库和 MyBatisPlus 依赖:
  1. <dependency>
  2.   <groupId>com.baomidou</groupId>
  3.   mybatis-plus-spring-boot3-starter</artifactId>
  4.   <version>3.5.11</version>
  5. </dependency>
  6. <dependency>
  7.   <groupId>com.mysql</groupId>
  8.   mysql-connector-j</artifactId>
  9.   <scope>runtime</scope>
  10. </dependency>
复制代码
3.设置配置文件:
  1. spring:
  2.   datasource:
  3.     url: jdbc:mysql://127.0.0.1:3306/testdb?characterEncoding=utf8
  4.     username: root
  5.     password: 12345678
  6.     driver-class-name: com.mysql.cj.jdbc.Driver
  7. # 配置打印 MyBatis 执行的 SQL
  8. mybatis-plus:
  9.   configuration:
  10.     log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  11. # 配置打印 MyBatis 执行的 SQL
  12. logging:
  13.   level:
  14.     com:
  15.       ai:
  16.         deepseek: debug
复制代码
4.编写实体类
  1. import com.baomidou.mybatisplus.annotation.IdType;
  2. import com.baomidou.mybatisplus.annotation.TableId;
  3. import com.baomidou.mybatisplus.annotation.TableName;
  4. import lombok.Getter;
  5. import lombok.Setter;
  6. import java.io.Serializable;
  7. import java.util.Date;
  8. @Getter
  9. @Setter
  10. @TableName("chat_message")
  11. public class ChatMessageDO implements Serializable {
  12.     private static final long serialVersionUID = 1L;
  13.     @TableId(value = "id", type = IdType.AUTO)
  14.     private Long id;
  15.     private String conversationId;
  16.     private String role;
  17.     private String context;
  18.     private Date createdAt;
  19. }
复制代码
5.编写 Mapper:
  1. import com.ai.chat.entity.ChatMessageDO;
  2. import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  3. import org.apache.ibatis.annotations.Mapper;
  4. @Mapper
  5. public interface ChatMessageMapper extends BaseMapper<ChatMessageDO> {
  6. }
复制代码
1.2 自定义ChatMemory类

自定义的 ChatMemory 实现类,将对话记录存储到 MySQL:
  1. import com.ai.deepseek.entity.ChatMessageDO;
  2. import com.ai.deepseek.mapper.ChatMessageMapper;
  3. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  4. import org.springframework.ai.chat.memory.ChatMemory;
  5. import org.springframework.ai.chat.messages.Message;
  6. import org.springframework.ai.chat.messages.UserMessage;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.stereotype.Component;
  9. import java.util.List;
  10. import java.util.stream.Collectors;
  11. @Component
  12. public class MySQLChatMemory implements ChatMemory {
  13.     @Autowired
  14.     private ChatMessageMapper repository;
  15.     @Override
  16.     public void add(String conversationId, Message message) {
  17.         ChatMessageDO entity = new ChatMessageDO();
  18.         entity.setConversationId(conversationId);
  19.         entity.setRole(message.getMessageType().name());
  20.         entity.setContext(message.getText());
  21.         repository.insert(entity);
  22.     }
  23.     @Override
  24.     public void add(String conversationId, List<Message> messages) {
  25.         messages.forEach(message -> add(conversationId, message));
  26.     }
  27.     @Override
  28.     public List<Message> get(String conversationId, int lastN) {
  29.         LambdaQueryWrapper<ChatMessageDO> queryWrapper = new LambdaQueryWrapper<>();
  30.         queryWrapper.eq(ChatMessageDO::getConversationId, conversationId);
  31.         // queryWrapper.orderByDesc(ChatMessageDO::getId);
  32.         return repository.selectList(queryWrapper)
  33.         .stream()
  34.         .limit(lastN)
  35.         .map(e -> new UserMessage(e.getContext()))
  36.         .collect(Collectors.toList());
  37.     }
  38.     @Override
  39.     public void clear(String conversationId) {
  40.         LambdaQueryWrapper<ChatMessageDO> queryWrapper = new LambdaQueryWrapper<>();
  41.         queryWrapper.eq(ChatMessageDO::getConversationId, conversationId);
  42.         repository.delete(queryWrapper);
  43.     }
  44. }
复制代码
1.3 代码调用

编写代码测试历史对话保存到 MySQL 的功能:
  1. import com.ai.deepseek.component.MySQLChatMemory;
  2. import org.springframework.ai.chat.client.ChatClient;
  3. import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.web.bind.annotation.RequestMapping;
  6. import org.springframework.web.bind.annotation.RequestParam;
  7. import org.springframework.web.bind.annotation.RestController;
  8. import reactor.core.publisher.Flux;
  9. @RestController
  10. @RequestMapping("/multi")
  11. public class MultiChatController {
  12.     @Autowired
  13.     private ChatClient chatClient;
  14.     @Autowired
  15.     private MySQLChatMemory chatMemory;
  16.     @RequestMapping("/chat")
  17.     public Flux<String> chat(@RequestParam("msg") String msg,
  18.                              @RequestParam(defaultValue = "default") String sessionId) {
  19.         // 添加MessageChatMemoryAdvisor,自动管理上下文
  20.         MessageChatMemoryAdvisor advisor =
  21.         new MessageChatMemoryAdvisor(chatMemory, sessionId, 10); // 保留最近5条历史
  22.         return chatClient.prompt()
  23.         .user(msg)
  24.         .advisors(advisor) // 关键:注入记忆管理
  25.         .stream()
  26.         .content();
  27.     }
  28. }
复制代码
以上程序执行结果如下:
1.jpeg

2.SpringAIAlibaba实现连续对话

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

  • 添加依赖。
  • 设置配置文件,配置 Redis 连接信息。
  • 添加 Redis 配置类,注入 RedisChatMemoryRepository 对象。
  • 配置 ChatClient 实现连续对话。
具体实现如下。
2.1 添加依赖
  1. <dependency>
  2.   <groupId>com.alibaba.cloud.ai</groupId>
  3.   spring-ai-alibaba-starter-memory-redis</artifactId>
  4. </dependency>
复制代码
2.2 设置配置文件

设置配置文件,配置 Redis 连接信息:
  1. spring:
  2.   ai:
  3.     memory:
  4.       redis:
  5.         host: localhost
  6.         port: 6379
  7.         timeout: 5000
复制代码
2.3 添加Redis配置类

添加 Redis 配置类,注入 RedisChatMemoryRepository 对象,实现 Redis 自定义存储器注入:
  1. import com.alibaba.cloud.ai.memory.redis.RedisChatMemoryRepository;
  2. import org.springframework.beans.factory.annotation.Value;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.context.annotation.Configuration;
  5. @Configuration
  6. public class RedisMemoryConfig {
  7.     @Value("${spring.ai.memory.redis.host}")
  8.     private String redisHost;
  9.     @Value("${spring.ai.memory.redis.port}")
  10.     private int redisPort;
  11.     //    @Value("${spring.ai.memory.redis.password}")
  12.     //    private String redisPassword;
  13.     @Value("${spring.ai.memory.redis.timeout}")
  14.     private int redisTimeout;
  15.     @Bean
  16.     public RedisChatMemoryRepository redisChatMemoryRepository() {
  17.         return RedisChatMemoryRepository.builder()
  18.         .host(redisHost)
  19.         .port(redisPort)
  20.         // 若没有设置密码则注释该项
  21.         //           .password(redisPassword)
  22.         .timeout(redisTimeout)
  23.         .build();
  24.     }
  25. }
复制代码
2.4 配置ChatClient实现连续对话
  1. import com.alibaba.cloud.ai.memory.redis.RedisChatMemoryRepository;
  2. import org.springframework.ai.chat.client.ChatClient;
  3. import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
  4. import org.springframework.ai.chat.memory.MessageWindowChatMemory;
  5. import org.springframework.ai.chat.model.ChatModel;
  6. import org.springframework.web.bind.annotation.GetMapping;
  7. import org.springframework.web.bind.annotation.RequestMapping;
  8. import org.springframework.web.bind.annotation.RestController;
  9. import static org.springframework.ai.chat.memory.ChatMemory.CONVERSATION_ID;
  10. @RestController
  11. @RequestMapping("/redis")
  12. public class RedisMemoryController {
  13.     private final ChatClient chatClient;
  14.     private final int MAXMESSAGES = 10;
  15.     private final MessageWindowChatMemory messageWindowChatMemory;
  16.     public RedisMemoryController(ChatModel dashscopeChatModel,
  17.                                  RedisChatMemoryRepository redisChatMemoryRepository) {
  18.         this.messageWindowChatMemory = MessageWindowChatMemory.builder()
  19.         .chatMemoryRepository(redisChatMemoryRepository)
  20.         .maxMessages(MAXMESSAGES)
  21.         .build();
  22.         this.chatClient = ChatClient.builder(dashscopeChatModel)
  23.         .defaultAdvisors(
  24.             MessageChatMemoryAdvisor.builder(messageWindowChatMemory)
  25.             .build()
  26.         )
  27.         .build();
  28.     }
  29.     @GetMapping("/call")
  30.     public String call(String msg, String cid) {
  31.         return chatClient.prompt(msg)
  32.         .advisors(
  33.             a -> a.param(CONVERSATION_ID, cid)
  34.         )
  35.         .call().content();
  36.     }
  37. }
复制代码
小结

通过以上代码大家也可以看出来,使用 Spring AI 实现连续对话是比较复杂的,需要自己实现数据库增删改查的代码,并且重写 ChatMemory 才能实现连续对话功能;而 Spring AI Alibaba 因为内置了连续对话的多种实现(Redis 和其他数据库),所以只需要简单配置就可以实现了。
本文已收录到我的面试小站 www.javacn.site,其中包含的内容有:场景题、SpringAI、SpringAIAlibaba、并发编程、MySQL、Redis、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、JVM、设计模式、消息队列、AI常见面试题等。
   

关注公众号(加好友):

            
作者:        王磊的博客        
出处:        http://vipstone.cnblogs.com/        
   

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册