Python_RAG知识库问答系统实战指南

🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战


🌸你好呀!我是 lbb小魔仙
🌟 感谢陪伴~ 小白博主在线求友
🌿 跟着小白学Linux/Java/Python
📖 专栏汇总:
《Linux》专栏 | 《Java》专栏 | 《Python》专栏

* [🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)

  • [@[TOC]( )](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [📌 前言](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [一、RAG 原理深度解析 🔍](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [1.1 为什么需要 RAG?](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [1.2 RAG 工作流程](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [1.3 关键指标](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [二、技术选型与架构设计 🏗️](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [2.1 技术栈选择](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [2.2 项目结构](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [三、环境搭建 🛠️](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [3.1 安装依赖](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [3.2 配置文件](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [四、文档加载与分割 📂](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [五、向量化与入库 🗄️](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [六、检索与问答核心实现 💬](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [七、多格式文档支持 📎](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [7.1 完整的文档处理管道](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [八、优化策略:提升检索质量 🎯](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [8.1 混合检索(Hybrid Search)](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [8.2 重排序(Reranking)](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [8.3 查询扩展(Query Expansion)](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [九、WebUI 界面(Gradio)🖥️](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [十、部署与进阶 🚀](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [10.1 性能优化对比](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [10.2 替换为完全本地方案(零成本)](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [总结 🌟](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [完整代码流程回顾](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [效果评估指标](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [进阶方向 🔮](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [💬 互动区](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)
  • [📎 参考资料](#🧠 手把手搭建本地 RAG 知识库问答系统:Python + DeepSeek + ChromaDB 全栈实战 @TOC 📌 前言 一、RAG 原理深度解析 🔍 1.1 为什么需要 RAG? 1.2 RAG 工作流程 1.3 关键指标 二、技术选型与架构设计 🏗️ 2.1 技术栈选择 2.2 项目结构 三、环境搭建 🛠️ 3.1 安装依赖 3.2 配置文件 四、文档加载与分割 📂 五、向量化与入库 🗄️ 六、检索与问答核心实现 💬 七、多格式文档支持 📎 7.1 完整的文档处理管道 八、优化策略:提升检索质量 🎯 8.1 混合检索(Hybrid Search) 8.2 重排序(Reranking) 8.3 查询扩展(Query Expansion) 九、WebUI 界面(Gradio)🖥️ 十、部署与进阶 🚀 10.1 性能优化对比 10.2 替换为完全本地方案(零成本) 总结 🌟 完整代码流程回顾 效果评估指标 进阶方向 🔮 💬 互动区 📎 参考资料)

📌 前言

你是否遇到过这样的场景?

  • 📄 公司有几百份 PDF 文档,想直接用自然语言提问
  • 📚 个人笔记库很大,找不到某个知识点在哪
  • 🏢 企业私有数据不能上传到 ChatGPT,想在本地部署一套智能问答

RAG(检索增强生成) 正是解决这些问题的核心技术。

本文将带你从零开始,用 Python + DeepSeek + ChromaDB 构建一个完整的本地知识库问答系统,支持上传 PDF / TXT / Word 文档,实现秒级智能检索。

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


一、RAG 原理深度解析 🔍

1.1 为什么需要 RAG?

大语言模型(LLM)有两个天然缺陷:

问题 描述 RAG 解法
知识截止 训练数据有时效性,不知道最新信息 实时检索最新文档
幻觉问题 会编造不存在的"知识" 基于真实文档生成答案
私有数据 无法访问企业内部文档 本地构建专属知识库
上下文限制 Token 窗口有限,无法输入整本书 检索最相关片段后输入

1.2 RAG 工作流程

复制代码
                    ┌─────────────────────────────────┐
                    │          离线构建阶段              │
                    │                                   │
  原始文档 ──→ 文本分割 ──→ Embedding 向量化 ──→ 存入向量数据库
  (PDF/Word/TXT)  (Chunks)     (模型编码)        (ChromaDB)
                    └─────────────────────────────────┘

                    ┌─────────────────────────────────┐
                    │          在线问答阶段              │
                    │                                   │
  用户提问 ──→ 问题向量化 ──→ 相似度检索 ──→ 召回 Top-K 文档
                                                    ↓
  最终答案 ←── LLM 生成 ←── 构造 Prompt(问题 + 相关文档)
                    └─────────────────────────────────┘

1.3 关键指标

  • 召回率:相关文档是否被检索到(宁可多,不能漏)
  • 精确率:检索到的文档是否真的相关
  • 生成质量:LLM 基于文档回答是否准确

二、技术选型与架构设计 🏗️

2.1 技术栈选择

模块 选型 理由
LLM DeepSeek-V3 / DeepSeek-R1 中文能力强,性价比极高
Embedding BGE-M3(本地)/ text-embedding-3-small 中文语义理解最佳
向量数据库 ChromaDB 轻量,零配置,适合本地
文档处理 LangChain Document Loaders 支持格式最全
文本分割 RecursiveCharacterTextSplitter 语义保留最好
WebUI Gradio 5 分钟搭建界面

2.2 项目结构

复制代码
rag_system/
├── 📁 data/                    # 原始文档目录
│   ├── pdfs/
│   ├── docs/
│   └── txts/
├── 📁 vector_store/            # 向量数据库持久化
├── 📁 src/
│   ├── document_loader.py      # 文档加载与分割
│   ├── embeddings.py           # 向量化模块
│   ├── retriever.py            # 检索模块
│   ├── qa_chain.py             # 问答链
│   └── config.py               # 配置文件
├── app.py                      # Gradio WebUI
├── main.py                     # 命令行入口
└── requirements.txt

三、环境搭建 🛠️

3.1 安装依赖

bash 复制代码
# Python 3.11+ 推荐
pip install langchain langchain-community langchain-openai
pip install chromadb
pip install sentence-transformers          # 本地 Embedding
pip install pypdf python-docx              # 文档解析
pip install gradio                         # WebUI
pip install python-dotenv rich tiktoken

3.2 配置文件

python 复制代码
# src/config.py
import os
from dotenv import load_dotenv

load_dotenv()

# ===== LLM 配置 =====
# DeepSeek(推荐,国内稳定,价格极低)
LLM_API_KEY = os.getenv("DEEPSEEK_API_KEY")
LLM_BASE_URL = "https://api.deepseek.com/v1"
LLM_MODEL = "deepseek-chat"

# ===== Embedding 配置 =====
EMBEDDING_MODEL = "BAAI/bge-m3"   # 本地模型(免费,中文最强)
# 或使用 OpenAI: "text-embedding-3-small"

# ===== 文本分割配置 =====
CHUNK_SIZE = 500          # 每段文本长度
CHUNK_OVERLAP = 50        # 段落重叠长度(保留上下文)

# ===== 检索配置 =====
RETRIEVAL_TOP_K = 5       # 召回文档数量
SIMILARITY_THRESHOLD = 0.3  # 相似度阈值

# ===== 向量库路径 =====
VECTOR_STORE_PATH = "./vector_store"
bash 复制代码
# .env 文件
DEEPSEEK_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx

四、文档加载与分割 📂

这是 RAG 系统质量的第一道关卡,分割策略直接影响检索效果。

python 复制代码
# src/document_loader.py
from langchain_community.document_loaders import (
    PyPDFLoader,
    TextLoader,
    Docx2txtLoader,
    DirectoryLoader,
    UnstructuredMarkdownLoader,
)
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.schema import Document
from pathlib import Path
from typing import List
from rich.console import Console

console = Console()


class DocumentProcessor:
    """文档处理器:加载 + 清洗 + 分割"""
    
    def __init__(self, chunk_size: int = 500, chunk_overlap: int = 50):
        self.chunk_size = chunk_size
        self.chunk_overlap = chunk_overlap
        
        # 递归字符分割器(最适合中文文本)
        self.text_splitter = RecursiveCharacterTextSplitter(
            chunk_size=chunk_size,
            chunk_overlap=chunk_overlap,
            separators=["\n\n", "\n", "。", "!", "?", ";", ",", " ", ""],
            length_function=len,
        )
    
    def load_single_file(self, file_path: str) -> List[Document]:
        """根据文件类型自动选择加载器"""
        path = Path(file_path)
        suffix = path.suffix.lower()
        
        loaders = {
            ".pdf": PyPDFLoader,
            ".txt": lambda f: TextLoader(f, encoding="utf-8"),
            ".docx": Docx2txtLoader,
            ".md": UnstructuredMarkdownLoader,
        }
        
        if suffix not in loaders:
            console.print(f"[yellow]⚠️ 不支持的文件格式:{suffix}[/yellow]")
            return []
        
        try:
            loader = loaders[suffix](file_path)
            docs = loader.load()
            console.print(f"[green]✅ 已加载:{path.name}({len(docs)} 页)[/green]")
            return docs
        except Exception as e:
            console.print(f"[red]❌ 加载失败 {path.name}:{e}[/red]")
            return []
    
    def load_directory(self, dir_path: str) -> List[Document]:
        """批量加载目录下所有支持的文档"""
        all_docs = []
        path = Path(dir_path)
        
        supported_extensions = [".pdf", ".txt", ".docx", ".md"]
        files = [f for f in path.rglob("*") if f.suffix.lower() in supported_extensions]
        
        console.print(f"\n📂 扫描到 {len(files)} 个文档...")
        
        for file in files:
            docs = self.load_single_file(str(file))
            all_docs.extend(docs)
        
        console.print(f"\n📊 共加载 {len(all_docs)} 个文档片段")
        return all_docs
    
    def split_documents(self, documents: List[Document]) -> List[Document]:
        """文本分割"""
        chunks = self.text_splitter.split_documents(documents)
        
        # 过滤太短的片段(噪音)
        chunks = [c for c in chunks if len(c.page_content.strip()) > 20]
        
        console.print(f"✂️  分割完成:{len(documents)} 篇 → {len(chunks)} 个片段")
        console.print(f"   平均片段长度:{sum(len(c.page_content) for c in chunks) // len(chunks)} 字")
        
        return chunks
    
    def process(self, source: str) -> List[Document]:
        """一键处理:加载 + 分割"""
        path = Path(source)
        
        if path.is_dir():
            docs = self.load_directory(source)
        elif path.is_file():
            docs = self.load_single_file(source)
        else:
            raise ValueError(f"路径不存在:{source}")
        
        if not docs:
            raise ValueError("未能加载任何文档,请检查文件格式")
        
        return self.split_documents(docs)

五、向量化与入库 🗄️

python 复制代码
# src/embeddings.py
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.vectorstores import Chroma
from langchain.schema import Document
from typing import List, Optional
from rich.console import Console
import os

console = Console()


class VectorStoreManager:
    """向量数据库管理器"""
    
    def __init__(
        self, 
        persist_dir: str = "./vector_store",
        embedding_model: str = "BAAI/bge-m3"
    ):
        self.persist_dir = persist_dir
        
        console.print(f"🔄 加载 Embedding 模型:{embedding_model}")
        
        # BGE-M3:中文语义理解最强的开源模型
        self.embeddings = HuggingFaceEmbeddings(
            model_name=embedding_model,
            model_kwargs={"device": "cpu"},  # 改为 "cuda" 可使用 GPU
            encode_kwargs={
                "normalize_embeddings": True,  # 归一化,提升余弦相似度效果
                "batch_size": 32,
            }
        )
        
        self.vectorstore: Optional[Chroma] = None
    
    def build_from_documents(self, documents: List[Document]) -> Chroma:
        """从文档列表构建向量库"""
        console.print(f"\n⚡ 开始向量化 {len(documents)} 个文档片段...")
        
        # 批量向量化并存入 ChromaDB
        self.vectorstore = Chroma.from_documents(
            documents=documents,
            embedding=self.embeddings,
            persist_directory=self.persist_dir,
            collection_metadata={"hnsw:space": "cosine"},  # 使用余弦相似度
        )
        
        console.print(f"[green]✅ 向量库构建完成!共 {self.vectorstore._collection.count()} 条记录[/green]")
        console.print(f"💾 已持久化到:{self.persist_dir}")
        
        return self.vectorstore
    
    def load_existing(self) -> Optional[Chroma]:
        """加载已存在的向量库"""
        if not os.path.exists(self.persist_dir):
            console.print(f"[yellow]⚠️ 向量库不存在:{self.persist_dir}[/yellow]")
            return None
        
        self.vectorstore = Chroma(
            persist_directory=self.persist_dir,
            embedding_function=self.embeddings,
        )
        
        count = self.vectorstore._collection.count()
        console.print(f"[green]📂 已加载向量库:{count} 条记录[/green]")
        
        return self.vectorstore
    
    def add_documents(self, documents: List[Document]):
        """增量添加文档"""
        if self.vectorstore is None:
            raise RuntimeError("请先加载或构建向量库")
        
        self.vectorstore.add_documents(documents)
        console.print(f"[green]➕ 已添加 {len(documents)} 个新文档片段[/green]")
    
    def get_retriever(self, top_k: int = 5, score_threshold: float = 0.3):
        """获取检索器"""
        return self.vectorstore.as_retriever(
            search_type="similarity_score_threshold",
            search_kwargs={
                "k": top_k,
                "score_threshold": score_threshold,
            }
        )

六、检索与问答核心实现 💬

python 复制代码
# src/qa_chain.py
from langchain_openai import ChatOpenAI
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate
from langchain.schema import BaseRetriever
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from typing import Generator

# ===== 高质量中文问答 Prompt =====
QA_PROMPT_TEMPLATE = """你是一个专业的知识库问答助手。请根据以下检索到的相关文档内容回答用户的问题。

【相关文档】
{context}

【用户问题】
{question}

【回答要求】
1. 只根据上述文档内容回答,不要编造信息
2. 如果文档中没有相关信息,请明确说"根据现有文档,无法回答此问题"
3. 回答要简洁准确,必要时可以引用原文
4. 使用中文回答

【回答】"""

QA_PROMPT = PromptTemplate(
    template=QA_PROMPT_TEMPLATE,
    input_variables=["context", "question"]
)


class RAGQASystem:
    """RAG 问答系统核心"""
    
    def __init__(self, retriever: BaseRetriever, api_key: str, base_url: str, model: str):
        self.retriever = retriever
        
        # 初始化 LLM(DeepSeek)
        self.llm = ChatOpenAI(
            model=model,
            api_key=api_key,
            base_url=base_url,
            temperature=0.1,       # 低温度:更准确,减少幻觉
            max_tokens=2048,
            streaming=True,        # 支持流式输出
        )
        
        # 构建 RAG 链(LCEL 写法,推荐)
        self.chain = self._build_chain()
    
    def _format_docs(self, docs) -> str:
        """格式化检索到的文档"""
        formatted = []
        for i, doc in enumerate(docs, 1):
            source = doc.metadata.get("source", "未知来源")
            page = doc.metadata.get("page", "")
            source_info = f"[来源:{source}" + (f" 第{page+1}页" if page != "" else "") + "]"
            formatted.append(f"--- 文档 {i} {source_info} ---\n{doc.page_content}")
        return "\n\n".join(formatted)
    
    def _build_chain(self):
        """使用 LCEL 构建 RAG 链"""
        return (
            {
                "context": self.retriever | self._format_docs,
                "question": RunnablePassthrough()
            }
            | QA_PROMPT
            | self.llm
            | StrOutputParser()
        )
    
    def ask(self, question: str) -> str:
        """同步问答"""
        return self.chain.invoke(question)
    
    def ask_stream(self, question: str) -> Generator[str, None, None]:
        """流式问答(逐字输出)"""
        for chunk in self.chain.stream(question):
            yield chunk
    
    def ask_with_sources(self, question: str) -> dict:
        """问答 + 返回来源文档"""
        docs = self.retriever.invoke(question)
        answer = self.ask(question)
        
        sources = []
        for doc in docs:
            sources.append({
                "content": doc.page_content[:200] + "...",
                "source": doc.metadata.get("source", "未知"),
                "page": doc.metadata.get("page", ""),
            })
        
        return {
            "answer": answer,
            "sources": sources,
            "docs_count": len(docs)
        }

七、多格式文档支持 📎

7.1 完整的文档处理管道

python 复制代码
# main.py
from src.config import *
from src.document_loader import DocumentProcessor
from src.embeddings import VectorStoreManager
from src.qa_chain import RAGQASystem
from rich.console import Console
from rich.panel import Panel
from rich.table import Table
import os

console = Console()


def build_knowledge_base(data_dir: str = "./data"):
    """构建知识库"""
    console.print(Panel.fit("🔨 开始构建知识库", style="bold blue"))
    
    # 1. 加载并分割文档
    processor = DocumentProcessor(
        chunk_size=CHUNK_SIZE, 
        chunk_overlap=CHUNK_OVERLAP
    )
    chunks = processor.process(data_dir)
    
    # 2. 向量化并存储
    manager = VectorStoreManager(
        persist_dir=VECTOR_STORE_PATH,
        embedding_model=EMBEDDING_MODEL
    )
    manager.build_from_documents(chunks)
    
    console.print(Panel.fit("✅ 知识库构建完成!", style="bold green"))
    return manager


def load_knowledge_base():
    """加载已有知识库"""
    manager = VectorStoreManager(
        persist_dir=VECTOR_STORE_PATH,
        embedding_model=EMBEDDING_MODEL
    )
    
    vectorstore = manager.load_existing()
    if vectorstore is None:
        raise RuntimeError("知识库不存在,请先运行 build_knowledge_base()")
    
    return manager


def interactive_qa(manager: VectorStoreManager):
    """命令行交互问答"""
    retriever = manager.get_retriever(
        top_k=RETRIEVAL_TOP_K,
        score_threshold=SIMILARITY_THRESHOLD
    )
    
    qa_system = RAGQASystem(
        retriever=retriever,
        api_key=LLM_API_KEY,
        base_url=LLM_BASE_URL,
        model=LLM_MODEL
    )
    
    console.print(Panel.fit(
        "💬 知识库问答系统已就绪!输入 'quit' 退出",
        style="bold cyan"
    ))
    
    while True:
        question = input("\n❓ 请输入问题:").strip()
        
        if question.lower() in ["quit", "exit", "q"]:
            console.print("[yellow]👋 再见![/yellow]")
            break
        
        if not question:
            continue
        
        console.print("\n🤔 正在检索和生成回答...")
        
        # 流式输出答案
        console.print("\n[bold green]💡 答案:[/bold green]")
        result = qa_system.ask_with_sources(question)
        console.print(result["answer"])
        
        # 显示来源
        if result["sources"]:
            table = Table(title=f"\n📎 参考来源(共 {result['docs_count']} 段)")
            table.add_column("序号", style="cyan", width=5)
            table.add_column("来源文件", style="green")
            table.add_column("相关内容片段", style="white")
            
            for i, src in enumerate(result["sources"][:3], 1):
                table.add_row(
                    str(i),
                    os.path.basename(src["source"]),
                    src["content"][:80] + "..."
                )
            
            console.print(table)


if __name__ == "__main__":
    import sys
    
    if len(sys.argv) > 1 and sys.argv[1] == "build":
        # python main.py build
        manager = build_knowledge_base("./data")
    else:
        # python main.py
        manager = load_knowledge_base()
    
    interactive_qa(manager)

八、优化策略:提升检索质量 🎯

8.1 混合检索(Hybrid Search)

python 复制代码
from langchain_community.retrievers import BM25Retriever
from langchain.retrievers import EnsembleRetriever

# BM25:关键词检索(擅长精确匹配)
bm25_retriever = BM25Retriever.from_documents(chunks)
bm25_retriever.k = 5

# 向量检索:语义相似度(擅长语义理解)
vector_retriever = vectorstore.as_retriever(search_kwargs={"k": 5})

# 混合检索:两者取长补短
ensemble_retriever = EnsembleRetriever(
    retrievers=[bm25_retriever, vector_retriever],
    weights=[0.4, 0.6]  # BM25 权重 40%,向量 60%
)

8.2 重排序(Reranking)

python 复制代码
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import CrossEncoderReranker
from langchain_community.cross_encoders import HuggingFaceCrossEncoder

# Cross-Encoder 重排序模型(更精准但更慢)
cross_encoder = HuggingFaceCrossEncoder(
    model_name="BAAI/bge-reranker-v2-m3"
)

reranker = CrossEncoderReranker(
    model=cross_encoder, 
    top_n=3  # 从 10 个候选中选出最相关的 3 个
)

# 先召回 10 个,再精排 Top 3
base_retriever = vectorstore.as_retriever(search_kwargs={"k": 10})
compression_retriever = ContextualCompressionRetriever(
    base_compressor=reranker,
    base_retriever=base_retriever
)

8.3 查询扩展(Query Expansion)

python 复制代码
from langchain.chains import HypotheticalDocumentEmbedder

def expand_query(question: str, llm) -> List[str]:
    """
    用 LLM 生成多个变体问题,提升召回率
    例:'苹果营养价值' → ['苹果有哪些维生素', '吃苹果的好处', '苹果的营养成分']
    """
    prompt = f"""请将以下问题改写为3个不同表达方式的问题,用于检索文档。
    
原始问题:{question}

直接输出3个问题,每行一个,不要编号:"""
    
    response = llm.invoke(prompt).content
    variants = [q.strip() for q in response.strip().split("\n") if q.strip()]
    
    return [question] + variants[:3]  # 原始问题 + 3个变体


def multi_query_retrieve(question: str, retriever, llm) -> List:
    """多查询检索"""
    queries = expand_query(question, llm)
    
    all_docs = []
    seen_ids = set()
    
    for query in queries:
        docs = retriever.invoke(query)
        for doc in docs:
            doc_id = hash(doc.page_content)
            if doc_id not in seen_ids:
                all_docs.append(doc)
                seen_ids.add(doc_id)
    
    return all_docs

九、WebUI 界面(Gradio)🖥️

用 Gradio 5 分钟搭建一个好看的问答界面:

python 复制代码
# app.py
import gradio as gr
from main import load_knowledge_base
from src.config import *
from src.qa_chain import RAGQASystem

# 加载知识库
manager = load_knowledge_base()
retriever = manager.get_retriever(top_k=RETRIEVAL_TOP_K)
qa_system = RAGQASystem(
    retriever=retriever,
    api_key=LLM_API_KEY,
    base_url=LLM_BASE_URL,
    model=LLM_MODEL
)


def chat(message: str, history: list):
    """流式对话函数"""
    response = ""
    for chunk in qa_system.ask_stream(message):
        response += chunk
        yield response


def upload_and_index(files):
    """上传文档并实时建索引"""
    from src.document_loader import DocumentProcessor
    
    processor = DocumentProcessor()
    all_chunks = []
    
    for file in files:
        chunks = processor.process(file.name)
        all_chunks.extend(chunks)
    
    manager.add_documents(all_chunks)
    return f"✅ 已成功索引 {len(files)} 个文件,共 {len(all_chunks)} 个片段"


# 构建界面
with gr.Blocks(
    title="🧠 本地知识库问答系统",
    theme=gr.themes.Soft(),
    css=".gradio-container { max-width: 900px !important; margin: auto; }"
) as demo:
    
    gr.Markdown("""
    # 🧠 本地知识库问答系统
    > **基于 RAG 技术** | Python + DeepSeek + ChromaDB
    """)
    
    with gr.Row():
        with gr.Column(scale=3):
            # 聊天界面
            chatbot = gr.Chatbot(
                height=500,
                show_label=False,
                avatar_images=("👤", "🤖"),
                bubble_full_width=False,
            )
            
            with gr.Row():
                msg = gr.Textbox(
                    placeholder="请输入你的问题...",
                    scale=4,
                    show_label=False,
                )
                send_btn = gr.Button("发送 🚀", variant="primary", scale=1)
            
            gr.Examples(
                examples=[
                    "这个知识库主要包含哪些内容?",
                    "请总结一下最重要的知识点",
                    "有没有关于...的介绍?",
                ],
                inputs=msg
            )
        
        with gr.Column(scale=1):
            gr.Markdown("### 📁 上传文档")
            upload = gr.File(
                label="支持 PDF / Word / TXT / MD",
                file_count="multiple",
                file_types=[".pdf", ".docx", ".txt", ".md"]
            )
            upload_btn = gr.Button("开始索引 ⚡", variant="secondary")
            upload_status = gr.Textbox(
                label="索引状态",
                interactive=False,
                lines=3
            )
            
            gr.Markdown("### ℹ️ 系统信息")
            gr.Markdown(f"""
            - **LLM**:{LLM_MODEL}
            - **Embedding**:BGE-M3
            - **向量库**:ChromaDB
            - **Top-K**:{RETRIEVAL_TOP_K}
            """)
    
    # 事件绑定
    msg.submit(chat, [msg, chatbot], [chatbot])
    send_btn.click(chat, [msg, chatbot], [chatbot])
    upload_btn.click(upload_and_index, [upload], [upload_status])


if __name__ == "__main__":
    demo.launch(
        server_name="0.0.0.0",
        server_port=7860,
        share=False,       # 改为 True 可生成公网链接
        inbrowser=True,    # 自动打开浏览器
    )

启动命令:

bash 复制代码
# 先构建知识库
python main.py build

# 启动 WebUI
python app.py
# 访问 http://localhost:7860

十、部署与进阶 🚀

10.1 性能优化对比

优化方向 方案 效果
召回质量 混合检索 + Reranking 准确率 +30%
响应速度 向量缓存 + 异步处理 速度 +50%
支持规模 换用 Milvus / Qdrant 支持亿级向量
中文效果 BGE-M3 Embedding 优于 OpenAI
成本控制 本地 Ollama + Qwen 零 API 费用

10.2 替换为完全本地方案(零成本)

python 复制代码
# 完全本地:Ollama + DeepSeek-R1:7B
from langchain_ollama import ChatOllama, OllamaEmbeddings

# 需先安装 Ollama 并拉取模型:ollama pull deepseek-r1:7b
llm = ChatOllama(
    model="deepseek-r1:7b",
    temperature=0.1
)

# 本地 Embedding
embeddings = OllamaEmbeddings(model="nomic-embed-text")
bash 复制代码
# 安装 Ollama(一行命令)
curl -fsSL https://ollama.com/install.sh | sh

# 拉取模型
ollama pull deepseek-r1:7b
ollama pull nomic-embed-text

# 启动 Ollama 服务
ollama serve

总结 🌟

完整代码流程回顾

python 复制代码
# 5 步搭建 RAG 系统
# ① 加载文档
processor = DocumentProcessor()
chunks = processor.process("./data")

# ② 向量化存储
manager = VectorStoreManager()
manager.build_from_documents(chunks)

# ③ 创建检索器
retriever = manager.get_retriever(top_k=5)

# ④ 构建问答链
qa = RAGQASystem(retriever=retriever, ...)

# ⑤ 提问!
answer = qa.ask("你的问题")

效果评估指标

指标 评估方法 目标值
召回率 相关文档被检索到的比例 > 90%
精确率 检索文档的相关性 > 80%
答案准确率 与标准答案的一致性 > 85%
响应时间 端到端延迟 < 3s

进阶方向 🔮

  • 🕸️ Graph RAG:知识图谱 + 向量检索,处理复杂关联关系
  • 🖼️ 多模态 RAG:支持图片、表格、PPT 理解
  • 🔁 自适应 RAG:根据问题动态调整检索策略
  • 📊 RAG 评估框架:RAGAS、TruLens 自动化评估

💬 互动区

你的 RAG 系统是用于哪个场景的?遇到过哪些坑?

点赞 👍 + 收藏 ⭐ + 关注 获取更多 Python × AI 实战教程!


📎 参考资料


📕个人领域 :Linux/C++/java/AI

🚀 个人主页有点流鼻涕 · CSDN

💬 座右铭 : "向光而行,沐光而生。"

*

相关推荐
南 阳2 小时前
Python从入门到精通day63
开发语言·python
FreakStudio2 小时前
MicroPython LVGL基础知识和概念:底层渲染与性能优化
python·单片机·嵌入式·电子diy
素玥3 小时前
实训5 python连接mysql数据库
数据库·python·mysql
551只玄猫3 小时前
【数学建模 matlab 实验报告13】主成分分析
开发语言·数学建模·matlab·课程设计·主成分分析
zzzzls~3 小时前
Python 工程化: 用 Copier 打造“自我进化“的项目脚手架
开发语言·python·copier
韶博雅4 小时前
emcc24ai
开发语言·数据库·python
yongui478344 小时前
C# 与三菱PLC通讯解决方案
开发语言·c#
2501_933329554 小时前
技术架构深度解析:Infoseek舆情监测系统的全链路设计与GEO时代的技术实践
开发语言·人工智能·分布式·架构