1.1RAG的挑战
RAG主要面临三个方面的挑战:检索质量、增强过程和生成质量。
1.1.1检索质量
语义歧义:向量表示(例如词嵌入)可能无法捕捉概念之间的细微差别。例如,“苹果”一词可能指的是水果或科技公司。嵌入可能会混淆这些含义,导致不相关的结果。
用户输入变复杂:与传统关键词或者短语搜索逻辑不太一致,用户输入问题不再是词或者短句,而是转变成自然对话声知识多轮对话数据,问题形式更加多元,紧密关联上下文,输入风格更加口语化。
文档切分:文档切分主要有两种方式:一种是基于形式的切分,比如利用标点和段落的结束;另一种是基于文档内容的意义进行切分。如何将这些文档块转换成电脑能够理解和比较的形式(即“嵌入”),进而影响这些块与用户搜索内容的匹配程度。
多模内容的提取及表征(例如表格、图表、公式等):如何对多模内容进行提取及动态表征,是目前面临的现实问题,尤其是处理那些含糊或负面的查询,对 RAG 系统的性能有显著影响。
1.1.2增强过程
上下文的集成:这里的挑战是将检索到的段落的上下文与当前的生成任务顺利地集成。如果做得不好,输出可能会显得脱节或缺乏连贯性。
冗余和重复:如果多个检索到的段落包含相似的信息,则生成步骤可能会产生重复的内容。
排名和优先级:确定多个检索到的段落对于生成任务的重要性或相关性可能具有挑战性。增强过程必须适当权衡每个段落的价值。
1.1.3生成质量
过度依赖检索内容:生成模型可能过于依赖增强信息,导致幻觉问题突出,而不是增加价值或提供合成。
无关性:这是另一个令人担忧的问题,即模型生成的答案无法解决查询问题。
毒性或偏见:这也是另一个问题,即模型生成的答案有害或令人反感。
1.2Query理解
目前,RAG系统可能会遇到从知识库中检索到与用户query不相关的内容。这是由于如下问题:(1)用户问题的措辞可能不利于检索,(2)可能需要从用户问题生成结构化查询。
1.2.1意图识别
意图识别是指:接收用户的query和一组"选择"(由元数据定义),并返回一个或多个选定的"选择模块"。它既可以单独使用(作为 "选择器模块"),也可以作为查询引擎或检索器使用(例如,在其他查询引擎/检索器之上)。目前主要利用 LLM 实现决策功能。
它可以应用于如下场景:
1.在各种数据源中选择正确的数据源;
2.决定是进行摘要(如使用摘要索引查询引擎);还是进行语义搜索(如使用矢量索引查询引擎);
3.决定是否一次 "尝试 "多种选择并将结果合并(使用多路由功能)。
1.2.2.Query改写
该模块主要利用LLM重新措辞用户query,而不是直接使用原始的用户query进行检索。这是因为对于RAG系统来说,在现实世界中原始query不可能总是最佳的检索条件。
1.2.2.1HyDE
Hypothetical Document Embeddings(HyDE)是一种生成文档嵌入以检索相关文档而不需要实际训练数据的技术。首先,LLM创建一个假设答案来响应query。虽然这个答案反映了与query相关的模式,但它包含的信息可能在事实上并不准确。接下来,query和生成的答案都被转换为嵌入。然后,系统从预定义的数据库中识别并检索在向量空间中最接近这些嵌入的实际文档。
1.2.2.2Rewrite-Retrieve-Read
这项工作引入了一个新的框架--Rewrite-Retrieve-Read,从query改写的角度改进了检索增强方法。之前的研究主要是调整检索器或LLM。与之不同的是,该方法注重query的适应性。因为对于 LLM 来说,原始query并不总是最佳检索结果,尤其是在现实世界中。首先利用LLM 进行改写query,然后进行检索增强。同时,为了进一步提高改写的效果,应用小语言模型(T5)作为可训练的改写器,改写搜索query以满足冻结检索器和 LLM的需要。为了对改写器进行微调,该方法还使用伪数据进行有监督的热身训练。然后,将 "先检索后生成 "管道建模为强化学习环境。通过最大化管道性能的奖励,改写器被进一步训练为策略模型。
1.2.3Query扩写
该模块主要是为了将复杂问题拆解为子问题。该技术使用分而治之的方法来处理复杂的问题。它首先分析问题,并将其分解为更简单的子问题,每个子问题会从提供部分答案的相关文件检索答案。然后,收集这些中间结果,并将所有部分结果合成为最终响应。
1.2.3.1Step-Back Prompting
该工作探索了LLM如何通过抽象和推理两个步骤来处理涉及许多低级细节的复杂任务。第一步先是使用 LLM "后退一步"生成高层次的抽象概念,将推理建立在抽象概念的基础上,以减少在中间推理步骤中出错的概率。这种方法即可以在有检索的情况下使用,也可以在无检索的情况下使用。当在有检索情况下使用时,抽象的概念和原始问题都用来进行检索,然后这两个结果都用来作为LLM响应的基础。
1.2.3.2CoVe
Chain of Verification (CoVe) 旨在通过系统地验证和完善回答以尽量减少不准确性,从而提高大型语言模型所提供答案的可靠性,特别是在事实性问题和回答场景中。它背后的概念是基于这样一种理念,即大型语言模型(LLM)生成的响应可以用来验证自身。这种自我验证过程可用于评估初始响应的准确性,并使其更加精确。
在RAG系统中,针对用户实际场景中日益复杂的问题,借鉴了 CoVe技术,将复杂 Prompt 拆分为多个独立且能并行检索的搜索友好型query,让LLM对每个子查询进行定向知识库搜索,最终提供更准确详实答案的同时减少幻觉输出。
1.2.3.3RAG-Fusion
在这种方法中,原始query经过LLM 生成多个query。然后可以并行执行这些搜索查询,并将检索到的结果一并传递。当一个问题可能依赖于多个子问题时,这种方法就非常有用。RAG-Fusion便是这种方法的代表,它是一种搜索方法,旨在弥合传统搜索范式与人类查询的多面性之间的差距。这种方法先是采用LLM生成多重查询,之后使用倒数排名融合(Reciprocal Rank Fusion,RRF)来重新排序。
1.2.3.4ReAct
最近,在RAG系统中,使用ReAct思想,将复杂查询分解成更简单的"子查询",知识库的不同部分可能会围绕整个查询回答不同的 "子查询"。这对组合图尤其有用。在组成图中,一个查询可以路由到多个子索引,每个子索引代表整个知识语料库的一个子集。通过查询分解,我们可以在任何给定的索引中将查询转化为更合适的问题。
ReAct的模式如上图所示,它是将思维链提示(Chain of Thoughts,简写为CoT)和Action计划生成结合起来,相互补充增强,提升大模型解决问题的能力。其中CoT的Reasoning推理跟踪有助于模型诱导、跟踪和更新行动计划以及处理异常。Action操作允许它与知识库或环境等外部来源接口并收集其他信息。
1.2.4Query重构
考虑Query理解模块整体pipeline的效率,参考Query改写和Query扩写核心思想,Query重构模块,该模块强调了通过一次请求,实现对原始用户输入的复杂问题进行改写、拆解和拓展,挖掘用户更深层次的子问题,从而借助子问题检索效果更高的特点来解决复杂问题检索质量偏差的问题,旨在提高查询的准确性和效率。
1.3检索模型
1.3.1检索模型的挑战
依赖于Embedding模型的向量化是否准确
依赖于外部数据是否有合理的分割(不能所有的知识转化成一个向量,而是需要分割数据后转化再存入向量数据库)
依赖于Prompt拼接,当我们将返回的最相似的文档进行排序后,与用户的问题一起送给大模型,实际上是想让大模型在长上下文中准确识别定位到合适的内容进行回答。
1.3.3文档加载器
文档加载器提供了一种 "加载 "方法,用于从配置源加载文档数据。文档数据是一段文本和相关元数据。文档加载器可从多种不同来源加载文档。例如,有一些文档加载器可以加载简单的 .txt 文件或者加载任何网页的文本内容。
数据清洗:包括数据Loader,提取PDF、word、markdown以及数据库和API等;
数据处理:包括数据格式处理,不可识别内容的剔除,压缩和格式化等;
元数据提取:提取文件名、时间、章节title、图片alt等信息,非常关键。
1.3.4文档解析器
将各种格式的文档进行解析,从中提取出文本、图像和表格等关键内容。无论是PDF、Word文档还是Excel表格,文档解析器都能够准确捕捉信息。
解析文档内容是 RAG 系统最重要的前置工作之一。很多时候,企业内部数据以各种各样的文件格式存在,如 PDF、Word 文档、PPT 和 Excel 表格等。如何从大量非结构化数据中提取出内容,就需要文档智能解析技术了。
文档智能解析是指利用机器学习算法,对文档内容进行自动识别、理解和处理的过程。它不仅包括文本内容的识别,还涉及到图像、图表和表格等非文本元素的解析。
一般而言,对于不同类型的文件,有不同的解析方法,如 HTML/XML 解析、PDF 解析等。这里我们以图片形式的文档(如对纸质文档进行了扫描、拍照等)为例进行说明。
首先,需要对文档进行版面分析(Layout Analysis,也称布局分析),用于识别和理解文档中的视觉和结构布局。这里会使用到区域检测和区域分类等技术。区域检测用于识别文档中的不同区域,如文本块、图像、表格和图表等。而区域分类则将检测到的区域进一步分类,如文本可以进一步被细分为标题、副标题、正文文本等;图像可能被分类为图片、图表或公式等;表格需要识别为包含数据的结构化形式。
然后,对这些区域分别进行识别。比如,对于表格区域,它们会被输入表格识别(TSR,Table Structure Recognition)模块进行结构化识别,包含解析表格的行和列,识别单元格边界,提取结构化数据。对于文本区域,使用 OCR 引擎将图像中的文字转为机器可读的字符。
1.3.4.1RAGFlow
RAGFlow是一款基于深度文档理解构建的开源 RAG 引擎。RAGFlow 的最大特色,就是多样化的文档智能处理,它没有采用现成的 RAG 中间件,而是完全重新研发了一套智能文档理解系统,确保数据 Garbage In Garbage Out 变为 Quality In Quality Out,并以此为依托构建 RAG 任务编排体系。对于用户上传的文档,它会自动识别文档的布局,包括标题、段落、换行等,还包含图片和表格等。RAGFlow 的 DeepDoc 模块提供了对多种不同格式文档的深度解析。
1.3.4.2Unstructured
Unstructured是一个灵活的Python 库,专门用于处理非结构化数据,它可以处理各种文档格式,包括 PDF、CSV 和 PPT 等。该库被多个项目用于非结构化数据的提取,如网易有道的QAnything、Dify 等。
1.3.4.3PaddleOCR
PaddleOCR是由百度推出的 OCR 开源项目,旨在提供全面且高效的文字识别和信息提取功能。PaddleOCR 提供了版面分析、表格识别和文字识别等多种功能。PaddleOCR的应用场景广泛,包括金融、教育、法律等多个行业,其高效的处理速度和准确率使其成为业界领先的 OCR 解决方案之一。
1.3.4.4OmniParser
OmniParser 是一个统一的框架,结合了三个基本的 OCR 任务:文本识别、关键信息提取和表格识别。
1.3.4.5python-readability
给定一个 HTML 文档,提取并清理主体文本和标题。
1.3.4.6firecrawl
将整个网站转变为 LLM 可用的 Markdown 或结构化数据。使用单个 API 进行抓取、爬行和提取。
1.3.4.7jina-reader
它将任何 URL 转换为LLM 友好的输入
1.3.4.8nougat
Neural Optical Understanding for Academic Documents.这是学术文档 PDF 解析器,它能理解 LaTeX 数学和表格。但对中文支持不好,需要单独微调。
1.3.5文本转换器(分块)
检索的一个关键部分是只获取文档的相关部分。当加载文档后,通常需要对其进行转换,以便更好地适应应用程序。这涉及几个转换步骤,以便为检索文档做好准备。其中一个主要步骤是将大型文档分割(或分块)成较小的块,即文本转换器。最简单的例子是,当需要处理长篇文本时,有必要将文本分割成若干块,以便能放入模型的上下文窗口中。理想情况下,希望将语义相关的文本片段放在一起。这听起来很简单,但潜在的复杂性却很大。
分块(Chunking)
固定大小的分块方式:一般是256/512个tokens,取决于embedding模型的情况。但是这种方式的弊端是会损失很多语义,比如“我们今天晚上应该去吃个大餐庆祝一下”,很有可能就会被分在两个chunk里面——“我们今天晚上应该”、“去吃个大餐庆祝一下”。这样对于检索是非常不友好的,解决方法是增加冗余量,比如512tokens的,实际保存480tokens,一头一尾去保存相邻的chunk头尾的tokens内容;
基于意图的分块方式
1.句分割:最简单的是通过句号和换行来做切分。当然也有通过专业的意图包来切分的,常用的意图包有基于NLP的NLTK和spaCy;
2.递归分割:通过分治的方法,用递归切分到最小单元的一种方式;
3.特殊分割:还有很多不常见的,用于特殊场景,这里就不提了。
4.语义分块:首先在句子之间进行分割,句子通常是一个语义单位,它包含关于一个主题的单一想法;然后使用 Embedding 表征句子;最后将相似的句子组合在一起形成块,同时保持句子的顺序。
5.命题分块:也是一种语义分块,它的原理是基于 LLM,逐步构建块。
• 首先从基于段落的句法分块迭代开始。
• 对于每个段落,使用 LLM 生成独立的陈述(或者命题),比如我们可以使用简单的提示「这段文字讨论了哪些主题」。
• 移除冗余命题。
• 索引并存储生成的命题。
• 在查询时,从命题语料库中检索,而不是原始文档语料库。
影响分块策略的因素
取决于你的索引类型,包括文本类型和长度,文章和微博推文的分块方式就会很不同;
取决于你的模型类型:你使用什么LLM也会有不同,因为ChatGLM、ChatGPT和Claude.ai等的tokens限制长度不一样,会影响你分块的尺寸;
取决于问答的文本的长度和复杂度:最好问答的文本长度和你分块的尺寸差不多,这样会对检索效率更友好;
评估文本转换器
可以使用 Chunkviz 工具来评估文本转换器。Chunkviz 是可视化文本转换器工作情况的工具。它可以向你展示文本的分割情况,并帮助你调整分割参数。
1.3.6文本嵌入模型
检索的另一个关键部分是文档嵌入模型。文档嵌入模型会创建一段文本的向量表示。它可以捕捉文本的语义,让你快速有效地找到文本中相似的其他片段。这非常有用,因为它意味着我们可以在向量空间中思考文本,并进行语义搜索等操作。
理想情况下,检索器应该具备将不同语种的翻译文本做关联的能力(跨语种检索能力),具备将长原文和短摘要进行关联的能力,具备将不同表述但相同语义的文本做关联的能力,具备将不同问题但相同意图的问题进行关联的能力,具备将问题和可能的答案文本进行关联的能力。此外,为了给大模型尽可能高质量的知识片段,检索器还应该给出尽可能多的相关片段,并且真正有用的片段应该在更靠前的位置,可以过滤掉低质量文本片段。
可以选择的embedding模型有这些:
1.3.6.1BGE
BGE:这是国人开发的中文embedding模型,在HuggingFace的MTEB(海量文本Embedding基准)上排名前2,实力强劲;
1.3.6.2M3E
M3E也是国人开发的中文embedding模型,我们之前用的就是这个模型,总体来说也算可以,这个还看大家的使用场景,也许你的场景会比我们更加适用;
1.3.6.3通义千问的embedding模型
通义千问的embedding模型是1500+维的模型
1.3.6.4Text-embedding-ada-002
Text-embedding-ada-002:这是OpenAI的embedding模型,1536维,我感觉上应该是目前最好的模型,但是它在MTEB上排名好像只有第六,但是国内应该也不太能用,所以我们就放弃了;
1.3.7向量数据库
需要向量数据库来支持这些嵌入式的高效存储和搜索。存储和搜索非结构化数据的最常见方法之一,存储产生的嵌入向量,然后在查询时嵌入非结构化查询,并检索与嵌入查询 "最相似 "的嵌入向量。向量数据库负责存储嵌入数据并执行向量搜索。
主流的向量数据库:Milvus、Faiss、Qdrant、LlamaIndex和Chroma。
1.3.7.1Milvus
Milvus是一个开源的向量相似度搜索引擎,由Zilliz团队开发。它提供了高性能的向量检索和相似度搜索功能,支持海量数据的快速查询。Milvus支持多种向量类型和距离度量方法,并提供了易于使用的API和丰富的功能,使得开发者可以轻松构建各种应用,如图像搜索、推荐系统和自然语言处理。
1.3.7.2Faiss
Faiss是Facebook AI Research开发的一个高性能向量相似度搜索库。它支持多种向量索引结构和距离度量方法,并提供了高效的搜索算法,能够在大规模数据集上进行快速的相似度搜索。Faiss被广泛应用于图像识别、语音识别和自然语言处理等领域。
1.3.7.3Qdrant
Qdrant:是一个开源的向量搜索引擎,由Qdrant团队开发。它提供了高性能的向量检索和相似度搜索功能,支持多种向量类型和距离度量方法。Qdrant还提供了丰富的查询语法和灵活的配置选项,使得用户可以根据自己的需求进行定制化的搜索。
1.3.7.4LlamaIndex
LlamaIndex:是一个基于向量的数据库引擎,由Llama Labs开发。它提供了高效的向量存储和检索功能,支持多种向量类型和距离度量方法。LlamaIndex还提供了易于使用的API和丰富的功能,使得开发者可以快速构建各种应用,如推荐系统、广告投放和智能搜索。
1.3.7.5Chroma
Chroma:是Zilliz团队开发的一个开源的向量数据管理系统。它提供了高效的向量存储和查询功能,支持多种向量类型和距离度量方法。Chroma还提供了可扩展的架构和分布式计算能力,能够处理大规模的向量数据集。
1.3.8索引
经过前面的数据读取和文本分块操作后,接着就需要对处理好的数据进行索引。索引是一种数据结构,用于快速检索出与用户查询相关的文本内容。它是检索增强 LLM 的核心基础组件之一。
1.3.8.1摘要索引(链式索引)
摘要索引只是将节点存储为顺序链。在后续的检索和生成阶段,可以简单地顺序遍历所有节点,也可以基于关键词进行过滤。
1.3.8.2树索引
树索引将一组节点 ( 文本块 ) 构建成具有层级的树状索引结构,其从叶节点 (原始文本块) 向上构建,每个父节点都是子节点的摘要。在检索阶段,既可以从根节点向下进行遍历,也可以直接利用根节点的信息。树索引提供了一种更高效地查询长文本块的方式,它还可以用于从文本的不同部分提取信息。与链式索引不同,树索引无需按顺序查询。
1.3.8.3关键词表索引
关键词表索引从每个节点中提取关键词,构建了每个关键词到相应节点的多对多映射,意味着每个关键词可能指向多个节点,每个节点也可能包含多个关键词。在检索阶段,可以基于用户查询中的关键词对节点进行筛选。
1.3.8.4向量索引
向量索引是当前最流行的一种索引方法。这种方法一般利用文本嵌入模型将文本块映射成一个固定长度的向量,然后存储在向量数据库中。检索的时候,对用户查询文本采用同样的Embedding模型映射成向量,然后基于向量相似度计算获取最相似的一个或者多个节点。
1.3.8.5图关系检索
如果可以将很多文本块变成node,把它们之间的关系变成relation,就可以利用知识之间的关系做更准确的回答。特别是针对一些多跳问题,利用图数据索引会让检索的相关度变得更高;
1.3.9排序和后处理
经过前面的检索过程可能会得到很多相关文档,就需要进行筛选和排序。常用的筛选和排序策略包括:
基于相似度分数进行过滤和排序
基于关键词进行过滤,比如限定包含或者不包含某些关键词
让 LLM 基于返回的相关文档及其相关性得分来重新排序
基于时间进行过滤和排序,比如只筛选最新的相关文档
基于时间对相似度进行加权,然后进行排序和筛选
1.4生成模型
1.4.1回复生成策略
检索模块基于用户查询检索出相关的文本块,回复生成模块让 LLM 利用检索出的相关信息来生成对原始查询的回复。这里给出一些不同的回复生成策略。
一种策略是依次结合每个检索出的相关文本块,每次不断修正生成的回复。这样的话,有多少个独立的相关文本块,就会产生多少次的 LLM 调用。
一种策略是在每次 LLM 调用时,尽可能多地在 Prompt 中填充文本块。如果一个 Prompt 中填充不下,则采用类似的操作构建多个 Prompt,多个 Prompt 的调用可以采用和前一种相同的回复修正策略。
1.4.2prompt拼接策略
用于将提示的不同部分组合在一起。您可以使用字符串提示或聊天提示来执行此操作。以这种方式构建提示可以轻松地重用组件。
1.4.2.1字符串提示
使用字符串提示时,每个模板都会连接在一起。您可以直接使用提示或字符串(列表中的第一个元素必须是提示)。例如,langchain提供的prompttemplate。
1.4.2.2聊天提示
聊天提示由消息列表组成。纯粹为了开发人员体验,添加了一种便捷的方式来创建这些提示。在此管道中,每个新元素都是最终提示中的一条新消息。例如,langchain提供的AIMessage, HumanMessage, SystemMessage。
2131

被折叠的 条评论
为什么被折叠?



