当前位置: 首页 > news >正文

本地 RAG 检索器:加载 FAISS 索引并实现语义搜索

【学习记录】本地 RAG 检索器:加载 FAISS 索引并实现语义搜索

在前一篇文章中,我们构建了 PDF → 文本 → 向量 → FAISS 索引的完整流水线。本文展示如何使用该索引进行语义检索:加载已保存的 FAISS 索引和 LlamaIndex 存储上下文,创建一个不依赖 LLM 的检索器(Retriever),接受用户查询,返回最相似的文本片段及其相关度分数。代码完全独立,适合集成到问答系统或进一步分析检索结果。


📌 目录

  1. 功能概述
  2. 环境配置与依赖
  3. 核心原理解析
  4. 完整代码(检索脚本)
  5. 执行方法
  6. 运行效果示例
  7. 注意事项
  8. 总结

一、功能概述

本脚本实现了以下功能:

  1. 加载 Embedding 模型:使用与构建索引时相同的 HuggingFace 中文嵌入模型BAAI/bge-small-zh-v1.5,确保向量空间一致。
  2. 读取 FAISS 索引:从磁盘加载之前保存的 FAISS 索引文件vector_store.faiss
  3. 恢复 StorageContext:利用 LlamaIndex 的持久化机制,恢复文档存储(docstore)和索引结构。
  4. 创建检索器:基于索引构建一个检索器(retriever),支持top_k参数。
  5. 交互式检索:循环接受用户输入查询,输出最相关的文本片段及其相关度分数(L2 距离转换后的相似度)。

适用场景:在 RAG 系统中,可以先使用此脚本验证检索效果,调试chunk_sizetop_k等参数,再接入 LLM 生成最终答案。


二、环境配置与依赖

Python 库依赖

pipinstallllama-index-core llama-index-embeddings-huggingface llama-index-vector-stores-faiss faiss-cpu sentence-transformers
作用
llama-index-coreLlamaIndex 核心,提供索引加载、检索器等功能
llama-index-embeddings-huggingfaceHuggingFace 嵌入模型适配器
llama-index-vector-stores-faissFAISS 向量存储适配器
faiss-cpuFAISS 库(CPU 版本)
sentence-transformers嵌入模型依赖(自动安装)

前置要求

  • 已经运行过上一篇文章中的构建脚本,生成了./storage/faiss_index目录,其中包含:
    • vector_store.faiss:FAISS 索引文件。
    • docstore.jsonindex_store.json等 LlamaIndex 元数据文件。

三、核心原理解析

3.1 Embedding 模型一致性

检索时使用的嵌入模型必须与构建索引时完全相同(包括模型名称、维度)。本脚本显式设置了相同的EMBED_MODELdevice="cpu",保证查询向量与索引向量在同一空间。

3.2 加载 FAISS 索引

faiss_index=faiss.read_index(faiss_path)
  • faiss.read_index直接读取原生 FAISS 索引文件,获得一个faiss.Index对象。
  • 通过faiss_index.ntotal可以查看索引中的向量总数。

3.3 恢复 StorageContext

vector_store=FaissVectorStore(faiss_index=faiss_index)storage_context=StorageContext.from_defaults(persist_dir=INDEX_DIR,vector_store=vector_store)
  • 由于我们已经手动加载了 FAISS 索引,需要将其包装成FaissVectorStore对象。
  • StorageContext.from_defaults再从persist_dir中读取docstore.jsonindex_store.json,恢复文档节点和索引结构。

3.4 创建检索器

retriever=index.as_retriever(similarity_top_k=TOP_K)
  • 检索器只执行相似度搜索,不调用 LLM 生成答案。
  • 返回的每个节点带有score属性(对于 L2 距离索引,score是负的欧氏距离,越接近 0 表示越相似;实际使用中可转换为余弦相似度或直接使用)。

3.5 检索流程

  1. 用户输入查询文本query
  2. 脚本调用Settings.embed_model.get_text_embedding(query)将查询转换为向量(内部自动完成)。
  3. FAISS 索引执行search操作,返回top_k个最相似的向量索引及其距离。
  4. 通过storage_context将索引映射回原始文本节点,连同元数据一起返回。

四、完整代码(检索脚本)

创建文件search_index.py,内容如下:

importosimportsysfromllama_index.coreimport(StorageContext,load_index_from_storage,Settings)fromllama_index.embeddings.huggingfaceimportHuggingFaceEmbeddingfromllama_index.vector_stores.faissimportFaissVectorStoreimportfaiss# ==================================================# 配置(与构建脚本保持一致)# ==================================================INDEX_DIR="./storage/faiss_index"EMBED_MODEL="BAAI/bge-small-zh-v1.5"TOP_K=5# 检索 top-k 相似片段# ==================================================# 初始化 Embedding 模型# ==================================================print("加载 Embedding 模型...")Settings.embed_model=HuggingFaceEmbedding(model_name=EMBED_MODEL,device="cpu")# ==================================================# 加载 FAISS 索引# ==================================================faiss_path=os.path.join(INDEX_DIR,"vector_store.faiss")ifnotos.path.exists(faiss_path):print(f"错误:索引文件不存在 -{faiss_path}")sys.exit(1)print("读取 FAISS 索引...")faiss_index=faiss.read_index(faiss_path)print(f"FAISS 索引维度:{faiss_index.d}, 向量数量:{faiss_index.ntotal}")vector_store=FaissVectorStore(faiss_index=faiss_index)print("加载 StorageContext...")storage_context=StorageContext.from_defaults(persist_dir=INDEX_DIR,vector_store=vector_store)print("加载索引...")try:index=load_index_from_storage(storage_context)print("索引加载成功")exceptExceptionase:print(f"索引加载失败:{e}")sys.exit(1)# 获取文档节点数量doc_count=len(index.docstore.docs)ifhasattr(index,'docstore')else"未知"print(f"索引中的文档节点数:{doc_count}")# ==================================================# 创建检索器(不包含 LLM 生成)# ==================================================retriever=index.as_retriever(similarity_top_k=TOP_K)# ==================================================# 交互检索循环# ==================================================print("\n"+"="*60)print("索引加载成功!现在仅进行检索(不调用 LLM)。")print("输入 'exit' 或 'quit' 退出程序。")print("="*60)whileTrue:query=input("\n请输入检索查询:").strip()ifquery.lower()in['exit','quit','q']:print("退出程序。")breakifnotquery:continueprint("\n检索中...")nodes_with_scores=retriever.retrieve(query)print("\n【检索到的文档片段】")ifnodes_with_scores:foridx,node_with_scoreinenumerate(nodes_with_scores,1):score=node_with_score.scoreifhasattr(node_with_score,'score')else'N/A'node=node_with_score.nodeprint(f"\n片段{idx}(相关度:{score:.4f})")snippet=node.text[:800]+"..."iflen(node.text)>800elsenode.textprint(f"文本:\n{snippet}")ifnode.metadata:print(f"元数据:{node.metadata}")print("-"*40)else:print("未检索到任何片段(可能索引为空或查询无匹配)。")print("\n"+"="*60)

五、执行方法

5.1 确保索引已存在

首先运行上一篇文章中的构建脚本(build_index.py),生成./storage/faiss_index目录。

5.2 运行检索脚本

在终端中执行:

python search_index.py

5.3 交互示例

加载 Embedding 模型... 读取 FAISS 索引... FAISS 索引维度:512, 向量数量:126 加载 StorageContext... 加载索引... 索引加载成功 索引中的文档节点数:126 ============================================================ 索引加载成功!现在仅进行检索(不调用 LLM)。 输入 'exit' 或 'quit' 退出程序。 ============================================================ 请输入检索查询:医疗器械分类规则 检索中... 【检索到的文档片段】 片段 1 (相关度: 0.8234) 文本: 医疗器械按照风险程度分为三类:第一类是风险较低,第二类是中度风险,第三类是较高风险... 元数据: {'source': 'YY/T0664-2020'} ---------------------------------------- 片段 2 (相关度: 0.7651) ...

六、运行效果示例

假设索引中包含某医疗器械标准文档的内容,查询“分类规则”会返回相关段落及其相关度分数。score对于 L2 距离索引,实际是负的欧氏距离(越大表示越相似)。用户可以根据分数阈值过滤低相关片段。


七、注意事项

问题说明解决方案
模型不一致检索时使用的嵌入模型与构建时不同,会导致向量空间不匹配,检索结果完全错误。确保EMBED_MODEL与构建脚本完全一致。
索引路径错误脚本中INDEX_DIR必须指向正确的目录。使用绝对路径或确认相对路径正确。
内存不足加载大型 FAISS 索引可能占用大量内存。使用faissread_index时,可设置mmap模式(但 LlamaIndex 适配器可能需要全量加载)。
分数解释score不是标准的余弦相似度,而是 FAISS 返回的距离转换值。可忽略具体数值,仅用于排序。
无检索结果可能查询与文档内容完全不相关,或索引中文本过少。尝试更换查询词,或增加chunk_size重新构建索引。

八、总结

本文提供了一个即用型语义检索脚本,实现了:

  • ✅ 加载 FAISS 索引和 LlamaIndex 存储。
  • ✅ 创建不依赖 LLM 的检索器。
  • ✅ 交互式查询,展示相似文本片段及相关度分数。
  • ✅ 可直接集成到 RAG 系统的检索环节,或用于调试分块策略。

通过这个脚本,你可以:

  • 验证索引质量:检查检索结果是否符合预期。
  • 调整TOP_KCHUNK_SIZE参数,观察召回效果变化。
  • 将检索到的节点传递给 LLM,构建完整的问答系统。

下一步可以结合上一篇文章的构建脚本,形成一套完整的本地 RAG 知识库预处理与检索工具链。

http://www.rkmt.cn/news/1535203.html

相关文章:

  • Debian滚动更新实践:Rolling Ridley混合发布架构
  • 2026年 木托盘厂家推荐榜单:松木/免熏蒸/出口木托盘与IPPC热处理实力品牌大全 - 品牌发掘
  • 榆林黄金回收怎么选靠谱商家 避坑实操干货 - 余生黄金回收
  • Gemini 3.5 Flash API 实测指南:绕过UI限制的工程化接入方法
  • 2026年6月马鞍山机械刀片厂家推荐:锯齿刀片/包装机/印刷机刀片优选指南 - 海棠依旧大
  • 2026昆明卖黄金避坑全指南 教你分辨正规回收商家与套路 - 润富黄金回收
  • 2026年6月贵州包车游旅行社推荐:十大排名家庭包车防套路评测专业价格 - 品牌推荐
  • 榆林旧黄金回收避坑指南 看懂行情不被乱扣费 - 余生黄金回收
  • Product Group Reference Article 在 SAP Retail 商品主数据中的设计逻辑与落地边界
  • GPT-5.5 Instant:大模型事实对齐与幻觉抑制的工程化实践
  • 2026年取暖炉具加工厂推荐:煤炉/柴炉/电炉/回风炉/电暖炉家用商用全覆盖 - 海棠依旧大
  • 2026:温江室内除异味、甲醛治理专业度横向测评,多家服务商技术与落地能力比拼,优先选择成都肃醛环保 - 专注室内空气检测治理
  • 2026.6 南宁润滑油、轴承批发商家实力排行榜(权威测评版) - 星际AI
  • 2026年承插法兰、承插弯头、承插三通、承插隔膜阀厂家推荐榜:承插焊不锈钢球阀/锻钢止回阀/高压球阀/管件品牌优选 - 品牌发掘
  • 2026年6月邢台黄金回收行情解读与商家筛选技巧 - 余生黄金回收
  • Steam创意工坊下载神器WorkshopDL:无需Steam账号轻松获取游戏模组
  • Python性能验证利器:timeit模块原理与工程实践
  • Mac窗口置顶终极指南:Topit如何3分钟提升你的工作效率
  • 2026年沈阳建筑器材租赁服务商推荐:脚手架/钢管/围挡/钢支撑租赁 - 海棠依旧大
  • [论文学习]LLM 代理长程记忆安全调查:迈向记忆主权(Mnemonic Sovereignty)-攻击、防御与全生命週期治理框架
  • 从BabyRSA到RSA安全:小素数攻击原理与实战防御
  • 如何用ImageSearch实现本地千万级图片秒级搜索:告别找不到图片的烦恼
  • 本体层如何解决“当前用户上下文“的难题?告别机机接口改造
  • NBTExplorer完整攻略:Minecraft数据编辑神器的10个必学技巧
  • 样本量设计实战指南:从效应量到落地的七道关卡
  • MySQL连接被拒:host not allowed错误解析与解决方案
  • 2026海牙认证MBA硕士机构合规排行:五家主流项目全维度盘点 - 互联网科技品牌测评
  • 论文写作AI用哪个模型?4款学术大模型推荐 - 掌桥科研-AI论文写作
  • 慢查询拖垮整个系统?这套SQL优化方法让查询提速10倍
  • 2026最新东营黄金回收价格一览表 - 余生黄金回收