Chapter 08 · Part 2 RAG Track Full-stack Project

Advanced RAG Lab: retrieval that survives 5,000 test cases, not a toy corpus.

Basic RAG breaks at scale. This lab upgrades the pipeline with hybrid dense + sparse retrieval, Reciprocal Rank Fusion, cross-encoder reranking and query rewriting, all visible live in a two-pane explorer UI.

01 What students build

A production-shaped RAG explorer over a real corpus: 5,000 VWO test cases ingested into Qdrant. One bge-m3 model produces dense and sparse vectors from each chunk, queries are rewritten into alternate phrasings before search, both rank lists are fused with RRF, and a bge-reranker-v2-m3 cross-encoder picks the final context. Every stage is inspectable in the UI, nothing is a black box.

Hybrid + RRF

Dense vectors catch meaning, sparse vectors catch exact tokens like TC-00003 and P0. Reciprocal Rank Fusion merges both rank lists into one.

Cross-encoder Rerank

A before/after table shows candidates jumping ranks after bge-reranker-v2-m3 scores each (question, chunk) pair directly.

Query Rewriting

Groq rewrites each question into alternate phrasings before retrieval, so "role changes" also finds "permission updates".

02 Architecture

Questionfrom chat pane
──▶
Rewrite ×3Groq phrasings
──▶
bge-m3dense + sparse
──▶
Qdrant + RRFhybrid fuse k=60
──▶
Rerankerbge-reranker-v2-m3
──▶
Groq LLMgpt-oss-120b
──▶
Answer[Chunk N] cited
corpus: 5,000 vwo test cases · qdrant embedded (no docker) · live sse stage tracker

03 Live demo (simulated with sample data)

This is a UI walkthrough with pre-baked sample data so you can feel the pipeline without downloading the 2.3 GB bge-m3 model. In the course you run the real thing locally: Flask + Qdrant + Groq at localhost:5050.

advanced-rag-lab · localhost:5050 demo · sample data

04 Inputs & outputs

What goes in

  • A CSV/XLSX of test cases (5,000 VWO rows shipped with the lab)
  • Your pick of text columns to embed and metadata columns to filter on
  • Natural-language questions in the chat pane
  • Optional payload filters: priority, module, jira_id

What comes out

  • Grounded answer with [Chunk N] citations
  • Dense vs sparse vs RRF-fused rank tables per query
  • Rerank before/after table showing rank movement
  • The 3 query rewrites Groq generated
  • Chunk explorer: payloads, dense preview, sparse top tokens

05 How it's built

Ingest the CSV: one row becomes one chunk, with title, steps, expected result and tags concatenated into the embedded document.
Embed every chunk once with bge-m3, which emits a dense vector and a sparse token-weight vector from the same forward pass.
Index both vector types into a single Qdrant collection (embedded file store, no Docker required) with metadata payloads.
At query time, rewrite the question into alternate phrasings with Groq, then run dense and sparse searches for each phrasing.
Fuse all rank lists with Reciprocal Rank Fusion (k=60), then rerank the fused candidates with the bge-reranker-v2-m3 cross-encoder.
Generate the cited answer with Groq gpt-oss-120b and stream every pipeline stage to the UI over SSE.

06 Tech stack

Python · FlaskQdrant (embedded)bge-m3 dense + sparsebge-reranker-v2-m3RRF fusionGroq gpt-oss-120bQuery rewritingSSE stage trackerpandas