




















在构建检索增强生成(RAG)系统时,我们经常会遇到一个核心挑战:如何高效、准确地从海量知识库中检索出最相关的信息?
传统的向量搜索(语义搜索)虽然强大,但并非万能。今天,我想和大家深入探讨一种更强大的检索策略——混合搜索(Hybrid Search),它正在成为构建生产级RAG系统的关键组件。
向量搜索通过将文本转换为高维向量,能够捕捉语义相似性。但它在以下场景中表现不佳:
精确关键词匹配:如产品型号“iPhone 15 Pro Max”
罕见专有名词:如人名“埃隆·里夫·马斯克”
特定短语:如法律条文中的精确表述
传统的BM25等关键词搜索擅长精确匹配,但:
无法理解同义词(如“汽车”和“轿车”)
无法捕捉上下文语义
对拼写错误敏感
混合搜索将语义搜索和关键词搜索结合起来,通过智能融合机制,提供更全面、准确的检索结果。
用户查询
│
├───► 语义检索(向量搜索) ───┐
│ │
└───► 关键词检索(BM25) ─────┼───► 结果融合 ──► 重排序 ──► 最终结果
│
└───► 融合算法(RRF/加权平均)
使用嵌入模型(如OpenAI的text-embedding-3-small)将文本转换为向量,通过余弦相似度查找最相似的文档。
from sentence_transformers import SentenceTransformer
import numpy as np
model = SentenceTransformer('all-MiniLM-L6-v2')
query_vector = model.encode("什么是混合搜索?")
doc_vectors = model.encode(documents)
similarities = np.dot(query_vector, doc_vectors.T)
基于词频-逆文档频率(TF-IDF)的改进算法,考虑文档长度因素。
from rank_bm25 import BM25Okapi
tokenized_docs = [doc.split() for doc in documents]
bm25 = BM25Okapi(tokenized_docs)
scores = bm25.get_scores(query.split())
方法一:加权平均(Weighted Average)
# 归一化后加权求和
semantic_score = semantic_scores / max(semantic_scores)
keyword_score = keyword_scores / max(keyword_scores)
alpha = 0.7 # 语义权重
hybrid_score = alpha * semantic_score + (1 - alpha) * keyword_score
方法二:RRF(Reciprocal Rank Fusion)
def reciprocal_rank_fusion(ranked_lists, k=60):
scores = {}
for ranked_list in ranked_lists:
for rank, doc_id in enumerate(ranked_list, 1):
scores[doc_id] = scores.get(doc_id, 0) + 1 / (k + rank)
return sorted(scores.items(), key=lambda x: x[1], reverse=True)
方法三:学习排序(Learning to Rank)
使用机器学习模型学习最佳融合权重,适应特定领域数据。
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
from llama_index.vector_stores.elasticsearch import ElasticsearchVectorStore
from llama_index.core.retrievers import BM25Retriever
from llama_index.core.retrievers import RouterRetriever
# 1. 创建向量存储
vector_store = ElasticsearchVectorStore(
index_name="hybrid_demo",
es_url="http://localhost:9200"
)
# 2. 创建文档索引
documents = SimpleDirectoryReader("data").load_data()
vector_index = VectorStoreIndex.from_documents(
documents,
vector_store=vector_store
)
# 3. 配置混合检索器
vector_retriever = vector_index.as_retriever(similarity_top_k=10)
bm25_retriever = BM25Retriever.from_documents(documents)
# 4. 融合检索结果
from llama_index.core.retrievers import FusionRetriever
hybrid_retriever = FusionRetriever(
retrievers=[vector_retriever, bm25_retriever],
mode="reciprocal_rerank" # 使用RRF融合
)
# 5. 执行混合检索
results = hybrid_retriever.retrieve("什么是混合搜索?")
from llama_index.core.text_splitter import SentenceSplitter
# 使用语义感知的分块
splitter = SentenceSplitter(
chunk_size=512,
chunk_overlap=50,
separator="。", # 以句子为边界
)
# 在检索时添加元数据过滤
retriever = index.as_retriever(
similarity_top_k=10,
filters=MetadataFilters(
filters=[
ExactMatchFilter(key="category", value="技术文档"),
RangeFilter(key="date", min_value="2024-01-01")
]
)
)
from llama_index.core.postprocessor import SentenceTransformerRerank
reranker = SentenceTransformerRerank(
model="cross-encoder/ms-marco-MiniLM-L-6-v2",
top_n=5
)
# 对混合搜索结果重排序
final_results = reranker.postprocess_nodes(results, query_str)
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。