SpringAI实现聊天记录保存到MySQL
数据库相关的准备
添加依赖
<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>
添加配置
datasource:url: jdbc:mysql://localhost:3306/test_activiti?useUnicode=true&characterEncoding=utf-8username: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Driver
创建SQL脚本
create table chat_message
(id bigint auto_incrementprimary key,conversation_id varchar(255) not null,role varchar(50) not null,context text not null,created_at timestamp default CURRENT_TIMESTAMP null
);
创建实体类
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName("chat_message")
public class ChatMessage {@TableId(type = IdType.AUTO)private Long id;private String conversationId;private String role;private String context;private String createdAt;
}
创建mapper
@Mapper
public interface ChatMessageMapper extends BaseMapper<ChatMessage> {
}
SpringAI相关准备
不用阿里云的maven仓库,用默认的maven中央仓库。
版本控制
<properties><java.version>21</java.version><spring-ai.version>1.0.0-SNAPSHOT</spring-ai.version></properties>
<dependencyManagement><dependencies><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-bom</artifactId><version>${spring-ai.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>
添加依赖
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-model-openai</artifactId></dependency>
因为我对接的阿里云百炼平台
添加配置
spring:ai:openai:base-url: https://dashscope.aliyuncs.com/compatible-mode/api-key: ${ALIYUN_AK}chat:options:model: qwen-max
我的api-key 存储在我环境变量中
编写代码
创建MysqlChatMemory实现ChatMemory
@Component
public class MysqlChatMemory implements ChatMemory {@Autowiredprivate ChatMessageMapper chatMessageMapper;@Overridepublic void add(String conversationId, Message message) {ChatMessage chatMessage = ChatMessage.builder().conversationId(conversationId).role(message.getMessageType().name()).context(message.getText()).build();chatMessageMapper.insert(chatMessage);}@Overridepublic void add(String conversationId, List<Message> messages) {messages.forEach(message -> add(conversationId, message));}@Overridepublic List<Message> get(String conversationId) {LambdaQueryWrapper<ChatMessage> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(ChatMessage::getConversationId, conversationId);return chatMessageMapper.selectList(queryWrapper).stream().map(e -> new UserMessage(e.getContext())).collect(Collectors.toList());}@Overridepublic void clear(String conversationId) {LambdaQueryWrapper<ChatMessage> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(ChatMessage::getConversationId, conversationId);chatMessageMapper.delete(queryWrapper);}
}
创建chatModel
创建一个就行,我这里为了实现0代码切换大模型。
@Configuration
public class BaiLianConfig {@Value("${spring.ai.openai.api-key}")private String apiKey;@Value("${spring.ai.openai.base-url}")private String baseUrl;private final String BAILIAN_DEEPSEEK_MODEL = "deepseek-v3";private final String BAILIAN_QWEN_MODEL = "qwen-max";@Beanpublic OpenAiChatModel deepSeek(){return OpenAiChatModel.builder().openAiApi(OpenAiApi.builder().apiKey(apiKey).baseUrl(baseUrl).build()).defaultOptions(OpenAiChatOptions.builder().model(BAILIAN_DEEPSEEK_MODEL).build()).build();}@Beanpublic OpenAiChatModel qwen(){return OpenAiChatModel.builder().openAiApi(OpenAiApi.builder().apiKey(apiKey).baseUrl(baseUrl).build()).defaultOptions(OpenAiChatOptions.builder().model(BAILIAN_QWEN_MODEL).build()).build();}}
创建controller
@Slf4j
@RestController
@RequestMapping("/memory")
public class ChatMemoryController {private final ChatClient chatClient;public ChatMemoryController(ChatModel deepSeek) {this.chatClient = ChatClient.builder(deepSeek).build();}@Autowiredprivate MysqlChatMemory mysqlChatMemory;@GetMapping("/mysql")public Flux<String> mysql(String question, String conversationId){MessageChatMemoryAdvisor advisor = MessageChatMemoryAdvisor.builder(mysqlChatMemory).conversationId(conversationId).order(5).build();return chatClient.prompt().system("你是我的学习助手名字叫小菜包").user(question).advisors(advisor).stream().content();}}
测试
就是为了测试我的会话id就是我自己设置的,后面到了项目中肯定不是这样使用的。