【AI】----LangChain4j 整合spring boot3 和mybatis-plus 调用豆包LLM大模型(加RAG)
本文介绍了基于LangChain4j+Spring Boot3+Milvus实现大数据量向量数据库的解决方案。针对传统模糊查询在大数据量下性能差、精度低的问题,采用向量数据库通过语义相似度检索实现高效查询。技术栈选用开源向量数据库Milvus、LangChain4j封装向量操作、豆包Embedding API生成向量。文章详细说明了环境准备、Milvus的Docker部署方式,并提供了Spring
·
基于 LangChain4j + Spring Boot3 + Milvus 实现大数据量向量数据库案例
你想要在之前的整合案例基础上,升级为大数据量场景下的向量数据库方案(替代原有的模糊查询),我会以主流的开源向量数据库 Milvus 为例,带你实现从环境搭建到完整 RAG 流程的全链路案例,解决大数据量下语义检索精度低、性能差的问题。
一、核心前置知识
1. 为什么需要向量数据库?
- 模糊查询(
LIKE %关键词%):仅匹配字符,无法理解语义,大数据量下(百万级+)查询慢、精度低; - 向量数据库(Milvus):将文本转为向量(Embedding),通过余弦相似度/欧氏距离检索语义相似的内容,毫秒级响应,精度远超字符匹配,适配大数据量场景。
2. 技术栈选型
| 组件 | 作用 |
|---|---|
| Milvus | 开源向量数据库(支持百亿级向量检索,轻量版 Milvus Standalone 适合入门) |
| LangChain4j | 封装 Embedding 生成、向量入库/检索逻辑 |
| 豆包 Embedding API | 将文本转为向量(替代本地模型,降低部署成本) |
| Spring Boot3 | 基础框架 + 整合各组件 |
| MyBatis-Plus | 存储原始文本数据(向量数据库仅存向量和关联 ID,原始数据仍存在关系库) |
3. 环境准备
- 已完成上一版 LangChain4j + Spring Boot3 + MyBatis-Plus 基础环境;
- 安装 Milvus(推荐 Docker 部署,最快上手):
# 1. 下载 Milvus 单机版配置文件 wget https://github.com/milvus-io/milvus/releases/download/v2.4.3/milvus-standalone-docker-compose.yml -O docker-compose.yml # 2. 启动 Milvus(需提前安装 Docker & Docker Compose) docker-compose up -d # 3. 验证启动成功(查看容器状态) docker-compose ps - 豆包 Embedding API 权限(需确保 API Key 可调用
/embeddings接口,同 LLM API Key 通用)。
二、阶段1:集成 Milvus 依赖与配置
1.1 新增 Maven 依赖(pom.xml)
在原有依赖基础上添加:
<!-- Milvus Java SDK -->
<dependency>
<groupId>io.milvus</groupId>
<artifactId>milvus-sdk-java</artifactId>
<version>2.4.3</version>
</dependency>
<!-- LangChain4j 整合 Milvus(简化向量操作) -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-milvus</artifactId>
<version>0.32.0</version>
</dependency>
<!-- JSON 工具(可选,用于调试) -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.42</version>
</dependency>
1.2 新增配置(application.yml)
# 原有配置不变,新增以下内容
milvus:
host: 127.0.0.1 # Milvus 服务地址(Docker 部署默认本机)
port: 19530 # Milvus 默认端口
database-name: default
collection-name: knowledge_vector # 向量集合名称(相当于表)
dimension: 1536 # 向量维度(豆包 Embedding 输出维度为 1536)
index-type: IVF_FLAT # 索引类型(入门选 IVF_FLAT,平衡精度和性能)
metric-type: COSINE # 相似度计算方式(余弦相似度)
doubao:
# 原有 LLM 配置不变,新增 Embedding 配置
embedding:
api-key: ${doubao.llm.api-key} # 复用 API Key
base-url: ${doubao.llm.base-url} # 复用 API 地址
model: doubao-embedding # 豆包 Embedding 模型名称
三、阶段2:核心代码实现
3.1 配置类(向量数据库 + Embedding)
package com.example.config;
import dev.langchain4j.data.embedding.EmbeddingModel;
import dev.langchain4j.model.openai.OpenAiEmbeddingModel;
import dev.langchain4j.store.embedding.milvus.MilvusEmbeddingStore;
import io.milvus.param.ConnectParam;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
/**
* 向量数据库 & Embedding 配置类
*/
@Configuration
public class VectorConfig {
@Resource
private DouBaoProperties douBaoProperties;
@Resource
private MilvusProperties milvusProperties;
/**
* 初始化豆包 Embedding 模型(文本转向量)
*/
@Bean
public EmbeddingModel doubaoEmbeddingModel() {
return OpenAiEmbeddingModel.builder()
.apiKey(douBaoProperties.getEmbedding().getApiKey())
.baseUrl(douBaoProperties.getEmbedding().getBaseUrl() + "/embeddings") // 豆包 Embedding 接口路径
.modelName(douBaoProperties.getEmbedding().getModel())
.build();
}
/**
* 初始化 Milvus 向量存储
*/
@Bean
public MilvusEmbeddingStore milvusEmbeddingStore() {
// 1. 构建 Milvus 连接参数
ConnectParam connectParam = ConnectParam.newBuilder()
.withHost(milvusProperties.getHost())
.withPort(milvusProperties.getPort())
.withDatabaseName(milvusProperties.getDatabaseName())
.build();
// 2. 构建向量存储(LangChain4j 封装,简化操作)
return MilvusEmbeddingStore.builder()
.connectParam(connectParam)
.collectionName(milvusProperties.getCollectionName())
.dimension(milvusProperties.getDimension()) // 向量维度必须和 Embedding 输出一致
.indexType(milvusProperties.getIndexType())
.metricType(milvusProperties.getMetricType())
.build();
}
/**
* Milvus 配置属性类(绑定 yml 配置)
*/
@Data
@Component
@ConfigurationProperties(prefix = "milvus")
public static class MilvusProperties {
private String host;
private Integer port;
private String databaseName;
private String collectionName;
private Integer dimension;
private String indexType;
private String metricType;
}
}
注意:需在
DouBaoProperties中新增 Embedding 内部类:@Data public static class EmbeddingProperties { private String apiKey; private String baseUrl; private String model; }
3.2 向量入库工具类(初始化知识库)
package com.example.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.entity.KnowledgeBase;
import com.example.mapper.KnowledgeBaseMapper;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.Metadata;
import dev.langchain4j.data.embedding.Embedding;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.store.embedding.EmbeddingMatch;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
/**
* 向量入库工具:项目启动时将知识库文本转为向量存入 Milvus
* (实际生产可改为定时任务/接口触发,避免每次启动重复入库)
*/
@Slf4j
@Component
public class VectorIngestor implements CommandLineRunner {
@Resource
private KnowledgeBaseMapper knowledgeBaseMapper;
@Resource
private EmbeddingModel doubaoEmbeddingModel;
@Resource
private EmbeddingStore<TextSegment> milvusEmbeddingStore;
@Override
public void run(String... args) throws Exception {
// 1. 从 MySQL 读取所有知识库数据
List<KnowledgeBase> knowledgeList = knowledgeBaseMapper.selectList(new LambdaQueryWrapper<>());
if (knowledgeList.isEmpty()) {
log.warn("知识库无数据,跳过向量入库");
return;
}
// 2. 初始化 LangChain4j 向量入库器(简化分片、编码、入库流程)
EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
.embeddingModel(doubaoEmbeddingModel) // 文本转向量模型
.embeddingStore(milvusEmbeddingStore) // 向量存储(Milvus)
.build();
// 3. 逐行入库
for (KnowledgeBase knowledge : knowledgeList) {
// 构建文档(包含文本和元数据,元数据可用于过滤)
Document document = Document.from(knowledge.getContent(),
Metadata.from("id", knowledge.getId().toString(), "title", knowledge.getTitle()));
// 入库(自动分片→转向量→存入 Milvus)
ingestor.ingest(document);
log.info("知识库ID:{} 向量入库成功", knowledge.getId());
}
log.info("所有知识库向量入库完成,共{}条数据", knowledgeList.size());
}
}
3.3 语义检索服务(核心:替代模糊查询)
package com.example.service;
import dev.langchain4j.data.embedding.Embedding;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.store.embedding.EmbeddingMatch;
import dev.langchain4j.store.embedding.EmbeddingStore;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;
/**
* 向量检索服务:大数据量下的语义检索
*/
@Slf4j
@Service
public class VectorSearchService {
@Resource
private EmbeddingModel doubaoEmbeddingModel;
@Resource
private EmbeddingStore<TextSegment> milvusEmbeddingStore;
/**
* 语义检索:根据问题检索相似知识
* @param question 用户问题
* @param topK 返回最相似的K条结果(建议5-10)
* @return 相似知识文本列表
*/
public List<String> semanticSearch(String question, int topK) {
// 步骤1:将用户问题转为向量
Embedding questionEmbedding = doubaoEmbeddingModel.embed(question).content();
// 步骤2:Milvus 检索相似向量(语义相似)
List<EmbeddingMatch<TextSegment>> matches = milvusEmbeddingStore.findRelevant(questionEmbedding, topK);
// 步骤3:提取匹配到的知识文本(过滤低相似度结果,如相似度<0.7)
double similarityThreshold = 0.7; // 相似度阈值,可根据业务调整
return matches.stream()
.filter(match -> match.score() >= similarityThreshold) // 过滤低相似度
.map(match -> match.embedded().text()) // 提取文本内容
.collect(Collectors.toList());
}
}
3.4 升级 RAG 服务(替换模糊查询为向量检索)
package com.example.service;
import cn.hutool.core.collection.CollectionUtil;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.input.Prompt;
import dev.langchain4j.model.input.PromptTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 升级后的 RAG 服务:基于向量数据库的语义检索
*/
@Service
public class AdvancedRagService {
@Resource
private ChatLanguageModel doubaoChatModel;
@Resource
private VectorSearchService vectorSearchService;
@Resource
private DouBaoProperties douBaoProperties;
/**
* 大数据量下的 RAG 问答
*/
public String ragChat(String question) {
// 步骤1:向量数据库语义检索(替代原模糊查询)
List<String> relatedKnowledge = vectorSearchService.semanticSearch(question, 5); // 取最相似的5条
// 步骤2:构建 Prompt(复用原逻辑,无数据时降级为直接问答)
String promptTemplateStr = douBaoProperties.getPrompt().getRagTemplate();
String knowledgeStr = CollectionUtil.isEmpty(relatedKnowledge)
? "无相关参考知识,请直接回答问题"
: String.join("\n", relatedKnowledge);
// 步骤3:填充 Prompt 参数并调用 LLM
PromptTemplate promptTemplate = PromptTemplate.from(promptTemplateStr);
Map<String, Object> parameters = new HashMap<>();
parameters.put("related_knowledge", knowledgeStr);
parameters.put("question", question);
Prompt prompt = promptTemplate.apply(parameters);
return doubaoChatModel.generate(prompt.text());
}
}
3.5 新增控制器(测试向量 RAG)
package com.example.controller;
import com.example.service.AdvancedRagService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* 高级 RAG 控制器(基于向量数据库)
*/
@RestController
@RequestMapping("/api/advanced-rag")
public class AdvancedRagController {
@Resource
private AdvancedRagService advancedRagService;
/**
* 大数据量语义检索 RAG 问答
*/
@GetMapping("/chat")
public String ragChat(@RequestParam String question) {
return advancedRagService.ragChat(question);
}
}
四、测试验证
4.1 数据准备
- 向 MySQL
knowledge_base表插入大量测试数据(如1000+条不同的技术知识); - 启动项目,
VectorIngestor会自动将所有数据转为向量存入 Milvus; - 验证 Milvus 数据:
# 进入 Milvus 容器 docker exec -it milvus-standalone milvus_cli # 连接 Milvus connect -h 127.0.0.1 -p 19530 # 查看向量集合 list collections # 查看集合数据量 describe collection -c knowledge_vector
4.2 接口测试
访问升级后的 RAG 接口:
http://localhost:8080/api/advanced-rag/chat?question=Spring Boot3要求的JDK版本是多少
预期结果:
- 即使问题表述为“Spring Boot3需要什么版本的JDK”(与数据库中“Spring Boot3基于Spring Framework 6,要求JDK17+”语义相似但字符不同),也能精准检索到相关知识;
- 大数据量下(10万+条),响应时间仍在100-500ms(远快于模糊查询)。
五、大数据量优化(精通级)
5.1 性能优化
- 索引优化:
- 入门用
IVF_FLAT,百万级数据可改为HNSW(更快的检索速度); - 调整
nlist参数(IVF_FLAT 索引):nlist = 数据量^(1/2),平衡精度和性能。
- 入门用
- 批量入库:
替换逐行入库为批量入库,提升初始化效率:// 批量构建文档 List<Document> documents = knowledgeList.stream() .map(knowledge -> Document.from(knowledge.getContent(), Metadata.from("id", knowledge.getId().toString(), "title", knowledge.getTitle()))) .collect(Collectors.toList()); // 批量入库 ingestor.ingest(documents); - 缓存 Embedding 结果:
对高频文本(如固定知识库)缓存向量结果,避免重复调用 Embedding API。
5.2 数据管理
- 增量更新:
新增/修改知识库数据时,仅更新对应向量(而非全量重建):// 增量入库单条数据 public void addKnowledgeToVector(KnowledgeBase knowledge) { Document document = Document.from(knowledge.getContent(), Metadata.from("id", knowledge.getId().toString(), "title", knowledge.getTitle())); ingestor.ingest(document); } - 向量删除:
根据元数据(如 ID)删除向量:public void deleteKnowledgeFromVector(Long knowledgeId) { milvusEmbeddingStore.deleteByMetadata("id", knowledgeId.toString()); }
5.3 分布式部署(超大数据量)
- Milvus 从 Standalone 升级为 Cluster 模式(支持分片、副本);
- 引入 Redis 做检索结果缓存,进一步降低 Milvus 压力;
- 使用豆包私有化部署的 Embedding 模型,降低网络延迟。
六、总结
核心要点回顾
- 核心流程:文本 → Embedding 模型转向量 → 存入 Milvus → 用户问题转向量 → Milvus 语义检索 → 结合 LLM 生成回答;
- 关键配置:向量维度(豆包 Embedding 为 1536)、相似度算法(余弦相似度)、索引类型(入门选 IVF_FLAT)需匹配;
- 优化方向:大数据量下重点做索引调优、批量入库、增量更新,超大规模需升级 Milvus 集群。
核心优势
- 精度:语义检索替代字符匹配,即使问题表述不同也能精准找到相关知识;
- 性能:Milvus 对向量检索做了极致优化,百万级数据毫秒级响应;
- 扩展性:支持水平扩容,可适配从万级到亿级的向量数据场景。
这个案例完整覆盖了大数据量下向量数据库的集成、使用和优化,你可以基于此扩展到生产环境(如增加权限控制、限流、监控等)。
更多推荐


所有评论(0)