Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,38 @@ DASHSCOPE_API_KEY=replace-me
EMBEDDING_MODEL=text-embedding-v4
EMBEDDING_DIMENSION=1024
LLM_MODEL=qwen-plus
OCR_MODEL=qwen3.5-ocr
OCR_MAX_IMAGE_BYTES=6291456
OCR_MAX_OUTPUT_TOKENS=4096
VISION_MODEL=qwen3-vl-flash
VISION_MAX_IMAGE_BYTES=6291456
VISION_MAX_OUTPUT_TOKENS=1536

# Background ingestion and token-aware chunking
INGESTION_JOB_MAX_ATTEMPTS=3
WORKER_POLL_INTERVAL_SECONDS=1
WORKER_LEASE_SECONDS=900
WORKER_HEARTBEAT_SECONDS=30
WORKER_RETRY_DELAY_SECONDS=10
CHUNK_MAX_TOKENS=512
CHUNK_OVERLAP_TOKENS=64
CHUNK_TOKENIZER=cl100k_base

# Local Docling PDF layout/table inference; artifacts path is optional.
PDF_NATIVE_TEXT_THRESHOLD=20
# 低文字页还需满足大图覆盖率才判定为扫描页,避免图片/题注页误走纯 OCR。
PDF_SCAN_IMAGE_COVERAGE_THRESHOLD=0.65
# 扫描页 OCR 少于该字符数时追加 Vision,以保留图形和箭头关系;设为 0 可关闭。
PDF_SCAN_VISION_TEXT_THRESHOLD=300
PDF_RENDER_SCALE=2.0
PDF_VISION_CONCURRENCY=2
PDF_MAX_PICTURES=20
PDF_MIN_PICTURE_PIXELS=10000
DOCLING_DEVICE=cpu
DOCLING_NUM_THREADS=4
DOCLING_TIMEOUT_SECONDS=600
DOCLING_IMAGES_SCALE=2.0
# DOCLING_ARTIFACTS_PATH=/models/docling

# Local Docker Compose defaults
DATABASE_URL=postgresql+asyncpg://ultimate_rag:ultimate_rag@localhost:5432/ultimate_rag
Expand Down
56 changes: 56 additions & 0 deletions .github/workflows/deploy-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# 构建 VitePress 文档站点并发布到 GitHub Pages。
#
# 触发条件:
# - push 到 V2 分支且涉及 apps/docs/ 下文件变化
# - 手动 workflow_dispatch(兜底,可在任意分支构建当前内容)
#
# 站点地址:https://leonyangdev.github.io/UltimateRAG/
name: Deploy Docs to GitHub Pages

on:
push:
branches: [V2]
paths: ['apps/docs/**']
workflow_dispatch:

# 发布到 Pages 需要 id-token 与 pages 写权限;GitHub Actions 是 Pages 的唯一构建源。
permissions:
contents: read
pages: write
id-token: write

# 同一时间只保留一次发布,避免多次提交时并发部署互相覆盖。
concurrency:
group: pages
cancel-in-progress: true

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: apps/docs/package-lock.json
- name: Install dependencies
working-directory: apps/docs
run: npm ci
- name: Build VitePress site
working-directory: apps/docs
run: npm run docs:build
- uses: actions/configure-pages@v5
- uses: actions/upload-pages-artifact@v3
with:
path: apps/docs/.vitepress/dist

deploy:
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- id: deployment
uses: actions/deploy-pages@v4
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ htmlcov/
apps/web/.next/
apps/web/node_modules/
apps/docs/node_modules/
apps/docs/.vitepress/cache/
apps/docs/.vitepress/dist/
apps/web/out/
*.tsbuildinfo
.idea/
.vscode/

.DS_Store
10 changes: 9 additions & 1 deletion Dockerfile.api
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,20 @@ FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim
WORKDIR /app
ENV UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy PATH="/app/.venv/bin:$PATH"

# Docling 的 OpenCV 运行时需要基础图形/线程动态库;它们只用于后台 PDF 推理,不启动 GUI。
RUN apt-get update \
&& apt-get install -y --no-install-recommends libgl1 libglib2.0-0 \
&& rm -rf /var/lib/apt/lists/*

COPY pyproject.toml uv.lock README.md ./
# 依赖层不安装本项目本身,因此普通源码修改可以复用包含 Docling/Torch 的大体积缓存层。
RUN --mount=type=cache,target=/root/.cache/uv uv sync --frozen --no-dev --no-install-project

COPY src ./src
COPY apps/api ./apps/api
COPY alembic ./alembic
COPY alembic.ini ./
# BuildKit 缓存 uv 下载目录;源码变化仍会重装本项目,但不会反复下载大型二进制依赖
# 第二次同步只构建当前项目;锁文件依赖已在上一层安装,源码迭代无需重复编译整个 venv
RUN --mount=type=cache,target=/root/.cache/uv uv sync --frozen --no-dev

EXPOSE 8000
Expand Down
113 changes: 85 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
# UltimateRAG

一个从最小可用 RAG 持续演进为企业级知识平台的学习型工程。当前仓库实现 **V1.0 · Naive RAG**:
它既能作为 RAG 全链路学习项目,也保留了真实企业系统需要的数据边界、失败状态、可替换端口和可测试性。
一个从最小可用 RAG 持续演进为企业级知识平台的学习型工程。当前仓库实现
**V2.0 · Document Intelligence**:在保留 V1 可运行 RAG 闭环的基础上,把多种原始格式统一为
可追溯的文档领域模型,使新增 Parser 不需要修改 RAG 主流程。

## V1 能做什么
## V2 能做什么

用户可以在 Web 中完成以下闭环:

1. 创建知识库
2. 上传 UTF-8 Markdown
3. 查看文档从 `PENDING` 到 `READY` 的处理结果
4. 使用 Milvus Dense Retrieval 独立调试召回内容和分数
5. 使用阿里云百炼模型进行知识库问答
6. 查看答案引用的文档、章节和 Chunk
7. 删除文档或知识库,并同步清理三类存储

V1 明确不包含 PDF、OCR、混合检索、Reranker、Agent、ACL、异步任务和 RAGOps;这些属于后续版本。
2. 上传 Markdown、PDF、DOCX、XLSX、PPTX、HTML 或常见图片
3. 上传在文件与任务可靠落库后立即返回,由独立 Worker 后台处理
4. 使用本地 Docling 恢复 PDF 分栏顺序、标题、表格、图片区域和 BBox,扫描页融合百炼 OCR/Vision
5. 对独立图片融合精确文字与箭头、流程、嵌套关系,并清理 OCR 伪表格噪声
6. 前端自动刷新文档从 `PENDING` 到 `READY/FAILED` 的状态和实际 Parser
7. 使用 Milvus Dense Retrieval 独立调试召回内容和分数
8. 使用阿里云百炼模型进行知识库问答
9. 查看答案引用的章节、PDF 页码/BBox、Excel 区域或 PPT 幻灯片
10. 删除文档或知识库,并同步清理三类存储

V2 明确不包含混合检索、Reranker、Agent、ACL、DLQ 控制台和 RAGOps;这些属于后续版本。

## 架构

Expand All @@ -24,16 +28,19 @@ Next.js Web
FastAPI Interface
Application Services
├── Ingestion: Parse → Chunk → Embed → Index
└── RAG: Query Embed → Retrieve → Context → Generate → Citation
├── Upload → MinIO + PostgreSQL Job → 202
└── RAG Application → Retrieve → Context → Generate → Citation

PostgreSQL Job
Background Worker → Parse → Chunk → Embed → Index
Domain Ports
├── DocumentParser → MarkdownParser
├── Chunker → StructureAwareMarkdownChunker
├── DocumentParser → Markdown / PDF / Office / HTML / Image Intelligence
├── OCRClient → BailianOCRClient(扫描页/图片文字)
├── VisionClient → BailianVisionClient(图表/架构图语义)
├── Chunker → StructureAwareChunker(结构 + Token + 类型)
├── Embedder → BailianEmbedder
├── VectorStore → MilvusVectorStore
├── ObjectStorage → MinioObjectStorage
Expand All @@ -47,21 +54,26 @@ Domain Ports

- Domain 不依赖 FastAPI、SQLAlchemy、Milvus、OpenAI SDK 或 LangChain
- PostgreSQL 保存知识库、文档状态和 Chunk 元数据
- MinIO 保存原始 Markdown,且对象键由系统生成
- MinIO 保存所有原始文件,且对象键由系统生成
- Milvus 只保存可重建向量索引,不作为业务事实数据源
- 文档仅在 Parse、Chunk、Embedding、Index 全部成功后进入 `READY`
- Worker 使用 PostgreSQL 租约、心跳和有限重试,进程重启不会丢失上传任务
- 知识库内容按不可信输入处理,不能覆盖系统 Prompt

详细设计见 [V1 实现说明](docs/3.v1_implementation.md)。
详细设计见 [V2 实现说明](docs/4.v2_implementation.md),V1 的基础闭环见
[V1 实现说明](docs/3.v1_implementation.md)。

## 技术栈

- Python 3.12、FastAPI、Pydantic v2
- Docling Layout/TableFormer、PDFium、tiktoken
- SQLAlchemy 2、Alembic、PostgreSQL 16
- MinIO、Milvus 2.5、Attu
- 阿里云百炼 OpenAI 兼容 API
- Embedding 默认 `text-embedding-v4`,1024 维
- LLM 默认 `qwen-plus`
- OCR 默认 `qwen3.5-ocr`
- PDF/独立图片理解默认 `qwen3-vl-flash`
- Next.js 16、React 19、TypeScript、Tailwind CSS 4、shadcn/ui、AI SDK
- uv、pytest、Ruff、Mypy

Expand All @@ -79,6 +91,12 @@ DASHSCOPE_API_KEY=你的API-Key
EMBEDDING_MODEL=text-embedding-v4
EMBEDDING_DIMENSION=1024
LLM_MODEL=qwen-plus
OCR_MODEL=qwen3.5-ocr
OCR_MAX_IMAGE_BYTES=6291456
OCR_MAX_OUTPUT_TOKENS=4096
VISION_MODEL=qwen3-vl-flash
VISION_MAX_IMAGE_BYTES=6291456
VISION_MAX_OUTPUT_TOKENS=1536

# 可选;留空时浏览器自动访问当前页面主机的 8000 端口
NEXT_PUBLIC_API_URL=
Expand All @@ -98,8 +116,31 @@ docker compose up -d --build
```bash
docker compose ps
docker compose logs -f api
docker compose logs -f worker
```

第一次处理文字型 PDF 时,Worker 会把 Docling Layout/TableFormer 模型下载到持久化
`docling_cache` Volume。希望在离线验收前预热模型时可执行:

```bash
docker compose run --rm worker docling-tools models download layout tableformer
```

扫描 PDF 不依赖 Docling OCR,而是按页调用 `.env` 中的百炼 OCR;低文字页还必须存在覆盖大部分
页面的栅格图才判为扫描页,避免图文页错误退化。稀疏 OCR 页会补充 Vision 关系理解。文字型 PDF
的版面与表格推理在 Worker 本地完成。默认锁文件从 PyTorch 官方 CPU Index 安装 `torch/torchvision`,避免本地 Docker
镜像误装数 GB CUDA 依赖。GPU 部署应维护独立的 CUDA 镜像/锁定策略,而不是直接修改运行时设备名。
生产环境应为 Worker 单独配置 CPU/内存与副本数。

仓库 `data/` 中的真实图片与论文 PDF 可执行专项验收(会真实产生少量百炼用量):

```bash
uv run python scripts/smoke_v2_data.py --api-url http://localhost:8000
```

脚本断言上传立即返回、后台最终 `READY`、图片关系可召回、PDF Table 2 续块带完整多级表头,
并校验页码/BBox;默认只删除脚本自己创建的临时知识库。

### 3. 打开服务

| 服务 | 地址 | 用途 |
Expand Down Expand Up @@ -196,12 +237,16 @@ POST /api/chat/stream

## 文档处理状态

上传接口返回 `202 Accepted` 和 `PENDING` 文档,不等待解析。Worker 使用以下状态推进:

```text
PENDING → PARSING → CHUNKING → EMBEDDING → INDEXING → READY
└→ FAILED(任一处理阶段失败)
└── 临时故障有限重试 任一终态错误 → FAILED
```

失败文档保留原文件与错误状态,方便定位问题和未来重建。V1 是同步管线,因此上传请求会等待处理完成。
前端仅在存在非终态文档时每两秒自动刷新。失败文档保留原文件、Chunk 事实与可操作错误;Milvus
半成品会清理,检索还会按 PostgreSQL `READY` 状态二次过滤。

## 验证

Expand All @@ -218,16 +263,23 @@ npm run build
npm audit
```

固定 Smoke Test 文档位于 `tests/fixtures/rag.md`,推荐问题是“BGE-M3 是什么?”。
单元测试会在内存中生成各类格式,避免提交二进制 Fixture。固定 Markdown Smoke Test 文档位于
`tests/fixtures/rag.md`,推荐问题是“BGE-M3 是什么?”。

启动 Docker 全栈后,执行真实 PostgreSQL、MinIO、Milvus 和百炼闭环验收:

```bash
uv run python scripts/smoke_v1.py --api-url http://localhost:8000
```

脚本会创建临时知识库、上传 Fixture、验证文档 `READY`、检索命中、流式答案和 Citation,
最后删除临时知识库及其跨存储资源。
V1 脚本保留用于回归。V2 全格式验收使用:

```bash
uv run python scripts/smoke_v2.py --api-url http://localhost:8000
```

V2 脚本会动态生成全部支持格式,先验证上传立即返回 `202/PENDING`,再轮询 Worker 到 `READY`,
最后验证来源位置、检索、流式答案和 Citation,并删除临时知识库及其跨存储资源。

## 目录

Expand All @@ -236,7 +288,11 @@ apps/web/ Next.js Web
apps/api/ FastAPI 应用
src/ultimate_rag/domain/ 领域模型与端口
src/ultimate_rag/application/ 显式业务工作流
src/ultimate_rag/parsers/ Markdown 解析与注册表
src/ultimate_rag/parsers/ Markdown / PDF / Office / HTML / Image 解析与注册表
src/ultimate_rag/worker.py PostgreSQL 持久化任务 Worker
src/ultimate_rag/runtime.py API/Worker 共用依赖装配
src/ultimate_rag/vision/ 百炼图片语义理解适配器
src/ultimate_rag/ocr/ 百炼 OCR 适配器
src/ultimate_rag/chunkers/ 结构感知切块
src/ultimate_rag/embeddings/ 百炼向量适配器
src/ultimate_rag/vectorstores/ Milvus 适配器
Expand All @@ -250,9 +306,10 @@ docs/ 产品、架构与实现文档

## 安全提醒

- 上传文件必须是 UTF-8 Markdown,最大 10 MB
- 上传文件最大 10 MB;Markdown/HTML 必须使用 UTF-8,Office 会检查 ZIP Bomb 风险
- 图片提交模型前会验证/压缩;PDF 最多 500 页,扫描页按页 OCR,附图数量和并发均有界
- 用户文件名不参与本地路径或对象键构造
- `.env`、API Key 和生产凭据禁止提交
- 默认 Docker 密码只适合本地开发
- 检索内容和 LLM 输出都视为不可信数据
- 对公网部署前仍需要认证、ACL、限流与审计;这些不属于 V1 范围
- 对公网部署前仍需要认证、ACL、限流与审计;这些不属于 V2 范围
Loading
Loading