AI Tutorial
Home All Courses Blog Interview Prep ↗ 0%
1
Curious builder 0 XP earned · 300 to level 2
0 days Finish a lesson to begin
Badge collection
0 of 5 unlocked
small wins to finish your path
Next lesson →

What is RAG

RAG is a simple idea with big consequences: before the model answers, look up the relevant facts and hand them over. This lesson explains why that works, when RAG is the right tool (and when it is not), the components of every RAG system, and then builds a complete — if tiny — RAG pipeline in plain Python so you can see every moving part.

Last updated: 01 Nov, 2026

The problem RAG solves

LLM limitationExampleHow RAG fixes it
No private knowledge“What is our parental-leave policy?”Retrieves the policy from your HR documents.
Knowledge cutoff“What changed in last week's release?”Retrieves the release notes, indexed today.
HallucinationInvents a plausible but wrong refund windowAnswers from retrieved text and cites it.
No provenanceUsers cannot verify the answerShows the source passages and links.
Access controlEveryone should not see every documentFilters retrieval by the user's permissions.
Definition · Grounding

Anchoring a model's answer in specific, provided evidence rather than its internal memory. A grounded answer can be checked against its sources.

RAG vs fine-tuning vs long context

RAGFine-tuningPaste everything (long context)
Adds new knowledgeYes, instantlyPoorly — better at style and formatYes
Updating dataRe-index changed filesRetrainEdit the prompt
CitationsNaturalNoPossible
Cost per questionLow (only relevant chunks)LowHigh (every token, every time)
Scales toMillions of documentsN/AOne context window
Best forQ&A over changing knowledgeConsistent behaviour, tone, formatA few documents, one-off analysis

They combine well: a fine-tuned model can be used inside a RAG system, and a long-context model lets you retrieve more chunks. But for “answer questions from our documents”, RAG is almost always the first thing to build.

The components

ComponentJobLesson
LoaderRead PDFs, HTML, Markdown, docs, tickets into textLoading and chunking
ChunkerSplit text into retrievable passagesLoading and chunking
Embedding modelTurn chunks and questions into vectorsEmbeddings and similarity
Vector storeStore vectors and find nearest neighbours fastVector stores
RetrieverChoose which chunks to use (search, filters, reranking)Retrieval patterns
GeneratorPrompt the LLM with context and produce a cited answerGeneration with sources

A complete RAG in 50 lines

Here is the whole pipeline with no libraries beyond NumPy. Read it top to bottom: it indexes four tiny documents, embeds a question, retrieves the best two chunks, and builds the prompt that would be sent to an LLM.

Python
import hashlib
import re

import numpy as np

STOPWORDS = {"a", "an", "the", "is", "are", "be", "can", "do", "does", "i", "my", "to",
             "of", "in", "on", "for", "and", "or", "what", "how", "it", "you", "your", "at"}


def words(text: str) -> list[str]:
    """Lowercase, drop stopwords, and strip a few suffixes (refunded -> refund)."""
    out = []
    for w in re.findall(r"[a-z0-9-]+", text.lower()):
        if w in STOPWORDS:
            continue
        for suffix in ("ing", "ed", "s"):
            if w.endswith(suffix) and len(w) > len(suffix) + 3:
                w = w[: -len(suffix)]
                break
        out.append(w)
    return out


def embed(text: str, dim: int = 256) -> np.ndarray:
    """Toy embedding: hashed bag of words, L2-normalised. Real models capture meaning."""
    vec = np.zeros(dim, dtype=np.float32)
    for word in words(text):
        bucket = int(hashlib.md5(word.encode()).hexdigest(), 16) % dim
        vec[bucket] += 1.0
    norm = np.linalg.norm(vec)
    return vec / norm if norm else vec


# 1. INDEX: documents -> chunks -> vectors
documents = {
    "refunds.md": "Annual plans can be refunded within 30 days of purchase. Monthly plans are not refunded.",
    "backups.md": "Backups run every night at 2 AM. You can restore any file from the last 90 days.",
    "security.md": "All backups are encrypted with AES-256. Two-factor authentication is required for admins.",
    "billing.md": "Invoices are emailed on the first day of each month. You can change your card in Settings.",
}
chunks = [{"source": name, "text": text} for name, text in documents.items()]
matrix = np.stack([embed(c["text"]) for c in chunks])          # shape (4, 256)


# 2. RETRIEVE: question -> vector -> most similar chunks
def retrieve(question: str, k: int = 2) -> list[dict]:
    scores = matrix @ embed(question)                          # cosine similarity
    best = np.argsort(-scores)[:k]
    return [{**chunks[i], "score": round(float(scores[i]), 3)} for i in best]


# 3. AUGMENT: build a grounded prompt
def build_prompt(question: str, hits: list[dict]) -> str:
    context = "\n".join(f"[{h['source']}] {h['text']}" for h in hits)
    return (
        "Answer using only the context. Cite sources in brackets. "
        "If the answer is not in the context, say you don't know.\n\n"
        f"Context:\n{context}\n\nQuestion: {question}"
    )


question = "Can I get a refund on an annual plan?"
hits = retrieve(question)
for h in hits:
    print(h["score"], h["source"])
print()
print(build_prompt(question, hits))
0.645 refunds.md 0.139 backups.md Answer using only the context. Cite sources in brackets. If the answer is not in the context, say you don't know. Context: [refunds.md] Annual plans can be refunded within 30 days of purchase. Monthly plans are not refunded. [backups.md] Backups run every night at 2 AM. You can restore any file from the last 90 days. Question: Can I get a refund on an annual plan?

Step 4 — generate — is one API call with that prompt, exactly as in the LLM Fundamentals course. The model reads the refund policy and answers “Yes, within 30 days of purchase [refunds.md]”. Everything else in this course is about making each of these steps more robust.

Where RAG systems fail

A RAG answer can only be as good as the context it receives. When answers are wrong, diagnose which stage failed:

FailureSymptomStage to fix
Content missingThe answer is not in any documentData: add or update documents
Bad chunkingThe answer is split across chunks or drowned in noiseChunking
Missed retrievalThe right chunk exists but is not in the top-kEmbeddings, hybrid search, query rewriting
Wrong rankingThe right chunk is retrieved but ranked low or cut offReranking, top-k
Unfaithful generationCorrect context, but the answer ignores or distorts itPrompt, model, citations
Stale indexAnswers reflect old versions of documentsRe-indexing pipeline
Note

Practitioners consistently find that most RAG quality problems are retrieval problems, not generation problems. When debugging, always print the retrieved chunks first.

Try it
  1. Run the mini RAG and ask “How long are backups kept?” — which document wins?
  2. Ask “What encryption do you use?” and check the retrieval scores.
  3. Ask something unrelated (“What is the CEO's name?”) and look at the scores. What threshold would you use to say “I don't know”?
Key takeaways
  • RAG retrieves relevant passages and gives them to the LLM as context for each question.
  • It solves private knowledge, freshness, hallucination, provenance, and access control.
  • Prefer RAG for knowledge, fine-tuning for behaviour, and long context for small one-off document sets.
  • Every RAG system has the same components: loader, chunker, embedder, vector store, retriever, generator.
  • Most failures are retrieval failures — always inspect what was retrieved.