<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Lochan Jangid</title>
    <description>The latest articles on DEV Community by Lochan Jangid (@lochanjangid).</description>
    <link>https://dev.to/lochanjangid</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4231057%2Fb68986a4-b892-4a92-b2ed-f58688b5ec55.jpg</url>
      <title>DEV Community: Lochan Jangid</title>
      <link>https://dev.to/lochanjangid</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lochanjangid"/>
    <language>en</language>
    <item>
      <title>RAG from Zero to Hero: Building Naive, Advanced and Modular RAG from Scratch with Python</title>
      <dc:creator>Lochan Jangid</dc:creator>
      <pubDate>Fri, 06 Nov 2026 20:04:48 +0000</pubDate>
      <link>https://dev.to/lochanjangid/rag-from-zero-to-hero-building-naive-advanced-and-modular-rag-from-scratch-with-python-3k7m</link>
      <guid>https://dev.to/lochanjangid/rag-from-zero-to-hero-building-naive-advanced-and-modular-rag-from-scratch-with-python-3k7m</guid>
      <description>&lt;h1&gt;
  
  
  RAG from Zero to Hero: Building Naive, Advanced and Modular RAG from Scratch with Python
&lt;/h1&gt;

&lt;p&gt;🎥 Watch the complete video tutorial: &lt;a href="https://www.youtube.com/watch?v=aenpTk8blIs" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=aenpTk8blIs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb09pb0bb2b6lorl9zmfa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb09pb0bb2b6lorl9zmfa.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this hands-on tutorial, we'll build Naive RAG, Advanced RAG and Modular RAG step by step.&lt;/p&gt;

&lt;p&gt;I wanted to learn Retrieval-Augmented Generation (RAG) the way Andrej Karpathy teaches machine learning: understanding every concept from first principles, building things from scratch, and knowing what actually happens under the hood.&lt;/p&gt;

&lt;p&gt;But I struggled to find a single resource that covered the complete journey, from understanding the fundamentals to implementing more advanced RAG architectures.&lt;/p&gt;

&lt;p&gt;After learning it myself, I thought other developers might face the same problem. So I decided to create this walkthrough.&lt;/p&gt;

&lt;p&gt;In this article, we'll explore RAG, understand why we need it, and progressively build three types of RAG systems using Python:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Naive RAG&lt;/li&gt;
&lt;li&gt;Advanced RAG&lt;/li&gt;
&lt;li&gt;Modular RAG&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We'll also understand document chunking, vectorization, indexing, retrieval, query rewriting, reranking, routing and query fusion.&lt;/p&gt;

&lt;p&gt;The goal isn't just to make RAG work. It's to understand why each component exists.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Why Do We Need RAG?
&lt;/h2&gt;

&lt;p&gt;Large Language Models (LLMs) are impressive. They can understand questions, generate explanations, write code and perform complex reasoning.&lt;/p&gt;

&lt;p&gt;However, they have some important limitations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Hallucinations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;LLMs can generate answers that sound convincing but aren't factually correct.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Outdated knowledge&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;An LLM's knowledge comes primarily from its training data. It doesn't automatically know about events, documents or information created after its training cutoff.&lt;/p&gt;

&lt;p&gt;Consider a simple example:&lt;/p&gt;

&lt;p&gt;If you ask an LLM:&lt;/p&gt;

&lt;p&gt;"What happened in the latest news three days ago?"&lt;/p&gt;

&lt;p&gt;A model without access to that information cannot reliably answer.&lt;/p&gt;

&lt;p&gt;This is where Retrieval-Augmented Generation comes in.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is RAG?
&lt;/h3&gt;

&lt;p&gt;RAG stands for Retrieval-Augmented Generation.&lt;/p&gt;

&lt;p&gt;The central idea is simple:&lt;/p&gt;

&lt;p&gt;Instead of asking an LLM to answer a question using only its internal knowledge, we first retrieve relevant information from external documents and provide that information as context.&lt;/p&gt;

&lt;p&gt;The LLM then generates an answer based on the retrieved context.&lt;/p&gt;

&lt;p&gt;The basic workflow looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Load external documents.&lt;/li&gt;
&lt;li&gt;Split documents into smaller chunks.&lt;/li&gt;
&lt;li&gt;Convert chunks into numerical vectors.&lt;/li&gt;
&lt;li&gt;Store and index those vectors.&lt;/li&gt;
&lt;li&gt;Convert the user's query into a vector.&lt;/li&gt;
&lt;li&gt;Retrieve relevant chunks.&lt;/li&gt;
&lt;li&gt;Combine the retrieved context with the user's question.&lt;/li&gt;
&lt;li&gt;Send the prompt to an LLM.&lt;/li&gt;
&lt;li&gt;Generate an answer.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's the fundamental idea behind RAG.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Understanding the RAG Architecture
&lt;/h2&gt;

&lt;p&gt;Before writing code, let's understand the two main parts of a RAG system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Indexing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Indexing happens before the user asks a question.&lt;/p&gt;

&lt;p&gt;We load documents, split them into chunks, transform those chunks into vectors and store them in an index.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Retrieval and Generation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When a user asks a question, we transform the query into a vector, search for relevant chunks, construct a prompt and send it to the LLM.&lt;/p&gt;

&lt;p&gt;The overall architecture:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Documents → Chunking → Vectorization → Indexing&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;User Query → Vectorization → Retrieval → Context + Query → LLM → Answer&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is the foundation we'll use throughout the implementation.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Building Our First RAG System: Naive RAG
&lt;/h2&gt;

&lt;p&gt;Let's implement everything ourselves.&lt;/p&gt;

&lt;p&gt;For this walkthrough, I'll use a document containing the story of The Amazing Spider-Man.&lt;/p&gt;

&lt;p&gt;Why Spider-Man? Because it's an easy example to understand, and we can ask questions about its characters and story.&lt;/p&gt;

&lt;p&gt;Our goal is to answer questions using information from this document.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Load the document
&lt;/h3&gt;

&lt;p&gt;First, we load our text document using Python.&lt;/p&gt;

&lt;p&gt;We can inspect its contents and calculate its length.&lt;/p&gt;

&lt;p&gt;Imagine the document contains around 12,000 characters.&lt;/p&gt;

&lt;p&gt;One approach would be to send the entire document directly to an LLM along with every question.&lt;/p&gt;

&lt;p&gt;But that's inefficient.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We waste tokens on irrelevant information.&lt;/li&gt;
&lt;li&gt;Long documents increase the prompt size.&lt;/li&gt;
&lt;li&gt;The model receives more information than it needs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead, we need to divide the document into smaller pieces.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Document chunking
&lt;/h3&gt;

&lt;p&gt;Chunking means splitting a document into smaller sections.&lt;/p&gt;

&lt;p&gt;For example, we might initially choose a chunk size of 200 characters.&lt;/p&gt;

&lt;p&gt;Each chunk becomes a smaller unit that can be independently retrieved.&lt;/p&gt;

&lt;p&gt;However, simple character-based chunking creates a problem.&lt;/p&gt;

&lt;p&gt;Consider this sentence:&lt;/p&gt;

&lt;p&gt;"Peter Parker grows up with questions about his family when they disappear under mysterious circumstances."&lt;/p&gt;

&lt;p&gt;If we split this sentence at an arbitrary character position, we might get:&lt;/p&gt;

&lt;p&gt;Chunk 1: "Peter Parker grows up with questions about his family when they disappear under myster..."&lt;/p&gt;

&lt;p&gt;Chunk 2: "...ious circumstances."&lt;/p&gt;

&lt;p&gt;Now the second chunk has lost important context.&lt;/p&gt;

&lt;p&gt;This is a problem because retrieval might return incomplete information.&lt;/p&gt;

&lt;h3&gt;
  
  
  Improving chunking with paragraphs and overlap
&lt;/h3&gt;

&lt;p&gt;Instead of blindly splitting the document every 200 characters, we can first divide it into paragraphs.&lt;/p&gt;

&lt;p&gt;Then we combine paragraphs until we approach our desired chunk size.&lt;/p&gt;

&lt;p&gt;We also introduce &lt;strong&gt;overlapping chunks&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Overlap means carrying a small portion of the previous chunk into the next chunk.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chunk size: 200 characters&lt;/li&gt;
&lt;li&gt;Overlap: 50 characters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This preserves some surrounding context between chunks.&lt;/p&gt;

&lt;p&gt;We also need to avoid cutting words in the middle. If a chunk boundary falls inside a word, we can move the boundary to a nearby whitespace character.&lt;/p&gt;

&lt;p&gt;This gives us more meaningful chunks.&lt;/p&gt;

&lt;p&gt;Our initial implementation produces around 61 chunks, while the improved chunking approach produces around 63 chunks.&lt;/p&gt;

&lt;p&gt;The exact number depends on the document and chunking configuration.&lt;/p&gt;

&lt;p&gt;The important lesson is that chunking is not just about dividing text. It's about preserving meaning.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Vectorization: Converting Text into Numbers
&lt;/h2&gt;

&lt;p&gt;Computers cannot directly perform mathematical similarity searches on ordinary text.&lt;/p&gt;

&lt;p&gt;We need to represent our chunks numerically.&lt;/p&gt;

&lt;p&gt;This is where vectorization comes in.&lt;/p&gt;

&lt;p&gt;In this implementation, we'll use TF-IDF.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is TF-IDF?
&lt;/h3&gt;

&lt;p&gt;TF-IDF stands for Term Frequency-Inverse Document Frequency.&lt;/p&gt;

&lt;p&gt;It combines two ideas:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TF: Term Frequency&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;How frequently does a word appear in a document?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IDF: Inverse Document Frequency&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;How uncommon is that word across the collection of documents?&lt;/p&gt;

&lt;p&gt;Words that appear frequently in a particular document but are relatively uncommon across other documents can receive higher importance.&lt;/p&gt;

&lt;p&gt;Common words such as "the", "is" and "and" generally provide less useful information for distinguishing documents.&lt;/p&gt;

&lt;p&gt;TF-IDF converts text into numerical feature vectors based on these word statistics.&lt;/p&gt;

&lt;p&gt;We'll use Scikit-learn:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.feature_extraction.text&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TfidfVectorizer&lt;/span&gt;

&lt;span class="n"&gt;vectorizer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TfidfVectorizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;stop_words&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;english&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;vectors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vectorizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit_transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result is a sparse matrix.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a sparse matrix?
&lt;/h3&gt;

&lt;p&gt;A sparse matrix is a matrix in which most elements are zero.&lt;/p&gt;

&lt;p&gt;Instead of storing every zero value, sparse representations efficiently store the non-zero values.&lt;/p&gt;

&lt;p&gt;This saves memory when working with high-dimensional text vectors.&lt;/p&gt;

&lt;p&gt;For our implementation, we'll convert the vectors into dense NumPy arrays before passing them to FAISS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important distinction:&lt;/strong&gt; TF-IDF is a lexical vectorization technique. It represents word importance, not deep semantic meaning. Modern production RAG systems commonly use dense embedding models for semantic retrieval.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Indexing with FAISS
&lt;/h2&gt;

&lt;p&gt;Now we have vectors representing our document chunks.&lt;/p&gt;

&lt;p&gt;But how do we efficiently search through them?&lt;/p&gt;

&lt;p&gt;Imagine having thousands or millions of chunks. Searching through every document manually would be inefficient.&lt;/p&gt;

&lt;p&gt;We need an index.&lt;/p&gt;

&lt;p&gt;We'll use FAISS (Facebook AI Similarity Search).&lt;/p&gt;

&lt;p&gt;FAISS is a library designed for efficient similarity search over vectors.&lt;/p&gt;

&lt;p&gt;Think of our vectors as points in a high-dimensional mathematical space.&lt;/p&gt;

&lt;p&gt;When a query arrives, we convert it into a vector and search for nearby vectors.&lt;/p&gt;

&lt;p&gt;The nearest vectors represent our candidate chunks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Normalization and cosine similarity
&lt;/h3&gt;

&lt;p&gt;We also need to understand cosine similarity.&lt;/p&gt;

&lt;p&gt;Cosine similarity measures the angle between two vectors.&lt;/p&gt;

&lt;p&gt;A higher cosine similarity generally indicates that two vectors point in a more similar direction.&lt;/p&gt;

&lt;p&gt;Mathematically:&lt;/p&gt;

&lt;p&gt;[&lt;/p&gt;

&lt;h1&gt;
  
  
  \text{Cosine Similarity}(A,B)
&lt;/h1&gt;

&lt;p&gt;\frac{A \cdot B}{|A||B|}&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;We normalize our vectors so their lengths become 1.&lt;/p&gt;

&lt;p&gt;After normalization, the inner product between two vectors is equivalent to cosine similarity.&lt;/p&gt;

&lt;p&gt;We'll use FAISS to create an index and add our vectors to it.&lt;/p&gt;

&lt;p&gt;With an inner-product index and normalized vectors, we can retrieve the nearest neighbors efficiently.&lt;/p&gt;


&lt;h2&gt;
  
  
  6. Retrieval: Finding Relevant Chunks
&lt;/h2&gt;

&lt;p&gt;Now comes the interesting part.&lt;/p&gt;

&lt;p&gt;Let's ask:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Who is Spider-Man?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First, we transform the user's query using the same TF-IDF vectorizer.&lt;/p&gt;

&lt;p&gt;Then we search the FAISS index.&lt;/p&gt;

&lt;p&gt;We can request the top 3 nearest neighbors by setting:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;k = 3&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;FAISS returns similarity scores and the indices of the nearest chunks.&lt;/p&gt;

&lt;p&gt;Using those indices, we retrieve the original text chunks.&lt;/p&gt;

&lt;p&gt;These chunks become our context.&lt;/p&gt;

&lt;p&gt;Now we have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The user's question.&lt;/li&gt;
&lt;li&gt;The relevant document chunks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We're almost ready to connect our LLM.&lt;/p&gt;


&lt;h2&gt;
  
  
  7. Connecting the LLM
&lt;/h2&gt;

&lt;p&gt;We need an LLM to generate an answer using our retrieved context.&lt;/p&gt;

&lt;p&gt;For this implementation, I use Groq through an OpenAI-compatible client.&lt;/p&gt;

&lt;p&gt;The important part isn't the provider. It's how we construct the prompt.&lt;/p&gt;

&lt;p&gt;A basic prompt might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Answer using only the provided context.

If the answer is not present in the context,
respond with "I don't know".

Context:
{retrieved_context}

Question:
{user_question}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We combine our retrieved chunks into a single context string and send the prompt to the LLM.&lt;/p&gt;

&lt;p&gt;Now the model has access to information from our document.&lt;/p&gt;

&lt;p&gt;This completes our first Naive RAG implementation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing our first RAG system
&lt;/h3&gt;

&lt;p&gt;Let's ask:&lt;/p&gt;

&lt;p&gt;"Who is Spider-Man?"&lt;/p&gt;

&lt;p&gt;Our system retrieves relevant chunks and sends them to the LLM.&lt;/p&gt;

&lt;p&gt;The model can now answer using the information provided in the document.&lt;/p&gt;

&lt;p&gt;However, our initial implementation also reveals some problems.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Some chunks contain incomplete sentences.&lt;/li&gt;
&lt;li&gt;Retrieval can return irrelevant information.&lt;/li&gt;
&lt;li&gt;A user's query might not match the wording used in the document.&lt;/li&gt;
&lt;li&gt;The retrieved context may contain unnecessary information.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why we need to improve our architecture.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Advanced RAG: Improving Retrieval
&lt;/h2&gt;

&lt;p&gt;Naive RAG follows a straightforward pipeline:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Query → Retrieval → Context → LLM → Answer&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Advanced RAG introduces additional processing before and after retrieval.&lt;/p&gt;

&lt;p&gt;These are commonly called:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pre-retrieval optimization&lt;/li&gt;
&lt;li&gt;Post-retrieval optimization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The objective is to improve the quality of retrieved information before generating the final answer.&lt;/p&gt;

&lt;h3&gt;
  
  
  A. Pre-retrieval: Query Rewriting
&lt;/h3&gt;

&lt;p&gt;Imagine a user asks:&lt;/p&gt;

&lt;p&gt;"Who is Spider-Man?"&lt;/p&gt;

&lt;p&gt;The query is understandable, but it might not contain all the information needed for effective retrieval.&lt;/p&gt;

&lt;p&gt;We can send the query to an LLM and ask it to rewrite the query for retrieval.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Original query:&lt;/p&gt;

&lt;p&gt;"Who is Spider-Man?"&lt;/p&gt;

&lt;p&gt;Rewritten query:&lt;/p&gt;

&lt;p&gt;"Find details about Spider-Man, Peter Parker, including his identity, powers, creators and origin story."&lt;/p&gt;

&lt;p&gt;The rewritten query provides additional search terms and context.&lt;/p&gt;

&lt;p&gt;We then convert this new query into a vector and search our existing index.&lt;/p&gt;

&lt;p&gt;The goal is to retrieve more relevant chunks.&lt;/p&gt;

&lt;p&gt;This process is called query rewriting.&lt;/p&gt;

&lt;h3&gt;
  
  
  B. Post-retrieval: Reranking
&lt;/h3&gt;

&lt;p&gt;Retrieval gives us candidate chunks, but not every retrieved chunk is equally useful.&lt;/p&gt;

&lt;p&gt;Some chunks might be relevant, while others might contain unnecessary information.&lt;/p&gt;

&lt;p&gt;Reranking helps us improve the order and relevance of the retrieved results.&lt;/p&gt;

&lt;p&gt;In our implementation, we send the retrieved chunks to an LLM and ask it to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Identify relevant information.&lt;/li&gt;
&lt;li&gt;Rank the chunks according to relevance.&lt;/li&gt;
&lt;li&gt;Ignore irrelevant information.&lt;/li&gt;
&lt;li&gt;Preserve useful facts for answering the question.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, if we ask:&lt;/p&gt;

&lt;p&gt;"Who is Spider-Man?"&lt;/p&gt;

&lt;p&gt;A chunk explaining that Peter Parker is Spider-Man is much more useful than a chunk describing an unrelated event.&lt;/p&gt;

&lt;p&gt;The reranked context is then passed to the LLM.&lt;/p&gt;

&lt;h3&gt;
  
  
  Advanced RAG architecture
&lt;/h3&gt;

&lt;p&gt;Our improved pipeline now looks like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;User Query → Query Rewriting → Retrieval → Reranking → Context → LLM → Answer&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We've introduced two important improvements without changing the fundamental idea of RAG.&lt;/p&gt;

&lt;p&gt;Query rewriting improves what we search for.&lt;/p&gt;

&lt;p&gt;Reranking improves what we use after searching.&lt;/p&gt;




&lt;h2&gt;
  
  
  9. Modular RAG: Combining Different Retrieval Strategies
&lt;/h2&gt;

&lt;p&gt;Now we move to Modular RAG.&lt;/p&gt;

&lt;p&gt;This is where things become more interesting.&lt;/p&gt;

&lt;p&gt;Instead of treating RAG as one fixed pipeline, we treat different operations as independent modules.&lt;/p&gt;

&lt;p&gt;We can combine them depending on the problem.&lt;/p&gt;

&lt;p&gt;In this implementation, we'll explore three important techniques:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Routing&lt;/li&gt;
&lt;li&gt;Query Fusion&lt;/li&gt;
&lt;li&gt;Reciprocal Rank Fusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  A. Routing
&lt;/h3&gt;

&lt;p&gt;Does every question need document retrieval?&lt;/p&gt;

&lt;p&gt;Not necessarily.&lt;/p&gt;

&lt;p&gt;Imagine asking:&lt;/p&gt;

&lt;p&gt;"Who is Spider-Man?"&lt;/p&gt;

&lt;p&gt;An LLM already has general knowledge about Spider-Man.&lt;/p&gt;

&lt;p&gt;But what if we ask:&lt;/p&gt;

&lt;p&gt;"What happened to Spider-Man yesterday in my document?"&lt;/p&gt;

&lt;p&gt;Now we need to search our external document.&lt;/p&gt;

&lt;p&gt;Routing allows the system to decide whether it should answer directly or retrieve information from an external knowledge source.&lt;/p&gt;

&lt;p&gt;We can ask an LLM to classify a question:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chat: The question can be answered using the model's existing knowledge.&lt;/li&gt;
&lt;li&gt;Document: The question requires external document retrieval.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The system then follows the appropriate path.&lt;/p&gt;

&lt;p&gt;This avoids unnecessary retrieval operations for questions that don't need them.&lt;/p&gt;

&lt;h3&gt;
  
  
  B. Query Fusion
&lt;/h3&gt;

&lt;p&gt;Traditional retrieval often searches using one query.&lt;/p&gt;

&lt;p&gt;But a single query may not capture every possible interpretation of the user's question.&lt;/p&gt;

&lt;p&gt;Consider:&lt;/p&gt;

&lt;p&gt;"Who is Spider-Man?"&lt;/p&gt;

&lt;p&gt;We can generate multiple related queries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Who is Spider-Man?&lt;/li&gt;
&lt;li&gt;What is Spider-Man's real name?&lt;/li&gt;
&lt;li&gt;Which comic book character is known as Spider-Man?&lt;/li&gt;
&lt;li&gt;What is Spider-Man's origin story?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we have several search queries instead of one.&lt;/p&gt;

&lt;p&gt;We perform retrieval for each query.&lt;/p&gt;

&lt;p&gt;Each query can discover different relevant chunks.&lt;/p&gt;

&lt;p&gt;However, this introduces another problem: duplicate results and different rankings across queries.&lt;/p&gt;

&lt;p&gt;We need a way to combine them.&lt;/p&gt;

&lt;h3&gt;
  
  
  C. Reciprocal Rank Fusion (RRF)
&lt;/h3&gt;

&lt;p&gt;Reciprocal Rank Fusion is a ranking technique used to combine results from multiple ranked lists.&lt;/p&gt;

&lt;p&gt;Instead of relying only on raw similarity scores, it considers the position of each result in different rankings.&lt;/p&gt;

&lt;p&gt;The general formula is:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
RRF(d)=\sum_{r \in R}\frac{1}{k+r(d)}&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(d) is a document or chunk.&lt;/li&gt;
&lt;li&gt;(R) represents the different ranked result lists.&lt;/li&gt;
&lt;li&gt;(r(d)) is the rank of the document in a particular list.&lt;/li&gt;
&lt;li&gt;(k) is a smoothing constant.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Chunks that consistently appear near the top of multiple result lists receive higher combined scores.&lt;/p&gt;

&lt;p&gt;We can then sort the chunks and select the most relevant results.&lt;/p&gt;

&lt;p&gt;This helps us combine information retrieved through multiple query perspectives.&lt;/p&gt;

&lt;h3&gt;
  
  
  Modular RAG architecture
&lt;/h3&gt;

&lt;p&gt;Our modular pipeline can now include:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;User Query → Routing → Query Generation → Multiple Retrieval Operations → RRF → Context → LLM → Answer&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We can also combine the techniques from Advanced RAG:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Query rewriting&lt;/li&gt;
&lt;li&gt;Reranking&lt;/li&gt;
&lt;li&gt;Retrieval&lt;/li&gt;
&lt;li&gt;Query fusion&lt;/li&gt;
&lt;li&gt;Routing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important idea is that these components are modules. We can add, remove or combine them depending on the application.&lt;/p&gt;




&lt;h2&gt;
  
  
  10. Putting Everything Together
&lt;/h2&gt;

&lt;p&gt;We've now explored three different RAG architectures.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Naive RAG&lt;/th&gt;
&lt;th&gt;Advanced RAG&lt;/th&gt;
&lt;th&gt;Modular RAG&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Document chunking&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vectorization&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Indexing&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Retrieval&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Query rewriting&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Can be included&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reranking&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Can be included&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Routing&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Not in our basic implementation&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Query fusion&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Not in our basic implementation&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flexible modules&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Somewhat&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The progression is straightforward:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Naive RAG:&lt;/strong&gt; Retrieve relevant chunks and generate an answer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Advanced RAG:&lt;/strong&gt; Improve retrieval using query optimization and post-retrieval processing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Modular RAG:&lt;/strong&gt; Combine multiple independent techniques to create a more flexible retrieval system.&lt;/p&gt;

&lt;p&gt;These aren't rigid definitions or mandatory stages. Real-world RAG architectures can combine techniques from different approaches.&lt;/p&gt;




&lt;h2&gt;
  
  
  11. What Comes After Modular RAG?
&lt;/h2&gt;

&lt;p&gt;Building a basic RAG system is only the beginning.&lt;/p&gt;

&lt;p&gt;There are several other directions worth exploring.&lt;/p&gt;

&lt;p&gt;Some important challenges include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Retrieval quality&lt;/li&gt;
&lt;li&gt;Generation quality&lt;/li&gt;
&lt;li&gt;Chunking strategies&lt;/li&gt;
&lt;li&gt;Context relevance&lt;/li&gt;
&lt;li&gt;Query understanding&lt;/li&gt;
&lt;li&gt;Latency and cost&lt;/li&gt;
&lt;li&gt;Evaluation and reliability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can also explore different optimization strategies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Iterative RAG&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The system retrieves information, generates an answer and repeats retrieval when more information is needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recursive RAG&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The system can break complex questions into smaller questions and retrieve information recursively.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adaptive RAG&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The system adapts its retrieval strategy depending on the query and task.&lt;/p&gt;

&lt;p&gt;Beyond these approaches, we can explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dense embeddings&lt;/li&gt;
&lt;li&gt;Hybrid search&lt;/li&gt;
&lt;li&gt;Metadata filtering&lt;/li&gt;
&lt;li&gt;RAG evaluation&lt;/li&gt;
&lt;li&gt;Fine-tuning retrievers&lt;/li&gt;
&lt;li&gt;Context compression&lt;/li&gt;
&lt;li&gt;More advanced retrieval architectures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;RAG is not a single algorithm. It's a collection of techniques that can be combined to build better knowledge-grounded applications.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We started with a simple question:&lt;/p&gt;

&lt;p&gt;Why do we need RAG when we already have powerful LLMs?&lt;/p&gt;

&lt;p&gt;Then we built a complete progression:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Naive RAG from scratch.&lt;/li&gt;
&lt;li&gt;Advanced RAG with query rewriting and reranking.&lt;/li&gt;
&lt;li&gt;Modular RAG with routing, query fusion and Reciprocal Rank Fusion.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Along the way, we explored chunking, TF-IDF, vectorization, sparse matrices, FAISS, normalization, cosine similarity and prompt construction.&lt;/p&gt;

&lt;p&gt;My biggest takeaway is that understanding the individual components is much more valuable than simply knowing how to call a RAG framework.&lt;/p&gt;

&lt;p&gt;Once you understand the fundamentals, frameworks become tools rather than black boxes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep building, keep experimenting, and understand what's happening under the hood.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Watch the Complete Video Walkthrough
&lt;/h2&gt;

&lt;p&gt;I also recorded the complete implementation, explaining the concepts and building the different RAG architectures step by step using Python.&lt;/p&gt;

&lt;p&gt;🎥 &lt;strong&gt;RAG: Zero to Hero&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=aenpTk8blIs" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=aenpTk8blIs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're learning LLMs, Generative AI or AI engineering, I hope this resource helps you understand RAG from the ground up.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>rag</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
