什么是 RAG 重排?

重排 = 从“初步检索的一堆候选文档”里,再挑出最相关的那几个

重排在干嘛?

它会做一件更“聪明”的事:

让模型直接判断:这个文档能不能回答这个问题?

而不是只看向量距离。
—-say by gpt老师


这里讲一种最经典的重排方法吧

1 Cross-Encoder(最经典🔥)

1.1 首先安装库

1
!pip install sentence-transformers
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 模拟数据

documents = [

    {"id": 1, "text": "RAG 是一种结合检索和生成的技术"},

    {"id": 2, "text": "Embedding 用于文本向量化"},

    {"id": 3, "text": "RAG 中重排可以提升检索结果的相关性"},

    {"id": 4, "text": "搜索引擎的发展历史"},

]

#模拟问题

query = "embedding的作用"

1.2 召回

当然重排是在召回的后面的,我们要先召回,对得到的list[documet]重排,召回的步骤就很熟悉了吧,这边省略的文本切割还是挺快的

ps;我这里vector_store.similarity_search_with_score用的是这种检索方法,所以呢就是我得到的不是list[documet],而是list[(document,score ) ]这种二维元组列表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# ===== 步骤1:向量检索(粗排)=====

print("=" * 50)
print("步骤1: 向量检索 (Top-4)")
print("=" * 50)

#注意哦检索完返回的是list[(document,score)] 一个元组数列

initial_results = vector_store.similarity_search_with_score(query, k=4)
print(len(initial_results))

#查看检索结束的数组里面是不是有重复的

for doc,score in initial_results:
    print(1 / (1 + score))
    print(doc.page_content +  "\n")



for i, (doc, distance) in enumerate(initial_results, 1):
    similarity = 1 / (1 + distance)
    print(f"{i}. 相似度: {similarity:.4f} | {doc.page_content[:30]}...")

1.3 配对

这个我感觉有点弱智的地方,向量检索器接收的是一个str,但是词匹配用的检索器,接收的是一个元组(问题,chunk)或者这种元组列表,
所以呢我们需要准备一个配对好的列表给这个检索器排序

1
2
#配对,像对比配偶一样,是个二维数组,这个我们需要继续用第一轮召回得到数据嘛
pairs = [[query, doc.page_content] for doc, _ in initial_results]

配对后就是排序了

1.4 排序

zip的作用是把两个列表变成一个
list_a = [a1, a2, a3]
list_b = [b1, b2, b3]
zip(list_a, list_b) # → [(a1,b1), (a2,b2), (a3,b3)]

1
2
3
4
5
6
7
8
9
# 组合并排序

reranked = sorted(

    zip(initial_results, rerank_scores),
    key=lambda x: x[1],
    reverse=True
   
)