# 检索增强知识库 **Repository Path**: agent-dev-team/sonar-kb ## Basic Information - **Project Name**: 检索增强知识库 - **Description**: 本地可部署的RAG知识库系统,覆盖9环节检索增强全流程,可配置、可观测。 - **Primary Language**: Unknown - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: http://sonar-kb.zzrkyd.cn/ - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2026-06-22 - **Last Updated**: 2026-08-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # SonarKB 企业级检索增强知识库(RAG) 本地 / 私有化部署的企业级 RAG 知识库系统,强调全流程可控、可观测。支持 PDF / Markdown / Word / TXT,提供 FAISS + BM25 混合检索、多分块策略、重排序与可计量 Token 消耗。每一个 RAG 步骤都清晰可见、精确可控。 架构形态:**纯 Web,无 Electron、无桌面安装包**。后端 `backend/`(FastAPI)与三个网页 `frontend/`(消费者)、`admin/`(管理后台)、`website/`(营销站)相互独立,仅通过 HTTP + SSE 通信。三个网页打包进**同一个 Docker 容器**,由**同一个 Nginx** 托管静态资源并**反向代理 `/api` 到后端容器**;后端位于 Docker 内部网络,不暴露公网端口。 --- ## 一、项目背景 企业知识分散在大量 PDF / Word / 网页文档中,员工检索困难、答案不可溯源。通用大模型对话无法直接接入私有文档,且存在数据出域合规风险。 SonarKB 面向**企业内部私有化部署**场景,将企业文档构建为可检索知识库,员工用自然语言提问即可获得带原文出处的答案。系统所有环节(解析 → 分块 → 向量化 → 检索 → 重排 → 生成)均在自有环境内完成,数据不出域、过程可观测。 --- ## 二、项目目标 - **全流程可控可观测**:RAG 九环节(文件解析 → 文本分块 → 向量化 → 索引构建 → 查询改写 → 混合检索 → 重排序 → 推理生成)可视化、每步可配置,Token 消耗可计量。 - **高召回检索质量**:FAISS + BM25 双引擎混合检索,权重 / Top-K 可调;支持 4 种分块策略(auto / hierarchical / sliding_window / llm_semantic)与 LLM / 本地模型重排序。 - **企业级权限**:JWT 无状态鉴权 + 文件级 ACL(用户 / 用户组 / 公开,读 / 写 / 删),企业共享单一知识库。 - **私有化与易部署**:纯 Web 架构,三个网页合并为单一 Nginx 容器,前端直连后端,单条 `docker compose` 命令拉起全部服务,无外部 SaaS 依赖(仅可选调用外部 LLM)。 --- ## 三、架构 ### 3.1 服务与容器拓扑(部署态) 采用**三页一后端**架构:消费者端、管理后台、营销官网合并为**同一个 `web` 容器**,由单一 Nginx 托管静态资源并**反向代理 `/api` 到后端容器**;后端 `backend` 容器运行 FastAPI,位于 Docker 内部网络,不暴露公网端口。数据层为 MySQL 8,全部 Docker 容器化。 ```mermaid %%{init: {'themeVariables': {'fontSize': '15px', 'fontFamily': 'system-ui, -apple-system, sans-serif', 'primaryTextColor': '#ffffff', 'lineColor': '#94a3b8'}}}%% flowchart TB subgraph Browser["用户浏览器"] direction LR U1["访客
访问 /(宣传站)"] U2["员工 / 消费者
访问 /app/"] U3["管理员
访问 /admin/"] end subgraph WebContainer["Docker 容器: web :80 → 宿主机 :8080"] direction TB NG["Nginx
静态资源托管 + /api 反向代理"] subgraph NginxStatic["Nginx 静态目录 /usr/share/nginx/html"] direction LR PP["/
website 构建产物
宣传官网 (Vue3+TS)"] FE["/app/
frontend 构建产物
消费者端 (Vue3+TS)"] AD["/admin/
admin 构建产物
管理后台 (Vue3+TS)"] end NG --> PP NG --> FE NG --> AD end subgraph BackendContainer["Docker 容器: backend :8000(内部网络,不暴露公网)"] direction TB BE_GW["FastAPI 网关
JWT 鉴权 / SSE 流式 / lifespan"] subgraph BE_Modules["业务模块"] direction LR BE_RAG["RAG 引擎
索引 / 混合检索 / 重排 / 生成"] BE_Auth["鉴权与权限
注册登录 / 用户组 / 文件级 ACL"] BE_File["文件管理
上传 / 解析 / 分块 / 状态"] BE_Conf["配置管理
模型池 / 系统参数"] end BE_GW --> BE_RAG BE_GW --> BE_Auth BE_GW --> BE_File BE_GW --> BE_Conf end subgraph DBContainer["Docker 容器: db :3306(内部网络)"] direction TB DB[("MySQL 8 数据库
User / Permission
File / ChatSession")] end LLM["外部 LLM 服务
OpenAI / 阿里云百炼 / DeepSeek / 自定义协议"] %% 浏览器 → Nginx(静态资源 + API 都走 Nginx,同源免 CORS) U1 -->|"HTTP 静态资源 /"| NG U2 -->|"HTTP + SSE /app/ 与 /api"| NG U3 -->|"HTTP + SSE /admin/ 与 /api"| NG %% Nginx → 后端(Docker 内部网络,通过容器名 DNS 解析) NG -->|"proxy_pass /api
Docker 网络: backend:8000"| BE_GW %% 后端 → 数据库 & LLM BE_Auth -->|SQLAlchemy| DB BE_File -->|SQLAlchemy| DB BE_Conf -->|SQLAlchemy| DB BE_RAG -->|向量化 / 推理| LLM classDef browserNode fill:#7c2d12,stroke:#fb923c,color:#fff,stroke-width:2px classDef nginxNode fill:#0e7490,stroke:#22d3ee,color:#fff,stroke-width:2px classDef staticNode fill:#155e75,stroke:#67e8f9,color:#fff,stroke-width:1.5px classDef beNode fill:#1e3a5f,stroke:#38bdf8,color:#fff,stroke-width:2px classDef beModule fill:#1e40af,stroke:#93c5fd,color:#fff,stroke-width:1.5px classDef dbNode fill:#374151,stroke:#d1d5db,color:#fff,stroke-width:2px classDef extNode fill:#4c1d95,stroke:#a78bfa,color:#fff,stroke-width:2px class U1,U2,U3 browserNode class NG nginxNode class FE,AD,PP staticNode class BE_GW beNode class BE_RAG,BE_Auth,BE_File,BE_Conf beModule class DB dbNode class LLM extNode style Browser fill:transparent,stroke:#fb923c,stroke-width:1.5px,color:#ffffff style WebContainer fill:transparent,stroke:#22d3ee,stroke-width:2px,color:#ffffff style NginxStatic fill:transparent,stroke:#67e8f9,stroke-width:1px,color:#ffffff style BackendContainer fill:transparent,stroke:#38bdf8,stroke-width:2px,color:#ffffff style BE_Modules fill:transparent,stroke:#7dd3fc,stroke-width:1px,color:#ffffff style DBContainer fill:transparent,stroke:#d1d5db,stroke-width:2px,color:#ffffff ``` **架构要点**: - **三个网页合并为一个 `web` 容器**:Nginx 按路径分发静态产物——`/` 给宣传官网(落地页)、`/app/` 给消费者端、`/admin/` 给管理后台,减少容器数量和运维复杂度 - **Nginx 同时托管静态资源和反向代理 API**:`/`、`/app/`、`/admin/` 返回对应静态文件,`/api`、`/docs`、`/openapi.json` 通过 `proxy_pass` 转发到后端容器;SSE 流式响应关闭缓冲(`proxy_buffering off`),保证问答/检索进度实时推送 - **后端单容器**:FastAPI 网关统一处理 JWT / SSE,业务模块涵盖 RAG 引擎、鉴权权限、文件管理、配置管理,通过 SQLAlchemy 访问 MySQL - **Docker 内部网络**:`backend` 和 `db` 容器不暴露公网端口,仅在 Docker 自定义网络内通信;Nginx 通过容器名 `backend:8000` 解析并转发请求,更安全 - **同源免 CORS**:前端页面与 API 都经 Nginx 同一域名端口访问,浏览器视为同源,无需配置 `CORS_ORIGINS` - **MySQL 仅内部网络**:`db` 容器不暴露公网端口,仅 `backend` 可访问,数据通过 Docker Volume 持久化 ### 3.2 Nginx 静态托管与 API 反向代理 `web` 容器内的 Nginx **同时负责静态文件分发和 API 反向代理**: **静态资源路由**(按路径返回对应站点构建产物): - `/` → website(宣传官网,纯静态,不依赖后端) - `/app/` → frontend(消费者端 SPA,base `/app/`,`try_files` 兜底 `index.html`) - `/admin/` → admin(管理后台 SPA,base `/admin/`) **API 反向代理**(转发到后端容器,Docker 内部网络通过容器名 DNS 解析): - `/api` · `/docs` · `/openapi.json` · `/redoc` → `backend:8000` - SSE 端点关闭缓冲(`proxy_buffering off`、`proxy_cache off`、`chunked_transfer_encoding off`),保证流式响应实时推送 - 后端容器不暴露公网端口,仅 Nginx 可通过 Docker 网络访问 ### 3.3 鉴权与权限 - **登录**:QQ 邮箱验证码 / 微信 OAuth,登录即自动注册。 - **无状态 JWT**(HS256,7 天);SSE 用 `?token=` 查询参数。中间件白名单放行 `/api/auth`、`/api/health`、`/docs`、`/openapi.json`、`/redoc` 与 `OPTIONS`。 - **后台接口**:`require_admin` 守护 `/api/admin/*`。 - **文件级 ACL**:`backend/core/permissions.py` 提供 `can_read` / `can_delete` / `get_readable_doc_ids`;权限条目含 `principal_type`(user|group|public)、`principal_id`、`access`(read|write|delete)。 - **企业共享知识库**:所有请求使用同一工作空间 `DATA_ROOT/shared`,文件级权限由 `core/permissions` 控制,数据不按用户隔离。 ### 3.4 技术栈 - **网页**:Vue 3 + Pinia + Vue Router(hash 模式)+ Vite;UI 组件 `exploria-ui`;包管理器 **pnpm**。 - **后端**:FastAPI + `uvicorn[standard]`;检索 `faiss-cpu` / `rank-bm25` / `jieba`;解析 `pdfplumber` / `python-docx` / `Pillow`;鉴权 `pyjwt` + `sqlalchemy` + `aiomysql`;可选重排(torch + transformers)/ 本地 LLM(llama-cpp-python)。 - **依赖管理**:Python 用 **UV**(`backend/pyproject.toml`);Node/TS 用 **pnpm**(禁 npm/yarn)。 - **部署**:Docker + docker compose;CI 构建并推送 `web`(三站合一 Nginx)与 `backend` 镜像。 --- ## 四、启动方式 ### (a) 开发环境启动 无需 Docker,四个进程各自运行(端口已固定,被占用则启动失败): ```bash # 1) 后端(FastAPI,固定 127.0.0.1:8001) cd backend; uv sync; uv run python server.py # 2) 消费者网页(另开终端,固定 http://localhost:7001) cd frontend; pnpm install; pnpm dev # 3) 管理后台网页(另开终端,固定 http://localhost:7002) cd admin; pnpm install; pnpm dev # 4) 官网(可选,另开终端,固定 http://localhost:7000) cd website; pnpm install; pnpm dev ``` > 端口均为固定模式(strictPort),被占用时直接报错退出,不会自动加一。 > 网页开发时由 Vite dev server 把 `/api` 代理到 `http://localhost:8001`;未启动后端则仅网页壳可用。前端与后端完全分离,经 HTTP + SSE 通信(零 IPC)。 ### (b) 部署环境启动(Docker Compose) 三个网页合并为 `web` 容器(单一 Nginx 托管静态资源,宿主机 :8080),前端 API 直连后端容器: ```bash cd deploy cp .env.example .env # 填入 5 个密钥(见下方「注意事项」) docker compose up -d --build ``` 启动后访问: | 入口 | 地址 | |---|---| | 宣传官网 | `http://<服务器IP>:8080/` | | 消费者端 | `http://<服务器IP>:8080/app/` | | 管理后台 | `http://<服务器IP>:8080/admin/` | | API 文档(经 Nginx 代理) | `http://<服务器IP>:8080/docs` | - 首个注册且邮箱匹配 `SUPERADMIN_EMAIL` 的用户自动成为超级管理员。 - 生产环境用预构建镜像时,改用 `docker compose -f docker-compose.prod.yml pull && up -d`(镜像由 CI 推送,见 `cicd/README.md`)。 - `web` 容器多阶段构建:依次编译 frontend / admin / website,将 dist 拷贝到 Nginx 镜像的不同路径下。 --- ## 五、注意事项 - **密钥(5 项,在 `deploy/.env`,已被 `.gitignore` 忽略、勿提交)**:`JWT_SECRET`、`MYSQL_ROOT_PASSWORD`、`MYSQL_PASSWORD`、`SMTP_AUTH_CODE`、`WECHAT_APPSECRET`(可选,留空不启用微信登录)。 - **非密钥配置**:已内联在 `deploy/docker-compose.yml` / `deploy/docker-compose.prod.yml` 的 `environment:` 块(含 `SUPERADMIN_EMAIL`、`CORS_ORIGINS`、数据库名 / 用户、`SMTP_HOST/PORT`、`JWT_ALGORITHM`、过期时长、`DATA_ROOT` 等),一般无需修改。 - **pnpm 锁文件**:`frontend/` 与 `admin/` 当前仅有 `package-lock.json`,Dockerfile 靠 `package.json` 解析可构建但不冻结依赖;在本机各执行一次 `pnpm install` 生成 `pnpm-lock.yaml` 以对齐 pnpm 工具链。 - **`backend/static/` 为可选兼容**:默认由 `web` 容器统一托管网页静态产物。如需单包简化部署,仍可将 dist 放进 `backend/static/`(见 `backend/core/static_hosting.py`)。 - **外部 LLM**:用户各自在模型池条目中填 API Key,平台不承担费用;默认文本模型 `qwen-flash`。 - **技术深读文档**:检索评测指标与报告解读见 `eval/README.md`;PDF 解析器流程见 `docs/PDF解析器流程说明.md`;模型池与多模态轮询见 `docs/模型轮询与多模态调用.md`;PowerShell 脚本约束见 `docs/PowerShell错题本.md`。 > 根目录 `.venv/` 为孤立本地 Python 虚拟环境(后端使用 `backend/` 内自建环境),已被 gitignore,不进入仓库。 --- ## 六、检索评测 `eval/`目录提供检索量化评测,衡量「查询重写」与「关键词检索(BM25)」两个特性对召回质量的贡献。 - 指标:recall@k(前k条覆盖相关段落比例)、nDCG@k(按排序位置加权)、MRR(首个相关结果排名倒数),默认k=5、10。 - A/B组合:对同一测试集跑4种开关——baseline(纯向量)、+rewrite(向量+重写)、+keyword(混合向量+BM25)、full(生产默认,重写+关键词)。 - 前置条件:需先在某知识库workspace完成文档上传与索引构建(chunks.json+vector_dbs+bm25_dbs)。 ```bash uv run python eval/run_eval.py # 一键评测(无测试集时自动生成弱监督种子集) uv run python eval/run_eval.py --gen-seed # 仅生成种子测试集 uv run python eval/run_eval.py --check # 离线冒烟(不调API) uv run python eval/run_eval.py --self-test # 指标公式单元测试 ``` 测试集为eval/testset.json(query→相关chunk_id列表,可参考testset.example.json人工标注);评测报告输出到eval/reports/(含指标表与内联SVG图表)。Windows下也可双击eval/run_eval.ps1一键运行。 > 详细设计、指标定义与报告解读见eval/README.md。 ## 七、CI/CD 流水线由Gitee Webhook触发Jenkins,自动构建并部署全部服务到网关:8080。 1. 拉取代码:git checkout master。 2. 类型检查:cicd/Dockerfile.check镜像内跑pyright(backend/)与vue-tsc --noEmit(frontend/admin/website)。 3. 构建服务镜像:cicd/scripts/build-web.sh经docker compose构建web(三站合一Nginx)与backend镜像并推送镜像仓库。 4. 部署全部服务:scp deploy/docker-compose.prod.yml到服务器,docker compose pull && up -d拉起全部容器,静态资源统一入口http://host:8080/,后端API直连;构建通知邮件经cicd/send-mail.py发送。 关键文件:cicd/Jenkinsfile、cicd/Dockerfile.check、cicd/scripts/build-web.sh、cicd/send-mail.py。 > 完整凭据、环境变量与排查见cicd/README.md。