RAG向量知识库搭建教程(零基础通用版)

什么是RAG知识库

RAG(Retrieval-Augmented Generation)= 检索增强生成

简单来说:

  • 把你的文档(PDF、TXT、Word等)切成小块
  • 每一块转换成一个384维的数字向量
  • 当你提问时,问题也转成向量
  • 找到最相似的文档块返回给你

核心优势

  • 语义理解:搜"会话切换"能找到"session switch"
  • 模糊查询:不需要记住精确关键词
  • 跨语言:中文问题能找到英文文档,反之亦然
  • 概念匹配:理解相关概念之间的联系

技术原理

复制代码
【离线构建阶段】
文档 → 提取文本 → 分块(500字符) → 向量编码(384维) → 存储到索引文件

【在线查询阶段】
用户问题 → 向量编码 → 计算相似度 → 返回Top3最相关文档

相似度计算:余弦相似度

复制代码
similarity = (向量A · 向量B) / (||向量A|| × ||向量B||)
范围:0.0 ~ 1.0,越接近1越相似

准备工作

硬件要求

最低配置

  • CPU:任意(构建会慢一些)
  • 内存:8GB+
  • 硬盘:文档大小 × 3(例如10GB文档需要30GB空间)

推荐配置

  • CPU:多核处理器
  • 内存:16GB+
  • GPU:可选(加速构建,但不是必须)

软件要求

  • Python 3.8 或更高版本
  • 文本编辑器(记事本、VSCode等)

目录结构示例

复制代码
我的知识库/
├── 文档1/
│   ├── file1.pdf
│   ├── file2.txt
│   └── file3.docx
├── 文档2/
│   └── ...
└── (构建脚本将放在这里)

支持的文档格式

  • ✅ PDF(推荐)
  • ✅ TXT
  • ✅ Word(.docx)
  • ⚠️ 扫描版PDF需要先OCR识别文字

第一步:整理文档

1.1 检查文档格式

PDF文档

  • 原生PDF(可复制文字):✅ 直接使用
  • 扫描版PDF(图片):❌ 需要先OCR识别

检查方法

  1. 用PDF阅读器打开
  2. 尝试复制一段文字
  3. 如果能复制,说明是原生PDF
  4. 如果不能复制,需要OCR处理

TXT文档

  • 确保是UTF-8编码
  • 用记事本打开 → 另存为 → 选择"UTF-8"编码

1.2 OCR处理(如果需要)

如果有扫描版PDF,推荐工具:


第二步:安装依赖

2.1 安装Python包

打开命令行(Windows按Win+R,输入cmd),运行:

bash 复制代码
pip install sentence-transformers numpy PyPDF2 python-docx

说明

  • sentence-transformers:向量编码模型
  • numpy:数学计算库
  • PyPDF2:PDF文本提取
  • python-docx:Word文档提取

2.2 验证安装

bash 复制代码
python -c "import sentence_transformers; print('安装成功')"

如果显示"安装成功",说明依赖已就绪。

2.3 模型自动下载

第一次运行时,会自动下载模型(约120MB):

  • 模型名称:paraphrase-multilingual-MiniLM-L12-v2
  • 下载位置:~/.cache/huggingface/
  • 只需下载一次,以后所有项目都能用

如果下载很慢

bash 复制代码
# 使用国内镜像
set HF_ENDPOINT=https://hf-mirror.com

第三步:构建索引

3.1 创建构建脚本

在你的知识库根目录创建文件 build_rag.py

python 复制代码
#!/usr/bin/env python3
"""通用RAG索引构建工具 - 支持PDF/TXT/DOCX"""
import pickle
import numpy as np
from pathlib import Path
from sentence_transformers import SentenceTransformer

# ============ 配置区域 ============
ROOT = Path(__file__).parent
EXCLUDE_DIRS = {'构建脚本', '__pycache__', '.git'}  # 排除的目录
CHUNK_SIZE = 500      # 每块文本大小(字符)
OVERLAP = 50          # 重叠大小(字符)
# =================================

print("=" * 60)
print("RAG索引构建工具")
print("=" * 60)

# 加载模型
print("\n[1/5] 加载向量编码模型...")
model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2', device='cpu')
print("✓ 模型加载完成")

# 文本提取函数
def extract_text_from_pdf(pdf_path):
    """从PDF提取文本"""
    try:
        from PyPDF2 import PdfReader
        reader = PdfReader(pdf_path)
        text = ""
        for page in reader.pages:
            text += page.extract_text() + "\n"
        return text
    except Exception as e:
        print(f"  ✗ PDF提取失败: {pdf_path.name} - {e}")
        return ""

def extract_text_from_docx(docx_path):
    """从Word文档提取文本"""
    try:
        from docx import Document
        doc = Document(docx_path)
        text = "\n".join([para.text for para in doc.paragraphs])
        return text
    except Exception as e:
        print(f"  ✗ Word提取失败: {docx_path.name} - {e}")
        return ""

def extract_text_from_txt(txt_path):
    """从TXT提取文本"""
    try:
        return txt_path.read_text(encoding='utf-8')
    except UnicodeDecodeError:
        try:
            return txt_path.read_text(encoding='gbk')
        except Exception as e:
            print(f"  ✗ TXT读取失败: {txt_path.name} - {e}")
            return ""

# 扫描文档
print("\n[2/5] 扫描文档...")
files = []
for pattern in ['*.pdf', '*.PDF', '*.txt', '*.TXT', '*.docx', '*.DOCX']:
    for file in ROOT.rglob(pattern):
        if any(ex in file.parts for ex in EXCLUDE_DIRS):
            continue
        if file.stat().st_size < 100:  # 跳过太小的文件
            continue
        files.append(file)

print(f"✓ 找到 {len(files)} 个文档")

if len(files) == 0:
    print("✗ 错误:没有找到文档,请检查目录")
    exit(1)

# 文本分块函数
def chunk_text(text, chunk_size=500, overlap=50):
    """将长文本切分成小块"""
    if len(text) < chunk_size:
        return [text] if text.strip() else []

    chunks = []
    start = 0
    while start < len(text):
        end = min(start + chunk_size, len(text))
        chunk = text[start:end].strip()
        if chunk:
            chunks.append(chunk)
        if end == len(text):
            break
        start = end - overlap
    return chunks

# 处理文件并分块
print("\n[3/5] 提取文本并分块...")
all_chunks = []
all_sources = []

for i, file in enumerate(files, 1):
    # 根据文件类型提取文本
    if file.suffix.lower() == '.pdf':
        text = extract_text_from_pdf(file)
    elif file.suffix.lower() == '.docx':
        text = extract_text_from_docx(file)
    else:  # .txt
        text = extract_text_from_txt(file)

    if not text.strip():
        continue

    # 分块
    chunks = chunk_text(text, CHUNK_SIZE, OVERLAP)
    relative_path = str(file.relative_to(ROOT))

    for chunk in chunks:
        all_chunks.append(chunk)
        all_sources.append(relative_path)

    if i % 50 == 0:
        print(f"  进度: {i}/{len(files)} 文件")

print(f"✓ 总共 {len(all_chunks)} 个文本块")

# 生成向量
print("\n[4/5] 生成向量(这可能需要几分钟)...")
embeddings = model.encode(all_chunks,
                         convert_to_tensor=False,
                         show_progress_bar=True,
                         batch_size=32)

print(f"✓ 向量维度: {embeddings.shape}")

# 保存索引
print("\n[5/5] 保存索引文件...")
index_data = {
    'embeddings': embeddings,
    'chunks': all_chunks,
    'sources': all_sources
}

output_file = ROOT / 'rag_index.pkl'
with open(output_file, 'wb') as f:
    pickle.dump(index_data, f)

print(f"✓ 索引已保存: {output_file}")
print(f"✓ 文件大小: {output_file.stat().st_size / 1024 / 1024:.1f} MB")

print("\n" + "=" * 60)
print("构建完成!")
print("=" * 60)
print(f"文档数量: {len(files)}")
print(f"文本块数: {len(all_chunks)}")
print(f"索引文件: rag_index.pkl")
print("\n下一步:运行 python query_rag.py 测试查询")

3.2 运行构建

bash 复制代码
python build_rag.py

预计时间

  • 100个文件:2-5分钟
  • 1000个文件:20-40分钟
  • 取决于CPU性能和文档大小

输出文件

  • rag_index.pkl:索引文件(包含所有向量和文本)

第四步:测试查询

4.1 创建查询脚本

创建文件 query_rag.py

python 复制代码
#!/usr/bin/env python3
"""RAG查询脚本"""
import sys
import pickle
import numpy as np
from pathlib import Path
from sentence_transformers import SentenceTransformer

ROOT = Path(__file__).parent

# 加载模型
print("加载模型...")
model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2', device='cpu')

# 加载索引
print("加载索引...")
with open(ROOT / 'rag_index.pkl', 'rb') as f:
    data = pickle.load(f)

print(f"索引包含 {len(data['chunks'])} 个文本块\n")

def search(query, top_k=3):
    """检索最相关的文档"""
    # 问题向量化
    query_emb = model.encode([query], convert_to_tensor=False)[0]

    # 计算相似度
    scores = np.dot(data['embeddings'], query_emb) / (
        np.linalg.norm(data['embeddings'], axis=1) * np.linalg.norm(query_emb)
    )

    # 获取Top-K
    top_indices = np.argsort(scores)[::-1][:top_k]

    # 输出结果
    print("=" * 80)
    print(f"查询:{query}")
    print("=" * 80)

    for i, idx in enumerate(top_indices, 1):
        print(f"\n[{i}] 相似度: {scores[idx]:.3f}")
        print(f"来源: {data['sources'][idx]}")
        print(f"内容: {data['chunks'][idx][:400]}")
        print("-" * 80)

if __name__ == "__main__":
    if len(sys.argv) < 2:
        query = input("请输入查询: ")
    else:
        query = sys.argv[1]

    # 输出到文件避免编码问题
    sys.stdout = open(ROOT / 'query_result.txt', 'w', encoding='utf-8')
    search(query, top_k=3)
    sys.stdout.close()

    print("结果已保存到 query_result.txt", file=sys.__stdout__)

4.2 测试查询

bash 复制代码
python query_rag.py "你的问题"

查看结果:

bash 复制代码
# Windows
type query_result.txt

# 或用记事本打开
notepad query_result.txt

相似度判断标准

  • >0.7 = 高相关,结果可信
  • 0.5-0.7 = 中等相关,需要人工判断
  • <0.5 = 低相关,结果不可靠

第五步:配置AI使用

5.1 创建AI使用指南

创建文件 AI_AGENT_GUIDE.md,内容参考已提供的模板,确保包含:

  1. RAG检索调用方法
  2. 结果展示格式
  3. 文件链接规范
  4. 相似度判断标准

5.2 告诉AI如何使用

在与AI对话时,发送:

复制代码
我有一个知识库,位于:D:\我的知识库

请按照 AI_AGENT_GUIDE.md 的指引使用这个知识库回答我的问题。

当我询问相关问题时:
1. 运行 python query_rag.py "我的问题"
2. 读取 query_result.txt 获取RAG检索结果
3. 根据相似度和文件路径,使用Grep精确搜索关键词
4. 综合RAG和Grep的结果回答我
5. 必须提供可点击的文件链接

常见问题

Q1: 构建时提示"模型下载失败"

原因:网络问题,无法访问Hugging Face

解决

bash 复制代码
# 使用国内镜像
set HF_ENDPOINT=https://hf-mirror.com
python build_rag.py

Q2: 构建时提示"内存不足"

原因:文档太多,内存不够

解决

  • 减小batch_size(脚本中改为16或8)
  • 分批处理文档(先处理一部分)
  • 增加虚拟内存

Q3: 查询结果乱码

原因:Windows命令行编码问题

解决

  • 查询结果已自动保存到 query_result.txt
  • 用记事本或VSCode打开查看
  • 不要直接在cmd中查看

Q4: PDF提取的文本质量差

原因:扫描版PDF或图片PDF

解决

  • 使用OCR工具先识别文字
  • 推荐:Adobe Acrobat、ABBYY FineReader

Q5: 相似度都很低(<0.5)

原因

  • 问题表述和文档用词差异大
  • 文档中确实没有相关内容

解决

  • 换个问法,使用文档中的术语
  • 检查文档是否包含相关内容
  • 考虑补充相关文档

Q6: 如何更新知识库

添加新文档

  1. 把新文档放到文档目录
  2. 重新运行 python build_rag.py
  3. 会重新构建整个索引

注意

  • 目前不支持增量更新
  • 每次都是全量重建
  • 建议定期(如每月)统一更新

部署到新电脑

方法1:完整迁移(推荐)

需要复制的文件

复制代码
我的知识库/
├── rag_index.pkl              ← 必须
├── query_rag.py               ← 必须
├── AI_AGENT_GUIDE.md          ← 必须
├── 原始文档目录/              ← 可选(如果需要Grep原文)
└── 知识库搭建教程.md          ← 可选(参考文档)

新电脑操作

  1. 安装Python 3.8+
  2. 安装依赖:pip install sentence-transformers numpy
  3. 复制上述文件到任意目录(如 D:\知识库
  4. 修改 AI_AGENT_GUIDE.md 中的路径
  5. 测试:python query_rag.py "测试问题"

注意

  • 模型会在首次运行时自动下载(120MB)
  • 索引文件(.pkl)可以直接使用,无需重建
  • 如果只用RAG检索,原始文档可以不复制

方法2:仅索引文件(最小化)

如果只需要RAG检索功能,最小化部署:

复制文件

  • rag_index.pkl
  • query_rag.py

大小:通常几百MB

限制:无法使用Grep精确搜索原文


总结

你已经学会了

✅ RAG向量检索的原理

✅ 如何准备和整理文档

✅ 如何构建索引

✅ 如何查询和使用知识库

✅ 如何配置AI使用知识库

✅ 如何部署到新电脑

下一步

  1. 测试查询:多试几个问题,熟悉相似度判断
  2. 配置AI:让AI按照指南使用知识库
  3. 补充文档:发现缺失的内容及时补充
  4. 定期更新:每月重建一次索引

技术支持


参考资源

开源项目

技术文档

相关推荐
大模型真好玩1 小时前
一文详解2026年技术圈最火概念——Agent Engineering智能体工程
人工智能·langchain·agent
人工智能AI技术1 小时前
美团“问小团”同款架构:C# + ASP.NET Core 搭建本地生活 AI 搜索
人工智能·c#
无心水2 小时前
【OpenClaw:实战部署】10、OpenClaw自动化调度——打造7x24小时无人值守AI工作流
人工智能·ai·ai工作流·openclaw·openclaw·三月创作之星·养龙虾
十字花2 小时前
【CVPR 2025】SET:Spectral Enhancement for Tiny Object Detection
论文阅读·人工智能·目标检测·计算机视觉
湘美书院--湘美谈教育2 小时前
湘美谈教育精英智能实验室:当萨特遇上AI,跨存在对话
人工智能·深度学习·神经网络·机器学习·ai写作
我材不敲代码2 小时前
OpenCV 实战——图像形态学操作与边缘检测全解析:从腐蚀膨胀到 Canny 边缘检测
人工智能·opencv·计算机视觉
芯片-嵌入式2 小时前
具身智能(2):OpenExplorer下的模型量化
人工智能·深度学习·算法
DamianGao2 小时前
我用 OpenClaw 做了一个 AI 新闻早报,每天自动推送
人工智能·python·语言模型
Lab_AI2 小时前
电子实验记录本(ELN)助力熙华药业核心竞争力提升
大数据·人工智能·实验室管理·eln·药物研发·ai制药·电子实验记录本