news 2026/6/10 8:08:19

Python 本地 RAG 实战 | Ollama+ChromaDB 实现 PDF 离线智能问答

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python 本地 RAG 实战 | Ollama+ChromaDB 实现 PDF 离线智能问答

标签:Python、RAG、大模型、Ollama、ChromaDB、本地知识库


一、项目简介

检索增强生成(RAG)是当前大模型落地应用最主流的方案。本项目全程本地离线运行,无需调用任何云端 API,不受 Token 额度限制,同时能有效保护本地文档隐私。

本文以 PDF 简历 作为实战案例,完整落地标准 RAG 全流程:PDF文档读取 → 文本切片 → 本地Embedding向量化 → 向量库持久化存储 → 相似度检索 → 本地大模型生成答案

技术栈

  • PDF 解析:pdfplumber,解决传统 PDF 库末尾文字丢失、排版错乱问题

  • 文本处理:固定长度切片 + 重叠分片,保证语义完整性

  • 向量数据库:ChromaDB,轻量易上手、支持数据持久化

  • 向量模型:Qwen3-Embedding-0.6B(通义千问嵌入模型,Ollama 本地部署)

  • 对话大模型:qwen:7b(通义千问 7B 开源模型)

  • 环境管理:python-dotenv,统一管理环境变量

核心功能

  1. 逐页解析 PDF,构建文本块与页码映射,支持内容溯源

  2. 自定义切片大小与重叠长度,避免长文本语义割裂

  3. 向量库自动检测,已存在则直接加载,防止重复入库

  4. 交互式循环问答,模型仅依据文档内容作答,不编造信息

  5. 全流程离线运行,一次部署可长期使用


二、环境部署

1. 安装 Python 依赖库

打开终端,执行以下命令安装项目所需第三方库:

pip install pdfplumber chromadb ollama python-dotenv

2. 安装 Ollama

Ollama 跨平台支持 Windows / Mac / Linux,可一键本地运行各类大模型、向量模型。

  1. 官网下载对应系统安装包:https://ollama.com/

  2. 安装完成后,终端执行命令验证是否安装成功:

ollama --version

3. 拉取本地模型

国内网络环境建议延长超时时间,避免大模型下载中断:

# Mac/Linux 临时设置超时时间(网络不稳定必加)export OLLAMA_TIMEOUT=600# 拉取通义千问 Embedding 向量模型 ollama pull dengcao/Qwen3-Embedding-0.6B:Q8_0 # 拉取通义千问 7B 对话大模型 ollama pull qwen:7b

4. 项目目录结构

将 PDF 文件、代码、环境文件放在同一目录下,参考结构:

./ ├── xxx.pdf # 待解析的PDF知识库文档 ├── .env # 环境变量文件(本项目可置空) └── rag_pdf_qa.py # 项目主程序

三、完整可运行代码

代码附带详细注释,逻辑分层清晰,直接复制即可使用:

# ========================== # 一、全局配置项 # 所有可修改的参数统一放在这里,便于维护 # ========================== PDF_PATH = "./xxx.pdf" # 你的PDF文件路径 CHROMA_PATH = "./chroma_db" # 向量数据库存储目录 EMBED_MODEL = "dengcao/Qwen3-Embedding-0.6B:Q8_0" # Ollama向量模型 LLM_MODEL = "qwen:7b" # 对话大模型 CHUNK_SIZE = 300 # 文本切片长度 CHUNK_OVERLAP = 30 # 切片重叠长度,保证语义完整 TOP_K = 3 # 检索返回最相似的3条片段 # ========================== # 二、导入依赖库 # ========================== import pdfplumber # PDF解析工具 import os # 文件/目录操作 import pickle # 持久化存储页码映射 import chromadb # 轻量向量数据库 import ollama # 本地大模型调用接口 from dotenv import load_dotenv # 环境变量加载 # 加载.env环境变量,支持本地配置 load_dotenv("./.env", override=True) # ========================== # 三、PDF文档解析工具类 # 功能:读取PDF,按页提取文本 + 页码 # ========================== class PDFParser: @staticmethod def extract_pages(pdf_path): """ 从PDF文件中逐页提取文本 :param pdf_path: PDF路径 :return: 每页文本列表 + 对应页码列表 """ page_texts = [] page_nums = [] # 打开PDF并逐页读取 with pdfplumber.open(pdf_path) as pdf: for page_num, page in enumerate(pdf.pages, start=1): text = page.extract_text() or "" # 提取文本,空则设为"" page_texts.append(text.strip()) # 去除多余空格 page_nums.append(page_num) # 记录页码 return page_texts, page_nums # ========================== # 四、文本向量化工具类 # 功能:调用Ollama生成文本向量 # ========================== class Embedding: @staticmethod def get_embeddings(text_list): """ 批量生成文本向量 :param text_list: 文本列表 :return: 向量列表 """ resp = ollama.embed( model=EMBED_MODEL, input=text_list ) return resp.embeddings # ========================== # 五、向量数据库管理类 # 功能:切片、入库、检索、持久化、页码映射 # ========================== class VectorDB: def __init__(self): # 初始化Chroma客户端(持久化存储) self.client = chromadb.PersistentClient(CHROMA_PATH) self.collection = self.client.get_or_create_collection("knowledge_base") def build_db(self, page_texts, page_nums): """ 构建向量库:切片 → 向量化 → 入库 如果库已存在,则直接加载,不重复构建 """ # 尝试加载已存在的向量库 try: with open(f"{CHROMA_PATH}/chunk_page_mapping.pkl", "rb") as f: print("✅ 向量库已存在,直接加载") return pickle.load(f) except: print("📦 未检测到向量库,开始切片、向量化、入库...") all_chunks = [] chunk_page_map = {} # 遍历每页文本进行切片 for text, page in zip(page_texts, page_nums): text = text.strip() if not text: continue # 固定长度切片(带重叠) start = 0 text_len = len(text) while start < text_len: chunk = text[start:start + CHUNK_SIZE].strip() if chunk: all_chunks.append(chunk) chunk_page_map[chunk] = page # 记录文本块对应页码 start += CHUNK_SIZE - CHUNK_OVERLAP # 批量生成向量 vectors = Embedding.get_embeddings(all_chunks) # 存入向量库 self.collection.add( ids=[str(i) for i in range(len(all_chunks))], documents=all_chunks, embeddings=vectors ) # 保存文本块-页码映射文件 os.makedirs(CHROMA_PATH, exist_ok=True) with open(f"{CHROMA_PATH}/chunk_page_mapping.pkl", "wb") as f: pickle.dump(chunk_page_map, f) print(f"✅ 向量库构建完成,总文本块数量:{len(all_chunks)}") return chunk_page_map def search(self, query): """ 根据用户问题检索相似文本 :param query: 用户问题 :return: 匹配到的文档片段 """ # 问题向量化 q_vector = Embedding.get_embeddings([query]) # 向量相似度检索 res = self.collection.query(query_embeddings=q_vector, n_results=TOP_K) return res["documents"][0] # ========================== # 六、RAG问答引擎 # 功能:检索 + 构造Prompt + 调用大模型生成答案 # ========================== class RAG: def __init__(self): self.db = VectorDB() # 初始化向量库 def ask(self, question): """ 对外提供问答接口 :param question: 用户问题 :return: 模型回答 + 参考片段 """ # 1. 检索相关文档 docs = self.db.search(question) # 2. 拼接上下文 context = "\n".join(docs) # 3. 构造提示词(严格约束模型不编造) prompt = f""" 你是专业的简历问答助手,必须严格依据提供的简历内容回答,不允许编造信息。 回答简洁、准确、有条理。 简历内容: {context} 用户问题:{question} 助手回答: """ # 4. 调用本地大模型生成回答 resp = ollama.chat( model=LLM_MODEL, messages=[{"role": "user", "content": prompt}] ) return resp["message"]["content"], docs # ========================== # 七、主程序入口 # 流程:解析PDF → 构建向量库 → 启动循环问答 # ========================== if __name__ == "__main__": print("=" * 50) print("🔥 PDF 本地 RAG 智能问答系统(离线版)") print("=" * 50) # 1. 解析PDF文档 parser = PDFParser() texts, nums = parser.extract_pages(PDF_PATH) # 2. 初始化/加载向量库 db = VectorDB() db.build_db(texts, nums) # 3. 启动RAG问答引擎 rag = RAG() # 4. 循环交互问答 while True: query = input("\n🗣 请输入你的问题(输入 q 退出):") if query.lower() == "q": print("👋 感谢使用,再见!") break if not query.strip(): print("⚠️ 请输入有效问题!") continue # 获取回答 answer, docs = rag.ask(query) # 输出结果 print("\n🤖 回答:", answer) print("\n📄 参考片段:") for i, d in enumerate(docs, 1): print(f"{i}. {d[:80]}...")

四、运行说明

  1. 将待解析的 PDF 文件重命名为 xxx.pdf,和代码放在同一目录;

  2. 确保 Ollama 服务正常运行,对应模型已成功拉取;

  3. 直接执行 Python 脚本,首次运行会自动完成 PDF 解析、文本切片、向量化与入库;

  4. 程序启动后进入交互模式,输入问题即可问答,输入q退出程序;

  5. 再次运行脚本会自动加载已有向量库,不会重复处理文档。


五、常见问题解决

1. Ollama 拉取模型提示context deadline exceeded

网络不稳定导致超时,执行命令延长超时时间后重新拉取:

export OLLAMA_TIMEOUT=600 ollama pull 模型名称

2. 大模型无响应、卡死

  1. 检查设备显存 / 内存是否充足,7B 模型建议预留 4G 以上空闲资源;

  2. 可替换为轻量化模型qwen:3b/qwen2:1.5b,推理速度更快;

  3. 重启 Ollama 服务:pkill ollama && ollama serve &

3. 向量库数据异常

删除项目下chroma_db文件夹,重新运行代码重建向量库即可。


六、项目拓展方向

  1. 支持多 PDF 文档批量导入,搭建通用本地知识库;

  2. 增加语义重排、摘要优化,提升问答精准度;

  3. 接入 Web 界面,实现可视化问答;

  4. 更换不同 Embedding 模型与大模型,对比检索、生成效果。


七、总结

本项目参照 RAG实现原理,基于开源组件实现离线本地部署,无需依赖任何第三方云端接口。不消耗Token,可以帮助我们快速熟悉RAG底层原理,为后续LangChain等学习打下基础。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 8:02:10

审计严查招投标,这八类问题一查一个准

在招投标行业里&#xff0c;不少企业老板觉得“只要先把标投出去就行”。但现实情况恰恰相反&#xff0c;审计部门现在查得越来越细&#xff0c;很多过去被认为“问题不大”的操作方式&#xff0c;如今回头一看全是雷。想提前规避风险&#xff0c;第一步就是掌握真实的项目信息…

作者头像 李华
网站建设 2026/6/10 7:58:21

KMS智能激活实战指南:Windows与Office永久激活秘籍

KMS智能激活实战指南&#xff1a;Windows与Office永久激活秘籍 【免费下载链接】KMS_VL_ALL_AIO Smart Activation Script 项目地址: https://gitcode.com/gh_mirrors/km/KMS_VL_ALL_AIO 还在为Windows系统频繁弹出激活提示而烦恼吗&#xff1f;Office文档突然变成只读模…

作者头像 李华
网站建设 2026/6/10 7:53:01

1个终极解决方案:OneNote Md Exporter实现笔记格式自由迁移

1个终极解决方案&#xff1a;OneNote Md Exporter实现笔记格式自由迁移 【免费下载链接】onenote-md-exporter ConsoleApp to export OneNote notebooks to Markdown formats 项目地址: https://gitcode.com/gh_mirrors/on/onenote-md-exporter 你是否曾因OneNote的封闭…

作者头像 李华
网站建设 2026/6/10 7:52:14

江苏三维扫描仪定制:制造企业如何提升检测效率?

在现代工业生产中&#xff0c;产品质量控制已经成为企业竞争的重要环节。随着零件精度要求不断提高&#xff0c;传统检测方式正在逐渐向数字化、智能化方向发展。 三维扫描技术利用非接触式测量方式&#xff0c;能够快速获取产品完整数据&#xff0c;并帮助企业建立更加高效的检…

作者头像 李华
网站建设 2026/6/10 7:51:47

Dear PyGui:Python GUI 框架里的性能怪兽

文章目录Dear PyGui&#xff1a;Python GUI 框架里的性能怪兽1、 和其他 Python GUI 框架有什么不同2、 能做什么3、 上手有多简单4、 技术栈5、 适合哪些场景Dear PyGui&#xff1a;Python GUI 框架里的性能怪兽 DearPyGui 在 GitHub 上已经拿到 15,457 Star 了。 Python 的…

作者头像 李华
网站建设 2026/6/10 7:50:09

英雄联盟Akari助手:免费开源的游戏效率工具完全指南

英雄联盟Akari助手&#xff1a;免费开源的游戏效率工具完全指南 【免费下载链接】League-Toolkit An all-in-one toolkit for LeagueClient. Gathering power &#x1f680;. 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit 还在为英雄联盟中繁琐的符文配…

作者头像 李华