3.1 向量检索 本节导读:深入理解向量检索原理,掌握Haystack中EmbeddingRetriever的使用方法和企业级向量检索系统实现 学习目标 理解向量检索的核心原理和数学基础 掌握Haystack中EmbeddingRetriever的配置和使用 学会选择和配置合适的嵌入模型 构建高性能的企业级向量检索系统 理解相似度计算方法和优化策略 核心概念 向量检索原理 向量检索是将文本转换为高维向量空间中的点,通过计算向量之间的距离或相似度来找到最相关的文档。这种方法基于分布式语义假设,语义相似的文本在向量空间中也相互接近。
本节导读:深入理解向量检索原理,掌握Haystack中EmbeddingRetriever的使用方法和企业级向量检索系统实现
向量检索是将文本转换为高维向量空间中的点,通过计算向量之间的距离或相似度来找到最相关的文档。这种方法基于分布式语义假设,语义相似的文本在向量空间中也相互接近。
嵌入模型(Embedding Model)是将文本转换为向量的深度学习模型,常见的有BERT、Sentence-BERT、OpenAI Embeddings等。选择合适的嵌入模型对检索性能至关重要。
相似度计算是向量检索的核心,常用的方法包括余弦相似度、欧氏距离、内积等,不同的计算方法适用于不同的应用场景。
pip install haystack-ai sentence-transformers torch faiss-cpu numpy scikit-learn
| 模型名称 | 维度 | 语言 | 特点 | 适用场景 |
|---|---|---|---|---|
| all-MiniLM-L6-v2 | 384 | 多语言 | 轻量级,速度快 | 实时检索,原型验证 |
| all-mpnet-base-v2 | 768 | 多语言 | 性能均衡,效果好 | 一般性检索任务 |
| text-embedding-3-small | 1536 | 英文 | OpenAI出品,质量高 | 英文专业检索 |
| text-embedding-3-large | 3072 | 英文 | 最高质量,成本高 | 严格要求准确性的场景 |
| paraphrase-multilingual-MiniLM-L12-v2 | 384 | 多语言 | 多语言支持好 | 多语言应用 |
from haystack.components.embedders import SentenceTransformersTextEmbedder from haystack.document_stores import FAISSDocumentStore from haystack.components.retrievers import EmbeddingRetriever # 1. 初始化文本嵌入器 embedder = SentenceTransformersTextEmbedder( model="sentence-transformers/all-MiniLM-L6-v2", device="cpu", # 使用"cuda"启用GPU batch_size=32, # 批处理大小 ) # 2. 准备测试文本 texts = [ "机器学习是人工智能的一个分支", "深度学习使用神经网络来学习数据模式", "自然语言处理处理和理解人类语言", "计算机视觉使计算机能够理解图像", "RAG结合检索和生成提高回答准确性" ] # 3. 生成嵌入向量 embeddings = embedder.run(texts=texts) print(f"生成的向量形状: {embeddings['embeddings'].shape}") print(f"向量维度: {len(embeddings['embeddings'][0])}")
# 1. 创建FAISS文档存储 faiss_store = FAISSDocumentStore( embedding_dim=384, # 必须与嵌入模型维度匹配 faiss_index_factory="Flat", # 使用精确搜索,"IVF"用于近似搜索 return_embedding=True, # 存储并返回向量 similarity="cosine", # 相似度计算方法 faiss_index=faiss.IndexFlatIP # 使用内积索引 ) # 2. 创建并添加文档 documents = [ { "id": "doc1", "content": "机器学习是人工智能的一个分支,专注于让计算机系统从数据中学习模式。" }, { "id": "doc2", "content": "深度学习是机器学习的子集,使用多层神经网络来学习数据的复杂表示。" }, { "id": "doc3", "content": "自然语言处理(NLP)是AI的一个领域,专注于计算机与人类语言之间的交互。" }, { "id": "doc4", "content": "计算机视觉使计算机能够从图像和视频中获取高级理解,类似于人类视觉系统。" }, { "id": "doc5", "content": "检索增强生成(RAG)结合了信息检索和文本生成,通过外部知识库增强语言模型的能力。" } ] # 3. 写入文档到存储 faiss_store.write_documents(documents) print(f"已写入 {len(documents)} 个文档到FAISS存储")
# 1. 创建嵌入检索器 embedding_retriever = EmbeddingRetriever( document_store=faiss_store, top_k=3, # 返回最相关的3个文档 scale_score=True, # 对相似度分数进行归一化 ) # 2. 执行向量检索 query = "什么是深度学习?" results = embedding_retriever.run(query=query) # 3. 显示检索结果 print(f"查询: {query}") print(f"检索到 {len(results['documents'])} 个文档:\n") for i, doc in enumerate(results['documents'], 1): print(f"{i}. [分数: {doc.score:.4f}] {doc.content}") print(f" ID: {doc.id}\n")
# 1. 多样化检索器配置 class DiverseEmbeddingRetriever: def __init__(self, document_store, models_config): self.document_store = document_store self.retrievers = {} # 为不同类型的查询配置不同的嵌入模型 for model_name, config in models_config.items(): embedder = SentenceTransformersTextEmbedder( model=model_name, device="cpu", batch_size=config["batch_size"] ) retriever = EmbeddingRetriever( document_store=document_store, top_k=config["top_k"], scale_score=config["scale_score"] ) self.retrievers[model_name] = { "embedder": embedder, "retriever": retriever, "config": config } def run(self, query, model_type="general"): if model_type not in self.retrievers: model_type = "general" retriever_info = self.retrievers[model_type] results = retriever_info["retriever"].run(query=query) return { "documents": results["documents"], "model_type": model_type, "config": retriever_info["config"] } # 2. 配置多样化检索器 models_config = { "general": { "model": "sentence-transformers/all-MiniLM-L6-v2", "top_k": 5, "batch_size": 32, "scale_score": True }, "technical": { "model": "sentence-transformers/all-mpnet-base-v2", "top_k": 3, "batch_size": 16, "scale_score": True }, "multilingual": { "model": "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2", "top_k": 4, "batch_size": 32, "scale_score": True } } diverse_retriever = DiverseEmbeddingRetriever(faiss_store, models_config) # 3. 测试多样化检索 technical_query = "神经网络反向传播算法原理" results = diverse_retriever.run(query=technical_query, model_type="technical") print(f"技术查询: {technical_query}") print(f"使用模型: {results['model_type']}") print(f"检索结果:\n") for i, doc in enumerate(results['documents'], 1): print(f"{i}. [分数: {doc.score:.4f}] {doc.content[:100]}...")
import time import logging from typing import List, Dict, Any from dataclasses import dataclass from haystack.components.embedders import SentenceTransformersTextEmbedder from haystack.document_stores import FAISSDocumentStore from haystack.components.retrievers import EmbeddingRetriever from haystack.core import Pipeline # 配置日志 logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) @dataclass class RetrievalConfig: """检索系统配置""" model_name: str = "sentence-transformers/all-MiniLM-L6-v2" embedding_dim: int = 384 top_k: int = 5 batch_size: int = 32 device: str = "cpu" similarity: str = "cosine" @dataclass class PerformanceMetrics: """性能指标""" query_time: float result_count: int avg_score: float memory_usage: float class EnterpriseVectorRetriever: """企业级向量检索系统""" def __init__(self, config: RetrievalConfig): self.config = config self.embedder = None self.document_store = None self.retriever = None self.is_initialized = False def initialize(self): """初始化检索系统""" try: logger.info(f"正在初始化向量检索系统,使用模型: {self.config.model_name}") # 1. 初始化嵌入器 self.embedder = SentenceTransformersTextEmbedder( model=self.config.model_name, device=self.config.device, batch_size=self.config.batch_size ) # 2. 初始化文档存储 self.document_store = FAISSDocumentStore( embedding_dim=self.config.embedding_dim, faiss_index_factory="Flat", return_embedding=True, similarity=self.config.similarity ) # 3. 初始化检索器 self.retriever = EmbeddingRetriever( document_store=self.document_store, top_k=self.config.top_k, scale_score=True ) self.is_initialized = True logger.info("向量检索系统初始化完成") except Exception as e: logger.error(f"初始化失败: {e}") raise def index_documents(self, documents: List[Dict[str, Any]]): """索引文档""" if not self.is_initialized: raise RuntimeError("检索系统未初始化") try: logger.info(f"开始索引 {len(documents)} 个文档") # 批量写入文档 self.document_store.write_documents(documents) logger.info(f"成功索引 {len(documents)} 个文档") except Exception as e: logger.error(f"索引文档失败: {e}") raise def search(self, query: str, filters: Dict[str, Any] = None) -> Dict[str, Any]: """执行向量检索""" if not self.is_initialized: raise RuntimeError("检索系统未初始化") start_time = time.time() try: # 执行检索 results = self.retriever.run(query=query, filters=filters) # 计算性能指标 query_time = time.time() - start_time memory_usage = self._get_memory_usage() avg_score = ( sum(doc.score for doc in results['documents']) / len(results['documents']) if results['documents'] else 0.0 ) metrics = PerformanceMetrics( query_time=query_time, result_count=len(results['documents']), avg_score=avg_score, memory_usage=memory_usage ) return { "documents": results['documents'], "metrics": metrics, "query": query } except Exception as e: logger.error(f"检索失败: {e}") raise def _get_memory_usage(self) -> float: """获取内存使用情况""" import psutil process = psutil.Process() return process.memory_info().rss / 1024 / 1024 # MB def get_performance_stats(self, query_history: List[Dict[str, Any]]) -> Dict[str, Any]: """获取性能统计信息""" if not query_history: return {} query_times = [q['metrics'].query_time for q in query_history] scores = [q['metrics'].avg_score for q in query_history if q['metrics'].avg_score > 0] return { "avg_query_time": sum(query_times) / len(query_times), "max_query_time": max(query_times), "min_query_time": min(query_times), "avg_score": sum(scores) / len(scores) if scores else 0, "total_queries": len(query_history) } # 使用示例 if __name__ == "__main__": # 配置检索系统 config = RetrievalConfig( model_name="sentence-transformers/all-MiniLM-L6-v2", top_k=5, device="cpu" ) # 创建检索系统 retriever = EnterpriseVectorRetriever(config) retriever.initialize() # 准备文档数据 documents = [ { "id": "doc1", "content": "机器学习是人工智能的一个分支,专注于让计算机系统从数据中学习模式和规律。监督学习、无监督学习和强化学习是机器学习的三大主要范式。", "meta": {"category": "AI", "language": "zh"} }, { "id": "doc2", "content": "深度学习是机器学习的子集,使用多层神经网络来学习数据的复杂表示。卷积神经网络(CNN)在图像处理中表现出色,循环神经网络(RNN)和Transformer在序列数据处理中效果显著。", "meta": {"category": "AI", "language": "zh"} }, { "id": "doc3", "content": "自然语言处理(NLP)是AI的一个领域,专注于计算机与人类语言之间的交互。现代NLP主要基于Transformer架构,BERT、GPT等模型在理解、生成和翻译任务中取得了突破性进展。", "meta": {"category": "NLP", "language": "zh"} }, { "id": "doc4", "content": "计算机视觉使计算机能够从图像和视频中获取高级理解,类似于人类视觉系统。目标检测、图像分割、图像生成是计算机视觉的核心任务,YOLO、SSD、Mask R-CNN等算法被广泛应用。", "meta": {"category": "CV", "language": "zh"} }, { "id": "doc5", "content": "检索增强生成(RAG)结合了信息检索和文本生成,通过外部知识库增强语言模型的能力。这种方法解决了大语言模型的知识时效性和幻觉问题,提高了回答的准确性和可靠性。", "meta": {"category": "RAG", "language": "zh"} } ] # 索引文档 retriever.index_documents(documents) # 测试检索 queries = [ "什么是深度学习?", "自然语言处理有哪些应用?", "检索增强生成的优势是什么?" ] query_history = [] for query in queries: results = retriever.search(query) query_history.append(results) print(f"\n查询: {query}") print(f"检索时间: {results['metrics'].query_time:.4f}秒") print(f"结果数量: {results['metrics'].result_count}") print(f"平均分数: {results['metrics'].avg_score:.4f}") print("\n检索结果:") for i, doc in enumerate(results['documents'], 1): print(f"{i}. [分数: {doc.score:.4f}] {doc.content[:100]}...") # 输出性能统计 stats = retriever.get_performance_stats(query_history) print(f"\n性能统计:") print(f"平均查询时间: {stats['avg_query_time']:.4f}秒") print(f"最大查询时间: {stats['max_query_time']:.4f}秒") print(f"平均分数: {stats['avg_score']:.4f}")
A:选择嵌入模型时应考虑以下因素:
A:向量检索的主要优势在于:
A:优化策略包括:
根据应用场景选择合适的top_k值:
# 设置相似度阈值过滤低质量结果 def filter_by_similarity(results, threshold=0.3): filtered_docs = [doc for doc in results['documents'] if doc.score >= threshold] return { 'documents': filtered_docs, 'filtered_count': len(filtered_docs), 'original_count': len(results['documents']) }
常见错误:嵌入模型生成的向量维度与文档存储配置不匹配。
解决方案:确保FAISSDocumentStore的embedding_dim参数与嵌入模型输出的维度完全一致。
处理大量文档时可能出现内存不足。
解决方案:使用批处理索引,定期清理缓存,考虑使用磁盘存储的DocumentStore。
本章节详细介绍了向量检索的原理、实现和优化策略。通过Haystack的EmbeddingRetriever,我们可以构建高性能的企业级向量检索系统。关键要点包括:选择合适的嵌入模型、配置高效的相似度计算、实施性能优化策略,以及建立完善的监控系统。下一节我们将学习关键词检索技术,它将与向量检索形成互补。
关键词:向量检索, EmbeddingRetriever, FAISS, 相似度计算, 企业级检索, Haystack
难度:进阶
预计阅读:90分钟