本节导读:深入掌握检索效果的高级优化技巧,包括混合检索、重排序、相关性学习等核心技术,解决RAG系统中的检索质量问题。
混合检索是将多种检索策略有机结合,提升检索系统整体效果的关键技术。
混合检索结合了基于关键词的精确匹配、基于语义的相似度检索、基于图的知识检索等多种策略:
```重排序是提升检索结果质量的关键环节,通过算法对初步检索结果进行重新排序。
```# 核心依赖 pip install rank-bm25 transformers torch faiss-cpu sentence-transformers pip install sklearn pandas numpy tqdm # 高级优化依赖 pip install transformers[torch] accelerate pip install deepspeed
import numpy as np from rank_bm25 import BM25Okapi from sentence_transformers import SentenceTransformer import faiss from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.metrics.pairwise import cosine_similarity class HybridRetriever: def __init__(self, model_name='all-MiniLM-L6-v2'): # 初始化各个检索组件 self.semantic_model = SentenceTransformer(model_name) self.bm25 = None self.tfidf = TfidfVectorizer() self.index = None self.documents = [] def add_documents(self, documents): """添加文档到检索系统""" self.documents = documents # 初始化BM25 tokenized_docs = [doc.split() for doc in documents] self.bm25 = BM25Okapi(tokenized_docs) # 初始化TF-IDF self.tfidf.fit(documents) # 初始化向量索引 embeddings = self.semantic_model.encode(documents, convert_to_numpy=True) dimension = embeddings.shape[1] self.index = faiss.IndexFlatIP(dimension) self.index.add(embeddings) def retrieve(self, query, k=10, weights=None): """混合检索主函数""" if weights is None: weights = {'semantic': 0.5, 'bm25': 0.3, 'tfidf': 0.2} # 1. 语义检索 query_embedding = self.semantic_model.encode([query]) semantic_scores, semantic_indices = self.index.search(query_embedding, k * 2) # 2. BM25检索 tokenized_query = query.split() bm25_scores = self.bm25.get_scores(tokenized_query) bm25_top_k = np.argsort(bm25_scores)[-k:][::-1] # 3. TF-IDF检索 query_vec = self.tfidf.transform([query]) tfidf_scores = cosine_similarity(query_vec, self.tfidf.transform(self.documents)).flatten() tfidf_top_k = np.argsort(tfidf_scores)[-k:][::-1] # 4. 混合得分计算 hybrid_scores = {} # 语义检索得分 for i, score in enumerate(semantic_scores[0]): doc_idx = semantic_indices[0][i] if doc_idx not in hybrid_scores: hybrid_scores[doc_idx] = 0 hybrid_scores[doc_idx] += score * weights['semantic'] # BM25得分 for idx in bm25_top_k: if idx not in hybrid_scores: hybrid_scores[idx] = 0 hybrid_scores[idx] += bm25_scores[idx] * weights['bm25'] # TF-IDF得分 for idx in tfidf_top_k: if idx not in hybrid_scores: hybrid_scores[idx] = 0 hybrid_scores[idx] += tfidf_scores[idx] * weights['tfidf'] # 5. 最终排序 final_scores = sorted(hybrid_scores.items(), key=lambda x: x[1], reverse=True) return [(self.documents[idx], score) for idx, score in final_scores[:k]] # 使用示例 retriever = HybridRetriever() retriever.add_documents([ "RAG系统结合了检索和生成的优势", "向量嵌入是RAG的核心技术", "混合检索可以提高检索质量", "重排序算法优化检索结果排序" ]) results = retriever.retrieve("RAG混合检索技术", k=3) for doc, score in results: print(f"文档: {doc}, 得分: {score:.4f}")
from transformers import AutoTokenizer, AutoModelForSequenceClassification import torch import torch.nn.functional as F class CrossEncoderReranker: def __init__(self, model_name='cross-encoder/ms-marco-MiniLM-L-6-v2'): """初始化交叉编码器重排序模型""" self.tokenizer = AutoTokenizer.from_pretrained(model_name) self.model = AutoModelForSequenceClassification.from_pretrained(model_name) self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') self.model.to(self.device) def rerank(self, query, documents, k=5): """重排序函数""" pairs = [(query, doc) for doc in documents] # 编码输入对 inputs = self.tokenizer( pairs, padding=True, truncation=True, return_tensors='pt', max_length=512 ) # 移动到设备 inputs = {k: v.to(self.device) for k, v in inputs.items()} # 获取预测结果 with torch.no_grad(): outputs = self.model(**inputs) scores = F.softmax(outputs.logits, dim=-1)[:, 1] # 取正类概率 # 获取top-k结果 top_k_indices = torch.argsort(scores, descending=True)[:k] reranked_results = [] for idx in top_k_indices: reranked_results.append((documents[idx], scores[idx].item())) return reranked_results # 使用示例 reranker = CrossEncoderReranker() query = "RAG系统优化方法" documents = [ "RAG系统的向量嵌入技术", "检索增强生成的重排序算法", "混合检索系统的实现方案", "RAG系统的性能优化策略" ] results = reranker.rerank(query, documents, k=3) for doc, score in results: print(f"文档: {doc}, 相关度得分: {score:.4f}")
from sklearn.linear_model import LogisticRegression from sklearn.svm import SVC from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score class RelevanceFeedbackLearner: def __init__(self): self.models = { 'logistic': LogisticRegression(random_state=42), 'svm': SVC(kernel='rbf', probability=True, random_state=42), 'rf': RandomForestClassifier(n_estimators=100, random_state=42) } self.trained_model = None def extract_features(self, query, document): """提取文档-查询对的特征""" # 简单的特征提取示例 features = [] # 1. 长度特征 features.append(len(document)) features.append(len(query)) # 2. 重叠词数 query_words = set(query.lower().split()) doc_words = set(document.lower().split()) overlap = len(query_words & doc_words) features.append(overlap) # 3. 词频特征 for word in query_words: features.append(document.lower().count(word)) return features def train_feedback_model(self, query_doc_pairs, labels): """训练反馈模型""" X = [] for query, doc in query_doc_pairs: X.append(self.extract_features(query, doc)) # 分割训练测试集 X_train, X_test, y_train, y_test = train_test_split( X, labels, test_size=0.2, random_state=42 ) # 训练多个模型并选择最佳 best_score = 0 best_model = None for name, model in self.models.items(): model.fit(X_train, y_train) score = accuracy_score(y_test, model.predict(X_test)) print(f"{name} 模型准确率: {score:.4f}") if score > best_score: best_score = score best_model = model self.trained_model = best_model return best_model def predict_relevance(self, query, document): """预测相关性""" features = [self.extract_features(query, document)] return self.trained_model.predict_proba(features)[0][1] # 返回正相关概率 # 使用示例 learner = RelevanceFeedbackLearner() # 训练数据示例 training_data = [ ("RAG系统", "检索增强生成是自然语言处理的重要技术", 1), ("RAG系统", "天气预报今天晴朗", 0), ("向量嵌入", "向量嵌入将文本转换为数值向量", 1), ("向量嵌入", "明天要开会讨论项目", 0), ("重排序算法", "重排序优化检索结果的排序", 1), ("重排序算法", "我喜欢喝咖啡", 0) ] queries_docs = [(query, doc) for query, doc, _ in training_data] labels = [label for _, _, label in training_data] # 训练模型 model = learner.train_feedback_model(queries_docs, labels) # 预测新文档 new_query = "RAG优化方法" new_doc = "检索增强生成的性能优化策略" relevance_score = learner.predict_relevance(new_query, new_doc) print(f"新文档的相关度得分: {relevance_score:.4f}")
class AdvancedRAGRetriever: """高级RAG检索系统""" def __init__(self, config=None): self.config = config or self._default_config() self.semantic_retriever = None self.hybrid_retriever = None self.reranker = None self.feedback_learner = None self.evaluator = None def _default_config(self): """默认配置""" return { 'semantic_model': 'all-MiniLM-L6-v2', 'cross_encoder_model': 'cross-encoder/ms-marco-MiniLM-L-6-v2', 'hybrid_weights': { 'semantic': 0.5, 'bm25': 0.3, 'tfidf': 0.2 }, 'rerank_top_k': 5, 'feedback_enabled': True } def initialize_components(self, documents): """初始化所有检索组件""" print("初始化检索组件...") # 初始化语义检索 from sentence_transformers import SentenceTransformer from faiss import IndexFlatIP self.semantic_model = SentenceTransformer(self.config['semantic_model']) embeddings = self.semantic_model.encode(documents, convert_to_numpy=True) dimension = embeddings.shape[1] self.semantic_index = IndexFlatIP(dimension) self.semantic_index.add(embeddings) # 初始化混合检索 from rank_bm25 import BM25Okapi from sklearn.feature_extraction.text import TfidfVectorizer tokenized_docs = [doc.split() for doc in documents] self.bm25 = BM25Okapi(tokenized_docs) self.tfidf = TfidfVectorizer() self.tfidf.fit(documents) # 初始化重排序器 from transformers import AutoTokenizer, AutoModelForSequenceClassification self.reranker_tokenizer = AutoTokenizer.from_pretrained( self.config['cross_encoder_model'] ) self.reranker_model = AutoModelForSequenceClassification.from_pretrained( self.config['cross_encoder_model'] ) # 初始化反馈学习 if self.config['feedback_enabled']: from sklearn.linear_model import LogisticRegression self.feedback_model = LogisticRegression(random_state=42) print("检索组件初始化完成") def retrieve_with_rerank(self, query, k=10): """执行检索和重排序""" print(f"执行检索: {query}") # 1. 混合检索 hybrid_results = self._hybrid_search(query, k * 2) # 2. 重排序 reranked_results = self._rerank_documents(query, hybrid_results, k) return reranked_results def _hybrid_search(self, query, k): """执行混合搜索""" # 语义检索 query_embedding = self.semantic_model.encode([query]) semantic_scores, semantic_indices = self.semantic_index.search(query_embedding, k) # BM25检索 tokenized_query = query.split() bm25_scores = self.bm25.get_scores(tokenized_query) bm25_top_k = np.argsort(bm25_scores)[-k:][::-1] # 混合得分 hybrid_scores = {} for i, score in enumerate(semantic_scores[0]): doc_idx = semantic_indices[0][i] if doc_idx not in hybrid_scores: hybrid_scores[doc_idx] = 0 hybrid_scores[doc_idx] += score * self.config['hybrid_weights']['semantic'] for idx in bm25_top_k: if idx not in hybrid_scores: hybrid_scores[idx] = 0 hybrid_scores[idx] += bm25_scores[idx] * self.config['hybrid_weights']['bm25'] # 排序并返回结果 sorted_results = sorted(hybrid_scores.items(), key=lambda x: x[1], reverse=True) return [(self.documents[idx], score) for idx, score in sorted_results[:k]] def _rerank_documents(self, query, documents, k): """重排序文档""" if len(documents) <= k: return documents # 准备输入对 pairs = [(query, doc) for doc, _ in documents] # 编码 inputs = self.reranker_tokenizer( pairs, padding=True, truncation=True, return_tensors='pt', max_length=512 ) # 预测 with torch.no_grad(): outputs = self.reranker_model(**inputs) scores = torch.softmax(outputs.logits, dim=-1)[:, 1] # 排序 top_k_indices = torch.argsort(scores, descending=True)[:k] reranked = [] for idx in top_k_indices: reranked.append((documents[idx][0], scores[idx].item())) return reranked # 使用示例 if __name__ == "__main__": # 示例文档 documents = [ "RAG系统结合了检索和生成的优势", "向量嵌入是RAG的核心技术", "混合检索可以提高检索质量", "重排序算法优化检索结果排序", "相关性反馈提升检索效果", "检索性能评估需要多指标", "深度学习用于检索优化", "跨语言检索技术实现", "实时检索系统架构设计", "检索系统监控与调优" ] # 初始化系统 rag_system = AdvancedRAGRetriever() rag_system.documents = documents rag_system.initialize_components(documents) # 执行检索 query = "RAG优化技术" results = rag_system.retrieve_with_rerank(query, k=5) print(f"查询: {query}") print("检索结果:") for i, (doc, score) in enumerate(results, 1): print(f" {i}. {doc} (得分: {score:.4f})")
A:权重设置需要根据具体应用场景进行调整。一般来说:
建议通过实验验证不同权重的效果,可以使用验证集进行调优。
A:重排序确实计算复杂度较高,可以考虑以下优化:
A:相关性反馈的数据需求取决于模型复杂度:
建议采用主动学习策略,优先选择最具信息量的样本进行标注。
A:长文档检索需要特殊处理:
A:检索系统性能监控应该包括:
建议设置监控面板和告警机制,及时发现性能异常。
本节深入讲解了检索效果的高级优化技术,包括混合检索、重排序算法、相关性反馈学习和性能评估。通过这些技术,可以显著提升RAG系统的检索质量。下一节将继续讨论检索系统的实战优化策略。
关键词:RAG高级优化, 混合检索, 重排序算法, 相关性反馈, 检索性能评估, 教程, 实战, 最佳实践
难度:进阶
预计阅读:25 分钟