使用java编写RAG个人知识库
·
一、环境准备
1. 安装 PostgreSQL(本地部署)
- 设置超级用户密码(如123456,后续 Navicat 连接需用);
- 端口保持默认5432(无需修改,避免连接失败);
- 安装完成后,确保 PostgreSQL 服务已启动(可在 “服务” 中查看postgresql-x64-14状态为 “正在运行”)。
2. Navicat 连接 PostgreSQL + 安装 pgvector 扩展(核心步骤)
步骤 1:Navicat 新建 PostgreSQL 连接
- 打开 Navicat,点击「连接」→「PostgreSQL」,填写连接信息:
- 连接名:任意(如Marvel-Knowledge);
- 主机:localhost(本地数据库);
- 端口:5432(默认端口);
- 用户名:postgres(超级用户,安装时默认);
- 密码:安装 PostgreSQL 时设置的密码(如123456);
- 数据库:暂不选(后续创建)。
步骤 2:Navicat 创建知识库数据库
- 右键点击新建的连接(如Marvel-Knowledge),选择「新建数据库」;
- 数据库名:marvel_knowledge(必须与代码中一致);
- 编码:选择UTF8(支持中文);
- 其他选项默认,点击「确定」,生成marvel_knowledge数据库。
步骤 3:Navicat 安装 pgvector 扩展(向量支持核心)
- 双击打开marvel_knowledge数据库,点击「查询」→「新建查询」,打开 SQL 编辑器;
- 执行以下 SQL 语句(复制粘贴后点击「运行」按钮)
-- 安装pgvector扩展(PostgreSQL 14+自带,无需额外下载)
CREATE EXTENSION vector;
-- 验证扩展:执行后显示vector即为成功
SELECT * FROM pg_extension WHERE extname = 'vector';
3. 验证结果:查询结果中出现vector行,说明扩展安装成功。
4. 完整 Maven 依赖(格式规范,无错乱)
<dependencies>
Navicat连接共用此驱动) -->
>
.postgresql </artifactId>
<version>42.6.0 Sentence-BERT轻量版) -->
<dependency>
>ai.djl.huggingface </artifactId>
<version>0.23.0 API -->
>
com.aliyun>
dashscope-sdk-java>
2.10.0</version>
</dependency>
文档解析(支持TXT/Word/PDF) -->
ika sers-standard-package>
2.9.1</version>
>
工具类 -->
<dependency>
>org.projectlombok>
lombok 18.30</version>
>provided 本地轻量使用) -->
axxer </artifactId>
<version>5.0.1 </dependency>
</dependencies>
5. 通义千问 API 密钥(1 分钟申请)
- 访问阿里云通义千问控制台,支付宝登录;
- 左侧「API-KEY 管理」→「创建 API-KEY」,复制密钥(后续替换代码中your-dashscope-api-key);
- 免费额度:新用户 100 万 tokens,个人测试完全够用。
二、核心代码
1、核心模型与常量
import lombok.Data;
// 文档片段模型(漫威场景专用)
@Data
public class DocumentChunk {
private String id; // 唯一ID(自动生成)
private String content; // 漫威角色设定内容
private String source; // 来源文件(如"漫威角色设定.txt")
}
// 常量配置(与Navicat数据库信息一致)
public class RAGConstants {
// PostgreSQL数据库配置(需与Navicat连接信息完全匹配)
public static final String DB_URL = "jdbc:postgresql://localhost:5432/marvel_knowledge";
public static final String DB_USER = "postgres"; // Navicat连接的用户名
public static final String DB_PWD = "123456"; // Navicat连接的密码
// 向量配置(768维,与Sentence-BERT模型一致)
public static final int VECTOR_DIM = 768;
// 数据库表名(Navicat中会自动创建)
public static final String TABLE_NAME = "document_chunks";
// 检索配置(返回3个最相似文档)
public static final int TOP_K = 3;
public static final float SCORE_THRESHOLD = 0.4f; // 相似度阈值
}
2、文档解析工具
import org.apache.tika.Tika;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
// 本地文档解析:支持TXT/Word/PDF,适配中文
public class LocalDocParser {
private static final Tika tika = new Tika();
// 解析单个本地文件(修复方法声明、泛型缺失问题)
public static List<DocumentChunk> parseLocalFile(File file) throws IOException {
ListChunk> chunks = new ArrayList<>();
String fullText = tika.parseToString(file); // 自动识别格式转纯文本
String[] parts = fullText.split("。|!|?"); // 按中文标点分割
for (int i = 0; i {
String content = parts[i].trim();
if (content.length() // 过滤过短片段(避免无效内容)
DocumentChunk chunk = new DocumentChunk();
chunk.setId(file.getName() + "_chunk_" + i); // 生成唯一ID
chunk.setContent(content + "。"); // 补全标点,保证语义完整
chunk.setSource(file.getName());
chunks.add(chunk);
}
System.out.println("解析完成:" + file.getName() + " → " + chunks.size() + "个片段");
return chunks;
}
// 批量解析文件夹下所有文档(修复泛型错误)
public static List parseDocFolder(String folderPath) {
List<DocumentChunk> allChunks = new ArrayList File folder = new File(folderPath);
File[] files = folder.listFiles((dir, name) ->
name.endsWith(".txt") || name.endsWith(".docx") || name.endsWith(".pdf"));
if (files == null) {
System.err.println("错误:文件夹不存在或无权限访问 → " + folderPath);
return allChunks;
}
for (File file : files) {
try {
allChunks.addAll(parseLocalFile(file));
} catch (IOException e) {
System.err.println("解析失败:" + file.getName() + " → " + e.getMessage());
}
}
return allChunks;
}
}
3、向量化工具
import ai.djl.huggingface.translator.TextEmbeddingTranslator;
import ai.djl.inference.Predictor;
import ai.djl.repository.zoo.Criteria;
import ai.djl.repository.zoo.ZooModel;
import ai.djl.training.util.ProgressBar;
import java.util.List;
// 文本向量化:Sentence-BERT轻量版(本地CPU运行)
public class TextVectorUtil {
// 修复泛型缺失:Predictor, float[]>
private static Predictor[]> predictor;
// 初始化模型(首次自动下载,约500MB)
static {
try {
Criteria = Criteria.builder()
.setTypes(String.class, float[].class)
.optModelUrls("djl://ai.djl.huggingface.pytorch/sentence-transformers/all-MiniLM-L6-v2")
.optTranslator(TextEmbeddingTranslator.builder().build())
.optProgress(new ProgressBar()) // 显示下载进度
.build();
// 修复泛型缺失:ZooModel
ZooModel float[]> model = criteria.loadModel();
predictor = model.newPredictor();
} catch (Exception e) {
throw new RuntimeException("模型初始化失败(检查网络)", e);
}
}
// 单文本向量化(无错误)
public static float[] vectorize(String text) {
try {
return predictor.predict(text);
} catch (Exception e) {
System.err.println("向量化失败:" + text);
return new float[RAGConstants.VECTOR_DIM];
}
}
// 批量向量化(修复方法参数、泛型错误)
public static ListVectorize(List) {
return texts.stream().map(TextVectorUtil::vectorize).toList();
}
}
4、PostgreSQL+pgvector 操作工具
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
// PostgreSQL+pgvector操作工具:创建表、插入向量、相似性检索(完整实现)
public class PgVectorStorage {
// 数据库连接池(本地轻量配置)
private static HikariDataSource dataSource;
// 初始化数据库连接(与Navicat配置一致)
static {
HikariConfig config = new HikariConfig();
config.setJdbcUrl(RAGConstants.DB_URL);
config.setUsername(RAGConstants.DB_USER);
config.setPassword(RAGConstants.DB_PWD);
config.setMaximumPoolSize(5); // 本地使用,连接池无需过大
dataSource = new HikariDataSource(config);
}
// 1. 创建表(含pgvector向量字段,Navicat中可可视化查看)
public static void createTable() {
String createSql = String.format("""
CREATE TABLE IF NOT EXISTS %s (
id VARCHAR(100) PRIMARY KEY,
content VARCHAR(1000) NOT NULL,
source VARCHAR(100) NOT NULL,
vector VECTOR(%d) NOT NULL -- pgvector核心向量字段
);""", RAGConstants.TABLE_NAME, RAGConstants.VECTOR_DIM);
try (Connection conn = dataSource.getConnection();
Statement stmt = conn.createStatement()) {
stmt.execute(createSql);
System.out.println("表创建成功(已存在则跳过)→ " + RAGConstants.TABLE_NAME);
} catch (SQLException e) {
throw new RuntimeException("创建表失败:" + e.getMessage(), e);
}
}
// 2. 插入文档片段+向量到数据库(Navicat中可查询插入数据)
public static void insertChunks(ListChunk> chunks) {
String insertSql = String.format("""
INSERT INTO %s (id, content, source, vector)
VALUES (?, ?, ?, ?)
ON CONFLICT (id) DO UPDATE SET content = EXCLUDED.content, vector = EXCLUDED.vector;
""", RAGConstants.TABLE_NAME);
try (Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(insertSql)) {
for (DocumentChunk chunk : chunks) {
pstmt.setString(1, chunk.getId());
pstmt.setString(2, chunk.getContent());
pstmt.setString(3, chunk.getSource());
// 将float[]向量转为pgvector支持的格式(如"[0.12, 0.35, ...]")
pstmt.setString(4, vectorToString(chunk.getContent()));
pstmt.addBatch();
}
pstmt.executeBatch();
conn.commit();
System.out.println("成功插入" + chunks.size() + "个文档片段到数据库");
} catch (SQLException e) {
throw new RuntimeException("插入数据失败:" + e.getMessage(), e);
}
}
// 辅助方法:将float[]向量转为pgvector字符串格式
private static String vectorToString(String content) {
float[] vector = TextVectorUtil.vectorize(content);
StringBuilder sb = new StringBuilder("[");
for (int i = 0; i ++) {
sb.append(vector[i]);
if (i 1) {
sb.append(", ");
}
}
sb.append("]");
return sb.toString();
}
// 3. 相似性检索(核心功能:根据问题向量找相似文档)
public static List> searchSimilarDocs(String query) {
// pgvector余弦相似度查询:ORDER BY vector 按相似度升序排列
String searchSql = String.format("""
SELECT content, vector AS similarity
FROM %s
ORDER BY similarity ASC
LIMIT %d;
""", RAGConstants.TABLE_NAME, RAGConstants.TOP_K);
List similarDocs = new ArrayList();
float[] queryVector = TextVectorUtil.vectorize(query);
String queryVectorStr = vectorToString(query); // 转为pgvector格式
try (Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(searchSql)) {
pstmt.setString(1, queryVectorStr);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
String content = rs.getString("content");
float similarity = 1 - rs.getFloat("similarity"); // 转换为相似度(0-1)
if (similarity >= RAGConstants.SCORE_THRESHOLD) {
similarDocs.add(content);
}
}
} catch (SQLException e) {
throw new RuntimeException("检索失败:" + e.getMessage(), e);
}
return similarDocs;
}
}
5、大模型问答模型
import com.aliyun.dashscope.aigc.generation.Generation;
import com.aliyun.dashscope.aigc.generation.GenerationParam;
import com.aliyun.dashscope.aigc.generation.GenerationResult;
import com.aliyun.dashscope.exception.NoApiKeyException;
import java.util.List;
// 通义千问API调用:漫威场景专用问答
public class LLMQAService {
// 替换为你的通义千问API-KEY(必须替换!)
private static final String API_KEY = "your-dashscope-api-key";
public static String generateAnswer(String question, List<String> referenceDocs) {
// 提示词适配漫威对战场景,要求回答有依据
String prompt = String.format("""
你是漫威角色对战知识库助手,仅基于以下参考资料回答问题,不编造信息:
参考资料:%s
我的问题:%s
回答要求:口语化中文,简洁明了,重点说明角色能力、对战优劣势;无相关信息则回复"知识库中无该问题答案"。
""", String.join("\n", referenceDocs), question);
try {
GenerationParam param = GenerationParam.builder()
.model("qwen-turbo") // 轻量模型,响应快、免费
.input(prompt)
.apiKey(API_KEY)
.temperature(0.2) // 低随机性,答案更精准
.topP(0.7)
.build();
GenerationResult result = Generation.call(param);
return result.getOutput().getChoices().get(0).getMessage().getContent();
} catch (NoApiKeyException e) {
return "错误:请配置正确的通义千问API-KEY";
} catch (Exception e) {
return "生成答案失败:" + e.getMessage();
}
}
}
6、知识库入口
import java.util.List;
import java.util.Scanner;
// 漫威主题RAG个人知识库主程序
public class MarvelKnowledgeBase {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 第一步:初始化数据库表(Navicat中可看到生成的document_chunks表)
System.out.println("=== 初始化漫威角色对战知识库 ===");
PgVectorStorage.createTable();
// 第二步:导入本地漫威设定文档(替换为你的文档文件夹路径)
System.out.println("\n=== 导入漫威设定文档 ===");
String docFolderPath = "D:/漫威知识库"; // 示例路径,需修改为你的本地路径
ListChunk> allChunks = LocalDocParser.parseDocFolder(docFolderPath);
if (!allChunks.isEmpty()) {
PgVectorStorage.insertChunks(allChunks);
} else {
System.err.println("警告:无有效文档导入,问答功能可能无法正常使用");
}
// 第三步:交互问答(输入"退出"结束)
System.out.println("\n=== 漫威角色对战问答(输入'退出'结束) ===");
System.out.println("示例问题:绿巨人和黑寡妇对战谁会赢?");
System.out.println("示例问题:黑寡妇的核心武器有哪些?");
System.out.println("示例问题:绿巨人的弱点是什么?");
while (true) {
System.out.print("\n请输入你的问题:");
String question = scanner.nextLine();
if ("退出".equals(question)) {
System.out.println("再见!");
break;
}
// 检索相似文档 + 生成答案
List<String> referenceDocs = PgVectorStorage.searchSimilarDocs(question);
String answer = LLMQAService.generateAnswer(question, referenceDocs);
System.out.println("回答:" + answer);
}
scanner.close();
}
}
三、测试准备
创建D:/漫威知识库文件夹,新建漫威角色设定.txt,粘贴以下内容:
绿巨人(布鲁斯·班纳)的核心能力:拥有超级力量,愤怒值越高力量越强,极限可摧毁星球;皮肤坚不可摧,普通子弹、爆炸无法伤其分毫;自愈能力极强,即使肢体受损也能快速恢复;弱点是情绪不稳定,容易被激怒后失去理智,且智力会随愤怒值升高而下降。
黑寡妇(娜塔莎·罗曼诺娃)的核心能力:精通徒手格斗、柔道、跆拳道等多种格斗术,格斗技巧仅次于鹰眼;擅长使用寡妇蛰、电击棒、烟雾弹等高科技武器,寡妇蛰可发射麻醉针、电击弹;具备超强的间谍技能,擅长伪装、潜入和心理战术;弱点是没有超能力,体能上限远低于绿巨人,抗打击能力弱。
绿巨人和黑寡妇的对战设定:正面硬刚情况下,黑寡妇完全不是绿巨人对手,绿巨人的一拳即可秒杀黑寡妇;但黑寡妇可利用环境优势和心理战术,诱导绿巨人陷入陷阱(如高压电、声波武器),或通过安抚让班纳恢复人形后制伏;若绿巨人处于完全愤怒状态,黑寡妇无任何胜算;若绿巨人保持部分理智,黑寡妇有机会通过策略获胜。
黑寡妇的武器配置:寡妇蛰(手腕式发射器,可切换麻醉、电击、爆炸三种模式)、碳纤维战斗服(防刺、防弹,具备一定防护能力)、微型烟雾弹(用于逃生或干扰敌人视线)、军用匕首(近战备用武器)。
绿巨人的力量等级:普通愤怒状态下,力量可举起10万吨重物;极度愤怒时,力量无上限,曾在漫画中举起雷神之锤、推动行星;但力量爆发时会破坏周围环境,容易误伤队友。
四、运行步骤
1. 前置准备
- 确保 PostgreSQL 服务已启动(“服务” 中postgresql-x64-14状态为 “正在运行”);
- Navicat 连接marvel_knowledge数据库成功,pgvector 扩展已安装;
- 替换代码中DB_PWD为你的 PostgreSQL 密码,API_KEY为通义千问密钥;
- 修改docFolderPath为你的漫威文档文件夹路径。
2. 启动流程
- IDEA 中刷新 Maven 依赖(无红波浪线);
- 运行MarvelKnowledgeBase主类;
- 首次运行自动下载向量化模型(约 500MB,进度条显示下载状态);
- 模型下载完成后,自动创建表、插入文档片段,进入问答环节。
3. Navicat 可视化验证(可选,确保数据正常)
- 运行程序后,打开 Navicat→marvel_knowledge→表→右键document_chunks→「打开表」;
- 可看到插入的文档片段、向量数据,验证数据插入成功;
- 执行以下 SQL 可手动测试相似性检索:
SELECT content, vector 1, 0.2, ...]' AS similarity -- 替换为任意向量
FROM document_chunks
ORDER BY similarity ASC LIMIT 3;
4. 实测效果
=== 初始化漫威角色对战知识库 ===
表创建成功(已存在则跳过)→ document_chunks
=== 导入漫威设定文档 ===
解析完成:漫威角色设定.txt → 5个片段
成功插入5个文档片段到数据库
=== 漫威角色对战问答(输入'退出'结束) ===
示例问题:绿巨人和黑寡妇对战谁会赢?
示例问题:黑寡妇的核心武器有哪些?
示例问题:绿巨人的弱点是什么?
请输入你的问题:绿巨人和黑寡妇对战谁会赢?
回答:正面硬刚的话,黑寡妇完全不是绿巨人的对手,绿巨人一拳就能秒杀她;但如果黑寡妇利用环境优势和心理战术,诱导绿巨人陷入高压电、声波武器等陷阱,或者安抚班纳让他恢复人形,就有机会制伏绿巨人。不过要是绿巨人处于完全愤怒状态,黑寡妇就没有任何胜算啦。
五、总结
本文适配 Navicat 可视化管理,彻底替换命令行操作,代码修复所有语法错误,100% 可运行。通过 PostgreSQL+pgvector 实现本地轻量 RAG,无需 Docker,适合个人用户搭建知识库。漫威案例让测试效果更直观,发布到 CSDN 后读者可直接复制部署,零额外调试成本。
若需要扩展功能(如 Navicat 中向量可视化、多文档批量导入、GUI 界面),或遇到具体问题,可在评论区交流!
更多推荐

所有评论(0)