Java 实现 RAG 实战:给大模型外挂企业知识库(文档切分 + 向量检索 + 问答)

发布时间:2026/10/8 13:16:39
Java 实现 RAG 实战:给大模型外挂企业知识库(文档切分 + 向量检索 + 问答) 正文摘要大模型有知识截止日期、还会一本正经地胡说八道企业落地 AI 问答绕不开 RAG检索增强生成。本文用纯 Java 实现一条完整 RAG 链路文档加载与切分、文本向量化、余弦相似度检索、上下文组装与问答代码可直接运行不依赖重型框架。正文做企业知识库问答最常被问的一句话是“大模型不是什么都知道吗为什么还要自己存文档”因为大模型不知道你们公司的制度、你们产品的参数。RAG 的思路很简单先在你的文档里检索把相关内容拼给大模型再让它回答。这篇用 Java 完整实现一遍所有代码可直接跑。一、RAG 全链路长这样企业文档 → 切分 → 向量化 → 存向量库↓用户提问 → 向量化 → 相似度检索 → 命中片段↓拼进Prompt → 大模型 → 带来源的回答二、文档切分检索质量的地基切分粒度决定检索质量常用策略按段落切 滑动窗口 重叠public List splitDocument(String content, int chunkSize, int overlap) {List chunks new ArrayList();int start 0;while (start content.length()) {int end Math.min(start chunkSize, content.length());chunks.add(content.substring(start, end));if (end content.length()) break;start end - overlap; // 重叠防止切断语义}return chunks;}// 使用按150字切、重叠30字List chunks splitDocument(doc, 150, 30);踩坑记录 一开始按字符硬切一句话被切成两半检索全乱。后来改成 “先按换行分块再合并到接近 150 字”准确率明显提升。三、向量化与相似度检索不依赖向量库的最小实现生产用向量数据库如 Milvus、pgvector但原理用一段代码就能讲透public record VectorDoc(String id, String text, double[] vector) {}// 1. 向量化调用Embedding接口把文本转成向量示意public double[] embed(String text) {// POST /embeddings 返回 float[]维度以服务方为准如1024return llmClient.embed(text);}// 2. 余弦相似度最常用的向量距离public double cosineSimilarity(double[] a, double[] b) {double dot 0, normA 0, normB 0;for (int i 0; i a.length; i) {dot a[i] * b[i];normA a[i] * a[i];normB b[i] * b[i];}return dot / (Math.sqrt(normA) * Math.sqrt(normB) 1e-9);}// 3. Top-K检索全量扫描找最相似的K段生产换向量索引public List retrieve(List docs, double[] queryVec, int topK) {return docs.stream().sorted(Comparator.comparingDouble(d - -cosineSimilarity(d.vector(), queryVec))).limit(topK).toList();}生产环境一定要用向量数据库—— 全量扫描在几十万条文档时性能不可接受原理不变只是索引换了。四、组装上下文让大模型 “只答文档里有的”public String buildRagAnswer(String question, List hits) {// 1. 拼上下文把命中的片段按顺序拼接String context hits.stream().map(VectorDoc::text).collect(Collectors.joining(“\n—\n”));// 2. 拼系统提示词约束回答边界 String systemPrompt 你是一个企业知识库助手。请仅根据以下资料回答问题。 如果资料中没有相关内容请明确回答资料中未找到相关信息 不要编造。回答时注明信息来自哪份资料。 ; // 3. 调大模型 return llmClient.chat(systemPrompt \n【资料】\n context \n【问题】\n question);}关键设计 提示词里明确 “没有就说不没有不要编造”—— 这是 RAG 防幻觉的第一道闸。五、完整调用示例public class RagDemo {public static void main(String[] args) {// 1. 加载并切分企业文档String doc readFile(“公司考勤制度.txt”);List chunks splitDocument(doc, 150, 30);// 2. 向量化入库 ListVectorDoc docs chunks.stream() .map(c - new VectorDoc(uuid(), c, embed(c))) .toList(); // 3. 用户提问 → 检索 → 生成 String question 请假流程是什么; ListVectorDoc hits retrieve(docs, embed(question), 3); String answer buildRagAnswer(question, hits); System.out.println(answer); }}六、落地时的四个工程问题问题解法文档更新了怎么办增量切分 重向量化删除旧 chunk检索结果不准调切分粒度、调 topK、加 rerank 重排回答带幻觉收紧系统提示词 强制引用来源响应太慢向量库索引 缓存高频问题这套 RAG 我在北大青鸟长沙大计实训的 Java AI 项目里完整实现过从文档切分到检索到问答一次跑通。RAG 不神秘就是把 “找资料” 和 “问 AI” 两个环节串起来但每个环节都值得较真。正文相关问答QRAG 和微调有什么区别怎么选ARAG 是 “外挂知识库”不改模型、随时更新、可溯源微调是 “改变模型行为”成本高、更新慢。企业知识库场景首选 RAG微调用于风格 / 领域强约束场景。QJava 生态有没有现成的 RAG 框架A有如 LangChain4j、Spring AI都支持 Java。但建议先自己实现一遍理解原理再上框架 —— 否则排错都不知道从哪查。QEmbedding 模型选哪种A中文场景选中文优化过的 Embedding 模型如 bge 系列维度越高越精细但检索越慢。先跑通再根据准确率和性能权衡。QRAG 的检索准确率一般能达到多少A视文档质量和切分策略而定好的切分 重排在内部测试集上 Top-3 命中率可以到 85%-90%。没有绝对数字务必建自己的评测集验证。