让大模型真正读懂你的私有数据告别“一本正经地胡说八道”我见过太多企业花大价钱上大模型项目结果却卡在同一个地方模型很聪明但对你公司的业务一窍不通。问它“咱们公司年假怎么休”它给你搬出一套劳动法通用条款——没错但没用。因为真正的答案藏在你们那几百页的员工手册里。这就是大模型的“知识截止”困境。而RAG检索增强生成正是目前成本最低、效果最好的解法。它不重新训练模型而是给模型配一个“外挂知识库”让它回答前先查资料。今天这篇实战我就用Spring AI带你从零搭建一套企业级RAG知识库系统。一、先搞懂RAG在干什么RAG全称Retrieval-Augmented Generation流程拆开就三步第一步索引建库。把企业文档切分成小片段通过Embedding模型转成向量存进向量数据库。第二步检索召回。用户提问时把问题也转成向量去向量库里找语义最相似的Top-K个文档片段。第三步生成回答。把检索到的片段作为“参考资料”塞给大模型让它基于这些资料生成答案。听起来不复杂对吧关键就在向量检索的精度和生成时的上下文组织。下面我们上代码。二、技术栈选型这套方案我实测过稳定可靠组件选型说明基础框架Spring Boot 3.2JDK 17必备AI框架Spring AI 1.0.0统一抽象省去各家SDK适配的麻烦向量数据库Milvus / 阿里云百炼生产用Milvus快速验证用内存版SimpleVectorStoreEmbedding模型text-embedding-v3 / BGE-small中英混合场景建议v31024维度够用大模型Qwen-Plus / GLM-4-Flash知识库场景选性价比高的三、项目初始化xml!-- pom.xml 核心依赖 -- properties spring-ai.version1.0.0/spring-ai.version /properties dependencies !-- Spring AI 核心 -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-core/artifactId /dependency !-- 阿里云百炼DashScope适配 -- dependency groupIdcom.alibaba.cloud.ai/groupId artifactIdspring-ai-alibaba-starter-dashscope/artifactId version1.0.0/version /dependency !-- Web 支持 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency /dependenciesyaml# application.yml spring: ai: dashscope: api-key: ${DASHSCOPE_API_KEY} # 环境变量别硬编码 chat: options: model: qwen-plus temperature: 0.1 # 知识库场景温度要低减少幻觉 embedding: options: model: text-embedding-v3避坑temperature建议0.1-0.3太高模型会“发挥过头”编造不存在的信息。四、核心代码实现4.1 文档处理与向量化存储javaService Slf4j public class KnowledgeBaseService { Autowired private EmbeddingModel embeddingModel; Autowired private VectorStore vectorStore; /** * 加载文档并写入向量库 */ public void loadDocuments(String filePath) { // 1. 读取文档 Resource resource new FileSystemResource(filePath); DocumentReader reader new TextReader(resource); ListDocument documents reader.read(); // 2. 切分文档512 token/块50 token重叠 TextSplitter splitter new TokenTextSplitter(512, 50); ListDocument chunks splitter.apply(documents); // 3. 向量化并存入 vectorStore.write(chunks); log.info(成功加载 {} 个文档片段, chunks.size()); } }分块大小直接影响检索精度。技术文档建议512 token运维手册可放宽到1024 tokenFAQ类则按问答对切分不用额外分块。4.2 检索生成RAG核心这是RAG的命脉关键在于把检索到的上下文正确注入Prompt。javaService Slf4j public class RagService { private final ChatClient chatClient; private final VectorStore vectorStore; public RagService(ChatClient.Builder chatClientBuilder, VectorStore vectorStore) { this.vectorStore vectorStore; // 构建带RAG增强的ChatClient this.chatClient chatClientBuilder .defaultAdvisors(new QuestionAnswerAdvisor(vectorStore)) .defaultSystem( 你是一个企业知识助手。请严格基于提供的上下文信息回答问题。 如果上下文中没有相关信息请直接回答根据现有知识库我无法回答这个问题。 不要编造任何信息。 ) .build(); } /** * 基于知识库回答问题 */ public String ask(String question) { return chatClient.call(question); } }就这样对Spring AI的QuestionAnswerAdvisor自动完成了三件事把用户问题向量化去向量库检索Top-K相关文档把检索结果拼进Prompt上下文如果你要更精细的控制比如调整检索数量或混合检索策略可以手动实现javapublic String askWithCustomRetrieval(String question) { // 1. 手动检索Top 5 SearchRequest request SearchRequest.builder() .topK(5) .similarityThreshold(0.7) .build(); ListDocument context vectorStore.search(question, request); // 2. 构建Prompt String contextText context.stream() .map(Document::getText) .collect(Collectors.joining(\n\n---\n\n)); String prompt 请基于以下参考资料回答问题 【参考资料】 %s 【问题】 %s 【要求】 1. 只基于参考资料回答 2. 如果参考资料没有相关信息明确说无法回答 3. 引用参考资料中的具体内容 .formatted(contextText, question); // 3. 调用大模型 return chatClient.call(prompt); }4.3 Controller接口javaRestController RequestMapping(/api/rag) public class RagController { Autowired private RagService ragService; PostMapping(/ask) public ResponseEntityString ask(RequestBody AskRequest request) { String answer ragService.ask(request.getQuestion()); return ResponseEntity.ok(answer); } Data public static class AskRequest { private String question; } }五、生产环境必做的3个优化1. 换掉内存向量库SimpleVectorStore只是内存版重启即失。生产环境务必换成 Milvus、Redis Stack 或云厂商的向量服务。yamlspring: ai: vectorstore: milvus: host: localhost port: 19530 embedding-dimension: 10242. 混合检索提升召回率纯向量检索可能漏掉精确关键词匹配。BM25 向量检索双路召回再通过RRF融合排序效果显著提升。yamlretrieval: type: hybrid vector_weight: 0.7 bm25_weight: 0.3 top_k: 20 rerank_top_n: 53. 流式输出改善体验大模型生成需要时间用SSE实现“打字机效果”javaPostMapping(value /chat/stream, produces MediaType.TEXT_EVENT_STREAM_VALUE) public FluxString streamChat(RequestBody AskRequest request) { return chatClient.prompt(request.getQuestion()) .stream() .content(); }六、效果如何某企业5000份技术文档改造前新员工平均花40分钟才能从文档堆里找到答案改造后3秒返回精准回答问答精度从40%提升到92%。RAG的精髓就一句话不让大模型凭记忆瞎编让它带着资料答题。整套代码核心不过几十行剩下的功夫都在文档切分策略、检索参数调优、Prompt工程这些细节里。建议你先跑通Demo再根据自家文档特点逐步打磨。