Retrieval-Augmented Generation(RAG)
RAG(Retrieval-Augmented Generation):检索增强生成,一种结合检索技术和生成式AI的混和架构。原理是让模型在生成回答前先从知识库中检索相关信息,在基于这些信息生成回答。从而提高知识的 有效性和准确性。
RAG工作原理
工作流程为3步:检索-增强-生成的闭环、
1、检索(Retrieval):查询跟用户提问相关的知识片段。
- 当用户发送消息时,系统会先将查询转换为向量(通过Embedding模型),
- 利用向量数据库,从外部知识库中(文档、数据库、网页等)中检索于查询语义相关的内容(上下文匹配)。
- 检索策略 可结合:关键字匹配和语义向量检索。平衡找回率和相关性。
2、增强(Augmented)
将检索到的上下文片段和用户提问拼接,形成增强后的 提示词,更专业更丰富。
3、生成(Generation)
将增强提示词 输入给模型,模型基于检索到的信息生成回答,提高输出内容的可靠性。
知识库构建
-
文档收集和切割
文档收集:从不同场景中(网页、PDF、数据库等)收集原始数据文档。
文档预处理:清洗,格式化文本。
文档切割:将长文档分割为合适的片段,注意粒度、拆分逻辑。 -
向量存储和转换
向量转换:使用Embedding模型将文本转换为高维向量,可以获取到文本的语义特征。
向量存储:将生成的向量和对应的文本存储到向量数据库,以实现高效的相似性搜索。
RAG相关技术
知识库(Knowledge Base)
存储领域相关的结构化 / 非结构化数据,如文档(PDF、Word)、网页、数据库表、对话记录等;
需提前进行预处理(如拆分文档为短句、去除噪声),便于高效检索。
Embedding和Embedding模型
Embedding:是将高纬度的数据(如文字、图像),转为低维向量的过程,就是将文字转为对应的数据表示,方便机器理解。
模型: 将文本(查询和知识库内容)转换为高维向量(Embedding),捕捉语义信息;常用模型:OpenAI Embeddings、Sentence-BERT、LLaMA Embedding 等,
向量数据库:相较于传统数据库,具有高纬向量的存储和检索。
专门用于存储和检索向量的数据库,支持高效的索引算法、近似最近邻(ANN)搜索等高效搜索;核心功能:快速找到与查询向量最相似的知识库向量,返回对应的文本片段。执行流程:查询输入 - 查询向量化 - ANN搜索 - 相似度排序 -返回结果。检索过程:召回-粗排-精排召回:检索的第一阶段,**强调速度和广度,而非精度**。粗排:进行简单逻辑的 筛选。精排:高复杂的排序,考虑更多业务和特性。返回少量结果。
RAG 进阶
1、文档收集和切割-ETL:对准备好的知识库文档进行处理,保存到数据库中。处理过程称为ETL(抽取转换加载)。
ETL:在SpringAI中,对Document的处理遵循:1. 读取文档,使用DocumentReader组件从数据源中(本地文件、网络资源/数据库等)加载文件。2. 处理文档,根据需求将文档转为合适的格式方便后续处理,比如:去重,分词等操作,可以使用DocumentTransformer组件实现。3. 保存文档:使用DocumentWriter将文档保存,可以存储到向量数据库,或者以键值对字符串存储到Redis中。
因此SpringAI中 ETL核心组件:DocumentReader、DocumentTransformer、DocumentReader。
- 抽取(Extract)
实际开发中,SPringAI内置了多种Document Reader实现类,来处理不同类型的数据源。
DocumentReader接口实现了 Supplier<List<Document/ >>接口,主要负责从不同数据源中读取数据并转换Document对象集合。
- JsonReader: 读取 JSON 文档
- TextReader:读取纯文本文件
- MarkdownReader:读取 Markdown 文件
- PDFReader:读取 PDF 文档,基于 Apache PdfBox 库实现
- PagePdfDocumentReader:按照分页读取 PDF
- ParagraphPdfDocumentReader:按照段落读取PDF
- HtmlReader: 读取 HTML 文档,基于 jsoup 库实现
- TikaDocumentReader:基于 Apache Tika 库处理多种格式的文档,更灵活
更多文档阅读器
- 转换(Transform)
SpringAI通过DocumentTransformer组件实现文档转换。
DocumentTransfransformer接口实现了Function<List<Document/ >, List<Document/ >>接口,负责将一组文档转为另一组文档。
文档转换是保证RAG效果的核心步骤,即合理将大文档拆分为便于检索的碎片。SpringAI提供多种实现类,
- TextSplitter文本分割器
- MetadataEnricher元数据增强器:作用是为文档补充更多的元信息,便于后续检索。而不是改变文档本身的切分规则。包含
- keywordMetadataEnricher:使用AI提取关键词并添加到元数据。
- summaryMetadataEnricher:使用AI生成文档摘要并添加到元数据,不仅可以为当前文档生成摘要,还能关联文档,让摘要更完整。
- ContentFormatter内容格式化工具
用于统一文档内容格式。- 文档格式化:将文档内容于元数据 合并成特定格式的字符串,以便后续处理。
- 元数据过滤:根据不同元数据模式(MetadataMode)筛选要保留的元数据项。
- 自定义模板:支持自定义不同格式。
- 加载(Load)
SpringAi通过DocumentWriter组件实现文件加载(写入)
DocumentWrite接口实现了Consumer<List<Document/ >>接口,负责将处理后的文档写入到目标存储中。
- FeilDocumentWriter:将文档写入到文件系统中
- VectorStoreWriter:将文档写入到向量数据库中。
也可以自定义Writer。
ETL流程示例:
整合上面3个操作:
// 抽取:从 PDF 文件读取文档
PDFReader pdfReader = new PagePdfDocumentReader("knowledge_base.pdf");
List<Document> documents = pdfReader.read();// 转换:分割文本并添加摘要
TokenTextSplitter splitter = new TokenTextSplitter(500, 50);
List<Document> splitDocuments = splitter.apply(documents);SummaryMetadataEnricher enricher = new SummaryMetadataEnricher(chatModel, List.of(SummaryType.CURRENT));
List<Document> enrichedDocuments = enricher.apply(splitDocuments);// 加载:写入向量数据库
vectorStore.write(enrichedDocuments);// 或者使用链式调用
vectorStore.write(enricher.apply(splitter.apply(pdfReader.read())));
向量转换和存储
前面说到 知识库核心流程:文档收集和切割、向量转换和存储。
转为向量存储,是为了方便后续的高效相似度查询。
SpringAI 提供了 向量数据库接口和向量存储整合包。支持快速集成三方向量数据库。
VectorStore接口介绍:
是用于于向量数据库交互的核心接口。继承自DocumentWriter,主要功能:
提供了基础的增删改查。
- 添加文档到向量库。
- 从向量库删除文档
- 基于查询进行相似度搜索
- 获取原生客户端(用于实现特定的操作)
搜索请求构建:
SpringAItigong SearchRequest类,用于构建相似度搜索请求。
示例:
SearchRequest request = SearchRequest.builder().query("什么是RAG").topK(2) // 返回最相似的2个结果.similarityThreshold(0.7) // 相似度阈值,0.0-1.0之间.filterExpression("category == 'web' AND date > '2025-05-03'") // 过滤表达式.build();List<Document> results = vectorStore.similaritySearch(request);- query:搜索的查询文本- topK:返回最大结果数- similarityThreshold:相似度与之,低于此值的结构会被过滤掉- filterExpression:基于文档元数据的过滤表达式,语法类似SQL。[文档](https://docs.spring.io/spring-ai/reference/api/vectordbs.html#metadata-filters)
向量存储的工作原理
在向量数据库中,与普通数据相比。执行的是相似度匹配,而非精确匹配。
-
嵌入转换:当文档添加到向量存储时,SpringAI会使用嵌入模型,将文本转为向量。
-
相似度计算:查询时,查询文本同样被转为向量,然后系统计算 向量与存储中所有向量的相似度。
-
相似度度量:常用的相似度计算方法包括:
- 余弦度相似度:计算两个向量的夹角余弦值,范围在-1到1之间。
- 欧式距离:计算两个向量间的直线距离。
- 点积:两个向量的点积值
-
过滤和排序:根据相似阈值过滤结果,并按照相似度排序返回最相关的文档。
批处理文件:在使用向量存储时,可能会有大量文档嵌入,如果一次性处理存储大量文档,可能会有性能问题。因此SpringAI 提供了批处理策略(Batching Strategy),将大量文档分解为较小批次,符合嵌入模型的上下文窗口,提高性能。
SpringAi 通过Batching Strategy接口提供该功能。
文档过滤和检索
SpringAI 采用模块化 架构,通过不同模块优化模型回复的准确性。
即在文档过滤检索 的各个阶段进行埋点:检索前,检索时和检索后。针对不同阶段提供自定义的组件来增强模型提问。
- 检索前:系统将用户的原始提问,通过查询转换和查询扩展等方法 进行优化。输出增强的用户查询。
- 检索时:系统使用增强的查询从知识库中搜索相关的文档,可能涉及到多文档合并。最终输出一组相关文档。
- 检索后:系统会对检索的文档进一步处理,排序、选择最相关的子集。处理后返回。
查询前:优化用户查询,将用户提问转换或者扩展。
转换:重写、翻译、压缩
扩展:多查询扩展,不同关键字查询。
查询时:提高查询相关性,更好的理解用户提问。
负责从存储中检索最相关文档。
文档搜索
文档合并
查询后:优化文档处理,处理检索到的文档(限制上下文长度、排序、去重等操作)
查询增强和关联
负责将检索到的文档与用户提问结合起来,为AI提供必要的上下文,从而生成更准确,跟相关的回答。
SpringAI提供两种Advisor类增强查询。
- QuestionAnswerAdvisor查询增强:用户问题发送到模型时,Advisor会查询向量数据库获取与用户问题相关的文档,并将文档作为上下文附加到用户查询中。
- RetrievalAugmentationAdvisor查询增强:
- ContextQueryAugmenter空上下文处理。
文档过滤和检索、查询增强和关联 两者的关联与区别
前者聚焦于 “从知识库中找到有用的文档”,后者聚焦于 “让查询本身更精准、更完整”,两者共同服务于提升 RAG 的检索准确性(减少无关文档)和后续生成内容的质量(基于高质量候选文档)。
1、文档检索和过滤:
核心是 “从知识库中筛选出与查询相关的候选文档”,是 RAG 中 “检索” 环节的核心动作。
以 “用户查询(或优化后的查询)” 为依据,对预构建好的知识库(如向量数据库、结构化数据库)中的海量文档 / 片段进行筛选,最终输出一批 “最可能与查询相关” 的文档(称为 “候选文档”),供后续大模型生成内容时参考。
2、查询增强和关联
核心是 “优化用户原始查询,让其更精准、更完整地表达真实需求”,是 RAG 中 “检索前 / 检索中” 的查询预处理 / 优化动作。
用户的原始查询常存在 “模糊、简略、歧义” 等问题,查询增强通过补全、纠错、扩展、关联上下文等方式,将原始查询转化为 “更符合知识库检索逻辑、更能匹配核心需求” 的优化查询。
总结:
区别:查询增强是 “优化子弹”(让查询更精准),文档检索是 “瞄准射击”(用优化后的查询找文档);
关联:只有 “子弹” 优化到位,“射击” 才能命中目标(找到相关文档),而 “射击” 的初步结果也能反过来调整 “子弹”(进一步优化查询)。