LangChain4j 整合 Spring Boot 实战:接入通义千问 + MySQL 会话存储
·
在 AI 应用开发中,LangChain4j 是连接大模型与业务系统的重要工具。本文将完整演示如何基于 Spring Boot 整合 LangChain4j,实现通义千问模型调用、MySQL 持久化会话记忆、工具集成等核心功能,提供可直接复用的代码模板。
一、核心依赖配置(pom.xml)
首先需配置 Maven 依赖,核心包含 LangChain4j 相关组件(通义千问接入、Ollama 支持、Spring Boot starter)、Spring Boot 基础组件、MySQL 驱动及 MyBatis-Plus 等。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.nie</groupId>
<artifactId>langchaini4j-ai</artifactId>
<version>1.0.0</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-boot.version>3.5.0</spring-boot.version>
<knife4j.version>4.3.0</knife4j.version>
<langchain4j.version>1.0.0-beta3</langchain4j.version>
<mybatis-plus.version>3.5.11</mybatis-plus.version>
</properties>
<dependencies>
<!-- Spring Boot 基础 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 接口文档(Knife4j) -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>${knife4j.version}</version>
</dependency>
<!-- LangChain4j 核心 -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
</dependency>
<!-- LangChain4j 模型接入 -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-ollama-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-dashscope-spring-boot-starter</artifactId>
</dependency>
<!-- 数据持久化 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!-- Redis 缓存 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- JSON 处理 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.15.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.15.2</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<!-- Spring Boot 依赖管理 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- LangChain4j 依赖管理 -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-bom</artifactId>
<version>1.0.0-beta3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-bom</artifactId>
<version>${langchain4j.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
二、通义千问模型配置(application.yml)
通过配置文件指定通义千问模型名称,并从本地环境变量读取 API Key(避免硬编码泄露风险)。
langchain4j:
community:
dashscope:
chat-model:
api-key: ${MY_API_KEY} # 本地环境变量中配置 API Key
model-name: qwen-max # 通义千问模型名称(可替换为 qwen-plus 等)
三、核心业务代码实现
3.1 对话接口定义(Assistant)
定义 AI 对话接口,支持两种对话模式:基础对话和带用户信息的个性化对话,通过注解指定系统提示词。
import dev.langchain4j.agent.tool.P;
import dev.langchain4j.agent.tool.V;
import dev.langchain4j.memory.MemoryId;
import dev.langchain4j.model.input.PromptTemplate;
import dev.langchain4j.model.input.system.SystemMessage;
import dev.langchain4j.model.input.user.UserMessage;
public interface Assistant {
/**
* 基础对话(返回 Markdown 格式)
* @param memoryId 会话 ID(用于隔离不同用户会话)
* @param question 用户问题
* @return 模型回答(Markdown 格式)
*/
@SystemMessage("请以 Markdown 格式返回回答,确保内容清晰、结构合理")
String chat(@MemoryId int memoryId, @UserMessage String question);
/**
* 个性化对话(携带用户信息)
* @param memoryId 会话 ID
* @param question 用户问题
* @param username 用户名(从数据库查询)
* @param age 用户年龄(从数据库查询)
* @return 个性化回答
*/
@SystemMessage(fromResource = "system-prompt1.txt") // 从资源文件读取系统提示词
String chatInfo(@MemoryId int memoryId,
@UserMessage String question,
@V("username") String username,
@V("age") int age);
}
system-prompt1.txt:
我是{{username}}
我的年龄是{{age}}
{{current_date}}表示当前日期
3.2 会话记忆配置(AssistantChatMemoryConfig)
配置 AI 服务,指定模型、会话存储方式(MySQL)和工具集成(如计算器),实现会话隔离。
import dev.langchain4j.agent.tool.Tool;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.dashscope.QwenChatModel;
import dev.langchain4j.spring.ai.AiServices;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
@Configuration
public class AssistantChatMemoryConfig {
@Resource
private QwenChatModel qwenChatModel; // 通义千问模型实例
@Resource
private MysqlChatMemoryStore mysqlChatMemoryStore; // MySQL 会话存储
@Resource
private CalculatorTools calculatorTools; // 集成的工具(如计算器)
@Bean
public Assistant assistant() {
return AiServices.builder(Assistant.class)
.chatLanguageModel(qwenChatModel) // 指定大模型
// 会话隔离:为每个会话 ID 创建独立记忆
.chatMemoryProvider(memoryId -> MessageWindowChatMemory
.builder()
.id(memoryId)
.chatMemoryStore(mysqlChatMemoryStore) // 自定义 MySQL 存储
.maxMessages(20) // 每个会话最大消息数
.build())
.tools(calculatorTools) // 集成工具
.build();
}
}
3.3 MySQL 会话存储实现(MysqlChatMemoryStore)
自定义 ChatMemoryStore 接口实现,将会话消息序列化为 JSON 存储到 MySQL,支持增删改查。
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import dev.langchain4j.memory.chat.ChatMemoryStore;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.serializer.Json;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
@Slf4j
@Component
public class MysqlChatMemoryStore implements ChatMemoryStore {
@Resource
private ChatMemoryStoreMapper chatMemoryStoreMapper; // MyBatis Mapper 接口
/**
* 读取会话消息
*/
@Override
public List<ChatMessage> getMessages(Object memoryId) {
try {
ChatMessages chatMessages = chatMemoryStoreMapper.getMessages(memoryId.toString());
if (chatMessages == null || chatMessages.getContent() == null) {
return List.of(); // 无消息时返回空列表
}
// JSON 反序列化为 ChatMessage 列表
log.info("查询会话 {} 消息:{}", memoryId, chatMessages.getContent());
return Json.fromJson(chatMessages.getContent(), List.class);
} catch (Exception e) {
log.error("读取会话 {} 消息失败", memoryId, e);
return List.of();
}
}
/**
* 更新会话消息(新增/修改)
*/
@Override
public void updateMessages(Object memoryId, List<ChatMessage> messages) {
try {
// ChatMessage 列表序列化为 JSON
String messagesJson = Json.toJson(messages);
log.info("会话 {} 待存储消息:{}", memoryId, messagesJson);
ChatMessages chatMessages = chatMemoryStoreMapper.getMessages(memoryId.toString());
if (chatMessages == null) {
// 新增会话记录
ChatMessages newRecord = new ChatMessages();
newRecord.setMessageId(memoryId.toString());
newRecord.setContent(messagesJson);
chatMemoryStoreMapper.save(newRecord);
} else {
// 更新已有会话记录
chatMessages.setContent(messagesJson);
chatMemoryStoreMapper.updateData(chatMessages);
}
} catch (Exception e) {
log.error("更新会话 {} 消息失败", memoryId, e);
throw new RuntimeException("会话消息存储失败", e);
}
}
/**
* 删除会话消息
*/
@Override
public void deleteMessages(Object memoryId) {
try {
chatMemoryStoreMapper.deleteByMemoryId(memoryId.toString());
log.info("删除会话 {} 消息成功", memoryId);
} catch (Exception e) {
log.error("删除会话 {} 消息失败", memoryId, e);
throw new RuntimeException("会话消息删除失败", e);
}
}
// 会话消息实体类(与数据库表映射)
@Data
public static class ChatMessages {
private Integer id; // 主键
private String messageId; // 会话 ID(对应 memoryId)
private String content; // 会话消息 JSON
}
}
3.4 Mapper 接口与 XML(数据访问层)
定义 MyBatis Mapper 接口及 XML 文件,实现 MySQL 数据操作。
3.4.1 ChatMemoryStoreMapper 接口
import com.nie.ai.langchain4j.config.MysqlChatMemoryStore.ChatMessages;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ChatMemoryStoreMapper {
// 查询会话消息
ChatMessages getMessages(String memoryId);
// 新增会话消息
void save(ChatMessages chatMessages);
// 更新会话消息
void updateData(ChatMessages chatMessages);
// 删除会话消息
void deleteByMemoryId(String memoryId);
}
3.4.2 Mapper XML(ChatMemoryStoreMapper.xml)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nie.ai.langchain4j.mapper.ChatMemoryStoreMapper">
<!-- 结果映射 -->
<resultMap id="ChatMessagesResultMap" type="com.nie.ai.langchain4j.config.MysqlChatMemoryStore$ChatMessages">
<id column="id" property="id" />
<result column="message_id" property="messageId" />
<result column="content" property="content" />
</resultMap>
<!-- 新增 -->
<insert id="save">
INSERT INTO chat_messages (message_id, content)
VALUES (#{messageId}, #{content})
</insert>
<!-- 更新 -->
<update id="updateData">
UPDATE chat_messages
SET content = #{content}
WHERE message_id = #{messageId}
</update>
<!-- 删除 -->
<delete id="deleteByMemoryId">
DELETE FROM chat_messages
WHERE message_id = #{memoryId}
</delete>
<!-- 查询 -->
<select id="getMessages" resultMap="ChatMessagesResultMap">
SELECT id, message_id, content
FROM chat_messages
WHERE message_id = #{memoryId}
</select>
</mapper>
3.5 控制器(ChatController)
提供 HTTP 接口,接收前端请求并调用 Assistant 服务处理对话。
import com.nie.ai.langchain4j.config.Assistant;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@Tag(name = "Agent测试")
@RestController
@Slf4j
public class ChatController {
@Resource
private Assistant assistant;
/**
* 基础对话接口
*/
@PostMapping("/chat")
public String chat(@RequestParam("memoryId") int memoryId,
@RequestParam("question") String question) {
log.info("接收会话 {} 请求:{}", memoryId, question);
return assistant.chat(memoryId, question);
}
/**
* 个性化对话接口(接收 JSON 参数)
*/
@Operation(summary = "个性化对话")
@PostMapping("/chatInfo")
public String chatInfo(@RequestBody ChatRequest chatRequest) {
return assistant.chatInfo(chatRequest.getMemoryId(),
chatRequest.getQuestion());
}
}
四、数据库表结构(MySQL)
创建 chat_messages 表,用于存储会话消息 JSON 数据。
CREATE TABLE `chat_messages` (
`id` int NOT NULL AUTO_INCREMENT,
`messageId` int DEFAULT NULL,
`content` text,
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
五、关键注意事项
- API Key 安全:务必通过环境变量
MY_API_KEY配置,禁止硬编码到代码或配置文件中。 - 会话隔离:通过
memoryId区分不同用户会话,避免消息混淆。 - 消息序列化:使用 LangChain4j 自带的
Json工具类(或 Jackson)实现ChatMessage与 JSON 的转换,确保格式正确。 - 异常处理:会话存储的增删改查操作需添加异常捕获,避免单个会话错误影响整体服务。
- 依赖版本:LangChain4j 处于快速迭代阶段,需注意
langchain4j.version与 Spring Boot 版本的兼容性(本文使用 1.0.0-beta3 + Spring Boot 3.5.0)。
六、功能测试
- 配置环境变量:在本地终端设置
MY_API_KEY(通义千问 API Key,需从阿里云 DashScope 平台申请)。# Windows set MY_API_KEY=your_api_key # Linux/Mac export MY_API_KEY=your_api_key - 启动服务:运行 Spring Boot 应用,通过 Knife4j 文档(
http://localhost:8080/doc.html)测试/chat和/chatInfo接口。 - 验证存储:发送请求后,查看
chat_messages表,确认会话消息 JSON 已正确存储。
更多推荐
所有评论(0)