欢迎光临
我们一直在努力

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

🚀 欢迎来到我的CSDN博客:Optimistic _ chen ✨ 一名热爱技术与分享的全栈开发者,在这里记录成长,专注分享编程技术与实战经验,助力你的技术成长之路,与你共同进步!


🚀我的专栏推荐:

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

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

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

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


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

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

文章目录

  • 什么是RAG
  • RAG增强LLM
  • 构建向量数据库
    • 什么是向量
    • 向量数据库
    • RAG的工作流程
  • 简单上手
    • 文本向量化
    • 向量存储
    • 相似性检索
    • Advisor让LLM“看到”向量数据库
  • ETL(提取,转化,加载)
    • Document数据模型
      • DocumentReader(⽂档阅读器)
      • DocumentTransformer(⽂档转换器)
      • DocumentWriter(⽂档编写器)
  • 重排序
  • 完结撒花!🎉

什么是RAG

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

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

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

RAG增强LLM

RAG技术有一套严谨的工作流程,为LLM的回答提供真实有效的依据。 在这里插入图片描述   RAG第一个优势就是通过从外部知识库获取相关信息来增强⼤语⾔模型(LLM)的输出,从⽽⽣成更准确,上下⽂更丰富的回答,有效解决模型幻觉,知识过时等问题。

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

构建向量数据库

什么是向量

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

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

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

向量数据库

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

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

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

    在这里插入图片描述

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

    文本向量化

    添加pom.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>

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

    <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配置文件中添加配置:

    spring:
    ai:
    dashscope:
    api-key: ${DASHSCOPE_API_KEY}

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

    向量存储

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

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

    定义VectorStore

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

    存储⽂档到VectorStore

    @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));
    }

    相似性检索

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

    @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技术。 QuestionAnswerAdvisor 和RetrievalAugmentationAdvisor是SpringAI中实现RAG的两个核⼼组件。

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

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

    @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

    @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(⽂档阅读器)

    public interface DocumentReader extends Supplier<List<Document>> {
    default List<Document> read() {
    return get();
    }
    }

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

    DocumentReader 是一个统一的顶层接口(或称抽象概念),代表所有文档读取器的总称。而 JsonReader 则是DocumentReader接口的一个具体实现。 简单来说,JsonReader 是一种对特定文档类型(即 JSON 格式文件)的读取器。

    DocumentTransformer(⽂档转换器)

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

    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(⽂档编写器)

    public interface DocumentWriter extends Consumer<List<Document>> {
    default void write(List<Document> documents) {
    accept(documents);

    }
    }

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

    FileDocumentWriter writer = new FileDocumentWriter("output.txt",
    true, MetadataMode.ALL, false);

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

    重排序

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

    Re-Ranking(重排序) 是指在初步检索出⼀批候选⽂档后,使⽤⼀个更加精细、专精于相关性判断的模 型,重新评估每个⽂档与查询之间的匹配程度,并按新得分重新排序。

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

    @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 📌 收藏本文,下次需要时不迷路!

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


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

    赞(0)
    未经允许不得转载:171主机测评 » 【AI Agent 全栈开发】RAG(检索增强生成)
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址