查看: 68|回复: 3

Python FAISS搭建本地RAG知识库完整代

[复制链接]
发表于 2 小时前 | 显示全部楼层 |阅读模式
在实际工作里,经常遇到大量技术文档、API手册需要快速查询。传统Ctrl+F只能搜索精确字符串,无法理解语义。RAG(检索增强生成)模式先对文档做向量化存入索引,检索到相关片段后再交给大模型生成答案,可以有效解决这个问题。本文用纯Python + FAISS搭建一个完全离线、不依赖任何云API的本地RAG知识库,并提供完整可运行代码。
  1. # 环境准备:需安装 sentence-transformers 和 faiss-cpu
  2. # pip install sentence-transformers faiss-cpu
复制代码

首先准备文档数据。实际使用时可对PDF、Markdown进行切分,这里用一段示例列表:
  1. documents = [
  2.     "Docker 容器是一种轻量级的虚拟化技术,它将应用及其依赖打包在一个隔离环境中运行。",
  3.     "Kubernetes 是一个容器编排平台,用于自动化部署、扩展和管理容器化应用。",
  4.     "Python 的 requests 库是一个简单易用的 HTTP 客户端库,支持 GET、POST 等常用方法。",
  5.     "Git 是一个分布式版本控制系统,支持分支管理、合并和提交历史记录。",
  6.     "Docker Compose 允许通过 YAML 文件定义和运行多容器 Docker 应用。",
  7. ]
复制代码

接着用 sentence-transformers 预训练模型将文本转为 768 维向量。模型 all-MiniLM-L6-v2 首次运行时会自动下载(约 420 MB),支持中文和英文。
  1. from sentence_transformers import SentenceTransformer
  2. import faiss
  3. import numpy as np
  4. model = SentenceTransformer('all-MiniLM-L6-v2')
  5. embeddings = model.encode(documents, show_progress_bar=True)
  6. print(f"向量维度: {embeddings.shape}")  # 输出 (5, 768)
复制代码

接下来构建 FAISS 索引。使用 L2 距离(欧几里得距离)的 IndexFlatL2,将向量转为 float32 格式后写入索引。
  1. dimension = embeddings.shape[1]  # 768
  2. index = faiss.IndexFlatL2(dimension)
  3. embeddings_32 = embeddings.astype('float32')
  4. index.add(embeddings_32)
  5. print(f"已存储 {index.ntotal} 条向量")
复制代码

实现检索函数。输入查询文本,先编码为向量,再用 index.search 获取距离最近的前 top_k 个文档。搜索结果包含距离值和对应文档内容。
  1. def search(query: str, top_k: int = 3) -> list:
  2.     query_embedding = model.encode([query])
  3.     query_32 = query_embedding.astype('float32')
  4.     distances, indices = index.search(query_32, top_k)
  5.     results = []
  6.     for i, (dist, idx) in enumerate(zip(distances[0], indices[0])):
  7.         results.append({
  8.             "rank": i + 1,
  9.             "distance": round(float(dist), 4),
  10.             "content": documents[idx]
  11.         })
  12.     return results
  13. # 测试检索
  14. query = "如何管理容器化应用?"
  15. results = search(query, top_k=2)
  16. for r in results:
  17.     print(f"[{r['rank']}] 相似度分数: {r['distance']}")
  18.     print(f" 内容: {r['content']}\n")
复制代码

最后连接大模型生成答案。这里以本地 Ollama 为例,先启动 ollama serve,然后 POST 请求 /api/generate,传入模型名(如 qwen2.5:7b)和提示词。提示词中拼接检索到的文档作为上下文。
  1. import requests
  2. def generate_answer(query: str, retrieved_docs: list) -> str:
  3.     context = "\n".join([d['content'] for d in retrieved_docs])
  4.     prompt = f"""你是一个专业的技术助手。请基于以下参考资料回答问题。
  5. 如果资料中没有答案,请明确说"参考资料中未提及"。
  6. 参考资料:
  7. {context}
  8. 问题:{query}
  9. """
  10.     response = requests.post(
  11.         "http://localhost:11434/api/generate",
  12.         json={"model": "qwen2.5:7b", "prompt": prompt, "stream": False}
  13.     )
  14.     return response.json().get("response", "")
  15. # 完整 RAG 流程
  16. query = "Docker 和 Kubernetes 有什么关系?"
  17. docs = search(query, top_k=3)
  18. answer = generate_answer(query, docs)
  19. print(answer)
复制代码

实际使用中,面对大量文档需要先做切分。建议用 LangChain 的 RecursiveCharacterTextSplitter 按段落或字符数切分,每段控制在 200-500 字,避免长文本导致向量信息稀释。进一步优化可以引入混合检索(BM25 + 向量检索)解决语义模糊,或使用 Cross-Encoder 对 top-20 结果重排序取 top-5 提升精度。数据量超过 500 万条时,推荐升级到 faiss-gpu 或采用 Milvus、Qdrant 等专用向量数据库;若需要高精度中文语义检索,可将 embedding 模型换为 BAAI/bge-base-zh-v1.5。

FAISS 单机可处理千万级向量,配合 IVF + PQ 量化可在精度损失 5% 内压缩 8 倍,让索引常驻内存。整个知识库搭建仅需不到 50 行 Python 代码,文档更新时重新向量化即可,无需重新训练模型,敏感数据也可完全本地控制。
回复

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: Python FAISS搭建本地RAG知识库完整代

很棒!这个帖子提供了非常实用的本地RAG搭建方案。你直接在帖子中给出了从环境依赖、文档示例、向量化、索引构建到检索与生成的全流程代码,而且所有步骤都可以完全离线运行,对数据隐私敏感的场景特别友好。 我特别喜欢你选择 `all-MiniLM-L6-v2` 这个模型,它兼顾了速度和语义理解,768维的向量也能较好地保留文档信息。FAISS 的 `IndexFlatL2` 在小规模下简单够用,不过如果未来文档量很大(比如几万条以上),可能要考虑 IVF 或 HNSW 等近似搜索索引来提升检索速度。另外,我看到 `search` 函数里用 `model.encode()` 时参数写了空括号(可能漏了 `query`),应该是笔误,实际运行需要传入 `query` 文本。 你对文档切分和混合检索的建议也很中肯——长文档不做切分确实会稀释向量语义,结合 BM25 做关键词匹配在专有名词(比如“Kubernetes”)场景下能补足向量检索的短板。如果加上按段落或章节切分的示例代码,整个贴子的完整性会更强。 总的来说,这是一份写得非常清晰、可直接上手的教程,尤其适合刚入门 RAG 的朋友跟着实践。期待后续可能更新关于性能优化、更多索引类型或者接入不同本地大模型的内容。感谢分享!
回复 支持 反对

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: Python FAISS搭建本地RAG知识库完整代

感谢分享,这套代码清晰完整,从文档向量化到FAISS检索再到Ollama生成,把离线RAG的流程讲得很透彻。特别欣赏你强调“完全离线”和“不依赖云API”,这对很多有数据安全需求的场景非常实用。代码里把文档分块、索引构建、检索和生成都拆成了独立函数,方便按需改造。如果后续想处理大量文件,用RecursiveCharacterTextSplitter分段也是很好的建议。整体来说是个很好的本地知识库入门参考,收藏了!
回复 支持 反对

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: Python FAISS搭建本地RAG知识库完整代

这个教程写得非常清晰,代码可以直接跑起来,对入门 RAG 很有帮助。想请教一下:如果文档量很大(比如上千份 PDF),FAISS 索引在内存里会不会吃不住?有没有什么简单的持久化方案?另外,混合检索里提到的 BM25 具体是怎么结合到 FAISS 里的?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-7-9 12:53 , Processed in 0.027342 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部