RAG 检索优化实战:12 个策略里最容易被忽略的其实是分块大小
AIAI Summary (BLUF)
这篇文章系统讲解了RAG(检索增强生成)的基本流程和12个优化策略,涵盖数据清洗、分块处理、嵌入模型选择、元数据、多级索引、查询转换、检索参数、高级检索策略、重排模型和提示词工程。适合想提升RAG系统性能的开发者阅读。
核心洞察
这篇讲 RAGRetrieval-Augmented Generation - an AI framework that combines information retrieval with language generation to produce more accurate and contextually relevant responses. 的文章,把从文档准备到生成回答的整条链路拆得挺细,尤其是检索优化那部分,12 个策略基本覆盖了实际落地时会踩的坑。让我意外的是,作者对分块将文档分割成一系列片段(chunks)的过程,以便于后续的向量化和检索,需平衡片段大小与上下文完整性。大小的建议很实在——128 作为起点,这在很多教程里不太常见,但确实符合工程直觉。如果你正在搭企业知识库,检索参数和重排模型在检索后对结果进行精细化评估和重新排序的模型,旨在更精准地匹配用户查询意图,提升结果相关性。这两节值得反复看。
RAG 概述
ChatGPT、GLM 这类生成式模型在文本生成、图像生成等任务上表现确实亮眼。但它们有几个绕不开的毛病:会胡说八道、生成的东西不太好解释、专业领域知识理解得不够深,对最新信息的掌握也有限。想解决这些问题,提升模型能力,目前主要有两条路:一是微调,直接更新模型权重;二是让模型能跟外部世界互动,用不同方式获取知识。
微调效果是不错,能让模型真正“学会”一些私域知识。但麻烦也不少。首先,生成模型依赖内在知识,也就是权重,所以幻觉还是没法根除。在对准确性要求严格、理解门槛又高的场景里,这完全没法接受,因为用户很难从回答表面看出模型是不是在瞎编。其次,真实场景里数据每时每刻都在产生,一个概念迭代得飞快,比如某个政策的解读、某个指标的调整。微调又不是个简单活儿,从数据准备、算力资源、微调效果到训练时间,每个角度都看一遍就知道,随时拿新数据来微调根本不现实,效果也没法保证,能做到每月更新一次已经很理想了。
另一种方案是 RAG,给生成式模型提供了跟外部世界互动的路子,挺有前景。RAG 主要作用类似搜索引擎,找到用户提问最相关的知识或者相关对话历史,结合原始提问,造出一个信息丰富的 prompt,指导模型生成准确输出。它本质上用的是情境学习原理。
在 LLM 领域,做个最小可行产品相对简单,但要达到生产级性能和可用性,任务就很艰巨了,特别是构建高性能 RAG 系统。RAG 已经在企业私域知识问答等领域广泛用起来了,比如现在主流的各种 chat to PDF、chat to doc 应用,都是基于 RAG 搭的。
RAG 基本流程
如下图所示,RAG 可以分为 5 个基本流程:知识文档的准备、嵌入模型将文本转换为向量表示的模型,用于语义相似度计算。Semantic Router支持多种嵌入模型,如OpenAI、Cohere、HuggingFace等。、向量数据库A database system designed to store and perform high-dimensional semantic similarity searches on vector embeddings of data.、查询检索和生成回答。下面挨个说。
NO.1 知识文档的准备
构建高效 RAG 系统,第一步是准备知识文档。现实场景里,知识源格式五花八门,Word、TXT、CSV、Excel,甚至 PDF、图片和视频都有。所以第一步得用专门的文档加载器,比如 PDF 提取器,或者多模态模型比如 OCR,把这些知识源转成大语言模型能理解的纯文本数据。处理 PDF 时,可以用 PDF 提取器抽文本;图片和视频,OCR 能识别并转换里面的文字。另外,文档可能太长,还得做一步关键操作:文档切片。把长篇文档切成多个文本块,处理和检索信息更高效。这不仅能减轻模型负担,还能提高信息检索准确性。文档切片和背后逻辑后面会详细说。
NO.2 嵌入模型
嵌入模型的核心任务是把文本转成向量。我们在之前的文章《一文了解向量数据库在 RAG 中的扮演的角色》里详细讨论过把文本表示为向量的多种好处。简单说,日常语言里充满歧义和对表达词意没用的助词,向量表示更密集、精确,能捕捉句子的上下文关系和核心含义。这种转换让我们能通过简单计算向量之间的差异来识别语义上相似的句子。举例来说,想比较“苹果是一种水果”和“香蕉是黄色的”,嵌入模型可以把这些句子转成向量,然后算它们之间的相似度就能确定关联程度。那这样的嵌入模型怎么来的呢?经典例子是 Google 开发的 Word2Vec 模型,我们以它为基础探讨训练过程。
Word2Vec 有两种训练方法,为简单起见就以上图展示的 CBOW 模型方法讲解。CBOW 模型的核心思想是:给定一句话中心词的上下文,也就是该词周围的几个词,让模型预测这个中心词。比如有个句子:“The cat sat on the mat”。用 CBOW 模型,目标是预测中心词“sat”。具体训练流程如下:
对于上下文词“the”、“cat”、“on”、“the”、“mat”,首先生成它们的 one-hot 向量。One-hot 向量是个高维稀疏向量,代表词汇表中的每个单词,有这个词就是 1,其余全是 0,比如“the”的编码可以是 [1,0,0,0,0]
接下来,把每个 one-hot 向量与一个大小为 V×N 的权重矩阵 W 相乘,这里 V 是词汇表大小,N 是词向量维度,得到每个单词的词向量。然后,把所有词向量加起来求平均,得到代表整个句子上下文的向量 e,即图中的 projection layer 中的 1×N 向量。
接着,把向量 e 乘以另一个输出权重矩阵 W',通过 SoftMax 函数处理,得到一个大小为 1×V 的输出向量。这个向量代表模型预测每个词是中心词的概率。
最后,把模型预测结果跟实际中心词比较,通过差值不断更新两个权重矩阵 W 和 W'。经过足够训练,步骤 2 中得到的向量 e 就能有效代表整个句子的含义。
当然除了 Word2Vec,还有其他高级嵌入模型如 BERT 和 GPT 系列,它们通过更复杂的网络结构捕捉更深层次的语义关系。总之嵌入模型是连接用户查询和知识库的桥梁,确保系统回答的准确性和相关性。
NO.3 向量数据库
同样,我们在之前的文章《一文了解向量数据库在 RAG 中的扮演的角色》里详细介绍过向量数据库。顾名思义,向量数据库是专门设计用于存储和检索向量数据的数据库系统。在 RAG 系统中,通过嵌入模型生成的所有向量都会存在这样的数据库里。这种数据库优化了处理和存储大规模向量数据的效率,面对海量知识向量时,能迅速检索出与用户查询最相关的信息。
NO.4 查询检索
经过上述几步准备后,就可以开始处理用户查询了。首先,用户的问题会被输入到嵌入模型中进行向量化处理。然后,系统在向量数据库中搜索与该问题向量语义上相似的知识文本或历史对话记录并返回。
NO.5 生成回答
最后把用户提问和上一步检索到的信息结合,构建出一个提示模版,输入到大语言模型中,等模型输出答案就行。
RAG 优化
刚才讲的流程只是基本 RAG 流程,但各个环节都有极大的优化空间。下面我们从上述 5 个环节中穿插 12 个具体优化策略来依次讲解。下面介绍的方法在 AI 开发框架 langchain 和 LlamaIndex 中都有具体实现,操作方法可参考官方文档。
NO.1 数据清洗
高性能 RAG 系统依赖准确且清洁的原始知识数据。一方面为了保证数据准确性,需要优化文档读取器和多模态模型。特别是处理 CSV 表格等文件时,单纯文本转换可能丢失表格原有结构。所以得引入额外机制在文本中恢复表格结构,比如用分号或其他符号区分数据。另一方面也要对知识文档做些基本数据清洗,包括:
a) 基本文本清理:规范文本格式,去除特殊字符和不相关信息。去除重复文档或冗余信息。
b) 实体解析:消除实体和术语的歧义以实现一致的引用。比如把“LLM”、“大语言模型”和“大模型”标准化为通用术语。
c) 文档划分:合理划分不同主题的文档,不同主题是集中在一处还是分散在多处?如果作为人类都不能轻松判断出需要查阅哪个文档来回答常见提问,那检索系统也没法做到。
d) 数据增强:使用同义词、释义甚至其他语言的翻译来增加语料库多样性。
e) 用户反馈循环:基于现实世界用户反馈不断更新数据库,标记它们的真实性。
f) 时间敏感数据:对于经常更新的主题,实施一种机制来使过时的文档失效或更新。
NO.2 分块处理
在 RAG 系统中,文档需要分割成多个文本块再进行向量嵌入。不考虑大模型输入长度限制和成本问题的情况下,目的是在保持语义连贯性的同时,尽可能减少嵌入内容中的噪声,从而更有效地找到与用户查询最相关的文档部分。分块太大,可能包含太多不相关信息,降低检索准确性。分块太小,可能丢失必要上下文信息,导致生成的回应缺乏连贯性或深度。在 RAG 系统中实施合适的分块策略,就是找这个平衡,确保信息完整性和相关性。一般来说,理想的文本块应当在没有周围上下文的情况下对人类来说仍然有意义,这样对语言模型来说也有意义。
分块方法的选择:
固定大小的分块:最简单直接的方法,直接设定块中的字数,选择块之间是否重复内容。通常保持块之间的一些重叠,确保语义上下文不会在块之间丢失。与其他分块相比,固定大小分块简单易用且不需要很多计算资源。
内容分块:顾名思义,根据文档具体内容进行分块,比如根据标点符号如句号分割。或者直接用更高级的 NLTK 或 spaCy 库提供的句子分割功能。
递归分块:大多数情况下推荐的方法。通过重复应用分块规则来递归分解文本。比如在 langchain 中会先通过段落换行符(\n\n)分割。然后检查这些块的大小。如果大小不超过一定阈值,该块被保留。对于大小超过标准的块,使用单换行符(\n)再次分割。以此类推,不断根据块大小更新更小的分块规则,如空格、句号。这种方法可以灵活调整块的大小。比如对于文本中密集信息部分,可能需要更细的分割来捕捉细节;对于信息较少的部分,则可以使用更大的块。挑战在于,需要制定精细规则来决定何时和如何分割文本。
从小到大分块:既然小的分块和大的分块各有优势,一种更直接的解决方案是把同一文档进行从大到小所有尺寸的分割,然后把不同大小的分块全部存进向量数据库,并保存每个分块的上下级关系,进行递归搜索。但可想而知,因为要存储大量重复内容,这种方案的缺点就是需要更大的储存空间。
特殊结构分块:针对特定结构化内容的专门分割器。这些分割器特别设计来处理这些类型的文档,确保正确保留和理解其结构。langchain 提供的特殊分割器包括:Markdown 文件、Latex 文件,以及各种主流代码语言分割器。
分块大小的选择:
上述方法无一例外最终都需要设定一个参数——块的大小,那怎么选呢?首先不同的嵌入模型有其最佳输入大小。比如 OpenAI 的 text-embedding-ada-002 模型在 256 或 512 大小的块上效果更好。其次,文档类型和用户查询的长度及复杂性也是决定分块大小的重要因素。处理长篇文章或书籍时,较大的分块有助于保留更多上下文和主题连贯性;对于社交媒体帖子,较小的分块可能更适合捕捉每个帖子的精确语义。如果用户查询通常简短具体,较小分块可能更合适;相反,如果查询较复杂,可能需要更大分块。实际场景中,可能还是需要不断实验调整,在一些测试中,128 大小的分块往往是最佳选择,无从下手时可以从这个大小作为起点进行测试。
NO.3 嵌入模型
我们提到过嵌入模型能帮我们把文本转成向量,显然不同嵌入模型带来的效果也不一样。比如之前讨论的 Word2Vec 模型,尽管功能强大,但有个重要局限:它生成的词向量是静态的。一旦模型训练完成,每个词的向量表示就固定不变,处理一词多义时可能出问题。比如“我买了一张光盘”,这里“光盘”指具体的圆形盘片,而在“光盘行动”中,“光盘”指把餐盘里的食物吃光,是一种倡导节约的行为。语义完全不一样的词向量却是固定的。相比之下,引入自注意力机制的模型如 BERT,能提供动态的词义理解。它可以根据上下文动态调整词义,使得同一个词在不同语境下有不同的向量表示。之前的例子里,“光盘”这个词在两个句子中会有不同向量,从而更准确捕捉其语义。
有些项目为了让模型对特定垂直领域词汇有更好理解,会对嵌入模型进行微调。但这里不推荐这种方法,一方面对训练数据质量要求高,另一方面需要较多人力物力投入,效果未必理想,最终得不偿失。这种情况下,具体如何选择嵌入模型,推荐参考 Hugging Face 推出的嵌入模型排行榜 MTEB(https://huggingface.co/spaces/mteb/leaderboard)。这个排行榜提供了多种模型的性能比较,能帮我们做出更明智的选择。同时要注意并非所有嵌入模型都支持中文,选择时应查阅模型说明。
NO.4 元数据
在向量数据库中存储向量数据时,某些数据库支持将向量与元数据(即非向量化的数据)一同存储。为向量添加元数据标注是提高检索效率的有效策略,在处理搜索结果时作用不小。比如日期就是一种常见的元数据标签,能帮我们根据时间顺序筛选。设想一下,如果我们正在开发一款允许用户查询电子邮件历史记录的应用。这种情况下,日期最近的电子邮件可能与用户查询更相关。但从嵌入角度看,我们无法直接判断这些邮件与用户查询的相似度。通过把每封电子邮件的日期作为元数据附加到其嵌入中,可以在检索过程中优先考虑最近日期的邮件,从而提高搜索结果相关性。此外,还可以添加章节或小节的引用、文本关键信息、小节标题或关键词等作为元数据。这些元数据不仅有助于改进知识检索准确性,还能为最终用户提供更丰富和精确的搜索体验。
NO.5 多级索引
元数据无法充分区分不同上下文类型的情况下,可以考虑进一步尝试多重索引技术。多重索引技术的核心思想是把庞大数据和信息需求按类别划分,在不同层级中组织,实现更有效的管理和检索。这意味着系统不仅依赖单一索引,而是建立多个针对不同数据类型和查询需求的索引。比如可能有一个索引专门处理摘要类问题,另一个专门应对直接寻求具体答案的问题,还有一个专门针对需要考虑时间因素的问题。这种多重索引策略使 RAG 系统能根据查询性质和上下文,选择最合适的索引进行数据检索,从而提升检索质量和响应速度。但为了引入多重索引技术,还需配套加入多级路由机制。
多级路由机制确保每个查询被高效引导至最合适的索引。查询根据其特点如复杂性、所需信息类型等,被路由至一个或多个特定索引。这不仅提升处理效率,还优化资源分配和使用,确保对各类查询的精确匹配。比如对于查询“最新上映的科幻电影推荐”,RAG 系统可能首先将其路由至专门处理当前热点话题的索引,然后利用专注于娱乐和影视内容的索引来生成相关推荐。
总的来说,多级索引和路由技术可以进一步帮助我们高效处理大规模数据、精准提取信息,从而提升用户体验和系统整体性能。
NO.6 索引/查询算法
我们可以利用索引筛选数据,但说到底还是要从筛选后的数据中检索出相关文本向量。由于向量数据量庞大且复杂,寻找绝对最优解计算成本极高,有时甚至不可行。加上大模型本质上不是完全确定性的系统,这些模型在搜索时追求的是语义上的相似性,一种合理的匹配就行。从应用角度看,这种方法是合理的。比如在推荐系统中,用户不太可能察觉或关心是否每个推荐项目都是绝对最佳匹配;他们更关心推荐是否总体上与兴趣相符。因此查找与查询向量完全相同的项通常不是目标,而是找到“足够接近”或“相似”的项,这便是最近邻搜索。这样做不仅能满足需求,还为检索优化提供了巨大潜力。下面介绍一些常见向量搜索算法,方便大家在使用场景中取舍。
聚类
想象一下,网上购物时,通常不会在所有商品中盲目搜索,而是选择进入特定商品分类,比如“电子产品”或“服饰”,在更细分的范畴内寻找心仪商品。这能帮我们大大缩小搜索范围。同样思路,聚类算法可以帮我们实现这个范围的划定。比如可以用 K-mean 算法把向量分为数个簇,用户查询时,只需找到距离查询向量最近的簇,然后在这个簇中搜索。当然聚类方法并不保证一定正确,如下图,查询距离黄色簇的中心点更近,但实际上距离查询向量最近、最相似的点在紫色类。
有一些缓解这个问题的方法,比如增加聚类数量,并指定搜索多个簇。然而任何提高结果质量的方法都不可避免地增加搜索时间和资源成本。实际上质量和速度之间存在权衡关系。我们需要在两者之间找到最优平衡点,或者找到适合特定应用场景的平衡。不同算法也对应着不同平衡。
位置敏感哈希
沿着缩小搜索范围的思路,位置敏感哈希算法是另一种实现策略。传统哈希算法中,通常希望每个输入对应唯一输出值,并努力减少输出值重复。然而在位置敏感哈希算法中,目标恰恰相反,需要增加输出值碰撞的概率。这种碰撞正是分组的关键,哈希值相同的向量被分配到同一个组中,也就是同一个“桶”里。此外,这种哈希函数还需满足另一个条件:空间上距离较近的向量更有可能被分入同一个桶。这样搜索时,只需获取目标向量的哈希值,找到相应的桶,并在该桶内搜索即可。
量化乘积
上面介绍了两种牺牲搜索质量来提高搜索速度的方法,但除了搜索速度,内存开销也是巨大挑战。实际应用场景中,每个向量往往有上千个维度,数据数量可达上亿。每条数据都对应着实际信息,因此不可能删除数据来减少内存开销,唯一选择只能是把每个数据本身大小缩减。有一种乘积量化方法可以帮我们完成这点。图像有一种有损压缩方法,是把一个像素周围的几个像素合并,来减少需要储存的信息。同样我们可以在聚类方法之上改进一下,用每个簇的中心点来代替簇中的数据点。虽然这样会丢失向量的具体值信息,但考虑到聚类中心点和簇中向量相关程度,再加上可以不断增加簇的数量来减少信息损失,很大程度上可以保留原始点的信息。这样做带来的好处十分可观。如果给这些中心点编码,就可以用单个数字储存一个向量来减少存储空间。把每个中心向量值和他的编码值记录下来形成一个码本,这样每次使用某个向量时,只需用他的编码值通过码本找到对应的中心向量的具体值,虽然这个向量已经不再是当初的样子,但就像上面所说,问题不大。这个把向量用其所在簇中心点表示的过程就是量化。
但你可能会发现码本又引入了额外开销。真实场景中因为维度爆炸问题,更高维度中数据分布更加稀疏,所以需要更多聚类数量来减少丢失的细节。比如一个 128 维空间,需要 2 的 64 次方个聚类中心,最终这个码本所需内存会变得非常恐怖,甚至超越量化本身节省下来的内存。解决这个问题的办法是把高维向量分割成多个低维子向量,然后在这些低维子向量中独立量化。比如把 128 维向量分解成 8 个 16 维子向量,然后独立在 8 个独立子空间进行量化形成自己子码本。
每个 16 维空间只需要 256 个聚类就可以得到不错效果,并且每个子码本变得很小,即便 8 个子码本加在一起大小也仍然足够小。实际上我们是在把码本大小增长从指数模型分解为加法模式。最后,还可以把前面的提速度方法和减内存的乘积量化法结合使用,同时实现速度和内存优化。
分层导航小世界
从客户角度看,内存开销可能并不是最重要考量因素。他们更关注应用最终效果,也就是回答用户问题的速度和质量。导航小世界算法正是这样一种用内存换取更快速度和更高质量的实现方式。这个算法思路和“六度分割理论”类似——你和任何一个陌生人之间最多只隔六个人,也就是说,最多通过六个人你就能够认识任何一个陌生人。我们可以把人比作向量点,把搜索过程看作从一个人找到另一个人。查询时,从一个选定起始点 A 开始,然后找到与 A 相邻且最接近查询向量的点 B,导航到 B 点,再次进行类似判断,如此反复,直到找到一个点 C,其所有相邻节点都没有比它更接近目标。最终这个点 C 就是我们要找的最相似向量。
NO.7 查询转换
在 RAG 系统中,用户查询问题被转化为向量,然后在向量数据库中进行匹配。不难想象,查询的措辞会直接影响搜索结果。如果搜索结果不理想,可以尝试以下几种方法对问题进行重写,以提升召回效果:
a) 结合历史对话的重新表述:在向量空间中,对人类来说看似相同的两个问题其向量大小并不一定很相似。可以直接利用 LLM 重新表述问题来进行尝试。此外,进行多轮对话时,用户提问中的某个词可能指代上文中部分信息,因此可以把历史信息和用户提问一并交给 LLM 重新表述。
b) 假设文档嵌入:核心思想是接收用户提问后,先让 LLM 在没有外部知识的情况下生成一个假设性回复。然后把这个假设性回复和原始查询一起用于向量检索。假设回复可能包含虚假信息,但蕴含着 LLM 认为相关的信息和文档模式,有助于在知识库中寻找类似文档。
c) 退后提示:如果原始查询太复杂或返回信息太广泛,可以选择生成一个抽象层次更高的“退后”问题,与原始问题一起用于检索,以增加返回结果数量。比如原问题是“桌子君在特定时期去了哪所学校”,而退后问题可能是关于他的“教育历史”。这种更高层次的问题可能更容易找到答案。
d) 多查询检索/多路召回:使用 LLM 生成多个搜索查询,特别适用于一个问题可能需要依赖多个子问题的情况。
通过这些方法,RAG 系统能更精准处理和响应复杂用户查询,从而提升整体搜索效率和准确性。
NO.8 检索参数
终于把查询问题准备好了,可以进入向量数据库进行检索。具体检索过程中,可以根据向量数据库的特定设置来优化一些检索参数,以下是一些常见可设定参数:
a) 稀疏和稠密搜索权重:稠密搜索即通过向量进行搜索。然而某些场景下可能存在限制,此时可以尝试使用原始字符串进行关键字匹配的稀疏搜索。一种有效的稀疏搜索算法是最佳匹配 25,它基于统计输入短语中的单词频率,频繁出现的单词得分较低,而稀有的词被视为关键词,得分会较高。我们可以结合稀疏和稠密搜索得出最终结果。向量数据库通常允许设定两者对最终结果评分的权重比例,如 0.6 表示 40% 的得分来自稀疏搜索,60% 来自稠密搜索。
b) 结果数量:检索结果数量是另一个关键因素。足够的检索结果可以确保系统覆盖到用户查询的各个方面。回答多方面或复杂问题时,更多结果提供了丰富语境,有助于 RAG 系统更好理解问题上下文和隐含细节。但需注意,结果数量过多可能导致信息过载,降低回答准确性并增加系统时间和资源成本。
c) 相似度度量方法:计算两个向量相似度的方法也是一个可选参数。包括使用欧式距离和 Jaccard 距离计算两个向量差异,以及利用余弦相似度衡量夹角相似性。通常余弦相似度更受青睐,因为它不受向量长度影响,只反映方向上的相似度。这使得模型能忽略文本长度差异,专注于内容语义相似性。需要注意的是,并非所有嵌入模型都支持所有度量方法,具体可参考所用嵌入模型说明。
NO.9 高级检索策略
终于来到最关键和复杂的步骤——在向量数据库检索之上如何具体开发或改进整个系统的策略。这部分内容足够写成一篇独立文章。为了保持简洁,只讨论一些常用或新提出的策略。
a) 上下文压缩:我们提到过当文档文块过大时,可能包含太多不相关信息,传递这样的整个文档可能导致更昂贵的 LLM 调用和更差的响应。上下文压缩的思想就是通过 LLM 帮助根据上下文对单个文档内容进行压缩,或者对返回结果进行一定程度过滤,仅返回相关信息。
b) 句子窗口搜索:相反,文档文块太小会导致上下文缺失。其中一种解决方案就是窗口搜索,该方法核心思想是当提问匹配好分块后,将该分块周围的块作为上下文一并交给 LLM 进行输出,来增加 LLM 对文档上下文的理解。
c) 父文档搜索:无独有偶,父文档搜索也是一种很相似的解决方案。父文档搜索先将文档分为尺寸更大的主文档,再把主文档分割为更短的子文档两个层级,用户问题会与子文档匹配,然后将该子文档所属的主文档和用户提问发送给 LLM。
d) 自动合并:自动合并是在父文档搜索上更进一步的复杂解决方案。同样地,先对文档进行结构切割,比如将文档按三层树状结构进行切割,顶层节点块大小为 1024,中间层块大小为 512,底层叶子节点块大小为 128。检索时只拿叶子节点和问题进行匹配,当某个父节点下多数叶子节点都与问题匹配上则将该父节点作为结果返回。
e) 多向量检索:多向量检索同样会给一个知识文档转化成多个向量存入数据库,不同的是,这些向量不仅包括文档在不同大小下的分块,还可以包括该文档摘要、用户可能提出的问题等等有助于检索的信息。使用多向量查询的情况下,每个向量可能代表文档不同方面,使得系统能更全面考虑文档内容,并在回答复杂或多方面查询时提供更精确结果。比如如果查询与文档某个具体部分或摘要更相关,那么相应向量就可以帮助提高这部分内容的检索排名。
f) 多代理检索:多代理检索,简而言之就是选取我们提及的 12 大优化策略中的部分交给一个智能代理合并使用。比如使用子问题查询、多级索引和多向量查询结合,先让子问题查询代理把用户提问拆解为多个小问题,再让文档代理对每个子问题进行多向量或多索引检索,最后排名代理将所有检索的文档总结再交给 LLM。这样做的好处是可以取长补短,比如子问题查询引擎在探索每个子查询时可能缺乏深度,尤其是在相互关联或关系数据中。相反,文档代理递归检索在深入研究特定文档和检索详细答案方面表现出色,以此综合多种方法解决问题。需要注意的是现在网络上存在不同结构的多代理检索,具体在多代理选取哪些优化步骤尚未有确切定论,可以结合使用场景进行探索。
g) Self-RAG在 RAG 流程中设置四个自省检查点(是否需要检索、文档相关、答案有据、答案有用),动态调整策略以减少幻觉。:自反思搜索增强是一个全新 RAG 框架,其与传统 RAG 最大区别在于通过检索评分和反思评分来提高质量。它主要分三个步骤:检索、生成和批评。Self-RAG 首先用检索评分来评估用户提问是否需要检索,如果需要检索,LLM 将调用外部检索模块查找相关文档。接着,LLM 分别为每个检索到的知识块生成答案,然后为每个答案生成反思评分来评估检索到的文档是否相关,最后将评分高的文档当作最终结果一并交给 LLM。
NO.10 重排模型
完成语义搜索优化步骤后,我们能检索到语义上最相似的文档,但不知你是否注意到一个关键问题:语义最相似是否总代表最相关?答案是不一定。比如用户查询“最新上映的科幻电影推荐”时,可能得到的结果是“科幻电影的历史演变”,虽然从语义上这与科幻电影相关,但并未直接回应用户关于最新电影的查询。
重排模型可以帮我们缓解这个问题,重排模型通过对初始检索结果进行更深入的相关性评估和排序,确保最终展示给用户的结果更符合其查询意图。这一过程通常由深度学习模型实现,如 Cohere 模型。这些模型会考虑更多特征,如查询意图、词汇的多重语义、用户历史行为和上下文信息等。
举个例子,对于查询“最新上映的科幻电影推荐”,首次检索阶段,系统可能基于关键词返回包括科幻电影历史文章、科幻小说介绍、最新电影新闻等结果。然后重排阶段,模型会对这些结果进行深入分析,并将最相关、最符合用户查询意图的结果如最新上映的科幻电影列表、评论或推荐排在前面,同时将那些关于科幻电影历史或不太相关的内容排在后面。这样重排模型就能有效提升检索结果相关性和准确性,更好满足用户需求。
实践中,使用 RAG 构建系统时都应考虑尝试重排方法,以评估其是否能提高系统性能。
NO.11 提示词
大型语言模型的解码器部分通常基于给定输入来预测下一个词。这意味着设计提示词或问题的方式将直接影响模型预测下一个词的概率。这也给了我们一些启示:通过改变提示词形式,可以有效影响模型对不同类型问题的接受程度和回答方式,比如修改提示语,让 LLM 知道它在做什么工作,十分有帮助。为了减少模型产生主观回答和幻觉的概率,一般情况下 RAG 系统中的提示词中应明确指出回答仅基于搜索结果,不要添加任何其他信息。比如可以设置提示词如:“你是一名智能客服。你的目标是提供准确信息,并尽可能帮助提问者解决问题。你应保持友善,但不要过于啰嗦。请根据提供的上下文信息,在不考虑已有知识的情况下,回答相关查询。”当然也可以根据场景需要,适当让模型回答融入一些主观性或其对知识的理解。此外,使用少量样本的方法,将想要的问答例子加入提示词中,指导 LLM 如何利用检索到的知识,也是提升 LLM 生成内容质量的有效方法。这种方法不仅使模型回答更加精准,也提高了其在特定情境下的实用性。
NO.12 大语言模型
终于来到最后一步——LLM 生成回答。LLM 是生成响应的核心组件。与嵌入模型类似,可以根据自己需求选择 LLM,比如开放模型与专有模型、推理成本、上下文长度等。此外,可以使用一些 LLM 开发框架来搭建 RAG 系统,比如 LlamaIndex 或 LangChain。这两个框架都拥有比较好用的 debugging 工具,可以让我们定义回调函数,查看使用了哪些上下文,检查检索结果来自哪个文档等等。
结语
在本文中,我们一起深入探索了 RAG 系统的各个方面,从初步文档准备到复杂的多代理检索策略,希望得到了对 RAG 一个全面且深入的认识。这个旅程虽然充满挑战,但同样展现了 RAG 系统在处理大规模信息检索和理解任务时的巨大潜力。通过细致优化查询问题,灵活运用多级索引和路由技术,以及实施先进检索策略,我们能显著提高系统效率和准确性,从而更好满足用户需求。RAG 系统的未来发展令人充满期待,随着技术不断进步,我们有理由相信它将在各行各业中发挥越来越重要的作用。
● 本文部分内容及图片来自 Ele 实验室及公网。
核心结论
RAG 系统由 5 个基本流程组成:知识文档准备、嵌入模型、向量数据库、查询检索和生成回答,已在企业私域知识问答等领域广泛应用。
文档分块大小无从下手时,建议从 128 作为起点进行测试;OpenAI 的 text-embedding-ada-002 模型在 256 或 512 大小的块上效果更好。
嵌入模型选择可参考 Hugging Face 推出的 MTEB 排行榜(https://huggingface.co/spaces/mteb/leaderboard),同时需注意并非所有嵌入模型都支持中文。
RAG 优化涵盖 12 个具体策略,包括数据清洗、分块处理、嵌入模型选择、元数据标注、多级索引、索引/查询算法、查询转换、检索参数调优和高级检索策略等,在 LangChain 和 LlamaIndex 中均有具体实现。
检索参数优化中,余弦相似度通常更受青睐,因为它不受向量长度影响,只反映方向上的相似度,使模型能忽略文本长度差异,专注于内容语义相似性。
常见问题(FAQ)
RAG优化中分块大小怎么选?128作为起点合理吗?
分块大小需平衡语义完整性与噪声。文章建议128作为起点,符合工程直觉,可减少不相关信息,提升检索准确性。实际需根据文档类型和查询调整,确保块对人类仍有意义。
RAG系统检索参数和重排模型为什么重要?
检索参数影响召回相关文档的准确度,重排模型则对初步检索结果精细排序,提升最终生成质量。文章强调这两节值得反复看,尤其对企业知识库搭建,能显著优化性能。
RAG优化策略中,数据清洗具体包括哪些操作?
数据清洗包括基本文本清理、实体解析、文档划分、数据增强、用户反馈循环和时间敏感数据处理。这些操作确保知识库准确清洁,是高性能RAG系统的基础。
版权与免责声明:本文仅用于信息分享与交流,不构成任何形式的法律、投资、医疗或其他专业建议,也不构成对任何结果的承诺或保证。
文中提及的商标、品牌、Logo、产品名称及相关图片/素材,其权利归各自合法权利人所有。本站内容可能基于公开资料整理,亦可能使用 AI 辅助生成或润色;我们尽力确保准确与合规,但不保证完整性、时效性与适用性,请读者自行甄别并以官方信息为准。
若本文内容或素材涉嫌侵权、隐私不当或存在错误,请相关权利人/当事人联系本站,我们将及时核实并采取删除、修正或下架等处理措施。也请勿在评论或联系信息中提交身份证号、手机号、住址等个人敏感信息。



