type
status
date
slug
summary
tags
category
icon
password
本次学习的github repo是:https://github.com/Michaellzd/rag_learning1
为什么需要rag?
知识外挂,模型无需为特定任务来重新训练或者fine-tuning,提升模型在某个专业领域的能力和精度。
参数化的东西是训练过程中拿到的,更新的成本比较高;非参数化成本低
4个问题:
领域知识缺乏:通用数据训练
信息过时:很好理解,毕竟训练用的数据,肯定不是实时的。
幻觉:概率性输出
安全

图片来自论文 Retrieval-Augmented Generation for Large Language Models: A Survey
rag加入补上了实时这一环
应用场景:
qa系统;客服系统;金融医疗这种实时性要求高的系统

图片来自极客时间课程
RAG 标准流程由索引(Indexing)、检索(Retriever)和生成(Generation)三个核心阶段组成。
索引阶段,通过处理多种来源多种格式的文档提取其中文本,将其切分为标准长度的文本块(chunk),并进行嵌入向量化(embedding),向量存储在向量数据库(vector database)中。
检索阶段,用户输入的查询(query)被转化为向量表示,通过相似度匹配从向量数据库中检索出最相关的文本块。
最后生成阶段,检索到的相关文本与原始查询共同构成提示词(Prompt),输入大语言模型(LLM),生成精确且具备上下文关联的回答
RAG vs fine-tuning
RAG 更适用于需要动态响应、频繁更新外部知识的场景,而微调则适合固定领域内的深度优化与推理。
project1
技术框架:
RAG 技术框架:LangChainLangChain
索引流程 - 文档解析模块:pypdfpypdf
索引流程 - 文档分块模块:RecursiveCharacterTextSplitter采用 LangChain 默认的文本分割器 -RecursiveCharacterTextSplitter。
向量化模型:bge-small-zh-v1.5bge-small-zh-v1.5
向量库:FaissFaiss 全称 Facebook AI Similarity Search,
大语言模型:deepseek

就按照这个过程做一个:
索引阶段,通过处理多种来源多种格式的文档提取其中文本,将其切分为标准长度的文本块(chunk),并进行嵌入向量化(embedding),向量存储在向量数据库(vector database)中。
检索阶段,用户输入的查询(query)被转化为向量表示,通过相似度匹配从向量数据库中检索出最相关的文本块。
最后生成阶段,检索到的相关文本与原始查询共同构成提示词(Prompt),输入大语言模型(LLM),生成精确且具备上下文关联的回答
索引流程:
读pdf—提取内容。
RecursiveCharacterTextSplitter(langchain)来分割文本块
转换为embedding向量—》处理成numpy数组
将所有的嵌入向量添加到FAISS索引中,后续可以用来进行相似性检索
检索流程:
先对查询语句转为embedding,然后放入numpy数组
在faiss索引中检索最相似的前k个文本块
可以看看这个结果,就是通过embedding找到了最类似的
生成:
api的用法,这里可以以deepseek的这个格式为例子:
for chunk in response:
- 这里的response
是一个迭代器,包含了模型生成的每个小片段(chunk)。使用流式响应可以让我们在模型生成完整回答之前就开始接收和处理部分内容。if hasattr(chunk.choices[0].delta, 'content'):
- 检查当前chunk是否包含内容。在流式响应中,并非每个chunk都包含新的内容。content = chunk.choices[0].delta.content
- 如果chunk包含内容,我们从中提取文本内容。结果如下,根据了给定的pdf生成了如下的文本

文档解析技术
Quality in, Quality out” 是大模型技术的典型特征,高质量的文档解析能够从各种复杂格式的非结构化数据中提取出高精准度的信息,对 RAG 系统最终的效果起决定性的作用

LangChain 提供了一套功能强大的文档加载器(Document Loaders),帮助开发者轻松地将数据源中的内容加载为文档对象。LangChain 定义了 BaseLoader 类和 Document 类,其中 BaseLoader 类负责定义如何从不同数据源加载文档,而 Document 类则统一描述了不同文档类型的元数据。

注意:Document Loader 模块是封装好的各种文档解析库集成 SDK,项目中使用还需要安装对应的文档解析库。例如,当我们项目中使用 from langchain_community.document_loaders import PDFPlumberLoader 时,需要先通过命令行 pip install pdfplumber 安装 pdfplumber 库
这块就是给定一个folder,定一个loadermap,根据文档类型来找到

把上面全部读了

为什么rag里面有了索引,也要传文本块:
index只包含向量表示和对应索引,不包含原始文本内容;faiss只是进行相似度的搜索
pdf的文档解析
本质来说pdf是一系列显示和打印指令的集合。

选择 MarkDown 文件作为统一的输出格式最为合适。这是因为 MarkDown 文件关注内容本身,而非打印格式,能够表示多种文档元素内容。MarkDown 格式被广泛接受于互联网世界,其信息能够被大模型理解。
分块chunking和嵌入embedding

嵌入模型(Embedding Model)负责将文本数据映射到高维向量空间中,将输入的文档片段转换为对应的嵌入向量(embedding vectors)。这些向量捕捉了文本的语义信息,并被存储在向量库(VectorStore)中,以便后续检索使用。用户查询(Query)同样通过嵌入模型的处理生成查询嵌入向量,这些向量用于在向量数据库中通过向量检索(Vector Retrieval)匹配最相似的文档片段。根据不同的场景需求,评估并选择最优的嵌入模型
分块的重要性:
太大:无法捕获特定的细节;太小:丢失上下文信息
较小的块适用于需要细粒度分析的任务,例如情感分析,能够精确捕捉特定短语或句子的细节。更大的块则更为合适需要保留更广泛上下文的场景,例如文档摘要或主题检测。因此,块大小的确定必须在计算效率和上下文信息之间取得平衡。
多种分块策略从本质上来看,由以下三个关键组成部分构成:大小:每个文档块所允许的最大字符数。重叠:在相邻数据块之间,重叠字符的数量。拆分:通过段落边界、分隔符、标记,或语义边界来确定块边界的位置

固定大小分块:实现比较简单便于管理。但是不考虑内容上下文,可能导致无意义的chunk。
重叠分块:通过滑动窗口来切分,使得新文本块和前一块内容有重叠,增强语义。问题可能是存在冗余信息。
递归分块:通过预定义的文本分隔符(如换行符\n\n、\n ,句号、逗号、感叹号、空格等)迭代地将文本分解为更小的块,以实现段大小的均匀性和语义完整性。问题也可能是存在模糊语义。
文档特定分块:根据文档的格式(如 Markdown、Latex、或编程语言如 Python 等)进行定制化分割的技术。此方法依据文档的特定格式和结构规则,例如 Markdown 的标题、列表项,或 Python 代码中的函数和类定义等,来确定分块边界。但是不通用,比如不同格式的文档。
语义分块:基于文本的自然语言边界(如句子、段落或主题中断)进行分段的技术,需要使用 NLP 技术根据语义分词分句,旨在确保每个分块都包含语义连贯的信息单元。语义分块保留了较高的上下文保留,并确保每个块都包含连贯的信息,但需要更多的计算资源。
混合分块:通过综合利用不同分块技术的优势,提高分块的精准性和效率。例如,在初始阶段使用固定长度分块快速整理大量文档,而在后续阶段使用语义分块进行更精细的分类和主题提取。根据实际业务场景,设计多种分块策略的混合,能够灵活适应各种需求,提供更强大的分块方案
而langchain也提供了text spliiters的方法来使用

Embedding 嵌入是指将文本、图像、音频、视频等形式的信息映射为高维空间中的密集向量表示。这些向量在语义空间中起到坐标的作用,捕捉对象之间的语义关系和隐含的意义。通过在向量空间中进行计算(例如余弦相似度),可以量化和衡量这些对象之间的语义相似性。
向量是一组在高维空间中定义点的数值数组,而嵌入则是将信息(如文本)转化为这种向量表示的过程。这些向量能够捕捉数据的语义及其他重要特征,使得语义相近的对象在向量空间中彼此邻近,而语义相异的对象则相距较远。

在高纬度中比较,找到最近的。
embedding model的作用:向量化之后进行比较。

怎么选?:通过参考 MTEB 和 C-MTEB 的评测榜单,可以评估多个高得分的模型,并在具体的业务场景中进行测试,最终选择最适合该场景的嵌入模型。同时,使用 SentenceTransformers Python 模块可以简化嵌入模型的加载和嵌入计算,进而高效率集成测试
向量数据库

首先,数据隐私安全要求高的场景,比如要求内网环境,优先选择开源向量数据库;
在此场景下,如果客户需求超出开源向量数据库的功能表现,需要加强或者定制,可以考虑商业许可并获得官方的技术支持;
其次,数据隐私安全要求不高的场景,优先选择开源向量数据库,以节约成本;
项目比较小考虑Chroma、Qdrant;项目比较大就Milvus;
如果LLM应用在无服务器环境比如lambda,优先选择Zilliz或者Pinecone
为什么需要向量数据库

举个例子,如果你想要找到一本特定的书,只需通过书名来精准定位信息,键值数据库是最理想的选择。而如果你需要查询一本书的详细章节内容、作者简介等复杂的结构化信息,文档数据库则更为适用。如果你的目标是了解书籍之间的推荐关系,或者探索作者之间的合作网络,图数据库可以高效存储和查询这些复杂的关系数据。最后,如果你希望找到与某本书内容相似的书籍,比如基于主题、风格等特征进行相似性搜索,向量数据库则能够通过计算书籍内容语义在向量空间中的距离,为你提供语义最相关的数据信息。
向量数据库如何工作
向量数据库是一种专门用于存储和检索多维向量的数据库类型,与传统的基于行列结构的数据库不同,它主要处理高维空间中的数据点。传统数据库通常处理字符串、数字等标量数据,并通过精确匹配来查询数据。然而,向量数据库的操作逻辑则是基于相似性搜索,即在查询时,应用特定的相似性度量(如余弦相似度、欧几里得距离等)来查找与查询向量最相似的向量
为了优化查询性能,它采用了如哈希、量化和基于图形的多种算法。这些算法通过构建如层次化可导航小世界(HNSW)图、产品量化(PQ)和位置敏感哈希(LSH)等索引结构


使用chroma向量数据库来实验:
Chroma 是一种简单且易于持久化的向量数据库,它以轻量级、开箱即用的特性著称。Chroma 支持内存中操作和磁盘持久化,能够高效地管理和查询向量数据
之前用的是Faiss向量库 不支持持久化
设置了 ChromaDB 的存储路径,并在每次运行时清空旧的存储。然后创建了一个持久化的 ChromaDB 客户端和文档集合。
直接用collections.query来检索
rag检索
关键词检索

可以精确匹配,但是无法提供与订单相关更广泛的上下文。—》由此需要混合检索
RAG 检索场景中,首要目标是确保最相关的结果能够出现在候选列表中。向量检索和关键词检索各有其独特优势,混合检索通过结合这多种检索技术,弥补了各自的不足,提供了一种更加全面的搜索方案。仅具备混合检索的能力还不足以满足需求,检索到的结果还需要经过优化排序。重排序(Reranking)的目的是将混合检索的结果进行整合,并将与用户问题语义最契合的结果排在前列

混合检索,又称融合检索 / 多路召回,是指在检索过程中同时采用多种检索方式,并将各类检索结果进行融合,从而得到最终的检索结果


后面实验用的是bm25来作为关键词搜索算法
BM25 是一种强大的关键词搜索算法,通过分析词频(TF)和逆向文档频率(IDF)来评估文档与查询的相关性。具体来说,BM25 检查查询词在文档中的出现频率,以及该词在所有文档中出现的稀有程度。如果一个词在特定文档中频繁出现,但在其他文档中较少见,那么 BM25 会将该文档评为高度相关
BM25通过对文档和查询进行分词,然后比较这些词的匹配程度来实现基于关键词的匹配。它不仅考虑了词是否出现,还考虑了词的重要性(通过IDF)和出现频率(通过TF),从而提供了一种更加精细和有效的关键词匹配机制。
相当于给了更多的,有价值的参考内容放入到里面
为什么使用重排序?
尽管向量检索技术能够为每个文档块生成初步的相关性分数,但引入重排序模型仍然至关重要。向量检索主要依赖于全局语义相似性,通过将查询和文档映射到高维语义空间中进行匹配。然而,这种方法往往忽略了查询与文档具体内容之间的细粒度交互
1.重排序技术通过重新评估文档与查询的相关性,确保生成模型优先使用那些与查询最相关的文档
2.对于复杂的查询,初始检索可能会返回一些表面上相关但实际上不太匹配的文档。重排序技术可以根据查询的复杂性和具体需求,对这些结果进行更细致的分析和排序,优先展示那些能够提供深入见解或关键信息的文档。
重排序模型
RAG 流程有两个概念,粗排和精排。粗排检索效率较快,但是召回的内容并不一定强相关。而精排效率较低,因此适合在粗排的基础上进行进一步优化。精排的代表就是重排序(Reranking)

与嵌入模型不同,重排序模型将用户的查询(Query)和文档块作为输入,直接输出相似度评分,而非生成嵌入向量。(在生产环境中使用重排序模型会面临资源和效率问题,包括计算资源消耗高、推理速度慢以及模型参数量大等问题)
本次使用的是使用来自北京人工智能研究院 BGE 的 bge-reranker-v2-m3 作为 RAG 项目的重排序模型,这是一种轻量级的开源和多语言的重排序模型
为什么需要为每个query配对一个query:
- 模型输入格式要求:
重排序模型(如这里使用的 BAAI/bge-reranker-v2-m3)通常被设计为接受查询-文档对作为输入。这种设计允许模型同时考虑查询和文档的内容,从而更好地评估它们之间的相关性。
- 上下文相关性评估:
通过将每个文档块与查询配对,模型可以独立评估每个文档块与查询的相关性。这允许模型考虑查询和每个特定文档块之间的语义关系。
- 灵活性和可扩展性:
这种方法使得系统更加灵活。例如,如果我们后续想要比较不同查询对同一组文档的相关性,或者对多个查询进行批处理,这种结构会非常有用。
- 并行处理:
创建这样的配对还允许系统并行处理多个查询-文档对,这在处理大量文档时可以提高效率。5. 模型的一致性:保持查询-文档对的结构使得模型可以一致地处理输入,无论是在训练时还是在推理时。6. 细粒度的相关性评分:通过单独评估每个查询-文档对,模型可以提供更细粒度的相关性评分,而不是仅仅给出一个整体的排序。
rag生成流程

大模型的原理
最关键就是transformer
与传统的循环神经网络(RNN)相比,Transformer 模型不依赖于序列顺序,而是通过自注意力(Self-Attention)机制来捕捉序列中各元素之间的关系。Transformer 由多个堆叠的编码层(Encoder)和解码层(Decoder)组成,每一层包括自注意力层、前馈层和归一化层。这些层协同工作,逐步捕捉输入数据信息特征,从而预测输出,实现强大的语言理解和生成能力
Transformer 模型的核心创新在于位置编码和自注意力机制。位置编码帮助模型理解输入数据的顺序信息,而自注意力机制则允许模型根据输入的全局上下文,为每个词元分配不同的注意力权重,从而更准确地理解词与词之间的关联性。

右上图中的示例显示了输入句子中的填空任务,解码器依据输入句子的特征和已生成的部分句子,生成了“She”作为模型的预测结果。生成“She”的核心原因在于右下图所示的注意力机制,其中需要填空的部分对输入句子中的词元“The Doctor”和“Nurse”分配了较高的注意力权重,从而提高了“She”作为输出词元的生成概率。
可以看看这个来回顾整个transformers
提示工程prompt
一个提示通常包含以下几类元素:
指令(Instruction):指明模型要执行的特定任务或操作。
上下文(Context):为模型提供额外信息或背景,可以帮助引导模型生成更准确的响应。
输入数据(Input Data):我们希望模型回答的问题或感兴趣的输入内容。
输出指示符(Output Indicator):指定模型的输出类型或格式,例如格式、是否要求生成代码、总结文本或回答具体问题

优化检索精度

数据清洗和预处理
1.处理冗余的模板内容
- 消除文档中的额外空白和格式不一致
- 去除文档脚注、页眉页脚、版权信息
查询扩展:
通过大模型从原始查询语句生成多个语义相关的查询,可以覆盖向量空间中的不同区域,从而提高检索的全面性和准确性。这些查询在嵌入后能够击中不同的语义区域,确保系统能够从更广泛的文档中检索到与用户需求相关的有用信息
比如:
自查询
自查询策略通过大语言模型自动提取查询中对业务场景至关重要的元数据字段(如标签、作者 ID、评论数量等关键信息),并将这些信息结合到嵌入检索过程中。通过这种方式,可以确保嵌入向量中包含这些关键信息,从而提高检索的全面性与精确性
提示压缩:
减少上下文中的噪声,并突出最相关的信息,从而提高检索精度和生成质量
advanced rag

Advanced RAG 则通过增加检索前、检索中以及检索后的优化策略,提高了检索的准确性和生成的关联性,特别是在复杂任务中表现更为出色。Modular RAG 则进一步打破了传统的链式结构,允许不同模块之间的灵活组合以及流程的适应性编排,提供了更高的灵活性和可扩展性,用于处理多样化的需求和复杂任务。
case:

问题涉及:
明确的时间范围(三年)与多文档的信息(Nvidia 与 Apple 的材料)。
复杂的要求,需要分析专业领域指标(财务)并做出投资价值的判断。
可以看到Advanced RAG 通过引入多种技术,采用了检索前、检索中、检索后的优化策略,显著提高了检索质量
检索前优化:
1.滑动窗口:确保相邻文本有重叠区域,确保关键信息不丢失
2.元数据添加:为每个分块添加元数据(如创建日期、章节名称、文档类型等),能够使系统在检索时快速过滤掉无关内容。例如,用户在查询时可以通过元数据筛选特定时间段的文档,减少不相关信息的干扰。
3.分层索引
4.查询重写
5.查询扩展
检索优化:
1.动态嵌入:RAG 系统通过动态嵌入模型根据上下文变化实时调整单词的嵌入表示,能够捕捉单词在不同上下文中的不同含义。例如,“bank”在“river bank”(河岸)和“financial bank”(银行)中的语义完全不同,动态嵌入可以根据具体语境生成合适的向量,从而提高检索的精准性
2.领域特定嵌入微调:在实际应用中,不同领域的数据语境差异较大,通用的嵌入模型往往无法覆盖某些领域的专业术语或特定语义。通过对嵌入模型进行微调,可以增强其在特定领域中的表现。例如,针对医学、法律等专业领域,可以对嵌入模型进行定制化训练 / 微调,使其更好地理解这些领域中的特有词汇和语境
3.混合检索
检索后:
1.重排序
2.提示压缩
3.上下文重构
4.内容过滤
modular rag

Orchestration(编排) 是区别于 Advanced RAG 最显著的部分,它通过自由的流程控制和决策来优化检索和生成的全流程。这一部分的核心思想是通过智能路由和调度,动态地决定查询处理的路径和步骤
1.路由 routing
主要功能是在收到用户查询后,根据查询的特点和上下文,选择最合适的流程。
主要包括两个部分:
a. Query Analysis(查询分析):首先,对用户的查询进行语义分析,判断其类型和难度。例如,一个直接问答式的查询可能不需要复杂的检索过程,而一个涉及多步推理的复杂问题则可能需要走更长的检索路径。
b. Pipeline Selection(管道选择):根据查询分析的结果,Routing 模块会动态选择合适的流程(Pipeline)。比如针对简单的查询,可以仅用大模型的知识来回答,效率高。而针对需要领域知识及复杂推理的查询,系统会使用更多的检索步骤,结合外部文档及知识进行深度检索生成。
2.调度scheduling
调度的作用是管理查询的执行顺序,并动态调整检索和生成步骤
a. Query Scheduling(查询调度):当系统接收到查询时,调度模块会判断是否需要进行检索。调度模块根据查询的重要性、上下文信息、已有生成结果的质量等多维度因素进行评估。
b. Judgment of Retrieval Needs(检索需求判断):调度还通过特定的判断节点来确定是否需要额外检索。在某些情况下,系统可能会多次判断是否有必要执行新一轮的检索。
3.Knowledge Guide(知识引导)知识引导是结合知识图谱和推理路径来增强查询处理过程。
a. Knowledge Graph(知识图谱):在处理复杂查询时,系统可以调用知识图谱来辅助检索。这不仅提升了检索结果的准确性,还可以通过知识图谱中的上下文关系来推导出更为精确的答案。例如,若查询涉及多个实体的关系或多个时间点,知识图谱能够提供更深层次的推理支持。
b. Reasoning Path(推理路径):通过推理路径,系统可以设计出一条符合查询需求的推理链条,系统可以根据这一链条进行逐步地推理和检索。这在处理具有强逻辑性的问题时非常有效,例如跨多个文档的关系推理或时间序列推导。
graph rag
RAG 在使用向量检索时面临两个主要挑战:
信息片段之间的连接能力有限:RAG 在跨越多个信息片段以获取综合见解时表现不足。例如,当需要回答一个复杂的问题,必须通过共享属性在不同信息之间建立联系时,RAG 无法有效捕捉这些关系。这限制了其在处理需要多跳推理或整合多源数据的复杂查询时的能力。
归纳总结能力不足:在处理大型数据集或长文档时,RAG 难以有效地归纳和总结复杂的语义概念。例如,试图从一份包含数百页的技术文档中提取关键要点,对 RAG 来说是极具挑战性的。这导致其在需要全面理解和总结复杂语义信息的场景中表现不佳

知识图谱:
三要素
实体(Entities):表示具体的对象或概念,例如苹果公司、iPhone、智能手机。
属性(Attributes):描述实体的特征,如成立日期、创始人。
关系(Relations):连接实体之间的语义关联,如生产、竞争对手

构建知识图谱通常涉及以下步骤:
实体识别:从文本或数据源中识别出关键实体。
关系抽取:确定实体之间的关系,可能通过自然语言处理技术实现。
三元组生成:将实体和关系表示为 (主体,关系,客体) 的形式。
图谱存储:使用图数据库或专门的存储系统保存知识图谱
微软graphrag
