1. 项目概述:构建基于SpringAI的本地知识库系统
最近在探索大模型应用落地方案时,我实现了一个基于SpringAI框架的本地知识库系统。这个系统整合了Qwen3-8B大语言模型、bge-large-zh-v1.5嵌入模型和Milvus向量数据库,能够实现高效的语义检索和智能问答功能。整个项目从环境搭建到代码实现耗时约两周,期间踩了不少坑,也积累了一些实战经验,现在把完整方案分享给大家。
这个系统特别适合需要构建垂直领域知识库的场景,比如企业内部文档检索、学术资料查询等。相比直接使用公有云API的方案,本地部署的优势在于数据隐私有保障,且可以针对特定领域数据进行优化。系统架构上采用了经典的RAG(Retrieval-Augmented Generation)模式,通过向量检索获取相关文档片段,再交给大模型生成最终回答。
2. 环境准备与模型部署
2.1 硬件与基础环境要求
要运行这个系统,你需要准备以下环境:
- 显卡:至少24GB显存的NVIDIA显卡(如RTX 3090/4090),因为Qwen3-8B模型需要约16GB显存,bge-large-zh嵌入模型需要约4GB
- 内存:建议32GB以上,处理大型数据集时内存消耗较大
- 存储:至少50GB可用空间,用于存放模型文件和数据集
- 操作系统:Linux系统(如Ubuntu 20.04+)或WSL2环境
- Python环境:3.8+版本,建议使用conda创建虚拟环境
提示:如果显存不足,可以考虑使用量化版的Qwen3模型(如4bit量化版),但会牺牲一些生成质量。
2.2 模型部署实战
2.2.1 Qwen3-8B大模型部署
我选择使用vLLM框架来部署Qwen3-8B模型,这是目前性能最好的开源推理框架之一。部署命令如下:
bash复制nohup python -m vllm.entrypoints.openai.api_server \
--model /code/models/Qwen/Qwen3-8B \
--served-model-name qwen3-8b \
--max-model-len 8k \
--host 0.0.0.0 \
--port 6006 \
--dtype bfloat16 \
--gpu-memory-utilization 0.8 \
--enable-auto-tool-choice \
--tool-call-parser hermes &
关键参数说明:
--dtype bfloat16:使用bfloat16精度,在保持模型质量的同时减少显存占用--gpu-memory-utilization 0.8:限制GPU内存使用率为80%,防止OOM--max-model-len 8k:支持最大8k上下文长度
2.2.2 bge-large-zh嵌入模型部署
同样使用vLLM部署嵌入模型:
bash复制nohup python -m vllm.entrypoints.openai.api_server \
--model /code/models/BAAI/bge-large-zh-v1.5 \
--served-model-name bge-large-zh \
--host 0.0.0.0 \
--port 6007 \
--dtype bfloat16 \
--gpu-memory-utilization 0.4 \
--max-model-len 512 &
注意嵌入模型的max-model-len设置为512,这是大多数嵌入模型的标准输入长度限制。
2.2.3 Milvus向量数据库安装
使用Docker快速安装Milvus单机版:
bash复制curl -sfL https://raw.githubusercontent.com/milvus-io/milvus/master/scripts/standalone_embed.sh -o standalone_embed.sh
bash standalone_embed.sh start
安装完成后,可以通过docker ps检查容器是否正常运行。Milvus默认监听19530端口。
3. 项目配置与核心代码实现
3.1 SpringBoot项目初始化
创建一个新的SpringBoot项目,添加以下关键依赖:
xml复制<dependencies>
<!-- SpringAI核心依赖 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
<!-- 向量检索增强相关 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-advisors-vector-store</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-rag</artifactId>
</dependency>
<!-- Milvus向量存储 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-vector-store-milvus</artifactId>
</dependency>
<!-- 文档处理 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-tika-document-reader</artifactId>
</dependency>
</dependencies>
3.2 应用配置详解
application.yml配置文件:
yaml复制spring:
ai:
openai:
chat:
options:
model: qwen3-8b
base-url: http://192.168.10.102:6006/
embedding:
options:
model: bge-large-zh
base-url: http://192.168.10.102:6007/
api-key: sk-1234567890abcd # 任意值,本地部署不需要真实key
vectorstore:
milvus:
client:
host: 192.168.47.130
port: 19530
token: root:Milvus
database-name: default
embedding-dimension: 1024 # bge-large-zh的向量维度
collection-name: msj_ai
initialize-schema: true
重要配置说明:
embedding-dimension必须与嵌入模型输出的向量维度一致initialize-schema设为true会自动创建Milvus集合- 本地部署时api-key可以随意填写,但字段必须存在
3.3 核心组件配置类
java复制@Configuration
@RequiredArgsConstructor
public class ChatConfig {
final MilvusVectorStore vectorStore;
@Bean
public ChatClient chatClient(ChatModel chatModel) {
return ChatClient.builder(chatModel)
.defaultSystem("你作为一名专业的AI助手,请根据用户提示信息回答问题。")
.build();
}
@Bean
public RetrievalAugmentationAdvisor retrievalAugmentationAdvisor() {
VectorStoreDocumentRetriever retriever = VectorStoreDocumentRetriever.builder()
.vectorStore(vectorStore)
.similarityThreshold(0.5) // 相似度阈值
.topK(5) // 返回最相似的5个片段
.build();
return RetrievalAugmentationAdvisor.builder()
.documentRetriever(retriever)
.build();
}
}
3.4 数据加载实现
数据加载是知识库系统的关键环节,我使用了三国演义问答数据集:
java复制@Slf4j
@Component
@RequiredArgsConstructor
public class LoadData {
final MilvusVectorStore vectorStore;
@PostConstruct
public void loadData() throws IOException {
ClassPathResource resource = new ClassPathResource("train.json");
String content = new String(resource.getInputStream().readAllBytes());
// 文档分块处理
TokenTextSplitter splitter = TokenTextSplitter.builder()
.withChunkSize(512)
.withMinChunkSizeChars(200)
.withKeepSeparator(true)
.build();
var chunks = splitter.split(List.of(new Document(content)));
vectorStore.add(chunks);
log.info("成功加载{}个文本块到向量数据库", chunks.size());
}
}
分块策略对检索效果影响很大,关键参数:
chunkSize: 512:与嵌入模型的最大输入长度一致minChunkSizeChars: 200:避免产生过小的文本片段
3.5 问答接口实现
REST接口提供了问答功能:
java复制@RestController
@RequestMapping
@RequiredArgsConstructor
public class TalkController {
final ChatClient chatClient;
final RetrievalAugmentationAdvisor retrievalAugmentationAdvisor;
@GetMapping("/talk")
public Flux<String> talk(@RequestParam("question") String question) {
return chatClient.prompt(question)
.advisors(retrievalAugmentationAdvisor)
.stream()
.content();
}
}
这个接口实现了完整的RAG流程:
- 接收用户问题
- 通过嵌入模型将问题转换为向量
- 在Milvus中检索相似文档片段
- 将检索结果和原始问题一起发送给Qwen3生成最终回答
4. 效果优化与问题排查
4.1 性能优化技巧
在实际使用中,我总结了几点优化经验:
- 批量处理请求:当需要处理大量问题时,可以先批量生成嵌入向量,再统一检索
java复制List<String> questions = Arrays.asList("问题1", "问题2", "问题3");
List<Embedding> embeddings = embeddingModel.embed(questions);
- 调整检索参数:根据场景调整相似度阈值和返回数量
yaml复制similarityThreshold: 0.5 # 值越大匹配越严格
topK: 5 # 返回结果数量
- 启用缓存:对常见问题可以缓存嵌入向量和回答
4.2 常见问题解决方案
问题1:检索结果不准确
- 检查嵌入模型是否匹配(bge-large-zh模型需要使用bge-large-zh-v1.5)
- 确认文本分块策略合理,避免块过大或过小
- 调整相似度阈值,通常0.4-0.6之间效果较好
问题2:响应速度慢
- 检查vLLM服务是否启用了GPU加速
- 减少
topK参数值 - 升级Milvus配置或使用集群版
问题3:显存不足
- 使用
--gpu-memory-utilization参数限制内存使用 - 考虑使用量化模型
- 关闭不必要的服务释放显存
4.3 扩展建议
这个基础框架可以进一步扩展:
- 多模态支持:接入视觉模型处理图片、PDF等非文本数据
- 增量更新:实现向量数据库的增量更新机制
- 缓存层:添加Redis缓存高频问题和答案
- 评估体系:构建自动化评估流程监控系统效果
5. 项目部署与测试
5.1 完整启动流程
- 启动模型服务:
bash复制# Qwen3-8B
nohup python -m vllm... &
# bge-large-zh
nohup python -m vllm... &
# Milvus
bash standalone_embed.sh start
- 启动SpringBoot应用:
bash复制mvn spring-boot:run
- 测试问答接口:
bash复制curl "http://localhost:8081/talk?question=诸葛亮在哪场战役中使用了空城计"
5.2 测试结果示例
对于三国演义相关问题,系统能够给出准确回答:
code复制问:关羽的武器是什么?
答:关羽的武器是青龙偃月刀,又名冷艳锯,重八十二斤。
问:诸葛亮七擒孟获发生在哪里?
答:诸葛亮七擒孟获的故事发生在南中地区,主要是现在的云南、贵州一带。
6. 项目总结与资源
这个项目完整实现了基于SpringAI的本地知识库系统,主要优势在于:
- 完全本地化部署,保障数据安全
- 使用最新的大模型和嵌入模型,效果优秀
- SpringAI框架简化了开发流程
- 代码结构清晰,易于扩展
项目完整代码已开源,包含:
- 完整的SpringBoot应用代码
- 部署脚本
- 测试数据集
- 详细配置示例
在实际使用中,建议根据具体场景调整以下方面:
- 文本分块策略(chunk size/overlap等)
- 检索参数(相似度阈值、返回数量)
- 系统提示词(system prompt)
- 模型参数(temperature等)