什么是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识别
检查方法:
- 用PDF阅读器打开
- 尝试复制一段文字
- 如果能复制,说明是原生PDF
- 如果不能复制,需要OCR处理
TXT文档:
- 确保是UTF-8编码
- 用记事本打开 → 另存为 → 选择"UTF-8"编码
1.2 OCR处理(如果需要)
如果有扫描版PDF,推荐工具:
- Adobe Acrobat(识别文本功能)
- ABBYY FineReader
- 在线工具:https://www.ilovepdf.com/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,内容参考已提供的模板,确保包含:
- RAG检索调用方法
- 结果展示格式
- 文件链接规范
- 相似度判断标准
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: 如何更新知识库
添加新文档:
- 把新文档放到文档目录
- 重新运行
python build_rag.py - 会重新构建整个索引
注意:
- 目前不支持增量更新
- 每次都是全量重建
- 建议定期(如每月)统一更新
部署到新电脑
方法1:完整迁移(推荐)
需要复制的文件:
我的知识库/
├── rag_index.pkl ← 必须
├── query_rag.py ← 必须
├── AI_AGENT_GUIDE.md ← 必须
├── 原始文档目录/ ← 可选(如果需要Grep原文)
└── 知识库搭建教程.md ← 可选(参考文档)
新电脑操作:
- 安装Python 3.8+
- 安装依赖:
pip install sentence-transformers numpy - 复制上述文件到任意目录(如
D:\知识库) - 修改
AI_AGENT_GUIDE.md中的路径 - 测试:
python query_rag.py "测试问题"
注意:
- 模型会在首次运行时自动下载(120MB)
- 索引文件(.pkl)可以直接使用,无需重建
- 如果只用RAG检索,原始文档可以不复制
方法2:仅索引文件(最小化)
如果只需要RAG检索功能,最小化部署:
复制文件:
rag_index.pklquery_rag.py
大小:通常几百MB
限制:无法使用Grep精确搜索原文
总结
你已经学会了
✅ RAG向量检索的原理
✅ 如何准备和整理文档
✅ 如何构建索引
✅ 如何查询和使用知识库
✅ 如何配置AI使用知识库
✅ 如何部署到新电脑
下一步
- 测试查询:多试几个问题,熟悉相似度判断
- 配置AI:让AI按照指南使用知识库
- 补充文档:发现缺失的内容及时补充
- 定期更新:每月重建一次索引
技术支持
参考资源
开源项目
- RAG Skill示例 :https://github.com/ConardLi/rag-skill
- 完整的RAG实现参考
- 向量检索最佳实践
技术文档
- Sentence Transformers:https://www.sbert.net/
- NumPy文档:https://numpy.org/doc/