大模型上知天文下知地理却对你的公司内部制度、产品文档、最新销售数据一无所知。它像一个饱读诗书却从不看报纸的聪明人面对新问题只能靠胡编乱造Hallucination。这就是RAG (Retrieval-Augmented Generation检索增强生成)要解决的问题。简单来说就是给 LLM 装上一个知识库当用户提问时先从知识库里找到相关资料再把这些资料喂给 LLM让它基于证据来回答。本文将手把手教你如何用 Spring AI 2.0基于 Spring Boot 4.1 和 Spring Framework 7.0搭建一个 RAG 应用让你的 LLM 不再一本正经地胡说八道。什么是 RAG为什么需要它想象一下你有一个非常聪明的学生LLM他能回答各种通用知识。但如果你问他我们公司去年Q4的营收是多少他肯定不知道。RAG 的作用就是●外部知识接入让 LLM 获取最新的、特定领域的、私有的知识。●减少幻觉LLM 基于检索到的事实进行回答降低一本正经胡说八道的风险。●可解释性可以追溯 LLM 的答案是基于哪些知识生成的。●成本效益无需每次都微调大模型通过更新知识库即可实现知识迭代。RAG vs 微调Fine-tuning微调适合调整模型的语气和风格而 RAG 适合注入事实知识。两者并不互斥实际项目中常常组合使用。简单来说知识频繁变更用 RAG风格固定用微调。RAG 的核心流程是●数据摄取 (Ingestion)将原始数据PDF、文档、网页等分割成小块chunk生成向量嵌入Embedding存储到向量数据库。●检索 (Retrieval)将用户问题也转化为向量在向量数据库中搜索最相关的文档片段。●生成 (Generation)将用户问题和检索到的文档片段一起作为上下文发送给 LLM 生成最终答案。Spring AI 2.0 RAG 快速上手Spring AI 2.0 对 RAG 的支持非常完善我们以一个简单的 PDF 知识库为例。1. 引入依赖确保你的 Spring Boot 项目基于4.1版本并引入 Spring AI 2.0 的 BOM 及所需 Starter。Spring AI 2.0 统一了 artifact 命名Starter 依赖以 spring-ai-starter- 为前缀。dependencyManagement dependencies dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-bom/artifactId version2.0.0/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement dependencies !-- OpenAI 模型 -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-model-openai/artifactId /dependency !-- PgVector 向量数据库 -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-vector-store-pgvector/artifactId /dependency !-- Spring AI RAG 模块 -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-rag/artifactId /dependency !-- PostgreSQL 驱动 -- dependency groupIdorg.postgresql/groupId artifactIdpostgresql/artifactId scoperuntime/scope /dependency !-- Web -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- PDF 读取器 -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-pdf-document-reader/artifactId /dependency /dependencies注意Spring AI 2.0 将 RAG 能力拆到了独立的 spring-ai-rag 模块。使用 RetrievalAugmentationAdvisor 必须引入此依赖。如果只用更简单的 QuestionAnswerAdvisor引入 spring-ai-vector-store-advisor 即可。2. 配置 Embedding 模型和 PgVector在 application.properties 中配置 OpenAI API Key 和 PgVector 连接信息。前置条件确保已安装 PostgreSQL 并启用 pgvector 扩展CREATE EXTENSION IF NOT EXISTS vector;然后配置 Spring AI# OpenAI 配置 spring.ai.openai.api-key${OPENAI_API_KEY} spring.ai.openai.chat.options.modelgpt-4o-mini spring.ai.openai.embedding.options.modeltext-embedding-3-small # 数据源 spring.datasource.urljdbc:postgresql://localhost:5432/rag_db spring.datasource.usernameuser spring.datasource.passwordpassword spring.datasource.driver-class-nameorg.postgresql.Driver # PgVector 配置 spring.ai.vectorstore.pgvector.index-typeIVFFLAT spring.ai.vectorstore.pgvector.distance-typeCOSINE spring.ai.vectorstore.pgvector.dimension1536 spring.ai.vectorstore.pgvector.initialize-schematrue踩坑提醒VectorStore 默认不会自动建表。必须设置 initialize-schematrue否则启动报错。这是新手最常遇到的第一个坑。3. 数据摄取 (Ingestion)我们将 PDF 文档读取、分割然后生成 Embedding 存入 PgVector。Spring AI 的 ETL 框架将这个过程抽象为DocumentReader读取→ DocumentTransformer分割→ DocumentWriter写入。Component public classDataIngestionServiceimplementsCommandLineRunner { private finalVectorStore vectorStore; Value(classpath:/docs/sample.pdf) privateResource pdfResource; publicDataIngestionService(VectorStore vectorStore) { this.vectorStore vectorStore; } Override public voidrun(String... args) throwsException { // 1. 读取 PDF按页 PagePdfDocumentReader pdfReader newPagePdfDocumentReader(pdfResource); ListDocument documents pdfReader.get(); // 2. 分割文档 TokenTextSplitter textSplitter TokenTextSplitter.builder() .defaultChunkSize(800) .minChunkSizeChars(350) .minChunkLengthToEmbed(5) .maxNumChunks(10000) .keepSeparator(true) .build(); ListDocument chunks textSplitter.apply(documents); // 3. 写入向量库 vectorStore.add(chunks); System.out.println(摄取完成共 chunks.size() 个 chunk。); } }原理vectorStore.add(chunks) 内部会自动调用 EmbeddingModel 将文本转为向量连同元数据一起写入数据库不需要手动调用 EmbeddingModel。ETL 链式写法如果喜欢函数式风格三步可以浓缩为一行vectorStore.accept(textSplitter.apply(pdfReader.get()));4. RAG 问答服务Spring AI 2.0 提供了两种 RAG Advisor适用于不同复杂度的场景。方式一QuestionAnswerAdvisor简单快捷最简单的 RAG 方案——直接拿用户问题去向量库做相似度搜索把结果拼到 prompt 中发给 LLM。适合快速验证。RestController public classSimpleRagChatController { private finalChatClient chatClient; publicSimpleRagChatController(ChatClient.Builder builder, VectorStore vectorStore) { this.chatClient builder .defaultAdvisors(QuestionAnswerAdvisor.builder(vectorStore) .searchRequest(SearchRequest.builder() .similarityThreshold(0.75) .topK(5) .build()) .build()) .build(); } GetMapping(/rag/simple) publicStringchat(RequestParam(defaultValue \u4ec0\u4e48\u662f Spring AI\uff1f) String message) { return chatClient.prompt().user(message).call().content(); } }方式二RetrievalAugmentationAdvisor模块化、可扩展Spring AI 2.0 推荐的模块化 RAG 方案灵感来自论文 Modular RAG。将 RAG 流程拆解为四个可独立定制的阶段。重要RetrievalAugmentationAdvisor 没有接受 VectorStore 的直接构造函数必须通过 builder VectorStoreDocumentRetriever 构建。RestController public classRagChatController { private finalChatClient chatClient; publicRagChatController(ChatClient.Builder builder, VectorStore vectorStore) { Advisor ragAdvisor RetrievalAugmentationAdvisor.builder() .documentRetriever(VectorStoreDocumentRetriever.builder() .vectorStore(vectorStore) .similarityThreshold(0.50) .topK(5) .build()) .build(); this.chatClient builder.defaultAdvisors(ragAdvisor).build(); } GetMapping(/rag/chat) publicStringchat(RequestParam(defaultValue \u4ec0\u4e48\u662f Spring AI\uff1f) String message) { return chatClient.prompt().user(message).call().content(); } }默认行为RetrievalAugmentationAdvisor 默认不允许检索结果为空没检索到文档时会指示模型不要回答。如果希望即使没检索到也让模型用自身知识回答可以配置 allowEmptyContextRetrievalAugmentationAdvisor.builder() .documentRetriever(...) .queryAugmenter(ContextualQueryAugmenter.builder() .allowEmptyContext(true) .build()) .build();5. 运行与测试启动应用后DataIngestionService 会自动摄取 sample.pdf。然后访问●/rag/simple?message你的问题 — 使用 QuestionAnswerAdvisor●/rag/chat?message你的问题 — 使用 RetrievalAugmentationAdvisorSpring AI 2.0 模块化 RAG 架构RetrievalAugmentationAdvisor 的强大之处在于模块化设计。整个 RAG 流程被拆为四个阶段阶段一Pre-Retrieval检索前— 对用户查询预处理提升检索质量。●RewriteQueryTransformer用 LLM 改写查询使其更适合向量检索。●CompressionQueryTransformer将多轮对话历史压缩为一句独立查询。●TranslationQueryTransformer将查询翻译为 Embedding 模型支持的语言。●MultiQueryExpander将一个查询扩展为多个语义变体增加召回率。Advisor advisor RetrievalAugmentationAdvisor.builder() .queryTransformers(RewriteQueryTransformer.builder() .chatClientBuilder(chatClientBuilder) .build()) .documentRetriever(VectorStoreDocumentRetriever.builder() .vectorStore(vectorStore) .build()) .build();阶段二Retrieval检索— 从数据源获取相关文档。●VectorStoreDocumentRetriever基于向量相似度检索最常用。●支持元数据过滤Filter Expression。阶段三Post-Retrieval检索后— 对检索结果后处理。●重排 (Re-ranking)用 rerank 模型对结果重新排序。●去重与合并ConcatenationDocumentJoiner 合并多路召回结果。●文档压缩去除冗余内容减少 token 消耗。阶段四Generation生成— 将检索结果注入 prompt。●ContextualQueryAugmenter将文档拼接为上下文注入用户问题前。高级 RAG 示例查询改写 空上下文下面是一个更接近生产环境的配置包含查询改写和空上下文处理Bean publicAdvisoradvancedRagAdvisor(ChatClient.Builder builder, VectorStore vectorStore) { returnRetrievalAugmentationAdvisor.builder() .queryTransformers(RewriteQueryTransformer.builder() .chatClientBuilder(builder.build().mutate()) .build()) .documentRetriever(VectorStoreDocumentRetriever.builder() .vectorStore(vectorStore) .similarityThreshold(0.50) .topK(5) .build()) .queryAugmenter(ContextualQueryAugmenter.builder() .allowEmptyContext(true) .build()) .build(); }小技巧使用 QueryTransformer 时建议将 ChatClient 的 temperature 设为 0.0以获得更确定性的改写结果。RAG 最佳实践与踩坑点1. 分块策略 (Chunking Strategy)●保留语义完整尽量按段落、章节分割避免将完整论述拆到两个 chunk 中。●重叠块 (Overlap)相邻 chunk 之间增加少量重叠如 50-100 tokens避免关键信息被切断。●按文档类型选择读取器PagePdfDocumentReader按页、ParagraphPdfDocumentReader按段落、MarkdownDocumentReader、TikaDocumentReader支持 DOCX、PPTX、HTML 等。●Chunk 大小权衡太小丢上下文太大会稀释相似度并浪费 token。建议 500-1000 tokens 起步。2. 向量数据库与 Embedding 模型选择●向量数据库Spring AI 2.0 支持 PgVector、Redis、Chroma、Milvus、Qdrant、Elasticsearch、MongoDB Atlas、Pinecone、Weaviate 等 20 多种。已用 PostgreSQL 的项目PgVector 成本最低。●Embedding 模型中文场景推荐 DeepSeek、智谱 AI、月之暗面、百度千帆等国产模型。注意不同模型维度不同需对应配置 dimension。3. 检索质量优化●多路召回结合关键词搜索BM25、元数据过滤等方式。MultiQueryExpander 可扩展查询变体提升召回率。●重排 (Re-ranking)用 rerank 模型对初步结果重新排序。可通过实现 DocumentPostProcessor 自定义。●查询改写用 RewriteQueryTransformer 或 CompressionQueryTransformer 处理口语化、模糊或带指代的提问。●元数据过滤用 FilterExpression 按文档类型、时间范围、部门过滤。4. Advisor 的执行顺序RetrievalAugmentationAdvisor 默认在用户消息发送到模型前执行。如果同时使用 MessageChatMemoryAdvisor 等其他 Advisor注意通过 order 控制执行顺序this.chatClient builder .defaultAdvisors( MessageChatMemoryAdvisor.builder(chatMemory).order(1), RetrievalAugmentationAdvisor.builder() .documentRetriever(...) .build().order(2) ) .build();5. 性能与成本●缓存高频问题结合语义缓存显著提升性能降低成本。●异步摄取大规模数据摄取改为手动触发的 API 或定时任务避免阻塞启动。●LLM 选型通用问答用 gpt-4o-mini复杂任务再考虑 gpt-4o。●控制 Top-K一般 3-5 个 chunk 即可过多会浪费 token。●文档压缩用 DocumentPostProcessor 做摘要压缩减少 token 消耗。6. 数据更新与增量同步●增量摄入通过文档元数据文件 hash、更新时间判断哪些需要重新处理。●删除旧数据更新时先删旧 chunk 再写新的。VectorStore.delete() 支持按 ID 或 Filter 删除。●版本管理元数据中记录版本号方便回滚和 A/B 测试。总结RAG 是 LLM 走向生产可用的关键一步。通过 Spring AI 2.0Java 开发者可以非常优雅地集成 RAG 能力让你的 AI 应用不仅聪明更博学。回顾本文关键点●RAG 解决 LLM 知识盲区和幻觉问题通过外部知识注入提升回答质量。●Spring AI 2.0 提供完整 RAG 体系DocumentReader → TokenTextSplitter → VectorStore → RetrievalAugmentationAdvisor。●两种 Advisor 各有适用场景QuestionAnswerAdvisor 简单快捷RetrievalAugmentationAdvisor 模块化可扩展。●RetrievalAugmentationAdvisor 必须用 builder VectorStoreDocumentRetriever 构建不能直接传入 VectorStore。●RAG 是模块化的Pre-Retrieval、Retrieval、Post-Retrieval、Generation 四阶段均可独立定制。●分块策略、模型选择、检索质量、Advisor 顺序、性能优化、数据同步是生产环境重点。希望这篇文章能帮助你在 Java 世界里给 LLM 装上一个强大的知识库