随着人们对检索增强生成(Retrieval-Augmented Generation, RAG)管道的兴趣日益增加,开发者们开始讨论构建具备生产就绪性能的RAG管道所面临的挑战。就像生活中的许多方面一样,Pareto Principle在RAG管道中也是适用的,其中初始的80%相对容易达成,但实现剩下的20%以达到生产就绪则颇具挑战性。
一个经常被提到的主题是通过混合搜索来改善RAG管道中的检索组件。
本文将向你介绍混合搜索的概念,它如何通过检索出更相关的结果来帮助你提高RAG管道的性能,以及何时使用它。
什么是混合搜索
混合搜索是一种搜索技术,它结合了两种或多种搜索算法以提高搜索结果的相关性。尽管并未定义哪些算法被结合,但混合搜索最常指的是传统的基于关键词的搜索与现代的向量搜索的结合。
传统上,基于关键词的搜索是搜索引擎的首选。但随着机器学习(ML)算法的出现,向量嵌入使得一种新的搜索技术——称为向量或语义搜索——成为可能,使我们能够在语义上跨数据进行搜索。然而,这两种搜索技术都有需要考虑的重大权衡:
将基于关键词的搜索与向量搜索结合到一种混合搜索中,可以让你利用这两种搜索技术的优势来提升搜索结果的相关性,特别是对于文本搜索的用例。
例如,考虑搜索查询“如何用.concat()合并两个Pandas DataFrames?”。关键词搜索将帮助找到相关的.concat()方法的结果。然而,由于“merge”一词有“combine”、“join”和“concatenate”等同义词,如果我们能够利用语义搜索的上下文意识就会很有帮助。
混合搜索如何工作?
混合搜索通过融合基于关键词的搜索和向量搜索的结果,并对它们重新排名来工作。
基于关键词的搜索
在混合搜索的背景下,基于关键词的搜索通常使用一种称为稀疏嵌入的表示,这也是为什么它同时被称为稀疏向量搜索。稀疏嵌入是向量,大部分数值为零,只有几个非零值,如下所示。
[0, 0, 0, 0, 0, 1, 0, 0, 0, 24, 3, 0, 0, 0, 0, ...]
稀疏嵌入可以通过不同的算法生成。用于稀疏嵌入的最常用算法是BM25(最佳匹配25),它基于TF-IDF(词频-逆文档频率)方法,并对其进行了改进。简而言之,BM25根据术语在文档中的频率与其在所有文档中的频率相对比重,强调了术语的重要性。
向量搜索
向量搜索是一种现代的搜索技术,随着机器学习的进步而涌现。现代机器学习算法,如变换器(Transformers),可以生成数据对象在不同模态(文本、图像等)中的数值表示,称为向量嵌入。
这些向量嵌入通常信息密集,大多由非零值(密集向量)组成,如下所示。这就是为什么向量搜索也被称为密集向量搜索。
[0.634, 0.234, 0.867, 0.042, 0.249, 0.093, 0.029, 0.123, 0.234, ...]0.634, 0.234, 0.867, 0.042, 0.249, 0.093, 0.029, 0.123, 0.234, ...]
搜索查询被嵌入到与数据对象相同的向量空间中。然后,使用其向量嵌入来基于指定的相似度量准则(例如余弦距离)计算最接近的数据对象。返回的搜索结果按照它们与搜索查询的相似度排名列出最接近的数据对象。
关键词搜索和向量搜索结果的融合
通常,基于关键词的搜索和向量搜索返回一组独立的结果,通常是按照计算出的相关性排序的搜索结果列表。这些独立的搜索结果集必须被组合起来。
一般来说,搜索结果通常首先会被评分。这些分数可以基于指定的度量标准计算,比如余弦距离,或者仅仅是搜索结果列表中的排名。
然后,计算出的分数会与参数alpha进行加权,该参数决定了每个算法的权重,并对结果的重新排名产生影响。
hybrid_score = (1 - alpha) * sparse_score + alpha * dense_score
通常,alpha取值在0到1之间,其中:
下面,你可以看到一个基于排名和alpha = 0.5的关键词与向量搜索融合的最小示例。
混合搜索如何提高RAG管道的性能?
RAG管道有许多旋钮可以调整以提高其性能。其中一个旋钮是提高检索到的上下文的相关性,然后将其输入到LLM中,因为如果检索到的上下文与回答给定问题无关,LLM也无法生成相关答案。
根据你的上下文类型和查询内容,你必须确定哪种三种搜索技术最适合你的RAG应用。因此,控制关键词搜索和语义搜索之间权重的参数alpha可以视为需要调整的超参数。
在使用LangChain的一般RAG管道中,你将通过使用.as_retriever()方法来定义检索器组件,将使用的vectorstore组件设置为检索器,如下所示:
# Define and populate vector store
# See details here https://towardsdatascience.com/retrieval-augmented-generation-rag-from-theory-to-langchain-implementation-4e9bd5f6a4f2
vectorstore = ...
# Set vectorstore as retriever
retriever = vectorstore.as_retriever()
然而,这个方法只能实现语义搜索。如果你想在LangChain中启用混合搜索,你需要定义一个具有混合搜索能力的特定检索组件,比如WeaviateHybridSearchRetriever:
from langchain.retrievers.weaviate_hybrid_search import WeaviateHybridSearchRetriever
retriever = WeaviateHybridSearchRetriever(
alpha = 0.5, # defaults to 0.5, which is equal weighting between keyword and semantic search
client = client, # keyword arguments to pass to the Weaviate client
index_name = "LangChain", # The name of the index to use
text_key = "text", # The name of the text key to use
attributes = [], # The attributes to return in the results
)
原始RAG管道的其余部分将保持不变。
这个小的代码更改允许你尝试在基于关键词的搜索和向量搜索之间的不同权重。请注意,将alpha设为1等于完全的语义搜索,这相当于直接从向量存储组件定义检索器(retriever = vectorstore.as_retriever())。
何时使用混合搜索(混合搜索用例)
混合搜索非常适合于那些你想要开启语义搜索能力,实现更类似人类的搜索体验,但也需要对特定术语进行确切短语匹配的用例,例如产品名称或序列号。
一个出色的例子是平台Stack Overflow,该平台最近通过使用混合搜索扩展了其搜索功能。
总结
本文介绍了混合搜索的背景,作为基于关键词的搜索和基于向量的搜索的组合。混合搜索合并了独立搜索算法的搜索结果,并相应地重新排名。
在混合搜索中,参数alpha控制了基于关键词的搜索和语义搜索之间的权重。这个参数alpha可以被视为在RAG(Rapid Automatic Keyword Extraction)管道中调整的一个超参数,以提高搜索结果的准确性。