面向生产的多租户 RAG 平台,支持异步文档摄取、混合检索、可验证引用、RAGAS 评测与完整可观测性。
RAG System 是一个基于 FastAPI、PostgreSQL、MinIO 和 Milvus 构建的多租户检索增强生成平台。项目将文档摄取、版本激活、向量与全文检索、重排、答案生成、引用校验、离线评测和生产运维拆分为清晰模块,同时通过租户级资源路由和知识库 ACL 提供纵深隔离。
本项目适合用作:
- 企业知识库与内部问答服务;
- 多租户 RAG SaaS 后端;
- 可评测、可追踪的 RAG 工程基线;
- 自托管模型端点与私有数据基础设施的集成层。
项目提供生产导向的工程能力,但正式部署前仍应根据实际流量、模型、数据敏感度和基础设施完成容量规划、安全审查与评测基线校准。
- 租户、用户、角色、直接权限和知识库 ACL;
- 带作用域和知识库限制的 API Key;
- 每个租户使用独立 Milvus Collection Alias;
- PostgreSQL 与 Milvus 查询均保留
tenant_id和knowledge_base_id过滤; - 平台控制面与租户业务 API 使用不同凭证。
- PostgreSQL 持久化任务队列;
FOR UPDATE SKIP LOCKED并发领取任务;- 独立
rag-worker进程; - 文档版本、暂存、校验和原子激活;
- 幂等上传、失败重试和 reconciliation 基础;
- 支持 TXT、Markdown、PDF、DOCX、CSV、XLS/XLSX 和常见图片格式;
- PDF 页级结构、扫描件 OCR fallback、表格与标题路径保留;
- 基于 token 的稳定切分、重叠、内容哈希和稳定 context key。
- 向量检索、PostgreSQL 全文检索和混合检索;
- 可配置加权 RRF、候选数、分数阈值和单文档结果上限;
- Query Rewrite、Rerank 和答案生成;
- Milvus V2 metadata 前置过滤;
- Token Budget 上下文构建;
- 结构化答案、拒答状态和服务端 Citation ID 校验;
- 每个阶段保留独立分数、耗时和检索方法。
- Hit Rate、Precision、Recall、MRR、nDCG 等确定性指标;
- Filter Accuracy、租户泄漏、知识库泄漏、重复上下文和拒答准确率;
- RAGAS Faithfulness、Answer Relevancy、Context Precision、Context Recall 和 Factual Correctness;
- Golden、Smoke 和 Adversarial 数据集;
- Baseline 比较和 CI 质量门禁;
- Prometheus 指标、OpenTelemetry spans、Query / Retrieval 日志;
/health/live、/health/ready和/metrics。
Client
│
▼
FastAPI API
├── 身份认证 / ACL
├── 文档与任务 API
├── 检索与生成 API
└── Health / Metrics
│
├── PostgreSQL
│ ├── 租户与权限
│ ├── 文档、版本与 Chunk
│ ├── 摄取任务队列
│ ├── 全文检索
│ └── Query / Retrieval / Audit Logs
│
├── MinIO / S3
│ ├── 原始文件
│ └── 解析结果
│
├── Milvus
│ └── 租户级向量 Collection 与 Alias
│
└── 远程模型端点
├── Embedding
├── Rerank
├── Query Rewrite
├── LLM
└── OCR
rag-worker
└── 解析 → 切分 → Embedding → 索引 → 校验 → 激活
系统包含三条相互连接的主流程:文档摄取、检索问答和质量评测。
- 客户端使用租户 API Key 上传文件,API 完成身份认证、知识库 ACL 和上传限制校验。
- 原始文件写入 MinIO,PostgreSQL 创建文档版本和持久化摄取任务,接口返回
202 Accepted与job_id。 rag-worker使用FOR UPDATE SKIP LOCKED领取任务,并依次执行解析、OCR、清洗、结构恢复和 token-aware 切分。- Worker 调用 Embedding 服务,将 Chunk 元数据和全文检索字段写入 PostgreSQL,并将向量以暂存状态写入 Milvus。
- 系统校验 Chunk 与向量数量、版本和索引状态;校验成功后激活新版本并失活旧版本。
- 可重试错误进入
failed_retryable,终止错误进入failed_terminal;对账任务用于发现并修复跨 PostgreSQL、MinIO 和 Milvus 的残留或缺失数据。
- 客户端提交问题、知识库 ID、检索选项和过滤条件,API 再次执行租户与知识库授权。
- 系统解析最终检索配置,并可选执行 Query Rewrite。
- Hybrid 模式并行运行 Milvus 向量检索和 PostgreSQL 全文检索;两路结果通过加权 RRF 融合。
- 候选结果经过 PostgreSQL 水合、metadata 过滤、阈值过滤、去重、单文档数量限制和 Rerank。
- 系统按模型上下文窗口构建 token-budgeted context,并把文档内容作为不可信数据传给 LLM。
- LLM 返回结构化答案和实际使用的 Chunk ID;服务端验证所有 Citation ID 必须来自本次上下文。
- 引用校验通过后返回答案、引用、阶段分数、耗时、
query_id与trace_id;上下文不足时返回明确拒答状态。
- Query、Retrieval、模型版本、耗时和 token 使用量写入日志与监控系统。
rag-eval使用 Smoke、Golden 和 Adversarial 数据集调用真实检索 API。- 系统计算确定性指标与可选 RAGAS 指标,并和主分支 baseline 比较。
- 租户泄漏、知识库泄漏、未知引用或显著质量回退会触发质量门禁失败。
- 评测结果用于调整解析、切分、检索权重、阈值、Rerank、Prompt 和模型版本。
flowchart TD
U[租户客户端] --> A[FastAPI API<br/>认证、ACL、限流与输入校验]
subgraph INGEST[文档摄取与版本激活]
A -->|上传文档| I1[写入 MinIO 原始文件]
I1 --> I2[PostgreSQL 创建文档版本<br/>与持久化摄取任务]
I2 -->|202 + job_id| U
I2 --> I3[rag-worker 领取任务<br/>FOR UPDATE SKIP LOCKED]
I3 --> I4[解析 / OCR / 清洗<br/>恢复页面、标题和表格结构]
I4 --> I5[Token-aware 切分<br/>稳定 Chunk ID 与 Context Key]
I5 --> I6[Embedding 批处理]
I6 --> I7[PostgreSQL 写入暂存 Chunk<br/>全文检索与 Metadata]
I6 --> I8[Milvus 写入暂存向量]
I7 --> I9{Chunk、向量与版本校验}
I8 --> I9
I9 -->|通过| I10[激活新版本<br/>失活旧版本]
I9 -->|可重试失败| I11[failed_retryable<br/>退避后重试]
I9 -->|终止失败| I12[failed_terminal]
I11 --> I3
I10 --> I13[Reconciliation 对账与清理]
I12 --> I13
end
subgraph QUERY[检索、生成与可信引用]
A -->|问题 + 检索选项 + Filters| Q1[解析 Effective Options]
Q1 --> Q2{Query Rewrite?}
Q2 -->|是| Q3[改写查询]
Q2 -->|否| Q4[使用原始查询]
Q3 --> Q5[并行检索]
Q4 --> Q5
Q5 --> Q6[Milvus 向量检索<br/>租户、知识库与 Metadata 前置过滤]
Q5 --> Q7[PostgreSQL 全文检索]
Q6 --> Q8[加权 RRF 融合]
Q7 --> Q8
Q8 --> Q9[水合、阈值、去重<br/>单文档限制与 Rerank]
Q9 --> Q10{有足够上下文?}
Q10 -->|否| Q11[返回 insufficient_context]
Q10 -->|是| Q12[按 Token Budget 构建 Context]
Q12 --> Q13[LLM 生成结构化答案<br/>与 cited_chunk_ids]
Q13 --> Q14{Citation ID 全部有效?}
Q14 -->|否| Q15[生成校验失败<br/>不返回伪造引用]
Q14 -->|是| Q16[返回答案、引用、分数<br/>query_id 与 trace_id]
end
subgraph EVAL[可观测性与评测闭环]
Q11 --> E1[Query / Retrieval Logs<br/>Metrics / Traces]
Q15 --> E1
Q16 --> E1
I10 --> E1
E2[Smoke / Golden / Adversarial 数据集] --> E3[rag-eval 调用真实 API]
E3 --> E4[确定性指标 + RAGAS]
E4 --> E5{Baseline 与硬门禁}
E5 -->|通过| E6[允许发布或继续部署]
E5 -->|失败| E7[阻止回退并输出失败样本]
E7 --> E8[调整解析、切分、检索参数<br/>Prompt 与模型版本]
E8 --> E2
end
| 层级 | 技术 |
|---|---|
| API | FastAPI、Pydantic v2、Uvicorn |
| 数据库 | PostgreSQL 16、SQLAlchemy Async、Alembic |
| 对象存储 | MinIO / S3-compatible storage |
| 向量数据库 | Milvus |
| 检索 | Milvus ANN、PostgreSQL Full-Text Search、Weighted RRF |
| 模型协议 | OpenAI-compatible / 自定义 HTTP endpoints |
| 评测 | RAGAS、内置确定性指标 |
| 可观测性 | Prometheus、OpenTelemetry |
| 测试与质量 | Pytest、Ruff、Bandit、pip-audit、CycloneDX |
git clone https://github.com/ACBBZ/rag-system.git
cd rag-system
python -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e '.[dev]'Windows PowerShell 激活环境:
.venv\Scripts\Activate.ps1cp .env.example .env至少需要配置:
POSTGRES_DSN;MINIO_*;MILVUS_*;API_KEY_PEPPER和PLATFORM_API_KEY;- 已启用能力对应的 Embedding、Rerank、Rewrite、LLM 与 OCR 端点。
真实密钥不得提交到 Git 仓库。API_KEY_PEPPER 应使用至少 32 字节的随机值,并在密钥管理系统中长期保存。
docker compose up -d默认会启动 PostgreSQL、MinIO 和 Milvus。MinIO Console 默认位于 http://localhost:9001。
alembic upgrade head当前迁移链包含租户权限、向量资源、全文检索、异步摄取、检索 V3 和可观测性数据结构。
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000- OpenAPI:
http://localhost:8000/docs - Liveness:
http://localhost:8000/health/live - Readiness:
http://localhost:8000/health/ready - Metrics:
http://localhost:8000/metrics
在另一个终端运行:
rag-workerAPI 只负责接收文件并创建持久化任务;解析、切分、Embedding、索引和版本激活由 Worker 完成。
所有租户业务 API 使用:
Authorization: Bearer <tenant-api-key>平台控制面使用独立的 PLATFORM_API_KEY。
POST /v1/platform/tenants
GET /v1/platform/tenants/{tenant_id}/vector-resource
POST /v1/platform/tenants/{tenant_id}/vector-resource/retry
POST /v1/users
PATCH /v1/users/{user_id}/role
PUT /v1/users/{user_id}/scope-grants
DELETE /v1/users/{user_id}/scope-grants/{permission}
POST /v1/api-keys
DELETE /v1/api-keys/{api_key_id}
POST /v1/knowledge-bases
PUT /v1/knowledge-bases/{knowledge_base_id}/members/{user_id}
POST /v1/documents/embed
PATCH /v1/documents/{document_id}
DELETE /v1/documents/{document_id}/purge
GET /v1/ingestion-jobs/{job_id}
POST /v1/ingestion-jobs/{job_id}/retry
上传接口支持 Idempotency-Key,成功入队后返回 202 Accepted。
POST /v1/retrieval/search
示例:
curl -X POST http://localhost:8000/v1/retrieval/search \
-H "Authorization: Bearer $RAG_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"knowledge_base_id": "kb_example",
"query": "员工每年有多少天带薪年假?",
"options": {
"retrieval_mode": "hybrid",
"query_rewrite": true,
"rerank": true,
"agent_search": true,
"top_k": 30,
"final_k": 6
},
"filters": {
"metadata": {"department": "hr"}
}
}'支持的检索模式:
vector:仅 Milvus 向量检索;full_text:仅 PostgreSQL 全文检索;hybrid:两路并行检索并使用加权 RRF 融合;auto:根据请求和环境默认值解析实际模式。
响应包含 trace_id、effective_options、阶段耗时、Chunk 分数、答案状态和经过验证的引用。
安装评测依赖:
python -m pip install -e '.[eval]'运行确定性评测:
rag-eval \
--dataset evals/datasets/golden.jsonl \
--output evals/reports/results.jsonl \
--summary evals/reports/summary.json \
--baseline evals/baselines/main.json启用 RAGAS:
rag-eval \
--dataset evals/datasets/golden.jsonl \
--output evals/reports/results.jsonl \
--summary evals/reports/summary.json \
--baseline evals/baselines/main.json \
--ragas使用前需要将示例数据集中的知识库、参考答案和稳定 context key 替换为实际评测 Fixture。
ruff check .
pytest -v迁移回归:
alembic upgrade head
alembic downgrade 0004_retrieval_v2
alembic upgrade head安全工具:
python -m pip install -e '.[security]'
bandit -c pyproject.toml -r app rag
pip-audit负载测试:
python -m pip install -e '.[load]'
locust -f load/locustfile.py构建 API 镜像:
docker build -t rag-system:latest .生产部署中 API 与 rag-worker 应独立运行和扩缩容,并共享 PostgreSQL、MinIO、Milvus 和模型端点配置。
- 不要将生产密钥写入
.env.example、日志、Issue 或提交记录; - 上传文件应在网关和应用层同时限制大小;
- 对外部署时应启用 TLS、限流、审计、Secret Manager 和网络隔离;
- 文档内容按不可信输入处理,生成链路会校验模型返回的 Citation ID;
- 对高敏感数据部署前,应根据组织要求增加恶意文件扫描、数据保留和删除策略。
发现安全问题时,请避免在公开 Issue 中披露敏感细节,并优先通过仓库所有者提供的私密渠道报告。
欢迎提交 Issue 和改进建议。提交代码前请确保:
ruff check .
pytest -v较大的功能改动应同时提供迁移策略、失败恢复方案、测试以及评测影响说明。
本项目基于 Apache License 2.0 开源。