尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

all-in-rag 实战:向量数据库选型与 FAISS 本地向量存储实现指南

all-in-rag 实战:向量数据库选型与 FAISS 本地向量存储实现指南 all-in-rag 实战向量数据库选型与 FAISS 本地向量存储实现指南【免费下载链接】all-in-rag大模型应用开发实战一RAG 技术全栈指南在线阅读地址https://datawhalechina.github.io/all-in-rag/项目地址: https://gitcode.com/datawhalechina/all-in-rag导读本文是 Datawhale《大模型应用开发实战一RAG 技术全栈指南》中「索引构建」章节的深入讲解围绕向量数据库在 RAG 流水线中的核心作用展开。你将理解向量数据库与传统关系型数据库的本质差异、HNSW/IVF 等 ANN 索引的底层原理、主流向量数据库的选型思路并通过仓库中可运行的源码示例完整掌握基于 LangChain FAISS 的「创建 → 保存 → 加载 → 查询」本地向量存储流程以及 LlamaIndex 的 JSON 持久化方案为后续构建生产级 RAG 系统打下坚实基础。一、向量数据库的作用在上一节向量嵌入中我们已经学会了使用嵌入模型将文本、图像等非结构化数据转换为高维向量。这些向量是 RAG 系统进行语义理解的基础。然而当向量数量从几百个增长到数百万甚至数十亿时一个核心问题随之而来如何快速、准确地从海量向量中找到与用户查询最相似的那几个1.1 向量数据库主要功能向量数据库的核心价值在于其高效处理海量高维向量的能力。其主要功能可以概括为以下几点高效的相似性搜索这是向量数据库最重要的功能。它利用专门的索引技术如 HNSW、IVF能够在数十亿级别的向量中实现毫秒级的近似最近邻ANN查询快速找到与给定查询最相似的数据。高维数据存储与管理专门为存储高维向量通常维度成百上千而优化支持对向量数据进行增、删、改、查等基本操作。丰富的查询能力除了基本的相似性搜索还支持按标量字段过滤查询例如在搜索相似图片的同时指定年份 2023、范围查询和聚类分析等满足复杂业务需求。可扩展与高可用现代向量数据库通常采用分布式架构具备良好的水平扩展能力和容错性能够通过增加节点来应对数据量的增长并确保服务的稳定可靠。数据与模型生态集成与主流的 AI 框架如 LangChain、LlamaIndex和机器学习工作流无缝集成简化了从模型训练到向量检索的应用开发流程。1.2 向量数据库 vs 传统数据库传统的数据库如 MySQL擅长处理结构化数据的精确匹配查询例如WHERE age 25但它们并非为处理高维向量的相似性搜索而设计的。在庞大的向量集合中进行暴力、线性的相似度计算其计算成本和时间延迟无法接受。向量数据库Vector Database很好地解决了这一问题它是一种专门设计用于高效存储、管理和查询高维向量的数据库系统。在 RAG 流程中它扮演着「知识库」的角色是连接数据与大语言模型的关键桥梁。向量数据库与传统数据库的主要差异如下维度向量数据库传统数据库 (RDBMS)核心数据类型高维向量 (Embeddings)结构化数据 (文本、数字、日期)查询方式相似性搜索(ANN)精确匹配索引机制HNSW, IVF, LSH 等 ANN 索引B-Tree, Hash Index主要应用场景AI 应用、RAG、推荐系统、图像/语音识别业务系统 (ERP, CRM)、金融交易、数据报表数据规模轻松应对千亿级向量通常在千万到亿级行数据更大规模需复杂分库分表性能特点高维数据检索性能极高计算密集型结构化数据查询快高维数据查询性能呈指数级下降一致性通常为最终一致性强一致性 (ACID 事务)向量数据库和传统数据库并非相互替代的关系而是互补关系。在构建现代 AI 应用时通常会将两者结合使用利用传统数据库存储业务元数据和结构化信息而向量数据库则专门负责处理和检索由 AI 模型产生的海量向量数据。二、工作原理向量数据库的核心是高效处理高维向量的相似性搜索。向量是一组有序的数值可以表示文本、图像、音频等复杂数据的特征或属性。在 RAG 系统中向量一般通过嵌入模型将原始数据转换为高维向量表示比如上一节的图文示例。向量数据库通常采用四层架构通过存储层、索引层、查询层和服务层的协同工作来实现高效相似性搜索存储层负责存储向量数据和元数据优化存储效率并支持分布式存储索引层维护索引算法HNSW、LSH、PQ 等负责索引的创建与优化并支持索引调整查询层处理查询请求支持混合查询并实现查询优化服务层管理客户端连接提供监控和日志能力并实现安全管理。在上述架构中索引层是决定检索性能的关键。主要的技术手段包括基于树的方法如 Annoy 使用的随机投影树通过树形结构实现对数复杂度的搜索基于哈希的方法如 LSH局部敏感哈希通过哈希函数将相似向量映射到同一「桶」基于图的方法如 HNSW分层可导航小世界图通过多层邻近图结构实现快速搜索基于量化的方法如 Faiss 的 IVF 和 PQ通过聚类和量化压缩向量。关于不同索引类型FLAT、IVF 系列、HNSW、DiskANN的详细原理、优缺点对比与选型策略可继续阅读本仓库的第四节 Milvus 介绍及多模态检索实践与第五节 索引优化。三、主流向量数据库介绍目前市面上的向量数据库产品丰富多样可以从「开源/商业」与「专用向量数据库/支持向量搜索的通用数据库」两个维度进行归类。下面这张分类图清晰地展示了主流产品在整个生态中的位置当前主流的向量数据库产品包括Pinecone一款完全托管的向量数据库服务采用 Serverless 架构设计。它提供存储计算分离、自动扩展和负载均衡等企业级特性并保证 99.95% 的 SLA。Pinecone 支持多种语言 SDK提供极高可用性和低延迟搜索100ms特别适合企业级生产环境、高并发场景和大规模部署。Milvus一款开源的分布式向量数据库采用分布式架构设计支持 GPU 加速和多种索引算法。它能够处理亿级向量检索提供高性能 GPU 加速和完善的生态系统。Milvus 特别适合大规模部署、高性能要求的场景以及需要自定义开发的开源项目。Qdrant一款高性能的开源向量数据库采用 Rust 开发支持二进制量化技术。它提供多种索引策略和向量混合搜索功能能够实现极高的性能RPS4000和低延迟搜索。Qdrant 特别适合性能敏感应用、高并发场景以及中小规模部署。Weaviate一款支持 GraphQL 的 AI 集成向量数据库提供 20 AI 模块和多模态支持。它采用 GraphQL API 设计支持 RAG 优化特别适合 AI 开发、多模态处理和快速开发场景。Weaviate 具有活跃的社区支持和易于集成的特点。Chroma一款轻量级的开源向量数据库采用本地优先设计无依赖。它提供零配置安装、本地运行和低资源消耗等特性特别适合原型开发、教育培训和小规模应用。Chroma 的部署简单适合快速原型开发。选择建议新手入门/小型项目从ChromaDB或FAISS开始是最佳选择。它们与 LangChain/LlamaIndex 紧密集成几行代码就能运行且能满足基本的存储和检索需求。生产环境/大规模应用当数据量超过百万级或需要高并发、实时更新、复杂元数据过滤时应考虑更专业的解决方案如Milvus、Weaviate或云服务Pinecone。四、本地向量存储以 FAISS 为例FAISSFacebook AI Similarity Search是一个由 Facebook AI Research 开发的高性能库专门用于高效的相似性搜索和密集向量聚类。当与 LangChain 结合使用时它可以作为一个强大的本地向量存储方案非常适合快速原型设计和中小型应用。与 ChromaDB 等数据库不同FAISS 本质上是一个算法库它将索引直接保存为本地文件一个.faiss索引文件和一个.pkl映射文件而非运行一个数据库服务。这种方式轻量且高效。4.1 环境准备在开始之前请确保已安装所有必需的库。本仓库根目录下的 code/requirements.txt 已经声明了全部依赖其中向量存储相关的关键依赖包括langchain0.3.26、langchain-community0.3.27LangChain 生态提供FAISS向量存储封装langchain-huggingface0.3.1提供HuggingFaceEmbeddings等本地嵌入模型接入faiss-cpu1.7.0FAISS 算法库本体chromadb0.4.0Chroma 向量数据库pymilvus2.5.11、pymilvus.model0.3.2Milvus 客户端用于后续章节sentence-transformers3.0.0HuggingFace 嵌入模型底层依赖。pip install -r code/requirements.txt当前requirements.txt安装的faiss-cpu是 CPU 版本。如果你的机器有 GPU可以安装faiss-gpu以获得更好的性能。4.2 基础示例FAISS下面的代码演示了使用 LangChain 和 FAISS 完成一个完整的「创建 → 保存 → 加载 → 查询」流程。该示例与仓库中的 code/C3/02_langchain_faiss.py 完全一致可直接运行验证。from langchain_community.vectorstores import FAISS from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_core.documents import Document # 1. 示例文本和嵌入模型 texts [ 张三是法外狂徒, FAISS是一个用于高效相似性搜索和密集向量聚类的库。, LangChain是一个用于开发由语言模型驱动的应用程序的框架。 ] docs [Document(page_contentt) for t in texts] embeddings HuggingFaceEmbeddings(model_nameBAAI/bge-small-zh-v1.5) # 2. 创建向量存储并保存到本地 vectorstore FAISS.from_documents(docs, embeddings) local_faiss_path ./faiss_index_store vectorstore.save_local(local_faiss_path) print(fFAISS index has been saved to {local_faiss_path}) # 3. 加载索引并执行查询 # 加载时需指定相同的嵌入模型并允许反序列化 loaded_vectorstore FAISS.load_local( local_faiss_path, embeddings, allow_dangerous_deserializationTrue ) # 相似性搜索 query FAISS是做什么的 results loaded_vectorstore.similarity_search(query, k1) print(f\n查询: {query}) print(相似度最高的文档:) for doc in results: print(f- {doc.page_content})运行结果与解读当你运行上述脚本时会看到类似以下的输出FAISS index has been saved to ./faiss_index_store 查询: FAISS是做什么的 相似度最高的文档: - FAISS是一个用于高效相似性搜索和密集向量聚类的库。可见虽然查询语句「FAISS是做什么的」与文档原文「FAISS是一个用于高效相似性搜索和密集向量聚类的库。」用词并不完全一致但 FAISS 依然通过语义相似度准确召回了目标文档这正是向量检索区别于关键词匹配的核心价值。关键细节说明嵌入模型一致性load_local时必须传入与创建索引时完全相同的嵌入模型BAAI/bge-small-zh-v1.5。因为加载后的查询向量需要用同一模型编码才能在相同的向量空间中进行相似度比较。allow_dangerous_deserializationTrueFAISS 的本地文件包含序列化的docstore文档原文与元数据LangChain 出于安全考虑默认禁止反序列化此处需要显式开启。务必仅加载可信来源的索引文件不要加载来路不明的.pkl文件以免触发反序列化漏洞。4.3 索引创建实现细节LangChain 源码调用链通过深入 LangChain 源码可以发现索引创建是一个分层、解耦的过程主要涉及以下几个方法的嵌套调用from_documents封装层这是我们直接调用的方法。它的职责很简单从输入的Document对象列表中提取出纯文本内容page_content和元数据metadata。然后它将这些提取出的信息传递给核心的from_texts方法。from_texts向量化入口这个方法是面向用户的入口。它接收文本列表并执行关键的第一步调用embedding.embed_documents(texts)将所有文本批量转换为向量。完成向量化后它并不直接处理索引构建而是将生成的向量和其他所有信息文本、元数据等传递给一个内部的辅助方法__from。__from构建索引框架一个内部方法负责搭建 FAISS 向量存储的「空框架」。它会根据指定的距离策略默认为 L2 欧氏距离初始化一个空的 FAISS 索引结构如faiss.IndexFlatL2。同时它也准备好了用于存储文档原文的docstore和用于连接 FAISS 索引与文档的index_to_docstore_id映射。最后它调用另一个内部方法__add来完成数据的填充。__add填充数据真正执行数据添加操作的核心。它接收到向量、文本和元数据后执行以下关键操作添加向量将向量列表转换为 FAISS 需要的numpy数组并调用self.index.add(vector)将其批量添加到 FAISS 索引中。存储文档将文本和元数据打包成Document对象存入docstore。建立映射更新index_to_docstore_id字典建立起 FAISS 内部的整数 ID如 0, 1, 2...到我们文档唯一 ID 的映射关系。理解这条调用链的意义在于当你需要定制索引构建流程时例如更换距离度量、批量增量添加文档、或自定义文档 ID 映射你就知道应该从哪一层切入。例如生产环境中「先建索引框架、再分批add文档」的需求就可以直接基于__from与__add的思路进行扩展。4.4 生产环境中的 FAISS 封装实践FAISS 的用法不止于演示脚本。在仓库第八章的生产级 RAG 项目实战中code/C8/rag_modules/index_construction.py 就将 FAISS 封装成了可复用的VectorIndexBuilder类通过build_vector_index(chunks)方法调用FAISS.from_documents完成索引构建并通过load_local实现索引的持久化加载。这种「构建 → 保存 → 加载」的分层设计与本文 4.2 节的示例一脉相承但补充了日志记录、路径管理与异常处理等生产要素是学习如何将 FAISS 从脚本升级到工程模块的绝佳范例。五、LlamaIndex 的向量存储JSON 持久化实践除了 LangChain FAISS本教程的另一大框架是 LlamaIndex。LlamaIndex 的VectorStoreIndex默认使用内存存储但其StorageContext支持将索引以透明可读的 JSON 格式持久化到本地磁盘这一点与 FAISS 的二进制索引文件形成鲜明对比也便于开发者直接检查索引内容。仓库中的 code/C3/03_llamaindex_vector.py 演示了完整的创建与持久化流程from llama_index.core import VectorStoreIndex, Document, Settings from llama_index.embeddings.huggingface import HuggingFaceEmbedding # 1. 配置全局嵌入模型 Settings.embed_model HuggingFaceEmbedding(BAAI/bge-small-zh-v1.5) # 2. 创建示例文档 texts [ 张三是法外狂徒, LlamaIndex是一个用于构建和查询私有或领域特定数据的框架。, 它提供了数据连接、索引和查询接口等工具。 ] docs [Document(textt) for t in texts] # 3. 创建索引并持久化到本地 index VectorStoreIndex.from_documents(docs) persist_path ./llamaindex_index_store index.storage_context.persist(persist_dirpersist_path) print(fLlamaIndex 索引已保存至: {persist_path})运行后会生成llamaindex_index_store目录其中以 JSON 文件形式存储了向量default__vector_store.json、文档节点docstore.json与索引元数据index_store.json。由于 JSON 是明文格式你可以直接打开文件查看向量数值与文本的对应关系这在调试阶段非常有用——这也是 LlamaIndex「默认透明可读」设计理念的体现。5.1 加载与相似性搜索对应地加载持久化的索引并执行相似性搜索只需要使用StorageContext.from_defaults(persist_dir...)恢复存储上下文再通过load_index_from_storage重建索引from llama_index.core import StorageContext, load_index_from_storage # 加载持久化的存储上下文并重建索引 storage_context StorageContext.from_defaults(persist_dir./llamaindex_index_store) index load_index_from_storage(storage_context) # 转换为查询引擎并执行语义搜索 query_engine index.as_query_engine(similarity_top_k1) response query_engine.query(LlamaIndex 是用来做什么的) print(response)这里需要注意重建索引时Settings.embed_model必须与持久化时保持一致同样是BAAI/bge-small-zh-v1.5否则查询向量的向量空间与库内向量不一致检索结果将失去意义。这与 4.2 节 FAISS 的「嵌入模型一致性」原则是同一个道理。六、从本地走向生产Milvus 分布式向量数据库当业务数据量突破百万级、需要高并发与实时更新时FAISS/Chroma 这类本地轻量方案会逐渐触达瓶颈。此时应转向真正的分布式向量数据库。在本书的第四节 Milvus 介绍及多模态检索实践中你将看到使用 Docker Compose 一键部署 Milvus Standalone含etcd元数据存储与MinIO对象存储并基于pymilvus完成「Schema 设计 → 创建 Collection → 批量插入 → 构建 HNSW 索引 → 多模态检索」的完整流程其完整代码位于 code/C3/04_multi_milvus.py。值得注意的是04_multi_milvus.py 中创建 HNSW 索引时使用了params{M: 16, efConstruction: 256}检索时设置params{ef: 128}——这三个参数分别控制着图节点的最大连接数、索引构建时的搜索宽度与查询时的遍历深度是决定「召回率 vs 延迟」权衡的核心旋钮。理解这些参数是后续阅读第五节 索引优化中句子窗口检索、结构化索引等内容的前提。练习与延伸LlamaIndex 持久化观察运行 03_llamaindex_vector.py查看生成的llamaindex_index_store目录下 JSON 文件的内容体会 LlamaIndex 默认「透明可读」的存储设计。LlamaIndex 加载与检索新建一个代码文件参考 5.1 节示例实现对上述 JSON 数据的加载和相似性搜索并尝试更换查询语句观察召回结果的变化。FAISS 查询深度调参修改 02_langchain_faiss.py 中的k值如k2、k3观察返回的相似度文档排序理解 Top-K 召回的含义进一步可尝试在FAISS.from_documents中通过distance_strategy指定COSINE或MAX_INNER_PRODUCT对比不同度量方式对中文语义检索效果的影响。进阶阅读完成上述练习后建议继续阅读第四节 Milvus 介绍及多模态检索实践并运行 04_multi_milvus.py需要先启动 Milvus 服务体验从本地单机向量库到分布式向量库的完整升级路径。【免费下载链接】all-in-rag大模型应用开发实战一RAG 技术全栈指南在线阅读地址https://datawhalechina.github.io/all-in-rag/项目地址: https://gitcode.com/datawhalechina/all-in-rag创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表