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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 2 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# `full` contains the default embedding model; `slim` downloads it only when
# a user first indexes a custom corpus.
# `full` contains the default embedding and reranker models. `slim` keeps BM25
# available and offers separate explicit model downloads in Settings.
LAB_IMAGE_VARIANT=full
TINY_RAG_LAB_PORT=8000

Expand Down
85 changes: 85 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: CI

on:
push:
branches:
- main
pull_request:

permissions:
contents: read

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

jobs:
python:
name: Python tests
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v6
with:
enable-cache: true
- name: Set up Python
run: uv python install 3.12
- name: Check lockfile
run: uv lock --check
- name: Create test environment
run: uv venv --python 3.12
- name: Install CPU-only test dependencies
run: >-
uv pip install
--index https://download.pytorch.org/whl/cpu
--default-index https://pypi.org/simple
--index-strategy unsafe-best-match
'torch==2.7.1+cpu'
'.[qdrant]'
'pytest>=8.0'
- name: Run Python tests
run: uv run --no-sync pytest --tb=short -q

web:
name: Web tests and build
runs-on: ubuntu-latest
defaults:
run:
working-directory: web
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: web/package-lock.json
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Build production app
run: npm run build

guides:
name: Learning Guides build and links
runs-on: ubuntu-latest
defaults:
run:
working-directory: learning_materials
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: learning_materials/package-lock.json
- name: Install dependencies
run: npm ci
- name: Build guides and validate links
run: npm run build
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ __pycache__/
.Python
*.egg-info/
dist/
build/
/build/
.eggs/

# Virtual environments
Expand Down
17 changes: 10 additions & 7 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,27 @@ ARG LAB_IMAGE_VARIANT=full
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
TINY_RAG_LAB_DATA_DIR=/data \
HF_HOME=/opt/tiny-rag-models \
LAB_IMAGE_VARIANT=${LAB_IMAGE_VARIANT}
WORKDIR /app
COPY pyproject.toml README.md ./
# The local lab has no GPU execution path. Install the official CPU-only
# wheel first so sentence-transformers cannot resolve a CUDA/NVIDIA runtime
# transitively on Linux. Keeping it before application source preserves this
# expensive, CPU-only layer while the lab code is refined.
RUN pip install --no-cache-dir --index-url https://download.pytorch.org/whl/cpu 'torch==2.7.1+cpu'
RUN --mount=type=cache,target=/root/.cache/pip \
pip install --index-url https://download.pytorch.org/whl/cpu 'torch==2.7.1+cpu'
COPY tiny_rag_lab ./tiny_rag_lab
RUN --mount=type=cache,target=/root/.cache/pip pip install '.[qdrant]'
# Full prepares both exact CPU-only model snapshots; slim defers each one to
# its own explicit Settings action.
RUN if [ "$LAB_IMAGE_VARIANT" = "full" ]; then python -c "from tiny_rag_lab.embeddings import SentenceTransformerEmbedder; from tiny_rag_lab.reranker import CrossEncoderReranker; SentenceTransformerEmbedder(); CrossEncoderReranker.ensure_default_model(local_files_only=False)"; fi
COPY scripts ./scripts
COPY assets/seed/v1 /opt/tiny-rag-lab/seeds/v1
COPY docker-entrypoint.sh /usr/local/bin/tiny-rag-lab-entrypoint
RUN chmod +x /usr/local/bin/tiny-rag-lab-entrypoint \
&& pip install --no-cache-dir '.[qdrant]'
COPY assets/seed/v2 /opt/tiny-rag-lab/seeds/v2
COPY --from=web-build /web/dist /app/web-dist
COPY --from=guides-build /guides/.vitepress/dist /app/web-dist/docs
# Full prepares the existing default embedder at build time; slim defers it.
RUN if [ "$LAB_IMAGE_VARIANT" = "full" ]; then SENTENCE_TRANSFORMERS_HOME=/opt/tiny-rag-models python -c "from tiny_rag_lab.embeddings import SentenceTransformerEmbedder; SentenceTransformerEmbedder()"; fi
COPY docker-entrypoint.sh /usr/local/bin/tiny-rag-lab-entrypoint
RUN chmod +x /usr/local/bin/tiny-rag-lab-entrypoint
EXPOSE 8000
ENTRYPOINT ["tiny-rag-lab-entrypoint"]
CMD ["uvicorn", "tiny_rag_lab.web_api:create_packaged_app", "--factory", "--host", "0.0.0.0", "--port", "8000"]
42 changes: 29 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
[简体中文](README.zh-CN.md) · [Project site](https://jameswei.github.io/tiny-rag-lab/)

> A learning-first, inspectable classic RAG lab with readable Python, a rich
> browser Studio, direct CLI experiments, real-corpus traces, and bilingual
> Learning Guides.
> browser Studio, an interactive retrieval course, direct CLI experiments,
> real-corpus traces, and bilingual Learning Guides.

`tiny-rag-lab` makes the path between a question, a document corpus, retrieved
evidence, packed context, and a cited answer visible and inspectable. Readable
Expand All @@ -13,6 +13,12 @@ artifacts into guided replays and hands-on experiments; a direct CLI supports
repeatable inspection. Searchable English and Simplified Chinese Learning
Guides open beside the lab when a concept deserves quieter, deeper reading.

The Studio also teaches the retrieval stack as a live course: inspect BM25
term contributions, dense cosine math, the same vectors in NumPy and optional
Qdrant, hybrid RRF fusion, cross-encoder rank movement, and
two-configuration evaluation over 16 reviewed real-corpus questions. None of
this requires an LLM provider.

It is a learning tool, not a production RAG platform. The project favors
visible mechanics over framework magic, evaluation before optimization, and
failure analysis before advanced features.
Expand Down Expand Up @@ -103,17 +109,21 @@ A useful first visit follows this path:
pinned 40-document Cloudflare State & Coordination corpus.
2. **Learn:** step through corpus, chunks, embedding vector, retrieved
candidates, selected context, grounded answer, and citations.
3. **Explore:** ask a catalog or free-form question, compare Dense, BM25, and
Hybrid retrieval, then inspect the returned trace. Add a tested
3. **Retrieval:** follow six live modules from lexical and dense mechanics
through NumPy/Qdrant comparison, hybrid fusion, reranking, and browser A/B
evaluation over 16 reviewed questions.
4. **Explore:** ask a catalog or free-form question, compare Dense, BM25, and
Hybrid retrieval, optionally rerank a larger candidate pool, then inspect
the returned trace. Add a tested
OpenAI-compatible provider only when you want Live Ask generation.
4. **Build & Inspect:** build an index from a bundled corpus or a small
5. **Build & Inspect:** build an index from a bundled corpus or a small
Markdown/plain-text upload, then inspect documents, chunks, vectors, and
provenance.
5. **Failure Lab:** compare curated failure scenarios with their interventions.
6. **Failure Lab:** compare curated failure scenarios with their interventions.

Open **Read the learning guide** from Learn, Explore, or Failure Lab whenever
you want the corresponding concept in a quieter reading format. It opens in a
new tab, preserving the current experiment.
Open **Read the learning guide** from Learn, Retrieval, Explore, or Failure Lab
whenever you want the corresponding concept in a quieter reading format. It
opens in a new tab, preserving the current experiment.

The interface is available in English and Simplified Chinese. Bundled corpus
content, questions, recorded answers, and citations keep their original
Expand All @@ -122,6 +132,9 @@ language.
### What the lab includes

- Four provider-free Guided Learn replays with complete, saved artifacts.
- Six live Retrieval modules covering lexical and dense scoring, local vectors
versus optional Qdrant, hybrid fusion, cross-encoder reranking, and A/B
evaluation over 16 reviewed Cloudflare questions.
- A pinned Cloudflare learning corpus with ready structural and
fixed-character NumPy indexes.
- Bundled watsonxDocsQA source data and all 75 catalog questions after its
Expand All @@ -136,16 +149,18 @@ language.
- Curated failure lessons, raw-artifact inspection, source provenance,
candidate-versus-context selection, and reduced-motion-safe playback.

The default `full` image includes the local embedding model. It runs on CPU;
no GPU or CUDA runtime is required. To try the smaller image:
The default `full` image includes pinned local embedding and cross-encoder
reranker snapshots. It runs on CPU; no GPU or CUDA runtime is required. To try
the smaller image:

```bash
LAB_IMAGE_VARIANT=slim docker compose up --build
```

Guided Learn replay and BM25 retrieval remain available in the slim image. The
Settings page makes the embedding-model download explicit before it enables
Dense/Hybrid retrieval or index building.
Settings page provides separate explicit downloads for the embedding model and
reranker. Dense/Hybrid retrieval and index building require the embedding
model; cross-encoder experiments require the reranker.

To use the optional Qdrant comparison backend:

Expand Down Expand Up @@ -186,6 +201,7 @@ rag index --corpus PATH --index-dir .tiny-rag/index --chunking-strategy semantic
rag retrieve "question text" --index-dir .tiny-rag/index --top-k 5 --retriever dense
rag retrieve "question text" --index-dir .tiny-rag/index --top-k 5 --retriever bm25
rag retrieve "question text" --index-dir .tiny-rag/index --top-k 5 --retriever hybrid
rag retrieve "question text" --index-dir .tiny-rag/index --top-k 5 --retriever hybrid --reranker cross-encoder --rerank-top-n 20

rag ask "question text" --index-dir .tiny-rag/index --top-k 5
rag ask "question text" --index-dir .tiny-rag/index --context-budget 8192 --output-format json
Expand Down
30 changes: 22 additions & 8 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@
[English](README.md) · [项目主页](https://jameswei.github.io/tiny-rag-lab/)

> 一个以学习为先、可检查的经典 RAG 实验室:通过易读 Python、丰富的浏览器 Studio、
> 直接的 CLI 实验、真实语料 trace 与中英双语学习指南理解 RAG。
> 交互式检索课程、直接的 CLI 实验、真实语料 trace 与中英双语学习指南理解 RAG。

`tiny-rag-lab` 让用户问题、文档语料、检索证据、打包后的上下文与带引用答案之间的
完整路径清晰可见、可以检查。易读的 Python 直接呈现 RAG 机制;丰富的浏览器 Studio
将中间产物转化为引导回放和动手实验;直接的 CLI 支持可重复检查。当某个概念需要更
安静、深入的阅读时,可搜索的中英双语学习指南会在实验旁打开。

Studio 还把检索栈变成一套实时课程:检查 BM25 逐词贡献、稠密余弦计算、NumPy 与
可选 Qdrant 中的同一组向量、混合 RRF 融合、交叉编码器排名移动,以及在 16 道已
审核真实语料问题上的双配置评估。整个过程不需要 LLM 服务商。

它是学习工具,而不是生产级 RAG 平台。项目优先选择可见的机制,而非框架魔法;先评估再优化;先分析失败再引入高级特性。

![Guided Learn 回放展示真实检索证据](website/assets/screenshots/guided-retrieval.jpg)
Expand Down Expand Up @@ -61,32 +65,41 @@ http://127.0.0.1:8000/docs/,也可以从实验室中的相关阶段直接打

1. **Home → Start guided lesson:** 从固定的 40 篇 Cloudflare State & Coordination 文档中,选择四个已保存课程之一进行回放。
2. **Learn:** 逐步查看语料、文本块、查询嵌入向量、检索候选、选入上下文的证据、基于证据的答案和引用。
3. **Explore:** 提出题库问题或自由问题,比较稠密检索、BM25 和混合检索,并检查返回的 trace。只有希望进行 Live Ask 生成时,才需要配置并测试 OpenAI 兼容的 LLM 服务商。
4. **Build & Inspect:** 使用内置语料或小型 Markdown/纯文本上传构建索引,然后检查文档、文本块、向量和来源信息。
5. **Failure Lab:** 对比精心设计的失败场景及其改进方案。
3. **Retrieval:** 通过六个实时模块,从词法与稠密检索机制一路学习 NumPy/Qdrant
对比、混合融合、重排序,以及在 16 道已审核问题上的浏览器 A/B 评估。
4. **Explore:** 提出题库问题或自由问题,比较稠密检索、BM25 和混合检索,可选地
重排更大的候选池,并检查返回的 trace。只有希望进行 Live Ask 生成时,才需要
配置并测试 OpenAI 兼容的 LLM 服务商。
5. **Build & Inspect:** 使用内置语料或小型 Markdown/纯文本上传构建索引,然后检查文档、文本块、向量和来源信息。
6. **Failure Lab:** 对比精心设计的失败场景及其改进方案。

当你希望在更安静的阅读环境中理解相应概念时,可以从 Learn、Explore 或 Failure Lab
打开**阅读学习指南**。它会在新标签页打开,并保留当前实验状态。
当你希望在更安静的阅读环境中理解相应概念时,可以从 Learn、Retrieval、Explore 或
Failure Lab 打开**阅读学习指南**。它会在新标签页打开,并保留当前实验状态。

界面提供英文和简体中文。内置语料内容、问题、已记录答案和引用会保留其原始语言。

### 实验室包含什么

- 四个不依赖 LLM 服务商、带完整已保存产物的 Guided Learn 回放课程。
- 六个实时 Retrieval 模块,覆盖词法与稠密评分、本地向量与可选 Qdrant、混合融合、
交叉编码器重排序,以及对 16 道已审核 Cloudflare 问题的 A/B 评估。
- 固定的 Cloudflare 学习语料,以及可直接使用的结构化分块和固定字符分块 NumPy 索引。
- 内置 watsonxDocsQA 源数据;完成显式的后台索引构建后,可以使用全部 75 个题库问题。
- 不配置 LLM 服务商也可以进行纯检索探索;通过连接测试后,可使用任何 OpenAI 兼容 Chat Completions 服务进行 Live Ask。
- 支持小型自定义语料上传:最多 100 个 Markdown 或纯文本文件,总大小不超过 100 MiB。
- 默认使用 NumPy/文件索引;可选的本地 Qdrant 后端只改变存储和向量搜索的执行方式,不改变本项目要讲解的文本块、嵌入、检索、上下文、引用和 trace 概念。
- 精心设计的失败课程、原始产物检查、来源溯源、候选证据与上下文选择的对比,以及支持减少动画偏好的回放体验。

默认的 `full` 镜像包含本地嵌入模型,只使用 CPU,不需要 GPU 或 CUDA 运行时。若想体验更小的镜像:
默认的 `full` 镜像包含固定版本的本地嵌入模型和交叉编码器重排序模型,只使用 CPU,
不需要 GPU 或 CUDA 运行时。若想体验更小的镜像:

```bash
LAB_IMAGE_VARIANT=slim docker compose up --build
```

在 slim 镜像中,Guided Learn 回放和 BM25 检索仍然可用。设置页会明确提示下载嵌入模型;下载完成后才会解锁稠密/混合检索和索引构建。
在 slim 镜像中,Guided Learn 回放和 BM25 检索仍然可用。设置页分别提供嵌入模型与
重排序模型的显式下载。稠密/混合检索和索引构建需要嵌入模型;交叉编码器实验需要
重排序模型。

如需使用可选的 Qdrant 对比后端:

Expand Down Expand Up @@ -121,6 +134,7 @@ rag index --corpus PATH --index-dir .tiny-rag/index --chunking-strategy semantic
rag retrieve "question text" --index-dir .tiny-rag/index --top-k 5 --retriever dense
rag retrieve "question text" --index-dir .tiny-rag/index --top-k 5 --retriever bm25
rag retrieve "question text" --index-dir .tiny-rag/index --top-k 5 --retriever hybrid
rag retrieve "question text" --index-dir .tiny-rag/index --top-k 5 --retriever hybrid --reranker cross-encoder --rerank-top-n 20

rag ask "question text" --index-dir .tiny-rag/index --top-k 5
rag ask "question text" --index-dir .tiny-rag/index --context-budget 8192 --output-format json
Expand Down
Loading
Loading