Spring AI 代码分析(五)--RAG 分析

news/2025/11/22 23:00:33/文章来源:https://www.cnblogs.com/wasp520/p/19258824

Spring AI RAG 分析

请关注微信公众号:阿呆-bot

1. 工程结构概览

spring-ai-rag 是 Spring AI 的检索增强生成(Retrieval Augmented Generation)框架,它提供了完整的 RAG 能力,让 AI 模型能够访问外部知识库。

spring-ai-rag/
├── advisor/
│   └── RetrievalAugmentationAdvisor.java  # RAG Advisor
│
├── retrieval/                              # 检索层
│   └── search/
│       ├── DocumentRetriever.java          # 文档检索接口
│       └── VectorStoreDocumentRetriever.java  # 向量存储检索实现
│
├── preretrieval/                           # 检索前处理
│   └── query/
│       ├── transformation/                 # 查询转换
│       │   ├── QueryTransformer.java
│       │   ├── RewriteQueryTransformer.java
│       │   └── CompressionQueryTransformer.java
│       └── expansion/                       # 查询扩展
│           └── QueryExpander.java
│
├── postretrieval/                          # 检索后处理
│   └── DocumentPostProcessor.java
│
└── generation/                             # 生成层└── augmentation/└── ContextualQueryAugmenter.java    # 上下文查询增强

2. 技术体系与模块关系

RAG 框架通过 Advisor 机制集成到 ChatClient,实现了完整的检索增强生成流程:

image.png

3. 关键场景示例代码

3.1 基础 RAG 使用

最简单的 RAG 使用方式:

@Autowired
private ChatModel chatModel;
@Autowired
private VectorStore vectorStore;public void basicRAG() {// 创建向量存储检索器VectorStoreDocumentRetriever retriever = VectorStoreDocumentRetriever.builder().vectorStore(vectorStore).topK(5).similarityThreshold(0.7).build();// 创建 RAG AdvisorRetrievalAugmentationAdvisor ragAdvisor = RetrievalAugmentationAdvisor.builder().documentRetriever(retriever).build();// 使用 ChatClientChatClient chatClient = ChatClient.builder(chatModel).defaultAdvisors(ragAdvisor).build();String response = chatClient.prompt().user("查询文档中的信息").call().content();
}

3.2 带查询重写的 RAG

查询重写可以优化检索效果:

public void ragWithQueryRewrite() {// 创建查询重写器RewriteQueryTransformer queryTransformer = RewriteQueryTransformer.builder().chatClient(ChatClient.builder(chatModel)).targetSearchSystem("vector store").build();// 创建 RAG AdvisorRetrievalAugmentationAdvisor ragAdvisor = RetrievalAugmentationAdvisor.builder().documentRetriever(retriever).queryTransformers(queryTransformer).build();ChatClient chatClient = ChatClient.builder(chatModel).defaultAdvisors(ragAdvisor).build();
}

3.3 多查询扩展

查询扩展可以从一个查询生成多个相关查询:

public void ragWithQueryExpansion() {// 创建查询扩展器QueryExpander queryExpander = new MultiQueryExpander(ChatClient.builder(chatModel));RetrievalAugmentationAdvisor ragAdvisor = RetrievalAugmentationAdvisor.builder().documentRetriever(retriever).queryExpander(queryExpander).build();
}

4. 核心时序图

4.1 RAG 完整流程

image.png

5. 入口类与关键类关系

image.png

6. 关键实现逻辑分析

6.1 RetrievalAugmentationAdvisor 核心逻辑

RetrievalAugmentationAdvisor 是 RAG 流程的核心协调者:

public class RetrievalAugmentationAdvisor implements BaseAdvisor {@Overridepublic ChatClientRequest before(ChatClientRequest request, AdvisorChain chain) {// 1. 构建原始查询Query originalQuery = Query.builder().text(request.prompt().getUserMessage().getText()).history(request.prompt().getInstructions()).context(request.context()).build();// 2. 查询转换Query transformedQuery = originalQuery;for (QueryTransformer transformer : queryTransformers) {transformedQuery = transformer.transform(transformedQuery);}// 3. 查询扩展List<Query> expandedQueries = queryExpander != null ? queryExpander.expand(transformedQuery): List.of(transformedQuery);// 4. 并行检索文档Map<Query, List<List<Document>>> documentsForQuery = expandedQueries.parallelStream().map(query -> getDocumentsForQuery(query)).collect(...);// 5. 合并文档List<Document> documents = documentJoiner.join(documentsForQuery);// 6. 文档后处理for (DocumentPostProcessor processor : documentPostProcessors) {documents = processor.process(originalQuery, documents);}// 7. 查询增强Query augmentedQuery = queryAugmenter.augment(originalQuery, documents);// 8. 更新 Promptreturn request.mutate().prompt(augmentedQuery.toPrompt()).context(context).build();}
}

6.2 向量存储检索实现

VectorStoreDocumentRetriever 负责从向量存储中检索文档:

public class VectorStoreDocumentRetriever implements DocumentRetriever {@Overridepublic List<Document> retrieve(Query query) {// 1. 计算请求的过滤表达式Filter.Expression filterExpression = computeRequestFilterExpression(query);// 2. 构建搜索请求SearchRequest searchRequest = SearchRequest.builder().query(query.text()).filterExpression(filterExpression).similarityThreshold(this.similarityThreshold).topK(this.topK).build();// 3. 执行相似度搜索return vectorStore.similaritySearch(searchRequest);}
}

6.3 查询重写实现

RewriteQueryTransformer 使用 LLM 重写查询以优化检索:

public class RewriteQueryTransformer implements QueryTransformer {@Overridepublic Query transform(Query query) {// 使用 LLM 重写查询String rewrittenQueryText = chatClient.prompt().user(promptTemplate.getTemplate()).param("target", targetSearchSystem).param("query", query.text()).call().content();return query.mutate().text(rewrittenQueryText).build();}
}

6.4 查询增强实现

ContextualQueryAugmenter 将检索到的文档注入到用户查询中:

public class ContextualQueryAugmenter implements QueryAugmenter {@Overridepublic Query augment(Query query, List<Document> documents) {// 1. 格式化文档内容String documentContext = formatDocuments(documents);// 2. 使用模板增强查询String augmentedText = promptTemplate.render(Map.of("query", query.text(),"context", documentContext));return query.mutate().text(augmentedText).build();}
}

7. 如何集成 Vector Store

RAG 框架通过 DocumentRetriever 接口抽象了向量存储的集成:

7.1 抽象机制

DocumentRetriever 接口提供了统一的文档检索抽象:

public interface DocumentRetriever extends Function<Query, List<Document>> {List<Document> retrieve(Query query);
}

这种设计让 RAG 框架不直接依赖 VectorStore,而是通过 DocumentRetriever 抽象。这意味着:

  • 可以支持多种数据源:向量存储、知识图谱、数据库等
  • 易于扩展:可以实现自定义的 DocumentRetriever
  • 解耦:RAG 框架和向量存储完全解耦

7.2 VectorStoreDocumentRetriever 实现

VectorStoreDocumentRetriever 是向量存储的默认实现:

public class VectorStoreDocumentRetriever implements DocumentRetriever {private final VectorStore vectorStore;@Overridepublic List<Document> retrieve(Query query) {SearchRequest request = SearchRequest.builder().query(query.text()).topK(this.topK).similarityThreshold(this.similarityThreshold).filterExpression(computeFilterExpression(query)).build();return vectorStore.similaritySearch(request);}
}

7.3 自定义 DocumentRetriever

可以轻松实现自定义的 DocumentRetriever

public class CustomDocumentRetriever implements DocumentRetriever {@Overridepublic List<Document> retrieve(Query query) {// 自定义检索逻辑// 可以从数据库、知识图谱、API 等检索return customRetrieve(query);}
}

8. 外部依赖

spring-ai-rag 的依赖:

  • spring-ai-client-chat:ChatClient 和 Advisor 机制
  • spring-ai-vector-store:向量存储抽象
  • spring-ai-commons:Document 等基础类型
  • Spring Framework:IoC 和核心功能
  • Reactor Core:响应式处理(用于并行检索)

9. 工程总结

Spring AI RAG 框架的设计有几个亮点:

模块化设计。RAG 流程被拆成了多个独立的组件:查询转换、查询扩展、文档检索、文档后处理、查询增强。每个组件都能独立配置和替换,想用哪个用哪个。

抽象和解耦。通过 DocumentRetriever 接口,RAG 框架和向量存储完全解耦。这样就能支持多种数据源,想换就换,扩展起来也方便。

Advisor 机制集成。RAG 通过 Advisor 机制集成到 ChatClient,用起来特别简单,只需要加一个 Advisor 就行。

可扩展性。每个环节都支持自定义实现,比如自己写个查询转换器、文档后处理器什么的。这样 RAG 框架就能适应各种业务场景。

并行处理。查询扩展后生成的多个查询可以并行检索,性能更好。

总的来说,Spring AI RAG 框架是一个设计得不错、功能完整的 RAG 实现。它提供了完整的 RAG 能力,同时保持了高度的灵活性和可扩展性。开发者可以轻松构建基于 RAG 的 AI 应用,也能根据具体需求进行深度定制。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/973486.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

详细介绍:一个实例用全创建型模式-优化(冗余消除)

详细介绍:一个实例用全创建型模式-优化(冗余消除)pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas&quo…

我的博客园美化记录

这个博客是一个大佬写的,我只简单修改了个别样式 大佬地址改完之后的样子如下暗色主题亮色主题 ![]第一步 基本设置在博客皮肤里直接输入 Custom ![] 渲染引擎:选择:highlight.js ![]第二步 美化代码页面定制 CSS 代…

2025家装木制品定制品牌怎么选?欧雅斯——楼梯、木门、衣柜、橱柜、护墙板,源头精品

随着人们生活品质的提升,高端整木定制成为打造个性化家居空间的重要选择,而兼具设计感与工艺实力的品牌则是消费者的首选。在2025年的高端整木定制市场中,欧雅斯凭借专业的研发制造能力与完善的服务体系,成为中高端…

面向对象编程前三次大作业总结

面向对象编程前三次大作业总结前言 本次大作业是第一个面向对象编程的实操练习,难度从中到难,层层递进。OOP题目集01 大部分是作为前面Java程序练习的过渡用的练习题,题目简单,题型常见不复杂,能帮助我们学习更多…

iceberg sql怎么写

Iceberg SQL 是基于 Apache Iceberg 的数据查询接口,它允许你使用标准的 SQL 语句来查询和管理 Iceberg 表中的数据。以下是一些基本的 Iceberg SQL 示例:创建表 假设我们有一个名为 my_table 的表,具有以下列:id(…

iceberg sql如何用

Iceberg SQL 是基于 Apache Iceberg 的 SQL 查询接口,用于处理大规模数据集。以下是一些基本的使用步骤和示例:创建表 使用 CREATE TABLE 语句创建一个新的表。例如,以下语句创建一个名为 my_table 的表,其中包含 …

CSAPP Notes Labs

目录信息的处理和表示数字的存储二进制下的整数1. 补码2.符号扩展与数字截断3.运算二进制下的浮点数1.浮点数的表示标准化之前IEEE浮点数2.整数转浮点数3.思考:n位位数不能精确表示的最小正整数4.浮点数的运算5.C中浮…

VSCODE协助keil开发时无法识别uint8_t

VSCODE协助keil开发时无法识别uint8_t keil编译器中内部的define并没在vscode设置,只需同理设置即可.vscode folder下ctrl+shift+P ​C/C++:Edit Configurations​ ​/在json文件夹中添加打开keil魔术棒在VSCODE同理设…

CSAPP 信息的处理和表示

目录信息的处理和表示数字的存储二进制下的整数1. 补码2.符号扩展与数字截断3.运算二进制下的浮点数1.浮点数的表示标准化之前IEEE浮点数2.整数转浮点数3.思考:n位位数不能精确表示的最小正整数4.浮点数的运算5.C中浮…

NumPy ndarray 完全指南:多维数组的基石

NumPy ndarray 完全指南:多维数组的基石 ndarray(全称 N-dimensional array,即 N 维数组)是 NumPy 库的核心和灵魂。它是一个用于存储和处理同类型数据的多维容器,是 NumPy 所有强大功能的基础。如果你用过 Pytho…

最小生成树(整理篇)

最小生成树(整理篇)#include <bits/stdc++.h> using namespace std; const int N = 400500, INF = 2147483647; typedef pair<int, int> PII;bool st[N]; int n, m, dist[N], tot, ans;; vector<PII>…

有时我会想起莫名的愤怒的事情,是不是就是这里的偏执因起的情绪激动造成的

您这个问题问到了最关键的地方,它像一把钥匙,能直接解开您很多痛苦体验的锁。是的,您说得非常对。这种“心里想起一起莫名的愤怒”,极大概率就是“偏执”想法所引发的“情绪激动”,只是这个过程发生得太快、太自动…

A script to set mysql gtid-mode off by tortoise-orm

mysql_gtid.pyfrom __future__ import annotationsimport asyncio import contextlib import os import sys from collections.abc import AsyncGenerator from contextlib import asynccontextmanagerfrom tortoise i…

C Tcp通信

学完了c程序基础知识后,是不是感觉什么也干不了,总想找点事情来练手?本文暂且介绍一下,如何使用socket进行tcp通信;示例程序目前并不健壮,仅为演示socket通信的基本流程。用白话理解tcp通信 TCP通信就像打电话,…

SZMS 251019 订题赛笔记

串串 原题:[CEOI 2010] pin 题意 给定 \(n\) 个长度为 4 的字符串,你需要找出有多少对字符串满足恰好 \(d\) 个对应位置的字符不同。 \(n \le 5 \times 10 ^ 4, d \le 4\)。 思路 前面忘了。 注意到恰好。 注意到容易…

关于面向对象程序设计的第一阶段大作业总结

一、前言 本次三次题目集聚焦 “单部电梯调度系统”,是面向对象编程的迭代式实践。涉及的知识点包括 Java 类与对象、枚举封装、集合框架(LinkedList)、单一职责原则(SRP)、电梯调度算法及输入校验。但对我而言,…

Spring Boot核心知识点全解析 - 实践

Spring Boot核心知识点全解析 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monac…

RHCA - DO374 | Day03:通过自动化控制器运行剧本 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

离职/毕业-清理电脑

这段内容主要面向打工人,强调离职前清理电脑个人信息、保护隐私的重要性,并详细介绍了从微信聊天记录、电脑使用记录、上网记录、软件缓存四个方面一键清理个人信息的方法。开篇指出离职小白常误以为卸载软件就能清理…

2025.11.22

今天学习vue的项目布局,明天继续学习布局,然后就要开始前后端连接了