- 项目简介
- 当前能力
- 技术栈
- 项目目录结构
- 核心架构
- 配置说明
- 本地开发运行
- Docker 部署
- Ubuntu 22.04 + 1Panel 部署
- 后台控制台使用说明
- 网页对话测试
- 外部接口说明
- RAG 数据库目录说明
- 聊天接口排障与日志
- 维护注意事项
gdou_aichat_rag 是一个基于 Django 的 RAG 问答系统。系统支持通过后台 Web 控制台管理多个独立 RAG 数据库,并对外保持单一聊天接口。
当前版本的核心目标:
后台管理多个 RAG 数据库
↓
后台选择当前启用数据库
↓
外部始终调用同一个 /myapp/chat 接口
↓
系统使用当前启用数据库完成 RAG 问答
保留原有网页对话测试页面:
/myapp/chat_view
该页面用于测试后台当前启用的 RAG 数据库。
- 后台 Web 控制台:
/myapp/console/ - 多个独立 RAG 数据库管理
- 新增 RAG 数据库
- 向已有 RAG 数据库上传 PDF/TXT 数据
- 删除非当前 RAG 数据库
- 设置当前外部接口使用的 RAG 数据库
- 设置大语言模型 API 地址和 API Key
- 设置 DashScope API Key
- 在线修改回答提示词模板
- 设置最大输出 Token 数
- 保留单一外部问答接口:
POST /myapp/chat - 保留网页对话测试页面:
GET /myapp/chat_view - 上传文档统一通过后台控制台完成,不再公开未鉴权上传接口
当前不包含:
- 面向终端用户的业务用户体系
- 多后台账号管理
- Web 中修改后台账号密码
- 流式输出
- 文档级删除
- 前端工程化构建
- 多模型供应商动态切换
- Python 3.11
- Django 4.1.13
- LangChain 0.3.x
- Chroma / langchain-chroma
- DashScope Embedding:
text-embedding-v4 - DashScope Rerank:
gte-rerank-v2 - DeepSeek Chat:
deepseek-chat - MinerU:PDF 解析
- jieba + rank_bm25:中文 BM25 检索
- SQLite:Django 后台配置与元数据存储
app/
├── manage.py
├── api_r.py # 统一 JSON 响应封装
├── Dockerfile
├── requirements.txt
├── server/
│ ├── settings.py # Django 配置、后台账号、多库根目录
│ ├── urls.py
│ ├── wsgi.py
│ └── asgi.py
├── myapp/
│ ├── apps.py
│ ├── config.py # RAG 参数、上传限制、Prompt、固定模型常量
│ ├── document_parser.py # PDF/TXT 内容解析
│ ├── storage.py # 上传校验与保存
│ ├── models.py # RAG 数据库、运行配置、文档记录模型
│ ├── rag.py # SchoolRAG 与 RAGManager
│ ├── views.py # 前台接口与后台控制台视图
│ ├── urls.py # 前台与后台路由
│ ├── migrations/
│ │ ├── __init__.py
│ │ └── 0001_initial.py
│ └── templates/
│ ├── chat.html # 网页对话测试
│ ├── upload.html # 历史上传模板,当前未公开路由,上传以后台控制台为准
│ ├── console_login.html # 后台登录页
│ └── console_dashboard.html # 后台控制台
├── chroma_db/ # 兼容原始版本的默认 Chroma 目录
├── bm25/ # 兼容原始版本的默认 BM25 目录
├── uploads/ # 兼容原始版本的默认上传目录
├── mineru_output/ # 兼容原始版本的默认 MinerU 输出目录
└── rag_databases/ # 新增 RAG 数据库默认根目录
└── <slug>/
├── chroma_db/
├── bm25/
├── uploads/
└── mineru_output/
后台选择目标 RAG 数据库
↓
上传 PDF/TXT
↓
保存到该数据库 uploads/
↓
PDF 使用 MinerU 转 Markdown;TXT 直接读取
↓
MarkdownHeaderTextSplitter 按标题切分
↓
写入该数据库 Chroma
↓
写入该数据库 bm25/docs.json
↓
重建该数据库 Retriever
外部调用 /myapp/chat
↓
RAGManager 读取当前启用数据库
↓
加载或复用对应 SchoolRAG 实例
↓
Chroma similarity k=10
+
BM25 k=10
↓
EnsembleRetriever weights=[0.5, 0.5]
↓
DashScope Rerank gte-rerank-v2 top_n=3
↓
Prompt 拼接上下文
↓
DeepSeek deepseek-chat 生成回答
主要配置位于:
app/server/settings.py
后台账号密码不在 Web 中修改,需要通过配置文件或环境变量设置:
RAG_ADMIN_USERNAME = os.environ.get('RAG_ADMIN_USERNAME', 'admin')
RAG_ADMIN_PASSWORD = os.environ.get('RAG_ADMIN_PASSWORD', '')生产部署时必须设置 RAG_ADMIN_PASSWORD,否则后台无法正常登录。
RAG_DATABASE_ROOT = os.path.join(BASE_DIR, 'rag_databases')新增 RAG 数据库时会在该目录下生成独立目录。
首次迁移会创建一个默认 RAG 数据库,指向原始版本目录:
RAG_PERSIST_DIRECTORY = os.path.join(BASE_DIR, 'chroma_db')
UPLOAD_DIRECTORY = os.path.join(BASE_DIR, 'uploads')
MINERU_OUTPUT_DIRECTORY = os.path.join(BASE_DIR, 'mineru_output')
BM25_PERSIST_DIRECTORY = os.path.join(BASE_DIR, 'bm25')后台控制台中可配置:
- 大语言模型 API 地址
- 大语言模型 API Key
- DashScope API Key
- 回答提示词模板
- 最大输出 Token 数
回答提示词模板会用于最终回答生成,必须保留以下两个占位符:
{question}
{context}
字数限制、回答口吻、功能性约束等可通过提示词模板在线调整;最大输出 Token 数用于控制模型生成上限。
固定不可在后台修改:
- Embedding 模型:
text-embedding-v4 - Rerank 模型:
gte-rerank-v2 - 默认 LLM 类:
ChatDeepSeek - 默认 LLM 模型:
deepseek-chat
进入应用目录:
cd app安装依赖:
pip install -r requirements.txt初始化 Django 数据库:
python manage.py migrate启动开发服务器:
python manage.py runserver 0.0.0.0:8000访问:
- 后台控制台:
http://localhost:8000/myapp/console/ - 网页对话测试:
http://localhost:8000/myapp/chat_view
如果后台密码使用环境变量:
export RAG_ADMIN_USERNAME=admin
export RAG_ADMIN_PASSWORD='your-password'
python manage.py runserver 0.0.0.0:8000Dockerfile 位于:
app/Dockerfile
构建镜像:
cd app
docker build -t gdou-aichat-rag .运行容器:
cd app
mkdir -p data chroma_db bm25 uploads mineru_output rag_databases
docker run -d \
--name gdou-aichat-rag \
-p 8000:8000 \
-e RAG_ADMIN_USERNAME=admin \
-e RAG_ADMIN_PASSWORD='your-password' \
-e SQLITE_NAME=/app/data/db.sqlite3 \
-e CSRF_TRUSTED_ORIGINS='https://rag.example.com' \
-e LOG_LEVEL=INFO \
-v $(pwd)/data:/app/data \
-v $(pwd)/chroma_db:/app/chroma_db \
-v $(pwd)/bm25:/app/bm25 \
-v $(pwd)/uploads:/app/uploads \
-v $(pwd)/mineru_output:/app/mineru_output \
-v $(pwd)/rag_databases:/app/rag_databases \
gdou-aichat-rag如果希望把 SQLite 文件放在持久化目录中,可以通过环境变量指定:
-e SQLITE_NAME=/app/data/db.sqlite3不要在宿主机不存在 db.sqlite3 文件时直接把文件挂载到 /app/db.sqlite3,否则 Docker 可能创建同名目录导致 SQLite 打开失败。
首次运行前需要执行迁移。可以进入容器执行:
docker exec -it gdou-aichat-rag python manage.py migrate也可以在部署命令中覆盖启动命令,让容器启动前自动迁移。下面示例保留同样的持久化挂载:
docker run -d \
--name gdou-aichat-rag \
-p 8000:8000 \
-e RAG_ADMIN_USERNAME=admin \
-e RAG_ADMIN_PASSWORD='your-password' \
-e SQLITE_NAME=/app/data/db.sqlite3 \
-e CSRF_TRUSTED_ORIGINS='https://rag.example.com' \
-e LOG_LEVEL=INFO \
-v $(pwd)/data:/app/data \
-v $(pwd)/chroma_db:/app/chroma_db \
-v $(pwd)/bm25:/app/bm25 \
-v $(pwd)/uploads:/app/uploads \
-v $(pwd)/mineru_output:/app/mineru_output \
-v $(pwd)/rag_databases:/app/rag_databases \
gdou-aichat-rag \
sh -c "python manage.py migrate && gunicorn --bind 0.0.0.0:8000 --timeout 300 server.wsgi:application"生产部署建议挂载持久化目录,至少包括:
/app/data/db.sqlite3,需设置SQLITE_NAME=/app/data/db.sqlite3/app/chroma_db/app/bm25/app/uploads/app/mineru_output/app/rag_databases
以下步骤面向 Ubuntu 22.04 服务器,并使用 1Panel 面板部署。
建议配置:
- Ubuntu 22.04 LTS
- 2 核 CPU 以上
- 4GB 内存以上,PDF 解析较多时建议 8GB+
- 磁盘空间根据上传文档和向量库规模预留
更新系统:
sudo apt update
sudo apt upgrade -y在服务器执行 1Panel 官方安装脚本。请以 1Panel 官方文档为准,通常类似:
curl -sSL https://resource.fit2cloud.com/1panel/package/v2/quick_start.sh -o quick_start.sh
sudo bash quick_start.sh安装完成后登录 1Panel 面板。
在 1Panel 中确认安装:
- Docker
- Docker Compose
- OpenResty / Nginx,若需要域名反向代理
推荐目录:
/opt/gdou_aichat_rag
可以通过以下方式之一上传:
- 1Panel 文件管理上传压缩包后解压;
- 使用 Git 拉取;
- 使用 SFTP 上传。
项目结构应类似:
/opt/gdou_aichat_rag/
├── README.md
└── app/
├── Dockerfile
├── manage.py
└── ...
在服务器上创建目录:
cd /opt/gdou_aichat_rag/app
mkdir -p data chroma_db bm25 uploads mineru_output rag_databases如果已有原始版本数据,将原来的 chroma_db、bm25、uploads、mineru_output 放到 app/ 下对应目录。
在 1Panel 中选择:
容器 -> 编排/Compose -> 创建编排
可使用如下 docker-compose.yml:
version: "3.8"
services:
gdou-aichat-rag:
build:
context: /opt/gdou_aichat_rag/app
dockerfile: Dockerfile
container_name: gdou-aichat-rag
restart: always
ports:
- "8000:8000"
environment:
RAG_ADMIN_USERNAME: "admin"
RAG_ADMIN_PASSWORD: "请修改为强密码"
SQLITE_NAME: "/app/data/db.sqlite3"
CSRF_TRUSTED_ORIGINS: "https://rag.example.com"
LOG_LEVEL: "INFO"
volumes:
- /opt/gdou_aichat_rag/app/data:/app/data
- /opt/gdou_aichat_rag/app/chroma_db:/app/chroma_db
- /opt/gdou_aichat_rag/app/bm25:/app/bm25
- /opt/gdou_aichat_rag/app/uploads:/app/uploads
- /opt/gdou_aichat_rag/app/mineru_output:/app/mineru_output
- /opt/gdou_aichat_rag/app/rag_databases:/app/rag_databases
command: >
sh -c "python manage.py migrate && gunicorn --bind 0.0.0.0:8000 --timeout 300 server.wsgi:application"保存并启动编排。
注意:
RAG_ADMIN_PASSWORD必须修改为强密码。
如果需要通过域名访问,可在 1Panel 网站/OpenResty 中创建反向代理:
重要:通过 HTTPS 域名访问后台时,必须把完整来源写入
CSRF_TRUSTED_ORIGINS,例如https://rag.example.com。多个来源用英文逗号分隔,例如https://rag.example.com,https://www.rag.example.com。否则登录等后台 POST 表单可能出现CSRF verification failed。
- 域名:例如
rag.example.com - 代理地址:
http://127.0.0.1:8000
常见 Nginx 配置示例:
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 300s;
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
}PDF 解析和入库可能耗时较长,建议代理超时时间不低于 300 秒。
访问:
http://服务器IP:8000/myapp/console/
或域名:
https://rag.example.com/myapp/console/
使用 RAG_ADMIN_USERNAME 和 RAG_ADMIN_PASSWORD 登录。
登录后台后:
- 在“模型API与回答配置”中填写大语言模型 API 地址。
- DeepSeek 默认:
https://api.deepseek.com
- DeepSeek 默认:
- 填写大语言模型 API Key。
- 填写 DashScope API Key。
- 按需调整回答提示词模板和最大输出 Token 数。
- 保存配置。
- 如已有默认知识库,可直接打开
/myapp/chat_view测试。 - 如需新知识库,先创建数据库,再上传文档,最后设为当前数据库。
后台地址:
/myapp/console/
账号密码来自配置:
RAG_ADMIN_USERNAME
RAG_ADMIN_PASSWORD
在“新增RAG数据库”区域填写:
- 数据库名称
- 数据库标识 slug
- 描述
slug 只能包含:
字母、数字、下划线、短横线
创建后会生成独立目录。
上传入口只在后台控制台中提供,旧的 /myapp/upload 与 /myapp/upload_view 不再作为公开路由使用。
在“RAG数据库列表”中,每个数据库都有上传入口。
支持:
.pdf.txt
限制:
- 最大 10MB
上传成功后,系统会将数据写入该数据库对应的 Chroma 和 BM25。
点击“设为当前”,即可让外部接口 /myapp/chat 和测试页面 /myapp/chat_view 使用该数据库。
可以删除非当前数据库。
当前限制:
- 不能删除当前正在使用的数据库;
- 不能删除最后一个数据库;
- 不能删除默认兼容数据库
default。
后台可设置:
- 大语言模型 API 地址
- 大语言模型 API Key
- DashScope API Key
- 回答提示词模板
- 最大输出 Token 数
Key 输入框留空表示保持原值不变。提示词模板必须保留 {question} 和 {context} 两个占位符;字数限制、回答口吻、功能性约束等可在提示词模板中调整。保存后会清理 RAG 缓存,下一次问答使用最新配置。
访问:
/myapp/chat_view
该页面仍然调用:
POST /myapp/chat
测试对象是后台当前启用的 RAG 数据库。
POST /myapp/chat
Content-Type: application/json请求体:
{
"question": "中华白海豚是什么?"
}成功响应:
{
"code": 0,
"msg": "对话成功",
"data": "..."
}外部调用方不需要传数据库 ID。系统会自动使用后台当前启用的 RAG 数据库。
默认兼容库继续使用原始目录:
app/chroma_db
app/bm25
app/uploads
app/mineru_output
后台新增数据库使用:
app/rag_databases/<slug>/chroma_db
app/rag_databases/<slug>/bm25
app/rag_databases/<slug>/uploads
app/rag_databases/<slug>/mineru_output
其中:
chroma_db:Chroma 向量库bm25/docs.json:BM25 文档索引uploads:上传原始文件mineru_output:PDF 解析生成的 Markdown 和资源
网页对话测试页 /myapp/chat_view 调用的是同一个外部接口:
POST /myapp/chat
如果页面显示请求失败或后端返回错误,优先检查浏览器页面中显示的详细错误,以及容器日志。
Docker 部署:
docker logs -f gdou-aichat-rag1Panel 部署:
容器 -> gdou-aichat-rag -> 日志
后端聊天接口会输出类似日志:
chat_request_start ...
chat_runtime_config database_id=... database_slug=... llm_key_configured=True dashscope_key_configured=True
chat_request_success ...
如果失败,会输出:
chat_request_failed ...
并带有 Python 异常类型和错误信息。
除了 DeepSeek / DashScope API Key 填写错误外,还应检查:
-
是否已执行数据库迁移:
python manage.py migrate
-
后台是否已设置“当前使用数据库”;
-
当前数据库是否已经上传并成功入库文档;
-
DashScope API Key 是否已配置,因为查询时 Rerank 也会使用 DashScope;如果 Rerank 返回 4xx/5xx,容器日志会输出
dashscope_rerank_http_error和响应正文; -
容器是否挂载了正确的
db.sqlite3、chroma_db、bm25、rag_databases目录; -
使用 HTTPS 域名访问后台时是否设置了
CSRF_TRUSTED_ORIGINS; -
反向代理是否设置了足够长的超时时间,建议不少于 300 秒。
可以用 curl 直接测试:
curl -i -X POST http://服务器IP:8000/myapp/chat \
-H "Content-Type: application/json" \
-d '{"question":"测试问题"}'正常情况下返回 JSON:
{
"code": 0,
"msg": "对话成功",
"data": "..."
}如果失败,也会尽量返回 JSON,例如:
{
"code": 1,
"msg": "聊天请求处理失败:..."
}可通过环境变量设置日志级别:
LOG_LEVEL=INFO需要更详细日志时可改为:
LOG_LEVEL=DEBUGdb.sqlite3保存后台配置、当前数据库、API key 和文档记录,生产环境应限制文件权限并做好备份。gte-rerank-v2通过项目内自定义 HTTP 调用接入,失败时会记录 DashScope HTTP 状态码和响应正文,并回退到原始召回结果继续问答。- Embedding 模型固定为
text-embedding-v4,不要直接修改,否则可能影响已有 Chroma 数据兼容性。 - 删除数据库会删除其物理目录;当前数据库、最后一个数据库和默认兼容数据库不允许删除。
- PDF 解析和入库可能耗时较长,反向代理和 Gunicorn timeout 建议不少于 300 秒。
- 当前后台为轻量 session 登录,不提供 Web 修改后台密码功能。
- 若 DeepSeek 或 DashScope API Key 未配置,聊天或入库链路会因外部服务不可用而失败。
- 不要将包含 API key 的
db.sqlite3提交到代码仓库。