【AI Agent 全栈开发】RAG(检索增强生成)

🚀 欢迎来到我的CSDN博客:Optimistic _ chen

一名热爱技术与分享的全栈开发者,在这里记录成长,专注分享编程技术与实战经验,助力你的技术成长之路,与你共同进步!


🚀我的专栏推荐

专栏 内容特色 适合人群
🔥C语言从入门到精通 系统讲解基础语法、指针、内存管理、项目实战 零基础新手、考研党、复习
🔥Java基础语法 系统解释了基础语法、类与对象、继承 Java初学者
🔥Java核心技术 面向对象、集合框架、多线程、网络编程、新特性解析 有一定语法基础的开发者
🔥Java EE 进阶实战 Servlet、JSP、SpringBoot、MyBatis、项目案例拆解 想快速入门Java Web开发的同学
🔥Java数据结构与算法 图解数据结构、LeetCode刷题解析、大厂面试算法题 面试备战、算法爱好者、计算机专业学生
🔥Redis系列 从数据类型到核心特性解析 项目必备

🚀我的承诺:

✅ 文章配套代码:每篇技术文章都提供完整的可运行代码示例

✅ 持续更新:专栏内容定期更新,紧跟技术趋势

✅ 答疑交流:欢迎在文章评论区留言讨论,我会及时回复(支持互粉)


🚀 关注我,解锁更多技术干货!
⏳ 每天进步一点点,未来惊艳所有人!✍️ 持续更新中,记得⭐收藏关注⭐不迷路 ✨

📌 标签:#技术博客#编程学习#Java#C语言#算法#程序员

文章目录

什么是RAG

官方给出的解释是:Retrieval Augmented Generation, 检索增强⽣成。是一种结合信息检索(retrieval)和文本生成(generation)的混合架构。

解释一下:传统⼤型语⾔模型(LLM)依赖训练数据中的知识,但⽆法获取最新信息以及⼀些⾮公开信息,所以当你询问一些私有信息时,就会出现"幻觉",答非所问。

RAG技术如同为LLM配备了实时更新的知识库。它不仅依靠预训练数据,还能通过检索特定知识片段来获取最新信息。这些检索到的内容作为上下文输入模型,使回答既准确又与时俱进,有效减少了信息误差,并实现了知识的动态更新。

RAG增强LLM

RAG技术有一套严谨的工作流程,为LLM的回答提供真实有效的依据。

RAG第一个优势就是通过从外部知识库获取相关信息来增强⼤语⾔模型(LLM)的输出,从⽽⽣成更准确,上下⽂更丰富的回答,有效解决模型幻觉,知识过时等问题。

但是RAG知识库可能包含多种格式和语言的文档,导致这些数据难以被有效检索。因此,我们需要将这些数据进行进一步处理,构建出可以被高效检索的知识库。

构建向量数据库

什么是向量

向量是数学中的基本概念,表示高维空间中的一个坐标点。在机器学习领域,向量常被用来将文本、图像、音频等非结构化数据映射为高维空间中的点。每个维度代表潜在的语义特征,这些特征虽然不一定对应人类直观理解的具体概念(如"颜色"或"大小"),但共同编码了对象的语义信息。

核心特性在于:向量位置反映语义关系,语义相近的对象在向量空间中的位置也会更接近。

关于向量的计算方法,我们主要通过Embedding模型将自然语言转换为机器可理解的"语义编码"。具体计算过程不在本文讨论范围内,感兴趣的读者可以自行探索。

向量数据库

向量数据库(Vector Database)是⼀种专⻔⽤于存储、管理和⾼效检索⾼维向量数据的数据库系统。它以向量作为基本存储单元,⽀持对⾮结构化数据(如⽂本、图像、⾳频、视频)进⾏语义级相似性搜索。

对比传统关系型数据库的精准匹配,向量数据库的核心是

  1. 向量化处理:可以将原始数据转化为高维向量
  2. 相似性度量:使用余弦相似度、欧式距离等方法衡量向量间的语义接近程度
  3. 高效检索:采⽤⾼效的索引算法,大幅度提高查询速度

RAG的工作流程

  1. 文档加载(Document Loading):加载不同来源的文档,不同的文档加载器可以加载不同格式的非结构化数据
  2. 文本分割(Splitting):文本分割把Document切分为指定大小的块
  3. 数据向量化:将切分好的Document块进行嵌入模型转化,即将⽂档块转换成向量的形式
  4. 存储(Storage):将Embedding后的向量数据,存储到向量数据库中
  5. 检索(Retrieval):数据存入向量数据库后,当我们需要进行数据检索时,通过检索算法找到与输入问题相似的文档块
  6. 增强上下文构建:系统将检索到的文本块与原始用户问题,按照一定模板组合成一个新的、内容丰富的提示词
  7. 输出:将上述增强后的Prompt发送给大模型,大模型生成的答案返回给用户

简单上手

文本向量化

添加pom.xml依赖

xml 复制代码
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
</dependencies>

文本向量化:这里需要引入嵌入模型来实现向量化,我使用的是阿里百炼平台提供的向量模型。

xml 复制代码
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webflux</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud.ai</groupId>
    <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
</dependency>

application.yml配置文件中添加配置:

yml 复制代码
spring:
  ai:
    dashscope:
      api-key: ${DASHSCOPE_API_KEY}

相关代码可以观看官方文档向量化模型

向量存储

目前支持的向量数据库有Vector Database,也可以使用Redis、Oracle等数据库

学习阶段,我们使用SimpleVectorStore来存储向量,SimpleVectorStore 是SpringAI内置的⼀个"内存版"向量数据库,⽆需外部依赖,开箱即⽤。

定义VectorStore

java 复制代码
//作⽤类似于 @Configuration ,但专⻔⽤于测试环境
@TestConfiguration
static class TestConfig {
    @Bean
    public VectorStore vectorStore(DashScopeEmbeddingModel embeddingModel){
        return SimpleVectorStore.builder(embeddingModel).build();
    }
}

存储⽂档到VectorStore

java 复制代码
@Test
public void init(@Autowired VectorStore vectorStore ){
     Document doc=Docment.builder()
                         .text("2026年美加墨世界杯,预计吸引全球目光")
                         ,build();
     Document doc2=Docment.builder()
                         .text("枯藤老树昏鸦,小桥流水人家")
                         ,build();
     Document doc3=Docment.builder()
                         .text("基于机器学习的大语言模型")
                         ,build();
     Document doc4=Docment.builder()
                         .text("今天天气不错,适合出游")
                         ,build();
     //文本向量化
     vectorStore.add(Arrays.asList(doc,doc2,doc3,doc4));
}

相似性检索

向量存⼊到向量数据库之后,就可以来查找了

java 复制代码
 @Test
    void similaritySearchTest(@Autowired VectorStore vectorStore) {
        // 3. 相似性查询
 
        SearchRequest searchRequest = SearchRequest
                .builder().query("机器学习")
                .topK(5)
                .similarityThreshold(0.3)
                .build();
        List<Document> results = vectorStore.similaritySearch(searchRequest);
        // 4.输出
        System.out.println(results);
    }

调用similaritySearch方法时,会执行相似性搜索:

将"搜索词"转为向量,计算它与1向量库中文档的相似度,根据请求,过滤出相似度≥0.3的文档,并去top 5,最后返回这些匹配的原始文档列表。

Advisor让LLM"看到"向量数据库

Advisor机制是Spring AI提供的开箱即用支持,用于实现RAG技术。
QuestionAnswerAdvisorRetrievalAugmentationAdvisor是SpringAI中实现RAG的两个核⼼组件。

  • QuestionAnswerAdvisor:⾯向问答场景的语义检索增强
  • RetrievalAugmentationAdvisor:灵活可控的通⽤RAG增强层,它不局限于问答场景,⽽是作为⼀个通⽤的增强层,适⽤于任何需要引⼊外部知识的⽣成任务.

程序员通过自定义的Retriever接口来控制检索逻辑

java 复制代码
@Bean
    public RetrievalAugmentationAdvisor retrievalAugmentationAdvisor(
            ChatModel chatModel,
            VectorStore vectorStore) {

        // 1. 创建检索器(指定返回3个文档)
        var retriever = VectorStoreRetriever.builder(vectorStore)
                .similarityThreshold(0.75)  // 可选:相似度阈值
                .topK(3)                    // 检索 top-3 结果
                .build();

        // 2. 自定义 Prompt 模板
        String promptTemplateStr = """
                你是一个企业智能助手,请根据以下【参考资料】回答问题。
                如果资料中没有相关信息,请回答"抱歉,我无法找到相关信息。"
                
                【参考资料】:
                {documents}
                
                【问题】:
                {question}
                
                【回答】:
                """;

        PromptTemplate template = new PromptTemplate(promptTemplateStr);

        // 3. 构建 Advisor
        return RetrievalAugmentationAdvisor.builder()
                .documentRetriever(retriever)   // 使用自定义检索器
                .queryAugmenter(new ContextualQueryAugmenter(template))  // 注入模板
                .build();

假设开发⼈员已经将数据加载到中 VectorStore,就可以通过QuestionAnswerAdvisor实例来执⾏RAG

java 复制代码
@Test
void chatRagTest(@Autowired VectorStore vectorStore,
        @Autowired DashScopeChatModel chatModel
) {
    ChatClient chatClient = ChatClient.builder(chatModel)
            .build();
    String message="世界杯什么时候举⾏";
    String content =chatClient.prompt()
            .advisors(new QuestionAnswerAdvisor(vectorStore))
            .user(message).call().content();
    System.out.println(content);
}

ETL(提取,转化,加载)

RAG的核⼼理念是通过从⼤量数据中检索相关信息来增强⽣成式AI模型的能⼒,从⽽提⾼⽣成内容的质量和相关性。⽽ETL过程正是实现这⼀⽬标的关键环节------它将原始文档转化为可以被高效检索和使用的结构化数据,为后续检索和生成过程奠定基础。

  • Extract:从原始数据源读取并捕获数据,输出为初步解析的中间格式
  • Transform:转化原始数据为向量化数据
  • Load:存入向量数据库,供检索使用

Document数据模型

Document是ETLAPI的核⼼数据模型,它构成了整个数据处理流程的基本单元。用来处理数据的提取、转化和加载。

DocumentReader(⽂档阅读器)

java 复制代码
public interface DocumentReader extends Supplier<List<Document>> {
    default List<Document> read() {
       return get();
    }
}

例如:JsonReader是一个用于将JSON数据转化为Document对象的工具类,主要用于从JSON文件中提取结构化数据并生成文档对象。

DocumentReader 是一个统一的顶层接口(或称抽象概念),代表所有文档读取器的总称。而 JsonReader 则是DocumentReader接口的一个具体实现。

简单来说,JsonReader 是一种对特定文档类型(即 JSON 格式文件)的读取器。

DocumentTransformer(⽂档转换器)

知识库中原始⽂档通常太⻓、格式混乱或缺乏结构化元数据,⽆法直接输⼊给LLM使⽤,对文本进行必要的转化和处理。

java 复制代码
public interface DocumentTransformer extends Function<List<Document>, 
List<Document>> {
       default List<Document> transform(List<Document> transform) {
            return apply(transform);
      }
}

主要有四个组件:

  • TextSplitter(文本切分器):把⻓⽂切成⼩块
  • ContentFormatTransformer(内容格式转换器): 统⼀清洗⽂本
  • KeywordMetadataEnricher(关键词提取器):借助AI模型⾃动提取关键词,类似给⽂档"贴标签"
  • SummaryMetadataEnricher(摘要⽣成器):借助AI模型⽣成⽂档摘要

具体代码可以到官方文档处查看

DocumentWriter(⽂档编写器)

java 复制代码
public interface DocumentWriter extends Consumer<List<Document>> {
     default void write(List<Document> documents) {
         accept(documents);
         
     }
}

FileDocumentWriter 是⼀个实现了 DocumentWriter 接⼝的类,⽤于将⼀组 Document 对象的内容写⼊到指定的⽂本⽂件中.适⽤于调试、⽇志记录或⽣成⼈类可读的⽂档输出。

java 复制代码
FileDocumentWriter writer = new FileDocumentWriter("output.txt",
         true, MetadataMode.ALL, false);

向量化的存储,上面提到的SimpleVectorStore就是其中一种。

重排序

RAG已经实现了快速从海量⽂档中"找到看起来相关的⽚段",但是,在实际应⽤中,我们发现其排序结果并不总是最优;最相似的向量 ≠ 最相关的答案

Re-Ranking(重排序) 是指在初步检索出⼀批候选⽂档后,使⽤⼀个更加精细、专精于相关性判断的模

型,重新评估每个⽂档与查询之间的匹配程度,并按新得分重新排序。

  1. 粗排阶段:使⽤向量数据库进⾏快速ANN搜索,召回⼀批候选⽂档
  2. 精排阶段:调⽤更精细的排序模型(如Cross-Encoder类重排序模型),计算每个⽂档与原始查询之间的细粒度语义匹配分数
  3. 根据重排序后的得分重新排列⽂档顺序,选取top-k⾼质量上下⽂;
  4. 将优化后的上下⽂注⼊Prompt,交由LLM⽣成最终回答

Spring AI中提供了开箱即用的支持组件:RetrievalRerankAdvisor

java 复制代码
@SpringBootTest
public class RerankTest {
    private SimpleVectorStore simpleVectorStore;

    @Autowired
    public RerankTest(EmbeddingModel embeddingModel) {
        this.simpleVectorStore = SimpleVectorStore.builder(embeddingModel).build();
    }

    @BeforeEach
    void testSimpleVectorStore(@Value("classpath:/file/rule.txt")Resource resource){
        //读取
        TextReader reader = new TextReader(resource);
        List<Document> documents = reader.get();
        TokenTextSplitter splitter = new TokenTextSplitter(200, 50, 5, 1000, true);
        List<Document> apply = splitter.apply(documents);
        simpleVectorStore.add(apply);
        System.out.println("向量存储写入完成");
    }

    @Test
    void testRerank(@Autowired DashScopeRerankModel rerankModel,
                    @Autowired DashScopeChatModel chatModel){
        ChatClient client = ChatClient.builder(chatModel).build();
        //1. 定义一个advisor, 提供rerank模型
        RetrievalRerankAdvisor rerankAdvisor = new RetrievalRerankAdvisor(simpleVectorStore,
                rerankModel, SearchRequest.builder().topK(10).build());
        //2. 把这个advisor 绑定给chatclient
        String content = client.prompt()
                .user("金卡会员打几折")
                .advisors(rerankAdvisor)
                .call()
                .content();
        System.out.println(content);

    }
}

完结撒花!🎉

如果这篇博客对你有帮助,不妨点个赞支持一下吧!👍
你的鼓励是我创作的最大动力~

想获取更多干货? 欢迎关注我的专栏 → optimistic_chen

📌 收藏本文,下次需要时不迷路!

我们下期再见!💫 持续更新中......


悄悄说:点击主页有更多精彩内容哦~ 😊

相关推荐
毕小宝3 小时前
Claude Code 模型切换脚本 switch.sh 编写
linux·运维·服务器
zhangxingchao3 小时前
AI应用开发四:RAG多模态数据处理
人工智能
碧海银沙音频科技研究院3 小时前
高通QCC3084-QCC518X蓝牙耳机项目
人工智能·深度学习·算法
@蔓蔓喜欢你3 小时前
CSS Grid布局完全指南:构建复杂布局的利器
人工智能·ai
xiami_world3 小时前
2026年团队AI工具栈架构指南:ChatGPT + Codex + AI白板智能体工程化落地方案
人工智能·ai·信息可视化·aigc·流程图
sheji1053 小时前
割草机器人行业浏览版内容汇总
人工智能·机器人·智能硬件
诸葛李3 小时前
集成构建xxxxx
java·junit·单元测试
乐维_lwops3 小时前
【无标题】
运维·人工智能
qcx233 小时前
【AI Daily】每日Arxiv论文研读Top5-2026-05-18
人工智能·ai·llm·论文·agent·arxiv