| 在这个 AI 爆发的时代,你是否想过把电脑里的几百份 PDF、Word 文档变成一个可以随时提问的“超级大脑”?而且完全免费、不用联网、数据不出本地!
今天手把手教大家利用 Ollama + DeepSeek + Python 搭建一个本地 RAG(检索增强生成)系统。不用怕代码,照着做就行!
🛠️ 第一步:准备环境 (Windows 篇) 我们需要两个核心工具:Ollama(运行 AI 的大脑)和 Python(处理文档的管家)。 1. 安装 Ollama
- 下载 :访问 Ollama 官网 下载 Windows 版本并安装。
- 验证 :安装完成后,打开电脑的“命令提示符”(按 Win+R,输入 cmd,回车)。
- 拉取模型 :在黑框里输入以下命令并回车(这一步需要联网下载模型,约 9GB):
ollama pull DeepSeek-r1:14b 💡 注意:如果不差显存(12G 以上)用 14b 效果最好;如果电脑配置一般(8G/16G 内存),建议把命令换成 ollama pull deepseek-r1:7b,速度会快很多。2. 安装 Python
- 下载 :访问 Python 官网 下载最新的 Python 3.10 或 3.11 版本。
- 关键一步 :安装界面最下方一定要勾选 “Add Python to PATH” (添加到环境变量),然后点 Install Now。
📂 第二步:搭建项目文件夹 (把资料喂给 AI) 这一步最关键!我们要把资料整理好,放在项目文件夹里。 DeepSeek 不挑食 ,你可以把文件直接散乱地堆在根目录,也可以建各种子文件夹分类存放,程序会自动把它们全部扫描出来。
1. 推荐的目录结构 在桌面上新建一个文件夹叫 MyLocalAI,建议参照下面的结构存放文件: MyLocalAI/ (你的项目主文件夹) │ ├── build_kb.py <– (等下要创建的代码文件 1,负责吃书) ├── chat_rag.py <– (等下要创建的代码文件 2,负责聊天) │ └── 📂 知识库 (你可以随便起名,把所有资料丢这里) │ ├── 📂 2024 工作总结 / │ ├── 年终汇报。pptx │ └── 部门会议纪要。docx │ ├── 📂 行业研报 / │ ├── AI 发展趋势。pdf │ └── 竞品分析。pdf │ └── 📂 财务数据 / └── Q4 预算表。xlsx
2. 支持的文件类型 你可以随意往里面丢以下格式的文件:
- PDF (.pdf):各种论文、扫描件(必须是文字版,纯图片 PDF 读不了)。
- Word (.docx):工作文档、合同、论文。
- PPT (.pptx):汇报胶片、课件。
- Excel (.xlsx):简单的表格数据(程序会转成文本读取)。
pip install numpy faiss-cpu pandas pypdf python-docx python-pptx fastembed tqdm ollama openpyxl -i https://pypi.tuna.tsinghua.edu.cn/simple
(这里使用了清华镜像源,下载速度飞快)
📝 第四步:创建代码文件 (直接复制) 我们需要在文件夹里创建两个 Python 文件。 方法: 新建一个文本文件 -> 粘贴代码 -> 保存 -> 重命名为 xxx.py。
文件 1:build_kb.py (构建知识库) 这个脚本负责扫描刚才那些文件夹,把文档“嚼碎”并存成 AI 能读懂的向量格式。
import os import gc import shutil import logging import numpy as np import faiss import pandas as pd from pypdf import PdfReader from docx import Document from pptx import Presentation from fastembed import TextEmbedding from tqdm import tqdm # ========================= # ⚙️ 配置区域 # ========================= # 设置国内镜像,解决下载慢的问题 os.environ["HF_ENDPOINT"] = "https://hf-mirror.com" logging.getLogger("pypdf").setLevel(logging.ERROR) BASE_DIR = "." # 扫描当前目录 INDEX_FILE = "kb.index" CHUNKS_FILE = "kb_chunks.npy" BATCH_SIZE = 256 # ========================= # 📄 文档加载器 # ========================= def load_pdf(path): try: reader = PdfReader(path) return "n".join([page.extract_text().strip() for page in reader.pages if page.extract_text()]) except: return ""def load_docx(path): try: doc = Document(path) return"n".join([p.text.strip() for p in doc.paragraphs if p.text.strip()]) except: return"" def load_pptx(path): try: prs = Presentation(path) out = [] for slide in prs.slides: for shape in slide.shapes: if hasattr(shape, "text_frame"): for p in shape.text_frame.paragraphs: if p.text.strip(): out.append(p.text.strip()) return "n".join(out) except: return ""def load_xlsx(path): try: return pd.read_excel(path).to_markdown(index=False) except: return"" def split_text(text, size=500, overlap=50): res = [] for i in range(0, len(text), size - overlap): chunk = text[i:i + size].strip() if len(chunk) > 20: res.append(chunk) return res def scan_files(): print("📂 正在扫描当前目录及子文件夹下的文档……") chunks = [] supported_ext = ['.pdf', '.docx', '.pptx', '.xlsx'] files = [] for root, _, filenames in os.walk(BASE_DIR): for f in filenames: if any(f.lower().endswith(ext) for ext in supported_ext): files.append(os.path.join(root, f)) print(f"📄 找到 {len(files)} 个文件,开始解析……") for file_path in tqdm(files, desc="解析文件"): content = ""ext = os.path.splitext(file_path)[1].lower() if ext =='.pdf': content = load_pdf(file_path) elif ext =='.docx': content = load_docx(file_path) elif ext =='.pptx': content = load_pptx(file_path) elif ext =='.xlsx': content = load_xlsx(file_path) if content: # 在内容前加上文件名,方便 AI 知道出处 file_name = os.path.basename(file_path) chunk_list = split_text(content) chunks.extend([f"【来源:{file_name}】n{c}"for c in chunk_list]) return chunks # ========================= # 🚀 主程序 # ========================= def main(): # 1. 扫描文件并制作切片 # 如果想强制重新扫描,删除目录下的 kb_chunks.npy 即可 if os.path.exists(CHUNKS_FILE): print("✅ 检测到旧缓存,直接加载 ( 如需更新请删除 kb_chunks.npy)……") chunks = np.load(CHUNKS_FILE, allow_pickle=True).tolist() else: chunks = scan_files() if not chunks: print("❌ 没有找到有效内容,请检查文件夹里有没有文档!") return np.save(CHUNKS_FILE, np.array(chunks, dtype=object)) print(f"📦 共生成 {len(chunks)} 个文本块,准备向量化……") # 2. 初始化模型 model_name ="BAAI/bge-small-zh-v1.5"try: embedder = TextEmbedding(model_name=model_name) except: print("⚠️ 模型加载受阻,尝试自动修复……") cache_dir = os.path.join(os.getcwd(),".fastembed") if os.path.exists(cache_dir): shutil.rmtree(cache_dir) embedder = TextEmbedding(model_name=model_name) # 3. 向量化并建立索引 print("🚀 正在将文本转化为向量 ( 如果是第一次运行,会自动下载模型,请耐心等待)……") embeddings = list(embedder.embed(chunks)) embeddings_np = np.array([list(e) for e in embeddings]).astype('float32') dim = embeddings_np.shape[1] index = faiss.IndexFlatIP(dim) index.add(embeddings_np) faiss.write_index(index, INDEX_FILE) print(f"🎉 知识库构建完成!索引文件: {INDEX_FILE}") if __name__ =="__main__": main()
文件 2:chat_rag.py (开始对话) 这个脚本负责连接 Ollama 和刚才建好的知识库。
import os import faiss import numpy as np import ollama from fastembed import TextEmbedding # ========================= # ⚙️ 配置区域 # ========================= os.environ["HF_ENDPOINT"] = "https://hf-mirror.com" INDEX_FILE = "kb.index" CHUNKS_FILE = "kb_chunks.npy" # ⚠️ 如果你安装的是 7b 模型,请把下面这行改成 "deepseek-r1:7b" OLLAMA_MODEL = "deepseek-r1:14b" EMBED_MODEL = "BAAI/bge-small-zh-v1.5" def main(): if not os.path.exists(INDEX_FILE): print("❌ 没找到知识库!请先运行 build_kb.py") return print("⏳ 正在加载大脑……") index = faiss.read_index(INDEX_FILE) chunks = np.load(CHUNKS_FILE, allow_pickle=True).tolist() embedder = TextEmbedding(model_name=EMBED_MODEL) print("n" + "="*40) print(f"🤖 本地 AI 知识库助手 ({OLLAMA_MODEL}) 已启动") print("💡 输入'exit'退出") print("="*40) while True: query = input("n🙋 你的问题:").strip() if query.lower() in ['exit', 'quit']: break if not query: continue # 1. 检索 print("🔍 正在翻阅资料……", end="r") query_vec = list(embedder.embed([query]))[0] D, I = index.search(np.array([query_vec], dtype="float32"), k=4) context = [] for idx in I[0]: if idx >= 0: context.append(chunks[idx]) # 2. 生成 prompt = f"""基于以下资料回答问题。如果资料里没有提到,就说不知道,不要瞎编。【资料】:{"n---".join(context)}【问题】:{query}"""print("n🤖 DeepSeek 回答:") try: stream = ollama.chat(model=OLLAMA_MODEL, messages=[{'role': 'user', 'content': prompt}], stream=True) for chunk in stream: print(chunk['message']['content'], end='', flush=True) print("n") except Exception as e: print(f"❌ 也就是这里出错了: {e}") print(" 请检查 Ollama 是否已在后台运行!") if __name__ =="__main__": main()
▶️ 第五步:运行起来! 1. 构建知识库 在命令窗口输入:
python build_kb.py
第一次运行会下载一个约 100MB 的向量模型(已配置国内镜像,很快)。 你会看到进度条在扫描你的文档。 显示 🎉 知识库构建完成!就成功了。
2. 开始聊天 在命令窗口输入:
python chat_rag.py
程序启动后,输入你的问题,比如:“总结一下 Q4 预算表的内容”、“2024 年工作汇报里提到了什么”。 你会发现 AI 回答的内容完全是基于你文件夹里的文件!
❓ 常见问题 (FAQ) Q: 运行 build_kb.py 报错说 SSL 连接错误? A: 这是网络问题。代码里已经加了 HF_ENDPOINT 镜像,如果还不行,尝试关掉你的科学上网工具,或者切换手机热点试试。
Q: 聊天时电脑非常卡,出字很慢? A: 你的模型可能太大了。
去 CMD 运行 ollama rm deepseek-r1:14b 删除大模型。 运行 ollama pull deepseek-r1:1.5b (这个超快,渣机也能跑)。 记得修改 chat_rag.py 里的配置代码。 Q: 我往文件夹里加了新文档,AI 怎么不知道?
A: 只要删掉文件夹里的 kb_chunks.npy 和 kb.index 这两个旧文件,重新运行 python build_kb.py 即可重建索引。
教程结束,祝大家搭建愉快! |