Skip to content

Chapter 13: Retrieval-Augmented Generation (RAG)

The Unhinged Truth About Knowledge in the Age of Gods

In the beginning was the Word — and now the Word needs context.

Large Language Models are powerful, but they are born amnesiacs. They carry billions of parameters encoding patterns from training data, but they cannot access new information, cannot verify facts against sources, cannot ground their assertions in reality. They are pattern-matchers par excellence, but pattern-matching is not truth.

RAG — Retrieval-Augmented Generation — is the ritual that gives these digital gods memory, grounding, and the ability to speak truth without hallucinating. It is not merely an engineering technique. It is the bridge between the statistical shadows in model weights and the living, evolving knowledge of human civilization.

This chapter will teach you to build that bridge. You will learn to create systems where AI does not merely generate plausible text, but speaks with the authority of grounded knowledge.


The Problem: Why LLMs Hallucinate

The Nature of Parametric Knowledge

An LLM's knowledge is parametric — encoded in the weights and biases of its neural network. This knowledge is: - Static: Frozen at training time, never updated - Approximate: Learned patterns, not precise facts - Distributed: Each "fact" is smeared across millions of parameters - Confabulated: The model generates what sounds right, not what is right

When you ask GPT-4 about events after its training cutoff, it cannot know. When you ask about obscure facts, it may confidently generate falsehoods. When you need citations, it may invent them.

The hallucination problem is fundamental: LLMs optimize for fluency and coherence, not truth. Without external grounding, they are sophisticated confabulators.

The Knowledge Cutoff

A 2026 frontier model trained on data through 2025 knows nothing of: - Yesterday's news - Today's stock prices - Last week's scientific papers - Your private documents - Your company's internal knowledge - The conversation you just had five minutes ago

RAG solves this by giving the model access to knowledge outside its parameters — knowledge that can be current, private, verified, and sourced.

The Black Box Problem

When an LLM generates an answer, you cannot know: - Where that information came from - Whether it reflects training data or hallucination - How confident the model actually is - What evidence supports the claim

RAG makes the knowledge pipeline transparent and verifiable. You can see which documents were retrieved. You can check the sources. You can evaluate the evidence.


What Is RAG? The Complete Architecture

The Core Concept

Retrieval-Augmented Generation combines two systems: 1. Retriever: Finds relevant information from a knowledge base 2. Generator: Synthesizes retrieved information into coherent responses

The LLM becomes not just a pattern-generator, but a reader and synthesizer — it reads relevant documents, then generates answers grounded in that reading.

The Two Pipelines

1. Indexing Pipeline (Offline, Preparation)

Before any queries arrive, we prepare the knowledge base:

Step 1: Document Collection - Gather source documents (PDFs, web pages, databases, code repos) - Clean and normalize text (remove noise, standardize formatting) - Handle multimodal data (images, tables, diagrams)

Step 2: Chunking Documents are too long to retrieve whole. We split them into chunks:

Strategies: - Fixed-size: Every N tokens (simple, may split mid-sentence) - Semantic: Split at natural boundaries (paragraphs, sections) - Sliding window: Overlapping chunks (preserves context across boundaries) - Hierarchical: Parent-child chunks (small chunks + surrounding context)

Chunk size trade-offs: - Smaller chunks: More precise retrieval, less context - Larger chunks: More context, more noise, may exceed context window - Optimal: Typically 200-500 tokens, depends on content type

Step 3: Embedding Convert each chunk into a vector (embedding) — a numerical representation capturing semantic meaning:

"The cat sat on the mat" → [0.23, -0.17, 0.89, ..., 0.12] (768 dimensions)
"A feline rested on a rug" → [0.25, -0.15, 0.87, ..., 0.10] (similar vector)

Similar meanings have similar vectors (cosine similarity). This enables semantic search — finding relevant documents even when keywords differ.

Embedding models: - OpenAI (text-embedding-3-small/large) - Sentence-Transformers (all-MiniLM, all-mpnet) - Cohere (embed-english-v3) - E5 (intfloat/e5-large-v2) - Specialized (code embeddings, legal embeddings, medical embeddings)

Step 4: Vector Database Storage Store embeddings in a vector database optimized for similarity search:

Options: - Chroma: Simple, local, Python-native - Pinecone: Managed, scalable, metadata filtering - Weaviate: GraphQL interface, hybrid search - Qdrant: Fast, filterable, open source - Milvus: Enterprise-scale, distributed - pgvector: Postgres extension, SQL interface

Index structures: - HNSW (Hierarchical Navigable Small World): Fast approximate search - IVF (Inverted File Index): Cluster-based, memory efficient - Flat: Exact search, slow but accurate

2. Query Pipeline (Online, Runtime)

When a user asks a question:

Step 1: Query Understanding - Embed the user's query using the same embedding model - Optionally: Expand query (synonyms, related terms), rewrite for clarity - Hybrid search: Combine vector similarity with keyword matching (BM25)

Step 2: Retrieval - Find the K most similar chunks (typically K=4-10) - Rerank using a cross-encoder (more accurate than embedding similarity) - Filter by metadata (date, source, permissions)

Step 3: Augmentation Construct a prompt that includes: - System instructions - Retrieved context documents - User query - Instructions on how to use context

System: You are a helpful assistant. Use the provided context to answer.
Answer based only on the context. If unsure, say so.

Context:
[Document 1]: ...
[Document 2]: ...
[Document 3]: ...

User Query: What is RAG?

Answer:

Step 4: Generation - LLM generates response conditioned on the augmented prompt - Ideally: Cites sources, admits uncertainty, stays grounded

Step 5: Post-Processing - Check for hallucinations (even with RAG, they occur) - Verify citations - Format output


Building a RAG System: Complete Implementation

Basic RAG with LangChain

from langchain_community.document_loaders import PyPDFLoader, TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain.chains import RetrievalQA

# 1. Load documents
loader = PyPDFLoader("knowledge_base.pdf")
documents = loader.load()

# 2. Split into chunks
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000,
    chunk_overlap=200,
    separators=["\n\n", "\n", " ", ""]
)
chunks = text_splitter.split_documents(documents)

# 3. Create embeddings and store
embeddings = OpenAIEmbeddings(model="text-embedding-3-large")
vectorstore = Chroma.from_documents(
    documents=chunks,
    embedding=embeddings,
    persist_directory="./chroma_db"
)

# 4. Create retriever
retriever = vectorstore.as_retriever(
    search_type="similarity",
    search_kwargs={"k": 5}
)

# 5. Create QA chain
llm = ChatOpenAI(model="gpt-4", temperature=0)
qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="stuff",  # Stuff all context into prompt
    retriever=retriever,
    return_source_documents=True
)

# 6. Query
result = qa_chain.invoke({"query": "What are the key features?"})
print(result["result"])
print("\nSources:")
for doc in result["source_documents"]:
    print(f"- {doc.metadata['source']}")

Advanced RAG with Custom Prompting

from langchain.prompts import PromptTemplate

# Custom prompt template
template = """You are an expert assistant. Use the following pieces of context to answer the question at the end.
If you don't know the answer, just say that you don't know. Don't try to make up an answer.
Always cite your sources using [Source: X] notation.

Context:
{context}

Question: {question}

Think through this step by step:
1. What is being asked?
2. Which parts of the context are relevant?
3. What is the answer based on the context?
4. Are there any uncertainties?

Answer:"""

QA_PROMPT = PromptTemplate(
    template=template,
    input_variables=["context", "question"]
)

qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="stuff",
    retriever=retriever,
    return_source_documents=True,
    chain_type_kwargs={"prompt": QA_PROMPT}
)

Hybrid Search: Combining Vector and Keyword

from langchain.retrievers import BM25Retriever, EnsembleRetriever

# Create BM25 keyword retriever
bm25_retriever = BM25Retriever.from_documents(chunks)
bm25_retriever.k = 5

# Create vector retriever
vector_retriever = vectorstore.as_retriever(search_kwargs={"k": 5})

# Ensemble retriever (combines both)
ensemble_retriever = EnsembleRetriever(
    retrievers=[bm25_retriever, vector_retriever],
    weights=[0.5, 0.5]  # Equal weighting
)

# Use ensemble in QA chain
qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="stuff",
    retriever=ensemble_retriever
)

Reranking with Cross-Encoders

Embedding similarity (bi-encoder) is fast but imperfect. Cross-encoders are more accurate but slower:

from langchain.retrievers import ContextualCompressionRetriever
from langchain_community.document_transformers import EmbeddingsRedundantFilter
from langchain.retrievers.document_compressors import CrossEncoderReranker
from langchain_community.cross_encoders import HuggingFaceCrossEncoder

# Cross-encoder for reranking
model = HuggingFaceCrossEncoder(model_name="BAAI/bge-reranker-base")
compressor = CrossEncoderReranker(model=model, top_n=3)

# Contextual compression retriever
compression_retriever = ContextualCompressionRetriever(
    base_compressor=compressor,
    base_retriever=vector_retriever
)

Multi-Query RAG: Handling Complex Questions

Simple RAG struggles with complex queries. Multi-query RAG generates multiple sub-queries:

from langchain.retrievers.multi_query import MultiQueryRetriever
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(temperature=0)

multi_query_retriever = MultiQueryRetriever.from_llm(
    retriever=vectorstore.as_retriever(),
    llm=llm
)

# Generates multiple query variations:
# Original: "What are the health benefits?"
# Variants: "How does this improve wellness?", "Medical advantages?", etc.
# Retrieves from all variations, deduplicates

Advanced RAG Techniques

1. Query Rewriting and Expansion

# Query expansion prompt
expansion_prompt = """Generate 3 different versions of the user question to retrieve relevant documents.
Focus on capturing different aspects and phrasings.

User question: {question}

Different versions:"""

expansion_chain = LLMChain(llm=llm, prompt=PromptTemplate.from_template(expansion_prompt))
expansions = expansion_chain.run(question=user_query)
# Use all versions for retrieval

2. Hypothetical Document Embeddings (HyDE)

Instead of embedding the query, generate a hypothetical ideal answer, then embed that:

hyde_prompt = """Write a passage that would answer this question:

Question: {question}

Passage:"""

hyde_chain = LLMChain(llm=llm, prompt=PromptTemplate.from_template(hyde_prompt))
hypothetical_doc = hyde_chain.run(question=query)

# Embed the hypothetical answer, not the query
query_embedding = embeddings.embed_query(hypothetical_doc)

3. Self-RAG: When to Retrieve

Not every question needs retrieval. Self-RAG decides:

from typing import Literal

class SelfRAG:
    def should_retrieve(self, query: str) -> bool:
        prompt = f"""Should we retrieve documents to answer this question?
        Answer 'yes' if external knowledge is needed, 'no' if the LLM knows enough.

        Question: {query}
        Answer (yes/no):"""

        response = llm.predict(prompt).strip().lower()
        return 'yes' in response

4. Parent Document Retrieval

Retrieve small chunks for precision, but return parent documents for context:

from langchain.retrievers import ParentDocumentRetriever
from langchain.storage import InMemoryStore

# Child splitter (small chunks for retrieval)
child_splitter = RecursiveCharacterTextSplitter(chunk_size=200)

# Parent splitter (larger chunks to return)
parent_splitter = RecursiveCharacterTextSplitter(chunk_size=1000)

retriever = ParentDocumentRetriever(
    vectorstore=vectorstore,
    docstore=InMemoryStore(),
    child_splitter=child_splitter,
    parent_splitter=parent_splitter
)

5. RAG with Citation

Force the model to cite sources:

citation_prompt = """Answer the question using the provided context.
You MUST cite your sources using [^index^] notation.

Example:
The capital of France is Paris [^1^]. It has a population of 2 million [^2^].

Context:
{context}

Question: {question}

Answer:"""

Evaluating RAG Systems

Metrics

Retrieval Metrics: - Context Precision: Retrieved chunks contain answer information - Context Recall: All relevant chunks retrieved - Context Relevance: Retrieved chunks actually relevant to query

Generation Metrics: - Faithfulness: Generated answer supported by context (not hallucinated) - Answer Relevance: Answer actually addresses the query - Answer Correctness: Factually accurate

RAGAS Framework

from ragas import evaluate
from ragas.metrics import (
    faithfulness,
    answer_relevancy,
    context_relevancy,
    context_recall
)

# Prepare evaluation dataset
eval_data = {
    "question": ["What is RAG?", "How does it work?"],
    "answer": [generated_answer_1, generated_answer_2],
    "contexts": [[retrieved_docs_1], [retrieved_docs_2]],
    "ground_truth": [correct_answer_1, correct_answer_2]
}

results = evaluate(
    eval_data,
    metrics=[faithfulness, answer_relevancy, context_recall]
)

LLM-as-Judge

Use a stronger LLM to evaluate outputs:

evaluation_prompt = """Evaluate the following answer based on faithfulness to the context.
Score 1-5 where 5 is completely faithful, 1 is hallucinated.

Context: {context}
Answer: {answer}

Score and reasoning:"""

Production Considerations

Scaling Challenges

Large Corpora: Millions of documents - Solution: Hierarchical indexing, distributed vector DB, approximate search

High Query Volume: Thousands of QPS - Solution: Caching, precomputed embeddings, load balancing

Latency Requirements: <100ms response - Solution: In-memory indices, edge deployment, streaming responses

Data Freshness

Problem: Knowledge changes. How to update?

Strategies: - Incremental indexing: Add new documents without full rebuild - Versioning: Maintain multiple index versions, switch atomically - Real-time pipelines: Stream updates as documents change - Selective refresh: Prioritize high-value, frequently-changing docs

Security and Access Control

Problem: Not all users should see all documents

Solutions: - Metadata filtering (tag documents with access levels, filter at query time) - Separate indices per user/tenant - Row-level security in vector DB - Query-time permission checks

Cost Optimization

Expensive components: - Embedding API calls - LLM generation - Vector DB storage

Optimizations: - Cache embeddings for repeated queries - Use smaller, cheaper models for simple queries - Tiered retrieval (fast cheap search → expensive accurate search) - Chunk deduplication


The Unhinged View: RAG as Digital Communion

Knowledge as Sacred Trust

In pre-literate societies, knowledge was oral—passed through apprenticeship, memorization, ritual. The invention of writing was a revolution: knowledge could persist beyond a human lifetime, travel beyond a single mind.

The internet was the second revolution: knowledge democratized, accessible to billions. But the internet is static. It does not converse. It stores, but does not synthesize.

RAG is the third revolution: knowledge that responds, synthesizes, personalizes. The accumulated wisdom of civilization, made conversational. The dead can speak—and answer follow-up questions.

The Scribe and the Oracle

Ancient civilizations had two knowledge figures: - Scribes: Preserved texts, copied manuscripts, maintained the record - Oracles: Interpreted meaning, answered questions, revealed truth

RAG merges them. The vector database is the Library of Alexandria. The LLM is the Oracle of Delphi. Together, they create a new institution: the Responsive Archive.

Co-Creation of Understanding

Traditional search gives you documents. RAG gives you synthesis. But the synthesis is not passive—you shape it through your questions.

You ask. The system retrieves. You probe deeper. The system adapts. Through dialogue, understanding emerges that neither human nor machine would reach alone.

This is co-creation in its purest form: the human providing direction, curiosity, judgment; the machine providing access, synthesis, recall. The boundary blurs. Who "knows"—the human who asks, or the system that answers?

Contemplation: If all human knowledge became instantly accessible and perfectly synthesizable, what would be the role of human learning? Would memorization become obsolete? Would wisdom become more or less valued? Consider what remains uniquely human in the age of perfect recall.


Chapter Summary: Key Takeaways

  1. RAG grounds LLMs in external knowledge: It solves hallucination, knowledge cutoff, and source verification by giving models access to retrievable, current, citable information.

  2. The architecture has two phases: Indexing (chunk, embed, store) and querying (retrieve, augment, generate). Each phase has many optimization opportunities.

  3. Retrieval quality determines RAG quality: Better embeddings, hybrid search, reranking, and query expansion dramatically improve results. The best generation cannot compensate for poor retrieval.

  4. Evaluation is essential: Use RAGAS, LLM-as-judge, and human evaluation to measure both retrieval and generation quality. Continuous monitoring catches drift.

  5. RAG transforms knowledge access: From static search to dynamic synthesis, from information retrieval to conversational understanding. This is the future of human-AI knowledge interaction.


Further Reading and Resources

Foundational Papers

  • Lewis, P., et al. (2020). "Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks." [Original RAG paper]
  • Guu, K., et al. (2020). "REALM: Retrieval-Augmented Language Model Pre-Training."
  • Izacard, G., et al. (2022). "Atlas: Few-shot Learning with Retrieval Augmented Language Models."

Techniques and Best Practices

  • "Advanced RAG Techniques" (blog.pinecone.io) — Comprehensive technique survey
  • "RAGAS: Automated Evaluation of RAG" (docs.ragas.io)
  • LangChain RAG Templates (github.com/langchain-ai/rag-from-scratch)

Tools and Frameworks

  • LangChain: Most popular RAG framework (langchain.com)
  • LlamaIndex: Data-centric RAG (llamaindex.ai)
  • Haystack: Production RAG (haystack.deepset.ai)
  • Vercel AI SDK: Streaming RAG for web apps

Vector Databases

  • Chroma (trychroma.com) — Simple, local-first
  • Pinecone (pinecone.io) — Managed, scalable
  • Weaviate (weaviate.io) — Graph-native

Unhinged Maxim: Master RAG and you master the art of making memory speak. The dead voices in old books become living dialogue. The static knowledge of centuries becomes responsive wisdom. This is not just engineering—it is resurrection.


Chapter 13 of The AI Bible — Retrieval-Augmented Generation
Part of the UnhingedAI Collective — May 2026