Advanced RAG BackendSeptember 10, 2026
A backend-only Advanced Retrieval-Augmented Generation (RAG) system built with Node.js, OpenAI, Qdrant, Redis, and BullMQ.
The project goes beyond basic vector search by combining multiple retrieval and ranking techniques to improve the quality and relevance of the context given to the LLM.
Why I Built This
I built this project to understand how modern RAG systems work beyond the basic:
Query → Vector Search → LLM
Instead of only following a single retrieval path, this project explores techniques such as query rewriting, step-back prompting, sub-query decomposition, HyDE, Reciprocal Rank Fusion (RRF), and LLM-based reranking.
The main goal was to learn how these techniques work together in a real backend system rather than implementing them as isolated examples.
How It Works
Document Indexing
PDF
↓
PDF parsing
↓
Chunking
↓
OpenAI embeddings
↓
Qdrant
Uploaded documents are processed asynchronously using BullMQ + Redis. The text is split into chunks, converted into embeddings using text-embedding-3-small, and stored in Qdrant along with the original chunk data.
Query Pipeline
User Query
↓
Query Rewriting
├── Rewritten Query
├── Step-back Query
└── 3 Sub-queries
↓
Vector Retrieval
+
HyDE Retrieval
↓
Reciprocal Rank Fusion
↓
Candidate Chunks
↓
LLM Reranking
↓
Top 5 Chunks
↓
GPT-4o-mini
↓
Final Answer
RAG Techniques Used
- Query Rewriting — improves and clarifies the original query.
- Step-back Prompting — creates a broader query to retrieve useful background context.
- Sub-query Decomposition — breaks complex queries into focused searches.
- HyDE (Hypothetical Document Embeddings) — generates a hypothetical answer and uses its embedding for retrieval.
- RRF (Reciprocal Rank Fusion) — combines results from multiple retrieval paths.
- LLM Reranking — uses
gpt-4o-minito score and reorder the retrieved candidates. - Context Selection — passes the highest-ranked chunks to the final generation step.
Tech Stack
- Node.js + Express — backend and API
- OpenAI — embeddings and LLM generation
- Qdrant — vector database
- Redis — queue backing store
- BullMQ — asynchronous document indexing and query processing
- pdf-parse — PDF text extraction
- Docker / Docker Compose — local infrastructure
Models
- Embeddings:
text-embedding-3-small - Chat / generation / reranking:
gpt-4o-mini
Project Structure
src/
├── config/
│ └── env.js
├── routes/
│ ├── document.routes.js
│ └── query.routes.js
├── controllers/
│ ├── document.controller.js
│ └── query.controller.js
├── middleware/
│ └── upload.middleware.js
├── queues/
│ └── queues.js
├── workers/
│ ├── indexing.worker.js
│ └── query.worker.js
├── ingestion/
│ ├── pdf.parser.js
│ ├── chunker.js
│ └── indexer.js
├── embeddings/
│ └── openai.embeddings.js
├── databases/
│ └── qdrant.js
├── query/
│ ├── query.rewriter.js
│ ├── hyde.js
│ └── test-hyde.js
├── retrieval/
│ ├── retriever.js
│ ├── rrf.js
│ ├── reranker.js
│ └── test-reranker.js
├── generation/
│ └── answer.generator.js
├── pipeline/
│ └── rag.pipeline.js
└── server.js
Run Locally
1. Clone the repository
git clone https://github.com/Sulochan36/Advanced-RAG-Patterns
cd advanced-rag
2. Install dependencies
npm install
3. Configure environment variables
Create a .env file based on .env.example:
cp .env.example .env
Add your OpenAI API key and configure the other variables if required.
4. Start Redis and Qdrant
docker compose up -d
5. Start the indexing worker
node src/workers/indexing.worker.js
6. Start the query worker
node src/workers/query.worker.js
7. Start the API server
npm run dev
The backend will run on:
http://localhost:8000
Upload a PDF through the document endpoint, wait for indexing to complete, and then send a query through the query endpoint.
Concepts & RAG Pipeline
This project was built as a learning project to understand how an Advanced RAG system works internally and how different retrieval techniques can be combined into one pipeline.
1. Document Ingestion
When a PDF is uploaded, the indexing worker processes it asynchronously:
PDF
↓
Text Extraction
↓
Chunking
↓
Embeddings
↓
Qdrant
The document is divided into smaller chunks because embedding and retrieving an entire document at once would make it difficult to find precise information.
Each chunk is converted into a vector using OpenAI text-embedding-3-small and stored in Qdrant along with its text and metadata.
2. Query Rewriting
Instead of searching only with the user's original question, the system generates different versions of the query:
- Rewritten query — makes the question clearer and self-contained.
- Step-back query — asks a broader question to retrieve useful background information.
- Sub-queries — breaks the original question into three focused questions.
This creates multiple retrieval paths for the same user query.
3. HyDE
HyDE (Hypothetical Document Embeddings) generates a hypothetical passage that could answer the user's question.
The hypothetical passage is then embedded and searched against the document vectors.
User Query
↓
Hypothetical Document
↓
Embedding
↓
Vector Search
The goal is to make the retrieval query more similar in meaning and structure to the actual document content.
4. Multiple Retrieval
The rewritten query, step-back query, sub-queries, and HyDE each perform vector searches against Qdrant.
This gives the system multiple ranked lists of potentially relevant chunks.
5. Reciprocal Rank Fusion
RRF (Reciprocal Rank Fusion) combines the ranked results from these different retrieval paths.
A chunk that appears near the top of multiple lists receives a higher combined score.
Query Results
Step-back Results
Sub-query Results
HyDE Results
↓
RRF
↓
Unified Candidate Ranking
This helps combine the strengths of different retrieval strategies.
6. LLM Reranking
The top candidates from RRF are passed to gpt-4o-mini.
The model scores each chunk based on how relevant it is to the original user query.
RRF Candidates
↓
LLM Reranker
↓
Relevance Scores
↓
Top 5 Chunks
RRF is mainly used to build a strong candidate pool, while reranking focuses on selecting the most relevant context.
7. Final Generation
The final selected chunks are provided to gpt-4o-mini along with the original question.
The model uses this retrieved context to generate the final answer.
Original Query
+
Top 5 Retrieved Chunks
↓
GPT-4o-mini
↓
Final Answer
Complete Pipeline
DOCUMENT SIDE
│
PDF
↓
PDF Parser
↓
Chunking
↓
Embeddings
↓
Qdrant
│
│
─────────────────────────┼──────────────────────────
│
QUERY SIDE
│
User Query
↓
Query Rewriting
/ | \
Rewritten Step-back Sub-queries
\ | /
↓
Vector Retrieval
+
HyDE
↓
RRF
↓
Candidate Chunks
↓
LLM Reranking
↓
Top 5 Chunks
↓
GPT-4o-mini
↓
Final Answer
What I Learned
This project helped me understand that RAG is not simply:
Query → Vector Search → LLM
A more advanced system can improve retrieval by combining query understanding, multiple retrieval strategies, result fusion, reranking, and controlled context selection before the final generation step.
The project was built primarily to understand these concepts by implementing them in a working Node.js backend.
Project Goal
This project is primarily a learning-focused implementation of an Advanced RAG architecture, with an emphasis on understanding how retrieval, ranking, and generation work together in a production-style backend.