Wicked Smart Data
LearnInsightsAboutContact
Sign InLet's Build
LearnInsightsAboutContact
Sign InLet's Build
Wicked Smart Data

Intelligence, automation, and expert execution — plus an elite library of free knowledge. We turn complexity into competitive advantage.

Start a conversation

Platform

  • Learning Paths
  • Insights
  • RSS Feed

Company

  • About
  • Contact
  • Work With Us

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Wicked Smart Data. All rights reserved.

Intelligence · Automation · Advantage

All Insights
AI & Machine Learning

Retrieval-Augmented Generation Explained: How RAG Works and When to Use It

LLMs are powerful reasoners, but they can't answer questions about your data — unless you give them a way to look things up. This lesson explains exactly how RAG works, walks you through building a real pipeline in Python, and shows you when to use it versus other approaches.

🌱 Foundation15 min readAug 24, 2026Updated Aug 24, 2026
Retrieval-Augmented Generation Explained: How RAG Works and When to Use It
On this page
  • Prerequisites
  • Why LLMs Can't Answer Questions About Your Data
  • The Three Stages of a RAG Pipeline
  • Stage 1: Indexing (the preparation work)
  • Stage 2: Retrieval (finding relevant context)
  • Stage 3: Augmented Generation (answering with context)
  • Building a Simple RAG Pipeline in Python
  • Step 1: Prepare and Index Your Documents
  • Step 2: Retrieve Relevant Chunks for a Query
  • Step 3: Generate an Answer Using Retrieved Context
  • When Should You Use RAG?
  • Hands-On Exercise
  • Common Mistakes & Troubleshooting
  • Summary & Next Steps
  • Retrieval-Augmented Generation Explained: How RAG Works and When to Use It

    Imagine you hire a brilliant consultant who has read every business book, academic paper, and industry report published before 2023. They're articulate, fast, and remarkably good at synthesizing ideas. But when you ask them about your company's Q3 earnings, the proprietary customer churn analysis your team just finished, or a news event from last week — they're lost. They'll either admit ignorance or, worse, confidently make something up. That's the fundamental problem with large language models (LLMs) used in isolation: they're extraordinarily capable reasoners, but their knowledge is frozen at a point in time and entirely disconnected from your data.

    Retrieval-Augmented Generation, or RAG, is the architecture that solves this. It gives your LLM a library card — a way to look things up before it answers, pulling relevant information from your documents, databases, or knowledge bases and using that information to ground its response. The result is an AI assistant that can reason about your specific data, stay current, and — critically — tell you where its answers came from.

    By the end of this lesson, you'll understand exactly how RAG works under the hood, when it's the right tool to reach for, and how to build a simple working RAG pipeline from scratch. You won't just know the buzzword — you'll be able to use it.

    What you'll learn:

    • Why LLMs have knowledge limitations and why fine-tuning alone doesn't fully solve the problem
    • How RAG works as a system: the retrieval step, the augmentation step, and the generation step
    • What vector embeddings and vector databases are and why they're central to RAG
    • How to build a basic RAG pipeline in Python using real documents
    • When RAG is the right architectural choice — and when it isn't

    Prerequisites

    • Basic Python familiarity (you should be comfortable reading and running a Python script)
    • A general understanding of what large language models are (you don't need to know how they work internally, just that they take text in and produce text out)
    • An OpenAI API key, or a free account with a provider like Cohere or Hugging Face — we'll use OpenAI in the examples, but the concepts translate directly

    Why LLMs Can't Answer Questions About Your Data

    To understand why RAG matters, you need to understand two hard limits that all LLMs share.

    Limit 1: The training cutoff. Every LLM is trained on a snapshot of data collected up to a certain date. GPT-4's knowledge, for example, doesn't include anything published after its training cutoff. If your users ask about recent regulatory changes, last quarter's results, or a product that launched six months ago, the model simply doesn't know.

    Limit 2: The context window. LLMs read and generate text inside a "context window" — think of it as the model's working memory. Modern models have impressively large windows (sometimes over 100,000 tokens), but they're still finite. You can't just paste your entire 500-page internal wiki into every prompt and hope for the best.

    A natural first instinct is to solve this through fine-tuning — taking a pretrained model and continuing to train it on your own data. Fine-tuning does work well for teaching a model how to behave (tone, format, domain-specific reasoning patterns), but it's a poor fit for teaching a model facts. Facts need to be updated constantly, and retraining a model every time your documentation changes is prohibitively expensive and slow. Fine-tuning also doesn't make the model reliably cite sources, which matters enormously in professional settings.

    RAG sidesteps both problems. Instead of baking knowledge into the model's weights, it retrieves knowledge at inference time — meaning every time a user asks a question. The model doesn't need to "remember" your documents; it just needs to be able to read and reason about them when they're placed in front of it.


    The Three Stages of a RAG Pipeline

    Every RAG system, from the simplest prototype to a production-grade enterprise search tool, follows the same three-stage architecture. Understanding these stages deeply is what separates someone who can copy-paste a tutorial from someone who can actually design and debug these systems.

    Stage 1: Indexing (the preparation work)

    Before your system can retrieve anything, it needs to know what's available. Indexing is the offline process of taking your source documents — PDFs, web pages, database records, support tickets, whatever — and converting them into a form that can be searched efficiently.

    This process involves three sub-steps:

    Chunking: You break your documents into smaller pieces. A 40-page policy document gets split into paragraphs or sections of, say, 500 words each. Why? Because you want to retrieve the relevant portion of a document, not an entire 40-page file. Chunk size is a tuning decision that matters — too small and you lose context; too large and you return too much noise.

    Embedding: Each chunk is passed through an embedding model, which converts text into a list of numbers called a vector. A vector is a mathematical representation of meaning. The magic of good embedding models is that chunks with similar meaning end up with vectors that are close together in mathematical space — even if they use completely different words. The phrase "the contract was terminated" and "the agreement was cancelled" will have very similar vectors.

    Storing: Those vectors get stored in a vector database — a specialized database built to answer the question "which vectors are closest to this query vector?" efficiently. Popular options include Pinecone, Weaviate, Chroma, and pgvector (an extension for PostgreSQL). The original text of each chunk is stored alongside its vector so you can retrieve it later.

    Stage 2: Retrieval (finding relevant context)

    When a user asks a question, the retrieval stage kicks in. Here's what happens:

    1. The user's question is passed through the same embedding model that was used during indexing.
    2. This produces a query vector representing the meaning of the question.
    3. The vector database performs a similarity search — mathematically finding the stored chunks whose vectors are closest to the query vector.
    4. The top-k most relevant chunks (often 3–10) are returned.

    This is faster than it sounds. Modern vector databases can search millions of stored chunks in milliseconds using algorithms like approximate nearest neighbor search. The key insight is that you're not doing keyword matching — you're doing semantic matching. A question about "how do I cancel my subscription" will retrieve chunks about "account termination procedures" even if the word "cancel" never appears in the document.

    Stage 3: Augmented Generation (answering with context)

    Now you have both the user's question and a handful of relevant document chunks. You combine them into a single prompt — usually called the augmented prompt — and send that to the LLM.

    A typical augmented prompt looks something like this:

    You are a helpful assistant. Answer the user's question using only the 
    information provided in the context below. If the answer is not in the 
    context, say so.
    
    CONTEXT:
    [Chunk 1 text here]
    [Chunk 2 text here]
    [Chunk 3 text here]
    
    USER QUESTION:
    What is the process for requesting a contract amendment?
    

    The LLM reads the context you've provided, reasons over it, and generates an answer. Because the relevant information is sitting right there in the prompt, the model doesn't need to "remember" anything from training — it just needs to read and synthesize. And because you know exactly which chunks were used, you can display citations to the user.


    Building a Simple RAG Pipeline in Python

    Let's make this concrete. We'll build a minimal RAG pipeline that lets you ask questions about a small set of text documents. We'll use chromadb as our local vector database, sentence-transformers for embedding, and the OpenAI API for generation.

    First, install the dependencies:

    pip install chromadb sentence-transformers openai
    

    Step 1: Prepare and Index Your Documents

    import chromadb
    from sentence_transformers import SentenceTransformer
    
    # Initialize a local Chroma vector database
    client = chromadb.Client()
    collection = client.create_collection("company_policies")
    
    # Initialize an embedding model
    embedder = SentenceTransformer("all-MiniLM-L6-v2")
    
    # Simulated document chunks — in production, you'd load these from files
    documents = [
        "Employees may request up to 15 days of paid time off per calendar year. "
        "Requests must be submitted at least two weeks in advance via the HR portal.",
        
        "Contract amendments must be reviewed by the Legal department and signed "
        "by both parties. The amendment process typically takes 5-10 business days.",
        
        "The company reimbursement policy covers travel, lodging, and meals up to "
        "$75 per day. Receipts must be submitted within 30 days of the expense.",
        
        "Remote work arrangements are available to employees who have completed "
        "at least six months of employment. Approval is granted by the direct manager.",
    ]
    
    # Embed all documents and store them
    embeddings = embedder.encode(documents).tolist()
    
    collection.add(
        documents=documents,
        embeddings=embeddings,
        ids=[f"doc_{i}" for i in range(len(documents))]
    )
    
    print(f"Indexed {len(documents)} document chunks.")
    

    Step 2: Retrieve Relevant Chunks for a Query

    def retrieve(query: str, top_k: int = 2) -> list[str]:
        query_embedding = embedder.encode([query]).tolist()
        
        results = collection.query(
            query_embeddings=query_embedding,
            n_results=top_k
        )
        
        # results["documents"] is a list of lists; flatten the top result set
        return results["documents"][0]
    
    # Test retrieval
    user_question = "How do I get reimbursed for a business trip?"
    retrieved_chunks = retrieve(user_question)
    
    print("Retrieved chunks:")
    for i, chunk in enumerate(retrieved_chunks, 1):
        print(f"\n[{i}] {chunk}")
    

    You should see the reimbursement policy chunk returned as the top result, even though the question used the word "reimbursed" and the document used "reimbursement policy."

    Step 3: Generate an Answer Using Retrieved Context

    from openai import OpenAI
    
    openai_client = OpenAI(api_key="your-api-key-here")
    
    def answer_with_rag(question: str) -> str:
        # Retrieve relevant context
        chunks = retrieve(question)
        context = "\n\n".join(chunks)
        
        # Build the augmented prompt
        augmented_prompt = f"""You are a helpful HR assistant. Answer the employee's 
    question using only the information provided in the context below. If the 
    answer is not covered in the context, say "I don't have information about that."
    
    CONTEXT:
    {context}
    
    QUESTION:
    {question}
    
    ANSWER:"""
    
        response = openai_client.chat.completions.create(
            model="gpt-4o-mini",
            messages=[{"role": "user", "content": augmented_prompt}],
            temperature=0  # Zero temperature for factual Q&A — more on this below
        )
        
        return response.choices[0].message.content
    
    # Ask a question
    answer = answer_with_rag("What is the daily meal allowance for business travel?")
    print(answer)
    

    The model should answer with "$75 per day" and mention the receipt submission requirement — information it pulled directly from your documents, not from its training data.

    Why temperature=0? Temperature controls how "creative" the model is in choosing its next word. For factual retrieval tasks, you want deterministic, grounded answers. Setting temperature to 0 tells the model to always pick the highest-probability next token, reducing hallucination risk. For creative writing or brainstorming tasks, you'd want a higher value.


    When Should You Use RAG?

    RAG is a powerful tool, but it's not the right tool for every problem. Here's a practical framework for deciding.

    Use RAG when:

    • Your application needs to answer questions about documents, databases, or knowledge bases that change frequently (product documentation, legal filings, support knowledge bases)
    • You need the system to cite its sources so users can verify answers
    • Your information is proprietary and can't or shouldn't be part of a model's training data
    • You're building customer support, internal Q&A, or document search tools

    Don't reach for RAG when:

    • You need the model to learn a skill or style — use fine-tuning for that (e.g., training a model to always respond in your brand voice)
    • Your knowledge fits comfortably in the context window and doesn't change — just include it directly in the system prompt
    • You need real-time, live data (stock prices, live sensor readings) — RAG with a static index won't help here; you'd need a tool-calling architecture instead
    • Your corpus is tiny (fewer than 50 documents) — at that scale, you might just stuff everything into a long context prompt and skip the retrieval machinery entirely

    Watch out for this misconception: RAG doesn't eliminate hallucination. The model can still reason incorrectly over the retrieved context, misinterpret passages, or hallucinate when the retrieved chunks are only partially relevant. RAG reduces hallucination by grounding answers in real text — it doesn't eliminate the fundamental behavior.


    Hands-On Exercise

    Now it's your turn to extend the pipeline you built above.

    The challenge: Your HR assistant currently answers from a flat list of documents. Make it smarter in two ways.

    Part 1 — Add a new domain: Add five more document chunks from a different domain — say, a simplified IT help desk policy covering topics like password resets, software installation requests, and VPN access. Re-index the full collection, then test queries from both domains. Verify that the retriever correctly distinguishes HR questions from IT questions.

    Part 2 — Surface citations: Modify the retrieve function to also return the chunk IDs or a document label (e.g., "HR Policy - Section 3: Reimbursement"). Update the augmented prompt to ask the model to reference which source it used in its answer. Print both the answer and the source labels for every response.

    Stretch goal: Add a simple fallback. If the highest similarity score returned by Chroma falls below a threshold (e.g., 0.4), have the system respond with "I couldn't find relevant information about that in our knowledge base" instead of passing low-quality context to the LLM. This prevents the model from hallucinating answers when the retrieval step fails.


    Common Mistakes & Troubleshooting

    Mistake 1: Chunks that are too large or too small

    If your chunks are 3,000 words each, you'll retrieve entire sections of documents and flood the context window with irrelevant text. If they're 50 words each, you'll retrieve snippets with no surrounding context and the model won't have enough to work with. A good starting point is 300–500 words per chunk with a 50-word overlap between adjacent chunks so ideas don't get cut off at the boundary.

    Mistake 2: Using a different embedding model at query time than at index time

    This is a silent, catastrophic failure. If you index your documents with all-MiniLM-L6-v2 and then accidentally query with a different model, the vectors are in different mathematical spaces — similarity scores become meaningless. Always use the same model for both indexing and retrieval, and make this explicit in your configuration.

    Mistake 3: Ignoring the quality of the source documents

    RAG is a "garbage in, garbage out" system. If your source documents are poorly written, out of date, or contradictory, the model will faithfully surface that bad information. Curating and maintaining your knowledge base is not optional maintenance — it's core product work.

    Mistake 4: Treating retrieved context as ground truth in the prompt

    Don't write your prompt as "The following information is correct: [context]." The retrieved chunks are relevant candidates, not verified facts. A better framing is "Answer based on the following context" — this keeps the model's reasoning appropriately calibrated rather than forcing it to accept potentially flawed source material without question.

    Mistake 5: Not evaluating retrieval and generation separately

    When a RAG system gives a wrong answer, the bug could be in the retrieval (the wrong chunks were returned) or in the generation (the right chunks were returned but the model reasoned incorrectly over them). Log both the retrieved chunks and the final answer during testing. If the chunks are wrong, tune your chunking strategy, embedding model, or retrieval parameters. If the chunks are right but the answer is wrong, tune your prompt.


    Summary & Next Steps

    You now understand RAG from first principles. Here's the mental model to carry forward: a RAG system is a librarian (retrieval) paired with a synthesizer (generation). The librarian finds the relevant pages; the synthesizer reads them and writes a coherent answer. Neither works well without the other.

    The three-stage pipeline — index, retrieve, generate — is the backbone of nearly every production RAG system, whether it's a simple internal chatbot or a sophisticated enterprise search platform. The core components are embeddings (which convert text to mathematical meaning), vector databases (which search that meaning efficiently), and augmented prompts (which give the LLM the context it needs to answer accurately).

    Where to go next:

    • Advanced chunking strategies: Explore recursive character splitting, semantic chunking, and document-aware chunking for structured sources like PDFs with headers and sections
    • Hybrid search: Combine vector search with traditional keyword search (BM25) for better coverage — vector search is great for semantic similarity, but keyword search wins when users search for exact product names, ID numbers, or technical terms
    • Reranking: After retrieving the top-k chunks, use a cross-encoder reranker to reorder them by relevance before passing them to the LLM — this is one of the highest-leverage improvements you can make to retrieval quality
    • RAG evaluation frameworks: Learn tools like RAGAS or LlamaIndex's built-in evaluators to measure retrieval precision, answer faithfulness, and answer relevance systematically
    • Agentic RAG: Once you're comfortable with basic RAG, explore architectures where the LLM decides when to retrieve, what to search for, and whether the retrieved results are good enough — a pattern that unlocks much more complex workflows

    The best way to build intuition for this is to build something real. Pick a set of documents you actually work with — meeting notes, process documentation, a team wiki — and build a RAG pipeline around them. The edge cases and failure modes you'll encounter in real data will teach you more than any tutorial.

    Work With Us

    From insight to implementation

    Reading is the start. When you're ready to build the data, automation, or AI systems behind it, our team turns strategy into shipped results.

    Let's Build

    Building with LLMs

    Previous

    Implementing LLM Gateway Middleware: Centralized Auth, Rate Limiting, Audit Logging, and Fallback Routing Across Multiple Providers

    Related Insights

    AI & Machine LearningFoundation

    What Is Generative AI? A Plain-Language Guide for Data and Business Professionals

    17 min
    AI & Machine LearningExpert

    Guardrails for RAG Pipelines: Implementing Input Validation, Output Filtering, and Policy Enforcement in Production

    29 min
    AI & Machine LearningExpert

    Implementing LLM Gateway Middleware: Centralized Auth, Rate Limiting, Audit Logging, and Fallback Routing Across Multiple Providers

    29 min

    On this page

    • Prerequisites
    • Why LLMs Can't Answer Questions About Your Data
    • The Three Stages of a RAG Pipeline
    • Stage 1: Indexing (the preparation work)
    • Stage 2: Retrieval (finding relevant context)
    • Stage 3: Augmented Generation (answering with context)
    • Building a Simple RAG Pipeline in Python
    • Step 1: Prepare and Index Your Documents
    • Step 2: Retrieve Relevant Chunks for a Query
    • Step 3: Generate an Answer Using Retrieved Context
    • When Should You Use RAG?
    • Hands-On Exercise
    • Common Mistakes & Troubleshooting
    • Summary & Next Steps