Skip to content

About

本地私有化智能文档问答系统:BM25+向量混合检索、本地 Rerank 重排、完全离线、数据零外传(LangChain + Ollama + ChromaDB)

Resources

Stars

61 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

📚 LocalSmartRAG

本地私有化智能文档问答系统 · Local Private Document Q&A System

LLM / Embedding / Rerank 全部跑在本机,文档与对话数据绝不上传外部 API。

License: MIT Python 3.11+ PRs Welcome Stars


📖 目录


🚀 项目简介

LocalSmartRAG 是一个面向学生、科研人员、隐私敏感个人用户的本地文档问答系统。上传 PDF / Word / Markdown / TXT 文档后,即可对文档内容进行自然语言提问,回答自带引用溯源(文档名 + 页码 + 原文片段)。

与传统云端 RAG 方案不同,本项目的 LLM、Embedding、Rerank 全部在本地运行:

  • 对话与向量化走 Ollama(本地推理)
  • 重排走 sentence-transformers(本地权重)
  • 文档与对话记录零外传,适合处理敏感资料

💡 为什么做这个项目? 云端的文档问答(如 ChatGPT 上传文件)意味着把资料交给第三方;企业内部方案又重又贵。本项目用一个 pip install + 两个模型,就能在个人电脑上搭起一套完全私有的知识库问答,是理解 RAG 工程化的绝佳练手项目,也可直接作为简历 / 毕设 / 课程设计背书。


✨ 核心亮点

亮点 说明
🔒 完全本地 · 隐私安全 LLM / Embedding / Rerank 全本地,代码审计只允许访问 OLLAMA_BASE_URL,数据零上传
🔀 混合检索(核心) BM25 关键词 + 向量语义检索加权融合,再经本地 Rerank 重排,召回精度显著优于单路检索
🧰 工程化完备 多知识库隔离、多轮会话、引用溯源、日志/异常/缓存、上传去重,非玩具 demo

🎯 功能特性

文档处理

  • ✅ 多格式解析:PDF(逐页保留页码)/ docx / Markdown / TXT
  • ✅ 自适应语义分块:标题结构感知 + 代码/公式块保护 + 段落边界优先
  • ✅ 文本清洗:乱码过滤、页眉页脚检测、空行压缩、全半角规范化
  • ✅ 上传去重(内容 SHA-256 哈希)+ 批量向量化进度条

检索问答

  • ✅ 混合检索:向量路 + BM25 路 → 归一化加权融合(或 RRF)→ 本地 Rerank 重排
  • ✅ 引用溯源:回答用 [n] 标注,可展开查看「文档名 + 页码 + 原文片段」
  • ✅ 幻觉约束:严格限定「仅基于资料回答,无相关信息则明说」,禁止编造
  • ✅ 流式输出,打字机效果

工程能力

  • ✅ 多知识库隔离:每库独立 Chroma collection,embedding 模型一致性校验
  • ✅ 多轮会话:滑动窗口记忆 + JSON 持久化,跨重启恢复
  • ✅ 模型可配置:侧边栏切换 LLM / temperature / top_k / 融合权重
  • ✅ 会话导出 Markdown、日志轮转、TTL 检索缓存

🖼 效果预览

效果预览

演示

主界面

引用溯源


🏗 架构设计

flowchart LR
    A[文档<br/>PDF/docx/md/txt] --> B[document_loader<br/>解析]
    B --> C[text_cleaner<br/>清洗]
    C --> D[smart_splitter<br/>分块]
    D --> E[embedding_engine<br/>向量化]
    E --> F[(Chroma<br/>向量库)]

    Q[用户问题] --> G[retriever_hybrid<br/>混合检索]
    F --> G
    G --> H[reranker<br/>重排]
    H --> I[rag_chain<br/>LLM 生成]
    I --> J[带引用回答]

    subgraph 支撑模块
        K[config<br/>配置]
        L[kb_service<br/>知识库]
        M[session_service<br/>会话]
        N[export_service<br/>导出]
    end
Loading

数据流:文档 → 解析 → 清洗 → 分块 → 向量化 → Chroma → 混合检索(向量 + BM25 融合)→ 重排 → LLM → 带引用回答。


🚀 快速开始

前置要求:Python 3.11+,可联网(首次需下载模型与 rerank 权重)。

第 1 步:安装 Ollama

Ollama 是本项目的推理引擎,负责本地跑 LLM 与 Embedding 模型。

Windows

  • 方式一(推荐):打开 ollama.com/download → 下载 Windows 安装包 → 双击安装 → 启动 Ollama 应用(出现在系统托盘)。
  • 方式二(命令行):
winget install Ollama.Ollama

⚠️ 安装后务必重开终端(让 PATH 生效),否则会报 ollama 不是内部或外部命令。

macOS

brew install ollama
brew services start ollama

Linux

curl -fsSL https://ollama.com/install.sh | sh

第 2 步:拉取模型

需要两个模型:对话模型 + 向量模型。

ollama pull qwen2.5:7b          # 对话模型(约 4.7GB)
ollama pull nomic-embed-text    # 向量模型(约 274MB)

💡 对话模型可换成任意 Ollama 支持的模型(如 llama3.1:8b、deepseek-r1:7b),改 .env 里的 LLM_MODEL 即可。

验证:

ollama list
# 应看到 qwen2.5:7b 和 nomic-embed-text 两行

第 3 步:准备 Python 环境

方式 A:conda(推荐)

conda create -n LocalSmartRAG python=3.11 -y
conda activate LocalSmartRAG

方式 B:venv

python -m venv .venv
# Windows:
.venv\Scripts\activate
# macOS / Linux:
source .venv/bin/activate

第 4 步:安装依赖

pip install -r requirements.txt

依赖较多(含 PyTorch 生态),首次安装需要几分钟。如遇网络慢,可先 pip install -U pip,或配置国内镜像源。

第 5 步:配置环境(可选)

# Windows:
copy .env.example .env
# macOS / Linux:
cp .env.example .env

不配置也能跑(有默认值),.env 用于自定义模型名、地址、分块/检索参数等,详见配置说明。

第 6 步:启动

streamlit run app.py
# 或(含启动前健康检查):
python main.py

浏览器访问 **http://localhost:8501**,开始使用 🎉

Docker 部署(可选)

docker build -t localsmartrag .
# Linux 下用 host.docker.internal 访问宿主机 Ollama
docker run -p 8501:8501 -e OLLAMA_BASE_URL=http://host.docker.internal:11434 localsmartrag

📝 使用教程

1. 创建知识库

打开页面后,在左侧「知识库」面板点击展开 新建知识库,输入名称(如「高等数学资料」)和描述,点击「创建知识库」。

2. 上传文档

在「上传文档」区域点击 Browse files(可多选),支持 .pdf / .docx / .md / .txt,然后点击 上传并建库。上传过程有进度条,完成后会显示「上传成功 X 个,新增 N 块」。

⚠️ 扫描件/图片型 PDF 暂不支持(没有文字层,需 OCR,见 FAQ)。请使用有文字层的电子版 PDF。

3. 提问

在页面底部输入框输入问题(如「这篇文档讲了什么?」),回车发送。回答以流式输出,句末带 [n] 引用标记。

4. 查看引用溯源

点击回答下方的 [n] 文档名 第X页 可展开查看对应原文片段,验证答案出处。

5. 调整检索参数(可选)

左侧「模型与参数」面板可实时调整:

  • LLM 模型:下拉切换已安装的模型
  • temperature:0 偏保守、1 偏发散
  • 单路检索 top_k:每路召回条数
  • 融合权重 alpha:越大越偏向量语义,越小越偏关键词
  • 滑动窗口:多轮对话携带的历史轮数

6. 多轮会话与导出

  • 点击「+ 新建会话」开新对话
  • 点击「导出」把当前会话存为 Markdown 文件(含问答与引用来源)

⚙️ 配置说明

.env 全参数(缺省均用默认值):

参数 默认值 说明
OLLAMA_BASE_URL http://localhost:11434 Ollama 服务地址(唯一允许的网络访问目标)
LLM_MODEL qwen2.5:7b 对话模型
EMBEDDING_MODEL nomic-embed-text 向量模型(换模型需重建索引)
RERANK_MODEL BAAI/bge-reranker-base 本地重排模型(sentence-transformers)
CHUNK_SIZE 800 分块字符数
CHUNK_OVERLAP 150 相邻块重叠字符数
TOP_K 8 单路检索数量
TOP_N 10 融合后合并数量
TOP_N_RERANK 5 重排后送入 LLM 的数量
RETRIEVAL_ALPHA 0.6 向量/BM25 融合权重(0~1)
TEMPERATURE 0.1 生成温度
SESSION_WINDOW 6 滑动窗口轮数
LOG_LEVEL INFO 日志级别
DATA_DIR ./data 数据目录

把模型存到其他盘(省 C 盘空间)

Ollama 默认把模型存在 C:\Users\<你>\.ollama\models,想改到 D 盘:

[Environment]::SetEnvironmentVariable("OLLAMA_MODELS", "D:\ollama\models", "User")

然后重启 Ollama(托盘右键 → Quit → 重新打开)才生效。


🧠 技术原理

1. 自适应语义分块

先按 Markdown 标题(#/##/###)切主块;检测代码围栏与 $$、\( \) 公式块并整体保留不截断;优先段落边界(\n\n)、其次句末标点;超长块递归字符切分降级。每个块携带 source / page / chunk_index 元数据。

2. 混合检索与融合

  • 向量路:Chroma 按 query 向量取 top_k,语义匹配(能懂同义词)
  • 关键词路:jieba 分词 + BM25Okapi 取 top_k,精确匹配(能命中专有名词/编号)
  • 融合:两路分数各自 min-max 归一化后加权
score = alpha × minmax(向量分) + (1 - alpha) × minmax(BM25分)
  • 备选:RRF 倒数排名融合(无需归一化、更鲁棒)

3. Rerank 重排

Ollama 无原生 rerank 端点,采用本地 BAAI/bge-reranker-base 交叉编码器对融合结果精排,取 top_n_rerank 送入 LLM。

4. 滑动窗口

仅携带最近 N 轮对话(默认 6 轮)作为上下文,超出丢弃最旧,防止上下文过长、成本失控。

5. 幻觉约束

Prompt 明确「仅基于资料回答、无相关信息则回答『资料中未找到相关信息』、回答需用 [n] 标注引用」,回答后处理将 [n] 映射为来源清单。


📂 目录结构

LocalSmartRAG/
├── main.py                 # 入口:健康检查 + 启动 Streamlit
├── app.py                  # Streamlit 界面
├── config/
│   ├── settings.py         # 全局配置类(读 .env)
│   └── constants.py        # 常量(路径/默认参数/停用词)
├── core/                   # RAG 核心引擎
│   ├── document_loader.py  # 多格式解析(工厂模式)
│   ├── text_cleaner.py     # 清洗 + 页眉页脚检测
│   ├── smart_splitter.py   # 自适应分块
│   ├── embedding_engine.py # Ollama 向量化封装
│   ├── retriever_hybrid.py # 混合检索 + 融合
│   ├── reranker.py         # 重排(抽象 + bge + 降级)
│   └── rag_chain.py        # 问答链路 + 引用后处理
├── service/
│   ├── kb_service.py       # 知识库 CRUD + 上传编排
│   ├── session_service.py  # 会话 + 滑动窗口
│   └── export_service.py   # 导出 Markdown
├── utils/
│   ├── logger.py           # 日志(RotatingFileHandler)
│   ├── file_utils.py       # 文件工具(校验/哈希/安全名)
│   └── cache.py            # TTL 缓存
├── data/                   # 运行时生成(uploads/chroma_db/sessions)
├── requirements.txt
├── Dockerfile
└── .env.example

❓ 常见问题 FAQ

Q1:ollama 提示「不是内部或外部命令」

没安装,或安装后没重开终端。确认已安装 Ollama,并新开一个终端窗口。

Q2:上传报「Embedding 模型未安装」

只拉了对话模型,没拉向量模型。执行 ollama pull nomic-embed-text。

Q3:上传后显示「未提取到文本(0 块)」

你的 PDF 是扫描件/图片型 PDF(没有文字层)。PyMuPDF 只能提取内嵌文字,图片里的字需 OCR。请换用电子版 PDF,或关注 Roadmap 中的 OCR 支持。

Q4:启动提示「无法连接 Ollama 服务」

Ollama 没在运行。Windows 打开 Ollama 应用,或命令行执行 ollama serve。

Q5:模型太大、C 盘空间不足

设置 OLLAMA_MODELS 环境变量改到其他盘,见配置说明。

Q6:首次启动卡在「下载 rerank 模型」

首次会从 HuggingFace 下载 BAAI/bge-reranker-base(约 1GB),属正常,之后走本地缓存离线可用。

Q7:换 embedding 模型后检索异常

换模型需重建知识库索引(向量维度/语义空间不同)。删除旧知识库重新上传即可。


⚠️ 项目局限性

  • 本地小模型回答质量有上限,复杂推理/长链问答不如云端大模型;
  • 首次启动需下载模型与 rerank 权重,耗时较长;
  • 单机单用户,无分布式 / 多用户并发能力;
  • 长文档、复杂表格精度有限;图片型 PDF 暂不支持 OCR;
  • 深度依赖 Ollama 生态,能力受限于本地硬件。

🗺 Roadmap

  • 增量索引(新文档追加,不重建整个库)
  • 单文档删除
  • OCR 支持(扫描件/图片型 PDF 文字提取)
  • URL 抓取入库
  • 多模态(图片 / 图文混合问答)
  • 检索评估脚本(Recall@k / MRR)
  • WebUI 美化
  • docker-compose 一键编排 Ollama + App

🤝 贡献指南

欢迎 Star、Fork、提 Issue 与 PR!

  1. Fork 本仓库
  2. 新建特性分支:git checkout -b feature/xxx
  3. 提交改动:git commit -m 'feat: xxx'
  4. 推送分支:git push origin feature/xxx
  5. 发起 Pull Request,并描述改动动机

提交前请确保:代码风格与现有保持一致、中文注释充分、无新增未声明依赖。


📄 License

本项目基于 MIT 协议开源,欢迎用于学习与二次开发。


⭐ 如果这个项目对你有帮助,欢迎点个 Star 支持一下!

About

本地私有化智能文档问答系统:BM25+向量混合检索、本地 Rerank 重排、完全离线、数据零外传(LangChain + Ollama + ChromaDB)

Resources

Stars

61 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages