Rerank——RAG 中百尺竿头更进一步的神器,从原理到解决方案

原文地址 www.luxiangdong.com

80 后,退役码农,非专业产品经理

本文主要内容:

检索增强生成(RAG)是解决大语言模型(LLM)实际使用中的一套完整的技术,它可以有效解决 LLM 的三个主要问题:数据时效性幻觉数据安全问题(在我之前的文章《大模型主流应用 RAG 的介绍——从架构到技术细节》中有详细介绍)。但是随着 RAG 越来越火热,使用者越来越多,我们也会发现用的好的人 / 团队其实还是不多的。这也是 RAG 常被人吐槽的一点:入门简单,用好却非常难!

对于 RAG 的效果,我们之前已经做了很多方面的优化了,包括:

这些优化确实给我们带来了非常好的效果,但不够!我们在一些客户的实践过程中,还是发现相关性效果不佳,甚至造成了其中一个客户选择了其他方案(使用 RAG+GPT-4 的方案)。

我们还是坚持用国产大模型(如 Baichuan2-13B、ChatGLM3-6B 和 QWen-14B 等),毕竟主要服务的还是国内客户,加上现在接触的多数客户其实都有私有化部署的需求。所以我们进行了一段时间的探索,发现我们还有一项很有效的优化没有去做——ReRank。

所以,虽然 Rerank 优化我们还在做,但是今天我们可以先聊聊 ReRank 这个话题。

我们发现,在 10 月中旬之前,国内外的互联网上很难发现 Rerank 相关的话题。有少量人提到了,但是基本上都没有提到解决方案。我和小明在讨论 Rerank 的时候其实是先从提问题开始的。

前面说了,我们自己的 RAG 产品之前是存在一些相关性问题的,其他方面能优化的我们觉得也基本上优化的差不多了,除了我们采用的国产大模型在通用能力上和 ChatGPT-3.5/4 是存在差距的。我们发现的最大的问题就是使用 elasticsearch 的 retrieval 召回的内容相关度有问题,多数情况下 score 最高的 chunk 相关度没问题,但是 top2-5 的相关度就很随机了,这是最影响最终结果的。

图 1:elasticsearch8.4 的 knn 使用方式

我们看了 elasticsearch 的相似度算法,es 用的是 KNN 算法(开始我们以为是暴力搜索),但仔细看了一下,在 es8 的相似度检索中,用的其实是基于 HNSW(分层的最小世界导航算法),HNSW 是有能力在几毫秒内从数百万个数据点中找到最近邻的。

图 2:elasticsearch 实际使用的是 HNSW 算法

我们想象这么一个场景:你昨天刚在其他地方看到过一本新书,你想在图书馆找到类似的书。K - 最近邻(KNN)算法的逻辑是浏览书架上的每一本书,并将它们从最相似到最不相似的顺序排列,以确定最相似的书(最有可能是你昨天看过的那本)。这也就是我们常说的暴力搜索,你有耐心做这么麻烦的工作吗?相反,如果我们对图书馆中的图书进行预排序和索引,要找到与你昨天看过的新书相似的书,你所需要做的就是去正确的楼层,正确的区域,正确的通道找到相似的书。

此外,你通常不需要对前 10 本相似的书进行精确排名,比如 100%、99% 或 95% 的匹配度,而是通通先拿回来。这就是**近似近邻(ANN)**的思想。你应该注意到了,这里已经出现了一些随机性——不做匹配分数的排名。但是这些准确度上的损失是为了让检索效率更快,为了显著降低计算成本,它牺牲了找到绝对最近邻的保证,这算是在计算效率和准确性之间取得平衡

ANN 算法目前主要有三种:

HNSW 借鉴了跳表(Skip List)的思路。跳表是一种数据结构,用于维护一组已排序的元素,并允许进行高效的搜索、插入和删除操作。它是由 William Pugh 在 1989 年发明的。图 (3) 显示了数字 [3、6、7、9、12、17、19、21、25、26] 的排序链表。假设我们想找到目标 19。当值小于目标时,我们向右移动,如果是传统的方式,需要 6 步才能找到它。

图 3:链表中查找数据

但是我们在每个节点增加向后的指向指针,比如列表中每三个其他节点都有一个指向后面三个节点的指针,如图 (4) 所示,那么只需要 3 步就可以到达 19

图 4:跳表每三个节点就设置一个多指向指针节点,可以让搜索速度明显加快,如果我们再增加这个指针节点数量呢?

这就是 small world 的底层思路,说回到小世界(small world)网络,它是一种特殊的网络,在这种网络中,你可以快速地联系到网络中的其他人或点。这有点像 “凯文 · 培根的六度”(Six Degrees of Kevin Bacon) 游戏,在这个游戏中,你可以通过一系列其他演员,在不到六个步骤的时间里,将任何演员与凯文 · 培根联系起来。想象一下,你有一群朋友排成一个圆圈,如图 5 所示。每个朋友都与坐在他们旁边的人直接相连。我们称它为“原始圆”。

现在,这就是奇迹发生的地方。你可以随机选择将其中一些连接改变给圆圈中的其他人,就像图 5 中的红色连接线一样。这就像这些连接的 “抢椅子” 游戏。有人跳到另一把椅子上的几率用概率 p 表示。如果 p 很小,移动的人就不多,网络看起来就很像原来的圆圈。但如果 p 很大,很多人就会跳来跳去,网络就会变得有点混乱。当您选择正确的 p 值 (不太小也不太大) 时,红色连接是最优的。网络变成了一个小世界网络。你可以很快地从一个朋友转到另一个朋友 (这就是“小世界” 的特点)。

图 5:small world 网络结构

现在我们要扩展到高维空间,图中的每个节点都是一个高维向量。在高维空间中,搜索速度会变慢。这是不可避免的 “维度的诅咒”。HNSW 是一种高级数据结构,用于优化高维空间中的相似性搜索。让我们看看 HNSW 如何构建图的层次结构。HNSW 从图(6) 中的第 0 层这样的基础图开始。它通常使用随机初始化数据点来构建。

图 6:HNSW 的结构示例

这里大家要注意再次出现了” 随机 “,所以,为了检索的快速,HNSW 算法会存在一些随机性,反映在实际召回结果中,最大的影响就是返回结果中 top_K 并不是我们最想要的,至少这 K 个文件的排名并不是我们认为的从高分到低分排序的。

因为在搜索的时候存在随机性,这应该就是我们在 RAG 中第一次召回的结果往往不太满意的原因。但是这也没办法,如果你的索引有数百万甚至千万的级别,那你只能牺牲一些精确度,换回时间。这时候我们可以做的就是增加top_k的大小,比如从原来的 10 个,增加到 30 个。然后再使用更精确的算法来做 rerank,使用一一计算打分的方式,做好排序。比如 30 次的遍历相似度计算的时间,我们还是可以接受的。

关于 HNSW 的内容,大家可以查看像光速一样搜索——HNSW 算法介绍

为了衡量我们的检索系统的有效性,我们主要依赖于两个被广泛接受的指标: 命中率和 ** 平均倒数排名 (MRR)**。让我们深入研究这些指标,了解它们的重要性以及它们是如何运作的。我们来解释一下这两个指标:

具体的评测过程大家可以看提升 RAG——选择最佳 Embedding 和重新排名模型,也是 llamaindex 最近刚刚发布的一篇著名 rerank 评测文章,我这里就不具体展开了,直接用他们的结果。评测采用的是 embedding 模型 + rerank 模型的方式进行的。

以下是使用的模型:

Embedding 模型:

Rerank 模型:

值得一提的是,这些结果为这个特定数据集和任务的性能提供了坚实的见解。但是,实际结果可能会根据数据特征、数据集大小和其他变量 (如 chunk_size、similarity_top_k 等) 而有所不同。

下表展示了基于命中率MRR 指标的评估结果:

图 7:测试结果

我对 LlamaIndex 的评测结果做一个简单总结:

目前最无脑的方式就是使用 bge-reranker-large,我们可以在 https://huggingface.co/BAAI/bge-reranker-large/tree/main 上找到 models 文件,下载安装。我已经下载了:

图 8:bge-reranker-large 的 models 文件,大约 4.5GB

这两天要给它安装起来,测测我们的产品 rerank 之后的效果。

其实还有一种比较简单的方式,这种方式其实是从上面的原理中得出来的: