标签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统一管理环境变量核心功能逐页解析 PDF构建文本块与页码映射支持内容溯源自定义切片大小与重叠长度避免长文本语义割裂向量库自动检测已存在则直接加载防止重复入库交互式循环问答模型仅依据文档内容作答不编造信息全流程离线运行一次部署可长期使用二、环境部署1. 安装 Python 依赖库打开终端执行以下命令安装项目所需第三方库pip install pdfplumber chromadb ollama python-dotenv2. 安装 OllamaOllama 跨平台支持 Windows / Mac / Linux可一键本地运行各类大模型、向量模型。官网下载对应系统安装包https://ollama.com/安装完成后终端执行命令验证是否安装成功ollama --version3. 拉取本地模型国内网络环境建议延长超时时间避免大模型下载中断# Mac/Linux 临时设置超时时间网络不稳定必加export OLLAMA_TIMEOUT600# 拉取通义千问 Embedding 向量模型 ollama pull dengcao/Qwen3-Embedding-0.6B:Q8_0 # 拉取通义千问 7B 对话大模型 ollama pull qwen:7b4. 项目目录结构将 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, overrideTrue) # # 三、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, start1): 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( modelEMBED_MODEL, inputtext_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))], documentsall_chunks, embeddingsvectors ) # 保存文本块-页码映射文件 os.makedirs(CHROMA_PATH, exist_okTrue) 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_embeddingsq_vector, n_resultsTOP_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( modelLLM_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]}...)四、运行说明将待解析的 PDF 文件重命名为 xxx.pdf和代码放在同一目录确保 Ollama 服务正常运行对应模型已成功拉取直接执行 Python 脚本首次运行会自动完成 PDF 解析、文本切片、向量化与入库程序启动后进入交互模式输入问题即可问答输入q退出程序再次运行脚本会自动加载已有向量库不会重复处理文档。五、常见问题解决1. Ollama 拉取模型提示context deadline exceeded网络不稳定导致超时执行命令延长超时时间后重新拉取export OLLAMA_TIMEOUT600 ollama pull 模型名称2. 大模型无响应、卡死检查设备显存 / 内存是否充足7B 模型建议预留 4G 以上空闲资源可替换为轻量化模型qwen:3b/qwen2:1.5b推理速度更快重启 Ollama 服务pkill ollama ollama serve 。3. 向量库数据异常删除项目下chroma_db文件夹重新运行代码重建向量库即可。六、项目拓展方向支持多 PDF 文档批量导入搭建通用本地知识库增加语义重排、摘要优化提升问答精准度接入 Web 界面实现可视化问答更换不同 Embedding 模型与大模型对比检索、生成效果。七、总结本项目参照 RAG实现原理基于开源组件实现离线本地部署无需依赖任何第三方云端接口。不消耗Token可以帮助我们快速熟悉RAG底层原理为后续LangChain等学习打下基础。
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统一管理环境变量核心功能逐页解析 PDF构建文本块与页码映射支持内容溯源自定义切片大小与重叠长度避免长文本语义割裂向量库自动检测已存在则直接加载防止重复入库交互式循环问答模型仅依据文档内容作答不编造信息全流程离线运行一次部署可长期使用二、环境部署1. 安装 Python 依赖库打开终端执行以下命令安装项目所需第三方库pip install pdfplumber chromadb ollama python-dotenv2. 安装 OllamaOllama 跨平台支持 Windows / Mac / Linux可一键本地运行各类大模型、向量模型。官网下载对应系统安装包https://ollama.com/安装完成后终端执行命令验证是否安装成功ollama --version3. 拉取本地模型国内网络环境建议延长超时时间避免大模型下载中断# Mac/Linux 临时设置超时时间网络不稳定必加export OLLAMA_TIMEOUT600# 拉取通义千问 Embedding 向量模型 ollama pull dengcao/Qwen3-Embedding-0.6B:Q8_0 # 拉取通义千问 7B 对话大模型 ollama pull qwen:7b4. 项目目录结构将 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, overrideTrue) # # 三、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, start1): 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( modelEMBED_MODEL, inputtext_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))], documentsall_chunks, embeddingsvectors ) # 保存文本块-页码映射文件 os.makedirs(CHROMA_PATH, exist_okTrue) 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_embeddingsq_vector, n_resultsTOP_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( modelLLM_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]}...)四、运行说明将待解析的 PDF 文件重命名为 xxx.pdf和代码放在同一目录确保 Ollama 服务正常运行对应模型已成功拉取直接执行 Python 脚本首次运行会自动完成 PDF 解析、文本切片、向量化与入库程序启动后进入交互模式输入问题即可问答输入q退出程序再次运行脚本会自动加载已有向量库不会重复处理文档。五、常见问题解决1. Ollama 拉取模型提示context deadline exceeded网络不稳定导致超时执行命令延长超时时间后重新拉取export OLLAMA_TIMEOUT600 ollama pull 模型名称2. 大模型无响应、卡死检查设备显存 / 内存是否充足7B 模型建议预留 4G 以上空闲资源可替换为轻量化模型qwen:3b/qwen2:1.5b推理速度更快重启 Ollama 服务pkill ollama ollama serve 。3. 向量库数据异常删除项目下chroma_db文件夹重新运行代码重建向量库即可。六、项目拓展方向支持多 PDF 文档批量导入搭建通用本地知识库增加语义重排、摘要优化提升问答精准度接入 Web 界面实现可视化问答更换不同 Embedding 模型与大模型对比检索、生成效果。七、总结本项目参照 RAG实现原理基于开源组件实现离线本地部署无需依赖任何第三方云端接口。不消耗Token可以帮助我们快速熟悉RAG底层原理为后续LangChain等学习打下基础。