你以为“把文档喂给模型”就叫 RAG?那它为啥还会一本正经地胡说八道?

举报
bug菌 发表于 2026/01/13 11:00:52 2026/01/13
【摘要】 🏆本文收录于《滚雪球学SpringBoot 3》:https://blog.csdn.net/weixin_43970743/category_12795608.html,专门攻坚指数提升,本年度国内最系统+最专业+最详细(永久更新)。  本专栏致力打造最硬核 SpringBoot3 从零基础到进阶系列学习内容,🚀均为全网独家首发,打造精品专栏,专栏持续更新中…欢迎大家订阅持续学习。...

🏆本文收录于《滚雪球学SpringBoot 3》:https://blog.csdn.net/weixin_43970743/category_12795608.html,专门攻坚指数提升,本年度国内最系统+最专业+最详细(永久更新)。
  
本专栏致力打造最硬核 SpringBoot3 从零基础到进阶系列学习内容,🚀均为全网独家首发,打造精品专栏,专栏持续更新中…欢迎大家订阅持续学习。 如果想快速定位学习,可以看这篇【SpringBoot3教程导航帖】https://blog.csdn.net/weixin_43970743/article/details/151115907,你想学习的都被收集在内,快速投入学习!!两不误。
  
若还想学习更多,可直接前往《滚雪球学SpringBoot(全版本合集)》:https://blog.csdn.net/weixin_43970743/category_11599389.html,涵盖SpringBoot所有版本教学文章。

演示环境说明:

  • 开发工具:IDEA 2021.3
  • JDK版本: JDK 17(推荐使用 JDK 17 或更高版本,因为 Spring Boot 3.x 系列要求 Java 17,Spring Boot 3.5.4 基于 Spring Framework 6.x 和 Jakarta EE 9,它们都要求至少 JDK 17。)
  • Spring Boot版本:3.5.4(于25年7月24日发布)
  • Maven版本:3.8.2 (或更高)
  • Gradle:(如果使用 Gradle 构建工具的话):推荐使用 Gradle 7.5 或更高版本,确保与 JDK 17 兼容。
  • 操作系统:Windows 11

1) RAG(Retrieval-Augmented Generation)核心原理解析

一句话讲透 RAG:先找“相关材料”,再让模型“基于材料回答”
它解决的不是“模型会不会说”,而是“模型说的有没有根据”。

一个可落地的 RAG 流程通常长这样:

  1. Query 理解(可选):对用户问题做改写、扩展关键词
  2. 检索(Retrieval):把问题向量化(Embedding),去向量库做相似度搜索
  3. 构造上下文(Context Building):取 Top-K 文档片段 + 元数据(来源、时间、权限、标题)
  4. 生成(Generation):把“问题 + 检索结果片段”塞进 Prompt,让 LLM 输出
  5. 可追溯(Grounding):回答里带引用/出处(企业场景非常重要)

RAG 的“灵魂”其实就两句话:

  • 材料找得准不准(检索质量)
  • 模型是不是被迫“只依据材料说话”(提示词与约束)

2) Vector Database:Redis / Chroma / Pinecone 怎么选?

选向量库别一上来就“哪个最火用哪个”,先问自己两个问题:
数据在不在内网?吞吐和成本谁更敏感?(这句话很土,但很救命😅)

2.1 Redis Vector Store(偏“企业内网 + 低延迟 + 运维熟”)

Spring AI 的 RedisVectorStore 基于 Redis Stack(RedisJSON + RediSearch)来存储向量与元数据,并通过 RediSearch 做向量相似度检索。

适合:

  • 你公司已经有 Redis/Redis Stack 运维体系
  • 想把向量库当“基础设施”放内网
  • 需要低延迟、可控性强

注意:

  • 需要 Redis Stack 相关能力(RediSearch / RedisJSON)

2.2 Chroma(偏“本地/中小规模/研发快速验证”)

Spring AI 提供 Chroma Vector Store 的 Spring Boot 自动配置(starter 一把梭)。
Chroma 本身定位就是开源嵌入数据库:存向量、存元数据、支持过滤。

适合:

  • PoC / 内部工具 / 小团队快速跑通
  • 本地或单机部署优先
  • 不想引入重型基础设施

2.3 Pinecone(偏“云托管/扩展性/省运维”)

Spring AI 也提供 Pinecone Vector Store 的集成与自动配置。
Pinecone 是云端向量数据库,省心但意味着数据出网(看合规要求)。

适合:

  • 云优先、规模增长快、想少折腾运维
  • 允许数据走云(或做脱敏/分级)

3) ETL Pipeline:用 Spring AI Reader 解析文档并 Embedding

企业知识库 RAG 的成败,80% 在 ETL。真的。
你检索不准,模型再聪明也只能“胡说得更像真的”。

Spring AI 官方把 ETL pipeline 明确拆成三段:

  • DocumentReader(读取文档,产出 List<Document>
  • DocumentTransformer(转换/切分/清洗)
  • DocumentWriter(写入存储,通常是 VectorStore)

3.1 一个“可跑”的最小 ETL:读取 → 切分 → 向量化写入

下面示例用“伪代码风格但贴近 Spring AI 真实组件命名”,你可以直接按你选的 VectorStore 替换依赖与配置。

pom.xml(示例:Chroma)

<dependency>
  <groupId>org.springframework.ai</groupId>
  <artifactId>spring-ai-starter-vector-store-chroma</artifactId>
</dependency>

Spring AI 文档明确 Chroma 的 starter 依赖这样引入。

ETL 服务:

import org.springframework.ai.document.Document;
import org.springframework.ai.reader.DocumentReader;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

@Service
public class KnowledgeIngestService {

  private final VectorStore vectorStore;

  public KnowledgeIngestService(VectorStore vectorStore) {
    this.vectorStore = vectorStore;
  }

  public void ingest(DocumentReader reader, String sourceName) {
    // 1) 读取文档 -> Document 列表(Spring AI ETL 概念):contentReference[oaicite:8]{index=8}
    List<Document> docs = reader.get();

    // 2) 切分:强烈建议切块(chunk),否则检索会很飘
    var splitter = new TokenTextSplitter(); // 你可以配置 chunkSize/overlap
    List<Document> chunks = splitter.apply(docs);

    // 3) 写入向量库:VectorStore 会调用 EmbeddingModel 生成向量(配置在 Spring AI 里)
    // 额外:补齐元数据,后续用于引用与权限过滤
    chunks.forEach(d -> d.getMetadata().putAll(Map.of(
        "source", sourceName
        // 还可以加:docId、title、updatedAt、dept、aclLevel...
    )));

    vectorStore.add(chunks);
  }
}

重点:ETL 三段式不是“学院派概念”,它就是为了让你能把“读取/切分/存储”拆开、可替换、可复用。

3.2 切分策略(chunking)别靠感觉:给你一个工程化标准

经验规则(不绝对,但好用):

  • Chunk 太大:检索命中但上下文冗余,LLM 容易跑偏
  • Chunk 太小:命中碎片化,信息不足,答非所问
  • 一般从 300–800 tokens(或相近字符量)起步,配 10–20% overlap,再用离线评测调参

4) 实战:基于企业私有知识库的问答系统(Spring Boot 3)

这里给你一套“企业内网问答”的标准落地架构:

4.1 架构图(文字版)

  • Ingestion 服务:文档源(Wiki/网盘/数据库/工单)→ Reader → Splitter → VectorStore
  • Query 服务:用户问题 → Embedding → VectorStore similarity search → 拼 prompt → LLM 生成
  • 治理组件:权限过滤、来源引用、日志与评测、缓存、失败降级

4.2 Query 侧代码:检索 + 组装上下文 + 生成回答(带引用)

假设你已经有 VectorStore,并且 EmbeddingModel / ChatModel 都在 Spring AI 里配好了。

import org.springframework.ai.document.Document;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/rag")
public class RagQaController {

  private final VectorStore vectorStore;
  private final org.springframework.ai.chat.client.ChatClient chatClient;

  public RagQaController(VectorStore vectorStore,
                         org.springframework.ai.chat.client.ChatClient chatClient) {
    this.vectorStore = vectorStore;
    this.chatClient = chatClient;
  }

  @GetMapping("/ask")
  public RagAnswer ask(@RequestParam String q) {

    // 1) 向量检索:topK + 可选过滤(部门/文档类型/权限级别等)
    List<Document> hits = vectorStore.similaritySearch(
        SearchRequest.query(q).withTopK(5)
        // .withFilterExpression("aclLevel <= 2 AND dept == 'finance'")
    );

    // 2) 组装上下文:把命中文档拼成“证据区”
    String evidence = hits.stream()
        .map(d -> "SOURCE=" + d.getMetadata().getOrDefault("source", "unknown")
            + "\n" + d.getContent())
        .collect(Collectors.joining("\n\n---\n\n"));

    // 3) 生成:强约束模型“只基于证据回答”
    String prompt = """
        你是企业知识库助手。请严格只依据【证据】回答问题。
        如果证据不足,请回答“根据现有资料无法确定”,并说明缺少哪些信息。
        
        【问题】
        %s
        
        【证据】
        %s
        
        【输出要求】
        1) 先给结论(1-3 句)
        2) 再给依据(引用 SOURCE)
        """.formatted(q, evidence);

    String answer = chatClient.prompt(prompt).call().content();

    // 4) 返回:把引用也带回去,便于前端展示“来源”
    List<RagCitation> citations = hits.stream()
        .map(d -> new RagCitation(
            String.valueOf(d.getMetadata().getOrDefault("source", "unknown"))
        ))
        .toList();

    return new RagAnswer(answer, citations);
  }

  public record RagAnswer(String answer, List<RagCitation> citations) {}
  public record RagCitation(String source) {}
}

这段实战代码里,真正决定“企业能不能用”的是两点:

  1. prompt 里强制“只依据证据”
  2. 返回里带 citations(让用户能点回原文)

4.3 企业场景必做的三件事(不做就等着挨骂😂)

  1. 权限过滤(ACL)

    • 向量库里每个 chunk 都要带元数据:部门、密级、可见人群
    • 检索时用 filter expression 限制(不同向量库能力不同)
  2. 可观测性(Observability)

    • 记录:query、topK 命中、最终 prompt 长度、token 消耗、延迟
    • 否则“为什么这次答错?”你只能靠猜
  3. 评测闭环(Evaluation)

    • 建一个小的“问题集 + 标准答案/可接受答案”
    • 每次改切分策略/模型/过滤规则都跑一遍离线评测

Redis / Chroma / Pinecone 的“落地选择建议”(一句话版)

  • 内网合规 + 延迟敏感 + Redis 体系成熟:优先 RedisVectorStore(Redis Stack)
  • 快速 PoC / 研发自测 / 小规模知识库:Chroma(starter 配置快)
  • 云托管 + 规模增长 + 少运维:Pinecone(注意数据策略)

🧧福利赠与你🧧

  无论你是计算机专业的学生,还是对编程有兴趣的小伙伴,都建议直接毫无顾忌的学习此专栏「滚雪球学SpringBoot」,bug菌郑重承诺,凡是学习此专栏的同学,均能获取到所需的知识和技能,全网最快速入门SpringBoot,就像滚雪球一样,越滚越大, 无边无际,指数级提升。

最后,如果这篇文章对你有所帮助,帮忙给作者来个一键三连,关注、点赞、收藏,您的支持就是我坚持写作最大的动力。

同时欢迎大家关注公众号:「猿圈奇妙屋」 ,以便学习更多同类型的技术文章,免费白嫖最新BAT互联网公司面试题、4000G PDF编程电子书、简历模板、技术文章Markdown文档等海量资料。

ps:本文涉及所有源代码,均已上传至Gitee:https://gitee.com/bugjun01/SpringBoot-demo 开源,供同学们一对一参考 Gitee传送门https://gitee.com/bugjun01/SpringBoot-demo,同时,原创开源不易,欢迎给个star🌟,想体验下被🌟的感jio,非常感谢❗

🫵 Who am I?

我是 bug菌:

  • 热活跃于 CSDN:https://blog.csdn.net/weixin_43970743 | 掘金:https://juejin.cn/user/695333581765240 | InfoQ:https://www.infoq.cn/profile/4F581734D60B28/publish | 51CTO:https://blog.51cto.com/u_15700751 | 华为云:https://bbs.huaweicloud.com/community/usersnew/id_1582617489455371 | 阿里云:https://developer.aliyun.com/profile/uolxikq5k3gke | 腾讯云:https://cloud.tencent.com/developer/user/10216480/articles 等技术社区;
  • CSDN 博客之星 Top30、华为云多年度十佳博主&卓越贡献奖、掘金多年度人气作者 Top40;
  • 掘金、InfoQ、51CTO 等平台签约及优质作者;
  • 全网粉丝累计 30w+

更多高质量技术内容及成长资料,可查看这个合集入口 👉 点击查看:https://bbs.csdn.net/topics/612438251 👈️
硬核技术公众号 「猿圈奇妙屋」https://bbs.csdn.net/topics/612438251 期待你的加入,一起进阶、一起打怪升级。

- End -

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。