# rag_edu **Repository Path**: wy11111456/rag_edu ## Basic Information - **Project Name**: rag_edu - **Description**: RagPro 课程练习项目:Redis 缓存 + BM25 检索 + MySQL 回源的问答系统,含 docker 环境与语料资源 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-10-14 - **Last Updated**: 2026-10-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # EduRAG 智能问答系统 融合 **MySQL FAQ(BM25 + Redis 缓存)** 与 **Milvus 向量知识库** 的企业级 RAG 问答服务, 提供 REST 与 SSE 流式接口(保留 WebSocket 兼容通道),支持内网/离线部署。 ## 一、快速开始 ```bash # 1. 安装依赖 pip install -r requirements.txt # 2. 配置环境变量 cp .env.example .env # 编辑 .env,至少填写 OPENAI_API_KEY # 3. 启动服务 python app.py # 或 uvicorn app:app --host 0.0.0.0 --port 8080 # 4. 访问 # http://127.0.0.1:8080/ 对话页面 # http://127.0.0.1:8080/docs Swagger UI # http://127.0.0.1:8080/api/health 健康检查 ``` ### 登录与权限 首次启动会在 MySQL `app_user` 表创建默认管理员: ```text 用户名:admin 密码:Admin@123 ``` 生产环境必须通过 `.env` 的 `AUTH_BOOTSTRAP_PASSWORD` 修改默认密码,并设置随机的 `AUTH_SECRET_KEY`;HTTPS 部署时把 `AUTH_COOKIE_SECURE=true`。 | 角色 | 权限 | | --- | --- | | `guest` | 预留:仅公开页面/健康检查 | | `normal_user` | 问答、本人会话、本人历史、本人统计、本人收藏 | | `vip_user` | 普通用户权限 + 会话总结 | | `admin` | 全量会话/统计/用户数据、会话总结、运维指标 | 登录成功后服务端写入 HttpOnly + SameSite=Lax 的签名 Cookie,前端不保存 token。 普通用户的 history/sessions/search/stats/star 查询都会按 `user_id` 过滤;管理员看全量。 ### 对话页面的操作方式 | 操作 | 说明 | | --- | --- | | `Enter` | 发送问题 | | `Shift + Enter` | 输入框内换行(不发送) | | `↑` / `↓` | 调出历史问题:上键往前翻、下键往后翻 | | 学科过滤 | 下拉选择后只在该学科范围内匹配 FAQ | | 清空会话 | 删除服务端历史并清空页面 | 关于上下键历史导航: - 历史来源是**当前会话的历史提问**(页面打开时从 `/api/history/{session_id}` 载入, 之后再提问会追加到末尾),最多保留最近 100 条。 - 首次按 `↑` 时,输入框里未发送的内容会被**暂存为草稿**;一路按 `↓` 回到最新一条之后, 草稿会自动恢复,不会丢失。 - 输入框是**多行**的:当内容含换行且光标不在开头时,`↑`/`↓` 优先用于在行间移动光标, 不干扰正常编辑。此时若要调历史,先把光标移到开头或清空输入框即可。 命令行入口: ```bash python main.py ``` ## 二、文档索引 | 文档 | 内容 | | --- | --- | | [API.md](API.md) | 接口文档:9 个 REST/WS 接口、事件协议、错误码、调用示例 | | [DEPLOY.md](DEPLOY.md) | 部署说明:镜像构建、推送、服务器部署、运维、故障排查、内网部署 | ## 三、目录结构 ``` rag_edu/ ├── app.py # FastAPI 服务入口(REST + SSE,保留 WebSocket 兼容) ├── main.py # 命令行交互入口 ├── base/ # 配置与基础设施 │ ├── config.py # Pydantic Settings 配置类 │ ├── logger.py # 日志配置 │ └── console.py # 终端编码与文本清洗 ├── qa_system/ # 本地 FAQ 问答 │ ├── qa_service.py # 统一问答服务层(FAQ -> RAG 降级编排) │ ├── qa_search.py # BM25 检索 + Redis 缓存 │ ├── qa_cache.py # Redis 客户端 │ ├── qa_db.py # MySQL 客户端(FAQ + 会话历史) │ └── qa_utils.py # 分词、停用词等工具 ├── rag_system/ # RAG 知识库 │ ├── core/ # 流水线、意图分类、策略选择、向量库 │ ├── document_loaders/ # PDF/DOCX/PPTX/Markdown/图片 加载器 │ ├── text_splitters/ # 语义切分 │ ├── docs/ # 知识库原始文档(不入镜像,运行时挂载) │ └── models/ # 模型权重(不入镜像,运行时挂载) ├── evaluation/ # RAGAS 评估 ├── scripts/ # 训练与测试脚本 ├── docker/ # 编排文件 │ ├── docker-compose.yml # 基础设施:MySQL/Redis/Milvus/etcd/minio/attu │ └── docker-compose.app.yml # 应用服务 ├── res/ # 停用词表(5KB,进镜像) ├── data/ # 业务数据(FAQ CSV、训练集) ├── static/index.html # 内置对话页面 ├── Dockerfile # 应用镜像 ├── .env.example # 环境变量模板(不含密钥) ├── requirements.txt # 运行时依赖 └── requirements-train.txt # 模型微调依赖 ``` ## 四、技术栈 | 层次 | 组件 | | --- | --- | | Web 框架 | FastAPI + Uvicorn | | 本地问答 | rank-bm25 + jieba + Redis 缓存 + MySQL | | 向量检索 | Milvus + BGE-M3(dense + sparse 混合检索)+ BGEReranker 精排 | | 意图分类 | BERT(微调,判断「通用知识」/「专业咨询」) | | 大模型 | DeepSeek(OpenAI 兼容协议,可替换为内网 vLLM/Ollama/Xinference) | | 评估 | RAGAS | | 部署 | Docker + Docker Compose | ## 五、问答链路 ``` 用户问题 │ ├─ 问题清洗(全角转半角、去控制字符) │ ├─ 日常问候判定 ──▶ 命中则返回模板回复(source=系统问候) │ ├─ 本地 FAQ(BM25) │ ├─ Redis 缓存命中 ──▶ 直接返回(毫秒级) │ └─ BM25 分数 >= QA_MIN_SCORE_THRESHOLD(8.0) ──▶ 返回标准答案(source=本地问答库) │ └─ 降级到 RAG(source=RAG知识库) ├─ BERT 意图分类 │ ├─ 通用知识 ──▶ 跳过检索,大模型基于通用知识作答 │ └─ 专业咨询 ──▶ Milvus 混合检索 + Reranker 精排 -> 上下文注入 -> 生成 └─ 任一环节异常 ──▶ 系统兜底(提示联系人工客服) ``` - **RAG 惰性加载**:BGE-M3 / Reranker / BERT 只在首次降级时加载(40~75s), 服务启动无需等待模型,`rag_ready` 初始为 `false` 属正常。 - **初始化失败不重试**:`_rag_init_failed=True` 后进程内不再重试,修复问题后需重启。 ## 六、Docker 部署 ```bash # 1. 启动基础设施(MySQL / Redis / Milvus / etcd / minio / attu) cd docker docker compose -f docker-compose.yml up -d # 2. 构建并启动应用 docker compose -f docker-compose.app.yml up -d --build # 3. 验证 curl http://127.0.0.1:8080/api/health ``` 详见 [DEPLOY.md](DEPLOY.md)。 ## 七、注意事项 ### 7.1 代理环境 若宿主机启用了系统代理但代理端口无进程监听,`httpx` 会读取到无效代理导致大模型调用失败: ``` httpx.ConnectError: [WinError 10061] 由于目标计算机积极拒绝 ``` 解决:启动服务时设置 `NO_PROXY=*`。 ### 7.2 内网/离线 模型权重全部本地化,需设置 `HF_HUB_OFFLINE=1`、`TRANSFORMERS_OFFLINE=1`、`HF_DATASETS_OFFLINE=1`。 唯一外部依赖是 `LLM_BASE_URL`,换成内网 OpenAI 兼容服务即可,代码零改动。 ### 7.3 密钥 `.env` 已被 `.gitignore` 忽略。提交代码前确认 `git status` 里没有 `.env`。 模板见 `.env.example`(不含任何真实密钥)。 ### 7.4 BERT 意图分类的已知行为 当前微调模型把 467 条 FAQ 中约 99% 的问题判为「通用知识」,因此多数 FAQ 未命中问题 不会真正触发知识库检索,而是由大模型直接作答。这是训练数据分布决定的**设计行为**, 不是缺陷。若希望更激进地检索,可调整训练数据后重新微调(见 `scripts/train_generic_router.py`)。 ## 八、评估 ```bash # 构造评估数据集(从知识库父块抽题) python -m evaluation.build_eval_dataset # 运行 RAGAS 评估 python -m evaluation.rag_evaluator ``` 产物: | 文件 | 内容 | | --- | --- | | `evaluation/rag_evaluation_dataset.json` | 评估数据集 | | `evaluation/ragas_evaluation_results.csv` | 逐条指标 | | `evaluation/ragas_evaluation_results.summary.json` | 汇总指标 | 最近一次基于知识库出题的评估结果(6 条样本): | 指标 | 分数 | | --- | --- | | faithfulness | 0.7370 | | answer_relevancy | 0.7556 | | context_precision | 0.8333 | | context_recall | 0.8889 | > 评估须知:`contexts` 必须来自真实检索结果。早期版本曾用「答案冒充上下文」, > 会导致指标虚高,该问题已修复。