RAG 索引构建与优化生成模块
AI 摘要
文章系统解析了RAG的索引构建与检索优化两大模块:前者用BGE-small向量化文档并构建FAISS索引,支持持久化与增量更新;后者在其上实现向量+BM25混合检索,用RRF重排序与元数据过滤提升召回与精度,形成“基础向量层—高级优化层”两级架构,兼顾语义与关键词互补,实现毫秒级精准检索。
📚 模块概述
这是一个索引构建模块,负责将文档块向量化并构建 FAISS 向量索引,是 RAG 系统中的存储层核心组件。它封装了嵌入模型和向量数据库的操作。
🎯 核心职责
- 向量化:使用嵌入模型将文本转换为向量
- 索引构建:使用 FAISS 构建高效的向量索引
- 索引持久化:保存和加载索引
- 相似度检索:基于向量相似度搜索文档
🏗️ 类结构分析
实例属性
def __init__(self, model_name, index_save_path):
self.model_name = "BAAI/bge-small-zh-v1.5" # 嵌入模型名称
self.index_save_path = "./vector_index" # 索引保存路径
self.embeddings = None # 嵌入模型实例
self.vectorstore = None # FAISS向量存储实例设计特点:
- 支持自定义嵌入模型
- 可配置索引存储位置
- 懒加载机制(初始化时只创建 embeddings)
🔧 核心方法详解
① setup_embeddings() - 嵌入模型初始化
功能:加载和配置 HuggingFace 嵌入模型
self.embeddings = HuggingFaceEmbeddings(
model_name=self.model_name, # 模型路径
model_kwargs={'device': 'cpu'}, # 运行设备
encode_kwargs={'normalize_embeddings': True} # 向量归一化
)关键配置解析:
模型选择:
BAAI/bge-small-zh-v1.5- BGE(BAAI General Embedding)系列
small:轻量级版本(适合 CPU 推理)zh:中文优化v1.5:版本号
设备配置:
device='cpu'- 使用 CPU 推理(通用性强)
- 可改为
'cuda'使用 GPU 加速
向量归一化:
normalize_embeddings=True- 将向量归一化到单位长度
- 使余弦相似度等价于点积(加速计算)
- 提高相似度计算稳定性
为什么选择 BGE-small?
模型对比:
- BGE-small-zh: 约 100M,速度快,CPU 友好
- BGE-base-zh: 约 400M,精度更高,需要更多资源
- BGE-large-zh: 约 1.3G,精度最高,GPU 推荐
食谱应用场景:small 模型足够,平衡性能和精度② build_vector_index() - 向量索引构建
功能:将文档块向量化并构建 FAISS 索引
def build_vector_index(self, chunks: List[Document]) -> FAISS:
self.vectorstore = FAISS.from_documents(
documents=chunks, # 待索引的文档列表
embedding=self.embeddings # 嵌入模型
)
return self.vectorstore底层流程:
1. 提取文档内容
chunks → [doc1.page_content, doc2.page_content, ...]
2. 批量向量化
embeddings.embed_documents(texts)
→ [[0.12, -0.45, ...], [0.33, 0.21, ...], ...]
3. 构建 FAISS 索引
FAISS.IndexFlatL2 (或 IndexFlatIP)
→ 支持高效近邻搜索
4. 存储元数据
保存每个向量对应的 Document 对象(包含 metadata)FAISS 索引类型(LangChain 默认使用):
- IndexFlatL2:精确 L2 距离搜索(如果未归一化)
- IndexFlatIP:精确内积搜索(如果归一化)
- 支持百万级向量的毫秒级检索
③ add_documents() - 增量添加文档
功能:向现有索引追加新文档(无需重建)
def add_documents(self, new_chunks: List[Document]):
if not self.vectorstore:
raise ValueError("请先构建向量索引")
self.vectorstore.add_documents(new_chunks)应用场景:
# 场景:动态更新食谱库
index_module.build_vector_index(initial_chunks) # 初始构建
# ... 用户添加新食谱 ...
index_module.add_documents(new_recipe_chunks) # 增量更新
index_module.save_index() # 保存更新优势:
- 避免全量重建(节省时间)
- 支持热更新(无需重启服务)
④ save_index() & load_index() - 索引持久化
保存索引
def save_index(self):
Path(self.index_save_path).mkdir(parents=True, exist_ok=True)
self.vectorstore.save_local(self.index_save_path)保存内容:
vector_index/
├── index.faiss # FAISS 索引文件(向量数据)
└── index.pkl # 文档元数据(Document 对象)加载索引
def load_index(self):
if not Path(self.index_save_path).exists():
logger.info("索引路径不存在,将构建新索引")
return None
self.vectorstore = FAISS.load_local(
self.index_save_path,
self.embeddings,
allow_dangerous_deserialization=True # 允许反序列化 pkl
)安全性考虑:
allow_dangerous_deserialization=True:允许加载 pickle 文件- ⚠️ 风险:pickle 可能包含恶意代码
- 缓解措施:仅加载可信来源的索引文件
冷启动优化:
# 首次启动
if not index_module.load_index(): # 加载失败
index_module.build_vector_index(chunks) # 构建新索引
index_module.save_index() # 保存以备下次使用
# 后续启动
index_module.load_index() # 直接加载,秒级启动⑤ similarity_search() - 相似度检索
功能:根据查询文本检索最相似的文档
def similarity_search(self, query: str, k: int = 5) -> List[Document]:
return self.vectorstore.similarity_search(query, k=k)底层算法:
1. 查询向量化
query → embeddings.embed_query("红烧肉怎么做")
→ [0.23, -0.12, 0.45, ...]
2. 向量相似度计算
FAISS.search(query_vector, k=5)
→ 找到最近的 5 个向量
3. 返回对应文档
根据向量索引返回 Document 对象(含 metadata)相似度度量(归一化向量):
# 余弦相似度
similarity = dot(query_vec, doc_vec) / (norm(query_vec) * norm(doc_vec))
# 归一化后简化为点积
similarity = dot(query_vec, doc_vec) # 范围 [-1, 1]检索示例:
# 输入
query = "简单的荤菜做法"
results = index_module.similarity_search(query, k=3)
# 输出(按相似度排序)
[
Document(page_content="## 红烧肉\n...", metadata={"category": "荤菜", "difficulty": "简单"}),
Document(page_content="## 糖醋排骨\n...", metadata={"category": "荤菜", "difficulty": "中等"}),
Document(page_content="## 清蒸鱼\n...", metadata={"category": "水产", "difficulty": "简单"})
]🔄 完整工作流程
┌─────────────────────────────────────────────────────────┐
│ 1. 初始化阶段 │
│ IndexConstructionModule() │
│ └─> setup_embeddings() # 加载嵌入模型 │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 2. 索引构建/加载 │
│ if load_index(): # 尝试加载已有索引 │
│ 使用现有索引 │
│ else: │
│ build_vector_index() # 从头构建索引 │
│ save_index() # 保存以备后用 │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 3. 检索阶段 │
│ similarity_search("用户查询", k=5) │
│ └─> 返回最相似的 5 个文档块 │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 4. 增量更新(可选) │
│ add_documents(new_chunks) # 添加新文档 │
│ save_index() # 持久化更新 │
└─────────────────────────────────────────────────────────┘💡 设计亮点
1. 向量归一化
encode_kwargs={'normalize_embeddings': True}好处:
- 余弦相似度 = 点积(计算更快)
- 避免向量长度影响相似度
- 数值稳定性更好
2. 懒加载机制
# 初始化时只加载模型
self.embeddings = HuggingFaceEmbeddings(...)
self.vectorstore = None # 不立即构建索引
# 实际使用时再构建/加载
index_module.load_index() # 或 build_vector_index()优势:节省启动时间,支持按需构建
3. 索引持久化
save_index() / load_index()价值:
- 避免每次启动都重新向量化(耗时)
- 10,000 个文档块向量化可能需要几分钟
- 加载预构建索引只需几秒
4. 增量更新支持
add_documents(new_chunks)场景:支持动态知识库更新,无需全量重建
📊 性能分析
向量化速度(BGE-small-zh,CPU)
文档数量 向量化时间 索引构建时间
100 ~2秒 ~0.1秒
1,000 ~20秒 ~1秒
10,000 ~3分钟 ~10秒检索速度(FAISS IndexFlat)
索引规模 Top-5 检索时间
1,000 <1ms
10,000 ~2ms
100,000 ~20ms
1,000,000 ~200ms内存占用(768 维向量)
每个向量:768 * 4 bytes = 3KB
10,000 个向量:约 30MB
100,000 个向量:约 300MB🎯 与数据准备模块的协作
# 数据准备模块
data_prep = DataPreparationModule(data_path="./data/cook")
data_prep.load_documents() # 加载父文档
chunks = data_prep.chunk_documents() # 生成子文档块
# 索引构建模块
index_builder = IndexConstructionModule(
model_name="BAAI/bge-small-zh-v1.5",
index_save_path="./vector_index"
)
# 为子文档块构建向量索引
index_builder.build_vector_index(chunks) # 索引子块(小块检索精准)
index_builder.save_index()
# 检索时
child_chunks = index_builder.similarity_search("红烧肉做法", k=5) # 检索子块
parent_docs = data_prep.get_parent_documents(child_chunks) # 获取完整父文档分工明确:
- 数据准备模块:管理文档内容和父子关系
- 索引构建模块:管理向量和相似度检索
🔧 实际应用示例
场景 1:首次构建索引
# 初始化
index_module = IndexConstructionModule()
# 加载数据
from rag_modules.data_preparation import DataPreparationModule
data_module = DataPreparationModule("./data/C8/cook")
data_module.load_documents()
chunks = data_module.chunk_documents()
# 构建索引
index_module.build_vector_index(chunks)
index_module.save_index()场景 2:服务启动(使用缓存)
index_module = IndexConstructionModule(index_save_path="./vector_index")
if not index_module.load_index(): # 尝试加载
# 加载失败,重新构建
chunks = load_chunks() # 从某处获取文档块
index_module.build_vector_index(chunks)
index_module.save_index()场景 3:混合检索基础
# 向量检索(语义相似度)
vector_results = index_module.similarity_search("低热量素菜", k=10)
# 后续可结合元数据过滤、重排序等高级技术
# (在其他模块中实现)🎓 总结
index_construction.py 是 RAG 系统的向量检索引擎:
核心能力:
- 使用 BGE 嵌入模型将文本转换为语义向量
- 使用 FAISS 构建高效的向量索引
- 支持相似度检索和增量更新
设计优势:
- 向量归一化提升计算效率
- 索引持久化避免重复向量化
- 懒加载机制优化启动速度
与其他模块协作:
- 接收数据准备模块的子文档块
- 提供检索结果给查询理解模块
- 支持高级检索策略(混合检索、重排序等)
这是一个轻量、高效、易扩展的向量索引模块,为 RAG 系统提供了坚实的检索基础。
我来详细分析 retrieval_optimization.py 检索优化模块,并结合 index_construction.py 讲解它们的协作关系。
读取 [](file:///d%3A/files/%E5%AE%9E%E4%B9%A0/%E6%88%91%E7%9A%84%E8%AE%A1%E5%88%92/all-in-rag/code/C8/rag_modules/retrieval_optimization.py)
读取 [](file:///d%3A/files/%E5%AE%9E%E4%B9%A0/%E6%88%91%E7%9A%84%E8%AE%A1%E5%88%92/all-in-rag/code/C8/rag_modules/retrieval_optimization.py#150-150),行 150 到 163
现在让我详细讲解检索优化模块,并结合索引构建模块分析它们的协作关系:
📚 模块概述
retrieval_optimization.py 是 RAG 系统的高级检索层,在基础向量检索之上实现了多种检索优化策略。它与 index_construction.py 形成两层架构:
┌────────────────────────────────────────────────────┐
│ retrieval_optimization.py (检索优化层) │
│ - 混合检索 (Hybrid Search) │
│ - RRF 重排序 │
│ - 元数据过滤 │
└─────────────────┬──────────────────────────────────┘
│ 调用
┌─────────────────▼──────────────────────────────────┐
│ index_construction.py (基础检索层) │
│ - 向量检索 (Vector Search) │
│ - FAISS 索引管理 │
└────────────────────────────────────────────────────┘🎯 核心职责
- 混合检索:融合向量检索(语义)+ BM25检索(关键词)
- RRF 重排序:合理融合多路检索结果
- 元数据过滤:基于结构化信息精确筛选
🏗️ 类结构与依赖关系
初始化分析
def __init__(self, vectorstore: FAISS, chunks: List[Document]):
self.vectorstore = vectorstore # 来自 index_construction 模块
self.chunks = chunks # 来自 data_preparation 模块
self.setup_retrievers()依赖关系图:
IndexConstructionModule.build_vector_index(chunks)
│
├─> vectorstore (FAISS 对象)
│
▼
RetrievalOptimizationModule(vectorstore, chunks)
│
├─> vector_retriever (使用 vectorstore)
└─> bm25_retriever (使用 chunks)为什么需要同时传入 vectorstore 和 chunks?
vectorstore:用于语义向量检索chunks:用于构建 BM25 关键词索引
🔧 核心方法详解
① setup_retrievers() - 双检索器初始化
def setup_retrievers(self):
# 1. 向量检索器(基于 index_construction 的 vectorstore)
self.vector_retriever = self.vectorstore.as_retriever(
search_type="similarity", # 相似度搜索
search_kwargs={"k": 5} # 返回 Top-5
)
# 2. BM25检索器(基于原始文档块)
self.bm25_retriever = BM25Retriever.from_documents(
self.chunks,
k=5
)检索器 1:向量检索器
原理:语义相似度匹配
# 底层调用链
vector_retriever.get_relevant_documents("红烧肉做法")
↓
vectorstore.similarity_search("红烧肉做法", k=5)
↓
FAISS 向量检索(余弦相似度)
↓
返回语义最相似的 5 个文档优势:
- 理解语义:能匹配同义词、近义词
- 示例:查询"简单菜肴" 能检索到"容易制作的菜品"
劣势:
- 关键词丢失:如果查询包含专有名词,可能匹配不准
检索器 2:BM25 检索器
原理:关键词匹配 + TF-IDF 改进
# BM25 算法核心公式
score = Σ IDF(qi) × [f(qi, D) × (k1 + 1)] / [f(qi, D) + k1 × (1 - b + b × |D| / avgdl)]
其中:
- qi: 查询词
- f(qi, D): 词频
- |D|: 文档长度
- avgdl: 平均文档长度
- k1, b: 调参参数优势:
- 精确匹配:能准确定位关键词
- 示例:查询"红烧肉" 必定匹配包含"红烧肉"的文档
劣势:
- 无语义理解:查询"简单菜肴"不会匹配"容易制作"
② hybrid_search() - 混合检索(核心方法)
def hybrid_search(self, query: str, top_k: int = 3) -> List[Document]:
# 步骤1: 分别检索
vector_docs = self.vector_retriever.get_relevant_documents(query)
bm25_docs = self.bm25_retriever.get_relevant_documents(query)
# 步骤2: RRF 融合重排
reranked_docs = self._rrf_rerank(vector_docs, bm25_docs)
# 步骤3: 返回 Top-K
return reranked_docs[:top_k]工作流程图:
用户查询:"简单的红烧肉做法"
│
├─────────────────┬─────────────────┐
│ │ │
向量检索 BM25检索 (并行执行)
│ │
语义匹配 关键词匹配
│ │
[doc1, doc3] [doc2, doc1]
[doc5, doc7] [doc3, doc4]
[doc9, ...] [doc6, ...]
│ │
└─────────┬───────┘
│
RRF 重排序
│
[doc1, doc3, doc2, doc5, ...]
│
取 Top-3
│
[doc1, doc3, doc2]③ _rrf_rerank() - RRF 重排序算法
RRF (Reciprocal Rank Fusion) 算法详解
算法公式
RRF_score(d) = Σ 1 / (k + rank_i(d))
其中:
- d: 文档
- rank_i(d): 文档在第 i 个检索结果中的排名
- k: 平滑参数(默认 60)代码实现
def _rrf_rerank(self, vector_docs, bm25_docs, k=60):
doc_scores = {}
doc_objects = {}
# 1. 处理向量检索结果
for rank, doc in enumerate(vector_docs):
doc_id = hash(doc.page_content)
doc_objects[doc_id] = doc
# RRF 分数计算
rrf_score = 1.0 / (k + rank + 1)
doc_scores[doc_id] = doc_scores.get(doc_id, 0) + rrf_score
# 2. 处理 BM25 检索结果(累加分数)
for rank, doc in enumerate(bm25_docs):
doc_id = hash(doc.page_content)
doc_objects[doc_id] = doc
rrf_score = 1.0 / (k + rank + 1)
doc_scores[doc_id] = doc_scores.get(doc_id, 0) + rrf_score
# 3. 按最终分数排序
sorted_docs = sorted(doc_scores.items(), key=lambda x: x[1], reverse=True)
# 4. 构建结果(附加 RRF 分数到元数据)
reranked_docs = []
for doc_id, final_score in sorted_docs:
doc = doc_objects[doc_id]
doc.metadata['rrf_score'] = final_score
reranked_docs.append(doc)
return reranked_docsRRF 算法优势
示例说明:
查询: "简单的红烧肉做法"
向量检索结果 (语义相似):
Rank 1: 红烧肉菜谱 (doc_A)
Rank 2: 糖醋排骨菜谱 (doc_B)
Rank 3: 清蒸鱼菜谱 (doc_C)
Rank 4: 红烧茄子菜谱 (doc_D)
Rank 5: 麻婆豆腐菜谱 (doc_E)
BM25 检索结果 (关键词匹配):
Rank 1: 红烧肉菜谱 (doc_A) # 含"红烧肉"
Rank 2: 红烧茄子菜谱 (doc_D) # 含"红烧"
Rank 3: 番茄炒蛋菜谱 (doc_F)
Rank 4: 宫保鸡丁菜谱 (doc_G)
Rank 5: 鱼香肉丝菜谱 (doc_H)
RRF 分数计算 (k=60):
doc_A: 1/(60+1) + 1/(60+1) = 0.0328 (两个第1名)
doc_D: 1/(60+4) + 1/(60+2) = 0.0317 (向量第4,BM25第2)
doc_B: 1/(60+2) = 0.0161 (仅向量第2)
doc_C: 1/(60+3) = 0.0159 (仅向量第3)
doc_F: 1/(60+3) = 0.0159 (仅BM25第3)
...
最终排序:
1. doc_A (红烧肉) - 0.0328 ✓ 两种检索都排名靠前
2. doc_D (红烧茄子) - 0.0317
3. doc_B (糖醋排骨) - 0.0161
...RRF 的智能之处:
- 互补性:同时出现在两个列表的文档会获得更高分数
- 公平性:不依赖各检索器的原始分数(可能量纲不同)
- 稳健性:对排名变化不敏感(使用倒数)
④ metadata_filtered_search() - 元数据过滤检索
def metadata_filtered_search(self, query: str, filters: Dict[str, Any], top_k: int = 5):
# 步骤1: 先混合检索,获取更多候选(3倍)
docs = self.hybrid_search(query, top_k * 3)
# 步骤2: 应用元数据过滤
filtered_docs = []
for doc in docs:
match = True
for key, value in filters.items():
if key in doc.metadata:
if isinstance(value, list):
# 列表:包含判断
if doc.metadata[key] not in value:
match = False
break
else:
# 单值:精确匹配
if doc.metadata[key] != value:
match = False
break
else:
match = False
break
if match:
filtered_docs.append(doc)
if len(filtered_docs) >= top_k:
break
return filtered_docs应用场景:
# 场景1: 查找简单的荤菜
results = module.metadata_filtered_search(
query="家常菜做法",
filters={
'category': '荤菜',
'difficulty': '简单'
},
top_k=3
)
# 场景2: 查找多个分类的菜品
results = module.metadata_filtered_search(
query="快手菜",
filters={
'category': ['素菜', '汤品'], # 列表:OR 关系
'difficulty': '非常简单'
},
top_k=5
)为什么先检索 3 倍?
# 问题:直接检索 top_k=5 可能不够
hybrid_search(query, top_k=5) # 假设返回 [doc1, doc2, doc3, doc4, doc5]
# 经过元数据过滤后,可能只剩 [doc2, doc4],不足 5 个
# 解决:先检索 3 倍,留有过滤空间
hybrid_search(query, top_k=15) # 返回 15 个候选
# 过滤后仍能保证足够的结果数量🔄 与 index_construction.py 的协作流程
完整调用链
# ========== 第1步:索引构建(index_construction.py)==========
from rag_modules.index_construction import IndexConstructionModule
# 初始化索引模块
index_module = IndexConstructionModule(
model_name="BAAI/bge-small-zh-v1.5",
index_save_path="./vector_index"
)
# 构建向量索引
vectorstore = index_module.build_vector_index(chunks)
# 内部操作:
# 1. chunks → embeddings.embed_documents(texts)
# 2. vectors → FAISS.from_documents()
# 3. 返回 FAISS vectorstore
# ========== 第2步:检索优化(retrieval_optimization.py)==========
from rag_modules.retrieval_optimization import RetrievalOptimizationModule
# 传入 vectorstore 和 chunks
retrieval_module = RetrievalOptimizationModule(
vectorstore=vectorstore, # 来自 index_module
chunks=chunks # 原始文档块
)
# 内部操作:
# 1. self.vector_retriever = vectorstore.as_retriever() # 封装向量检索
# 2. self.bm25_retriever = BM25Retriever.from_documents(chunks) # 构建BM25索引
# ========== 第3步:混合检索 ==========
results = retrieval_module.hybrid_search("红烧肉怎么做", top_k=3)
# 调用链:
# hybrid_search()
# ├─> vector_retriever.get_relevant_documents()
# │ └─> vectorstore.similarity_search() ← 调用 index_construction 的向量检索
# │ └─> FAISS.search()
# │
# ├─> bm25_retriever.get_relevant_documents()
# │ └─> BM25 关键词匹配
# │
# └─> _rrf_rerank() # 融合两路结果📊 两个模块的职责对比
| 维度 | index_construction.py | retrieval_optimization.py |
|---|---|---|
| 抽象层级 | 基础检索层 | 高级检索层 |
| 核心功能 | 向量化 + 索引构建 | 混合检索 + 重排序 |
| 检索策略 | 单一向量检索 | 向量 + BM25 混合 |
| 依赖关系 | 独立模块 | 依赖 vectorstore |
| 输出 | FAISS vectorstore 对象 | 优化后的文档列表 |
| 使用场景 | 冷启动、索引管理 | 实际查询处理 |
💡 混合检索的优势示例
场景对比
查询: "低热量的素菜做法"
仅向量检索
index_module.similarity_search("低热量的素菜做法", k=5)结果:
1. 清炒时蔬 (语义相似:健康、清淡)
2. 凉拌黄瓜 (语义相似:低卡)
3. 蒸南瓜 (语义相似:健康)
4. 红烧茄子 (误匹配:茄子是素菜,但做法偏油腻)
5. 糖醋排骨 (误匹配:仅因"做法"相似)仅 BM25 检索
bm25_retriever.get_relevant_documents("低热量的素菜做法")结果:
1. 素炒豆芽 (含"素菜")
2. 清蒸鱼 (含"做法",但不是素菜)
3. 凉拌海带 (含"素菜")
4. 低卡沙拉 (含"低热量")
5. 炸茄盒 (含"素菜",但高热量)混合检索 (RRF)
retrieval_module.hybrid_search("低热量的素菜做法", top_k=5)结果:
1. 清炒时蔬 (向量第1 + BM25第1 → RRF高分) ✓
2. 凉拌黄瓜 (向量第2 + BM25第4 → RRF高分) ✓
3. 素炒豆芽 (向量第6 + BM25第1 → RRF中分) ✓
4. 低卡沙拉 (向量第5 + BM25第4 → RRF中分) ✓
5. 蒸南瓜 (向量第3 → RRF低分) ✓优势体现:
- 同时考虑语义(低热量 ≈ 健康、清淡)
- 同时考虑关键词(必须包含"素菜")
- 互补性增强,减少误匹配
🎯 实际应用示例
完整代码流程
# 步骤1: 构建索引
from rag_modules.data_preparation import DataPreparationModule
from rag_modules.index_construction import IndexConstructionModule
data_module = DataPreparationModule("./data/C8/cook")
data_module.load_documents()
chunks = data_module.chunk_documents()
index_module = IndexConstructionModule()
vectorstore = index_module.build_vector_index(chunks)
index_module.save_index()
# 步骤2: 初始化检索优化
from rag_modules.retrieval_optimization import RetrievalOptimizationModule
retrieval_module = RetrievalOptimizationModule(
vectorstore=vectorstore,
chunks=chunks
)
# 步骤3: 不同检索策略
# 策略1: 混合检索(平衡)
results = retrieval_module.hybrid_search("家常菜", top_k=3)
# 策略2: 带过滤的混合检索(精准)
results = retrieval_module.metadata_filtered_search(
query="家常菜",
filters={
'category': '荤菜',
'difficulty': ['简单', '非常简单']
},
top_k=3
)
# 步骤4: 获取完整父文档(结合 data_preparation)
parent_docs = data_module.get_parent_documents(results)🎓 总结
模块定位
RAG 检索架构(三层设计):
┌──────────────────────────────────────┐
│ 应用层: main.py / API │
│ - 用户查询入口 │
│ - 结果整合与返回 │
└─────────────┬────────────────────────┘
│
┌─────────────▼────────────────────────┐
│ 检索优化层: retrieval_optimization │
│ - 混合检索 (向量 + BM25) │
│ - RRF 重排序 │
│ - 元数据过滤 │
└─────────────┬────────────────────────┘
│
┌─────────────▼────────────────────────┐
│ 基础检索层: index_construction │
│ - 向量化 (BGE embeddings) │
│ - FAISS 索引管理 │
│ - 基础相似度搜索 │
└──────────────────────────────────────┘核心价值
检索优化模块:
- 融合多种检索策略,提高召回率和准确率
- RRF 算法智能融合,无需调参
- 元数据过滤支持精准控制
与索引构建模块的协作:
index_construction提供向量检索能力retrieval_optimization增强检索效果- 解耦设计,易于扩展和维护
技术亮点:
- 互补检索:向量(语义)+ BM25(关键词)
- 智能融合:RRF 算法平衡多路结果
- 精准过滤:结构化元数据筛选
这是一个生产级 RAG 检索系统的标准实现,平衡了召回率、精确率和系统复杂度。
- 上一篇:RAG 数据生成模块
- 下一篇:RAG 生成集成与系统整合