Spring AI--RAG知识库
目录
什么是RAG?
RAG工作流程
1.文档收集和切割
2.向量转换和存储
3.文档过滤和检索
4.查询增强和关联
RAG相关技术
1.Embedding和Embedding模型
2.向量数据库
3.召回
4.精排和Rank模型
5.混合检索策略
RAG实战:Spring AI+本地知识库
1. 文档准备
2.文档读取
RAG实战:Spring AI + 云知识库服务
1.准备云知识库
2.RAG开发
Spring AI Alibaba 概述-阿里云Spring AI Alibaba官网官网
什么是RAG?
RAG(Retrieval-AugmentedGeneration,检索增强生成)是一种结合信息检索技术和Al内容生成的混合架构,可以解决大模型的知识时效性限制和幻觉问题。
简单来说,RAG就像给AI配了一个“小抄本",让AI回答问题前先查一查特定的知识库来获取知识,确保回答是基于真实资料而不是凭空想象。
从技术角度看,RAG在大语言模型生成回答之前,会先从外部知识库中检索相关信息,然后将这些检索到的内容作为额外上下文提供给模型,引导其生成更准确、更相关的回答。
RAG和传统AI模型的区别:

RAG工作流程
1.文档收集和切割
文档收集:从各种来源收集原始文档
文档预处理:清洗、标准化文本格式
文档切割:将长文档分割成适当大小的片段(俗成chunks)
基于固定大小(如512个token)
基于语义边界(如段落、章节)
基于递归分割策略(如递归字符 n-gram 切割)

2.向量转换和存储
向量转换:使用Embedding模型将文本块转换为高维向量表示,可以捕获到文本的语义特征。
向量存储:将生成的向量和对应文本存入向量数据库,支持高效的相似性搜索

3.文档过滤和检索
查询处理:将用户问题也转换为向量表示
过滤机制:基于元数据、关键词或者自定义规则进行过滤
相似性搜索:在向量数据库中查找与问题向量最相似的文档块,常用的最相似搜索算法有余弦相似度、欧式距离等
上下文组装:将检索到的多个文档块组装成连贯上下文

4.查询增强和关联
提示词组装:将检索到的相关文档与用户问题组合成增强提示
上下文融合:大模型基于增强提示生成回答
源引用:在回答中添加信息来源引用
后处理:格式化、摘要或其他处理以优化最终输出
完整流程:

RAG相关技术
1.Embedding和Embedding模型
Embedding 嵌入是将高维离散数据(如文字、图片)转换为低维连续向量的过程。这些向量能在数学空间中表示原始数据的语义特征,使计算机能够理解数据间的相似性。
Embedding 模型是执行这种转换算法的机器学习模型,如Word2Vec(文本)、ResNet(图像)等。不同的Embedding 模型产生的向量表示和维度数不同,一般维度越高表达能力更强,可以捕获更丰富的语义信息和更细微的差别,但同样占用更多存储空间。

Embedding将离散数据转换为连续向量,使计算机能够理解数据之间的语义关系
2.向量数据库
向量数据库是专门存储和检索向量数据的数据库系统。通过高效索引算法实现快速相似性搜索,支持k近邻查询等操作。

并不是只有向量数据库才能存储向量数据,只不过与传统数据库不同,向量数据库优化了高维向量的存储和检索。
3.召回
召回是信息检索中的第一阶段,目标是从大规模数据集中快速筛选出可能相关的候选项子集。强调速度和广度,而非精确度。
例:要从搜索引擎查询“编程导航-程序员一站式编程学习交流社区”时,召回阶段会从数十亿网页中快速筛选出数千个含有“编程"、“导航"、“程序员”等相关内容的页面,为后续粗略排序和精细排序提供候选集。
4.精排和Rank模型
精排(精确排序)是搜索/推荐系统的最后阶段,使用计算复杂度更高的算法,考虑更多特征和业务规则,对少量候选项进行更复杂、精细的排序。
比如,短视频推荐先通过召回获取数万个可能相关视频,再通过粗排缩减至数百条,最后精排阶段会考虑用户最近的互动、视频热度、内容多样性等复杂因素,确定最终展示的10个视频及顺序。

候选集数量逐步减少,排序精度逐步提高
现代Rank模型通常基于深度学习,如BERT、LambdaMART等,综合考虑查询与候选项的相关性、用户历史行为等因素。

5.混合检索策略
混合检索策略结合多种检索方法的优势,提高搜索的效果。常见组合包括关键词检索、语义检索、知识图谱等。
RAG实战:Spring AI+本地知识库
Spring Al 框架为我们实现 RAG 提供了全流程的支持,参考 Spring Al和 Spring Al Alibaba 的官方文档。
1. 文档准备
准备用于给ai知识库提供只是的文档,推荐markdown格式,尽量结构化。
2.文档读取
首先,我们对自己准备好的知识库文档进行处理,然后保存到向量数据库中。这个过程俗成ETL(抽取、转换、加载),Spring AI提供了ETL的支持。
ETL的3大核心组件,按照顺序执行:
DocumentReader:读取文档,得到文档列表
DocumentTransformer:转换文档,得到处理后的文档列表
DocumentWriter:将文档列表保存到存储中(可以是向量数据库,也可以是其他存储)

1>引入依赖
SpringAl提供了很多种DocumentReaders,用于加载不同类型的文件。
我们可以使用MarkdownDocumentReader来读取Markdown文档。需要先引l入依赖,可以在 Maven中央仓库找到 。
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-markdown-document-reader</artifactId><version>1.0.0-M6</version>
</dependency>
2>在根目录下新建rag包,编写文档加载器类LoveAppDocumentLoader,负责读取所有Markdown 文档并转换为Document列表。代码如下:
@Component
@Slf4j
class LoveAppDocumentLoader {private final ResourcePatternResolver resourcePatternResolver;LoveAppDocumentLoader(ResourcePatternResolver resourcePatternResolver) {this.resourcePatternResolver = resourcePatternResolver;}public List<Document> loadMarkdowns() {List<Document> allDocuments = new ArrayList<>();try {// 这里可以修改为你要加载的多个 Markdown 文件的路径模式Resource[] resources = resourcePatternResolver.getResources("classpath:document/*.md");for (Resource resource : resources) {String fileName = resource.getFilename();MarkdownDocumentReaderConfig config = MarkdownDocumentReaderConfig.builder().withHorizontalRuleCreateDocument(true).withIncludeCodeBlock(false).withIncludeBlockquote(false).withAdditionalMetadata("filename", fileName).build();MarkdownDocumentReader reader = new MarkdownDocumentReader(resource, config);allDocuments.addAll(reader.get());}} catch (IOException e) {log.error("Markdown 文档加载失败", e);}return allDocuments;}
}
上述代码中,我们通过MarkdownDocumentReaderConfig文档加载配置来指定读取文档的细节,比如是否读取代码块、引用块等。特别需要注意的是,我们还指定了额外的元信息配置,提取文档的文件名(fileName)作为文档的元信息,可以便于后续知识库实现更精确的检索。
3>向量转换和存储
为了实现方便,我们先使用 Spring Al 内置的、基于内存读写的向量数据库 SimpleVectorStore 来保存文档。
SimpleVectorStore实现了VectorStore接口,而VectorStore 接口集成了DocumentWriter,所以具备文档写入能力。如图:

在将文档写入到数据库之前,会先调用Embedding大模型将文档转换为向量,实际保存到数据库中的是向量类型的数据。

在 rag 包下新建LoveAppVectorStoreConfig 类,实现初始化向量数据库并且保存文档的方法。代码如下:
@Configuration
public class LoveAppVectorStoreConfig {@Resourceprivate LoveAppDocumentLoader loveAppDocumentLoader;@BeanVectorStore loveAppVectorStore(EmbeddingModel dashscopeEmbeddingModel) {SimpleVectorStore simpleVectorStore = SimpleVectorStore.builder(dashscopeEmbeddingModel).build();// 加载文档List<Document> documents = loveAppDocumentLoader.loadMarkdowns();simpleVectorStore.add(documents);return simpleVectorStore;}
}
4>查询增强
Spring Al 通过 Advisor 特性提供了开箱即用的 RAG 功能。主要是QuestionAnswerAdvisor 问答拦截器和 RetrievaIAugmentationAdvisor检索增强拦截器,前者更简单易用、后者更灵活强大。
查询增强的原理其实很简单。向量数据库存储着AI模型本身不知道的数据,当用户问题发送给AI模型时,QuestionAnswerAdvisor会查询向量数据库,获取与用户问题相关的文档。然后从向量数据库返回的响应会被附加到用户文本中,为AI模型提供上下文,帮助其生成回答。
查看QuestionAnswerAdvisor源码,可以看到让Al基于知识库进行问答的Prompt:

根据官方文档,需要先引入依赖
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-advisors-vector-store</artifactId>
</dependency>
此处我们就选用更简单易用的QuestionAnswerAdvisor问答拦截器,在LoveApp中新增和RAG知识库进行对话的方法。代码如下:
@Resource
private VectorStore loveAppVectorStore;public String doChatWithRag(String message, String chatId) {ChatResponse chatResponse = chatClient.prompt().user(message).advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId).param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))// 开启日志,便于观察效果.advisors(new MyLoggerAdvisor())// 应用知识库问答.advisors(new QuestionAnswerAdvisor(loveAppVectorStore)).call().chatResponse();String content = chatResponse.getResult().getOutput().getText();log.info("content: {}", content);return content;
}
发现有元数据,分数,查询结果条数。ai回复结果包含了知识库中的内容。

RAG实战:Spring AI + 云知识库服务
在上一小节中,我们文档读取、文档加载、向量数据库是在本地通过编程的方式实现的。其实还有另外一种模式,直接使用别人提供的云知识库服务来简化RAG的开发。但缺点是额外的费用、以及数据隐私问题。
1.准备云知识库
首先我们可以利用云知识完成文档读取,文档处理,文档加载,保存到向量数据库、知识库管理等操作。
1>准备数据。在应用数据模块中,上传原始文档数据到平台,由平台来帮忙解析文档中的内容和结构。

2>进入阿里云百炼平台的知识库,创建一个知识库,选择推荐配置即可:

3>导入数据到知识库中,先选择要导入的数据:

导入数据时,可以设置数据预处理规则,智能切分文档为文档切片(一部分文档):

创建好知识库后,进入知识库查看文档和切片
如果觉得智能切分得到的切片不合理,可以手动编辑切片内容。
2.RAG开发
有了知识库后,我们就可以用程序来对接了。开发过程很简单,可以参考SpringAlAlibaba的官方文档来学习。
SpringAlAlibaba利用了SpringAl提供的文档检索特性(DocumentRetriever),自定义了一套文档检索的方法,使得程序会调用阿里灵积大模型API来从云知识库中检索文档,而不是从内存中检索。
使用下列代码就可以创建一个文档检索器并发起查询:
// 调用大模型的 API
var dashScopeApi = new DashScopeApi("DASHSCOPE_API_KEY");
// 创建文档检索器
DocumentRetriever retriever = new DashScopeDocumentRetriever(dashScopeApi,DashScopeDocumentRetrieverOptions.builder().withIndexName("你的知识库名称").build());
// 测试从云知识库中查询
List<Document> documentList = retriever.retrieve(new Query("谁是xx"));
如何使用这个文档检索器,让AI从云知识库查询文档呢?
这就需要使用SpringAI提供的另一个RAG Advisor--RetrievalAugmentationAdvisor检索增强顾问,可以绑定文档检索器、查询转换器和查询增强器,更灵活地构造查询。
示例代码如下:
Advisor retrievalAugmentationAdvisor = RetrievalAugmentationAdvisor.builder().queryTransformers(RewriteQueryTransformer.builder().chatClientBuilder(chatClientBuilder.build().mutate()).build()).documentRetriever(VectorStoreDocumentRetriever.builder().similarityThreshold(0.50).vectorStore(vectorStore).build()).build();String answer = chatClient.prompt().advisors(retrievalAugmentationAdvisor).user(question).call().content();
