RAG (Retrieval-Augmented Generation)

RAG connects LLMs to external knowledge at query time. Instead of relying on what the model memorised during training, you retrieve relevant documents and pass them as context for generation. The model answers grounded in your data, with citations back to the source.

Over 70% of RAG failures trace back to poor retrieval or chunking decisions, not the LLM itself. This article covers the full pipeline - from document ingestion to production evaluation - with emphasis on the decisions that actually determine quality.

The RAG Pipeline, Step by Step

Before the architecture diagrams and production patterns below, it helps to walk through what actually happens between a document landing in a source system and an LLM producing a grounded answer. RAG runs in two phases: an offline indexing phase that prepares the knowledge base, and an online query phase that runs on every user request.

Phase 1: Document indexing (offline)

This phase runs once per document, and again whenever source content changes.

  1. Collect documents - pull source material from PDFs, Word documents, wikis, databases, or wherever the knowledge lives.
  2. Extract text - convert each source format into plain text, stripping layout artefacts while preserving structure worth keeping (headings, tables, page boundaries).
  3. Chunk the text - split documents into smaller units sized for retrieval. See Chunking Strategies below for how this decision is actually made in production.
  4. Generate embeddings - run each chunk through an embedding model to produce a numerical vector.
  5. Store in a vector database - persist chunk text, embedding vector, and metadata (source document, page number, section heading) together. Metadata is what turns a vector match into a citable source.

Nothing in this phase happens in response to a user query. It runs as a batch or scheduled job, and letting that schedule go stale is one of the most common causes of the "stale answers" failure mode covered later in this article.

Phase 2: Query flow (online, per request)

Everything here happens synchronously, inside the request path, on every question a user asks.

  1. User asks a question - the query arrives as free text.
  2. Query understanding and framing - the system identifies intent, extracts key concepts, and expands ambiguous terms before anything gets embedded.
  3. Query chunking - complex or multi-part questions may be broken into logical sub-questions ahead of retrieval. This is query decomposition, covered under Query Transformation below.
  4. Convert the query to an embedding - using the same embedding model used during indexing. A mismatch here (different model, different version, different dimensionality) silently degrades every retrieval that follows.
  5. Run similarity search - the vector database compares the query vector against stored chunk vectors (approximate nearest-neighbour search at scale, not exhaustive comparison) and surfaces the closest matches.
  6. Retrieve the top-K chunks - keep the highest-scoring candidates. In production this list is rarely final; see Re-ranking below for why an initial top-50 typically gets cut down to a re-ranked top-5.
  7. Build the prompt - assemble the retrieved chunks and the original question into a single prompt for the LLM, along with any system instructions and citation formatting.
  8. Generate the final answer - send the assembled prompt to the LLM, which generates an answer grounded in the retrieved context rather than in training-time memory alone.
ℹ️
Info

The Naive RAG diagram below compresses this flow and skips steps 7 and 8 entirely - it embeds the raw query as-is. Advanced RAG and Agentic RAG extend steps 7 through 11 with query rewriting, hybrid search, re-ranking, and self-correction, at exactly the points where naive retrieval tends to fail.

Architecture

Naive RAG (baseline)

Advanced RAG (production)

Agentic RAG (2026 dominant pattern)

The agent decides what to retrieve, evaluates whether the context is sufficient, and re-retrieves if needed. This handles multi-hop questions and ambiguous queries that naive RAG fails on.

Chunking Strategies

Chunking is where most RAG pipelines fail. The wrong chunk size means either too little context (model hallucinates) or too much noise (model ignores relevant information).

StrategyHow it worksBest forTypical size
Fixed tokenSplit every N tokens with overlapGeneral documents, quick baseline512 tokens, 128 overlap
Recursive characterSplit by paragraphs, then sentences, then tokensStructured text with clear paragraphs1000 chars, 200 overlap
SemanticGroup sentences by embedding similarityDocuments without clear structureVariable (cluster-based)
Document structureSplit by headings, sections, pagesTechnical docs, manuals, specsSection-level
AgenticLLM decides chunk boundaries based on meaningHigh-value documents worth the costVariable

Chunking rules that hold across strategies

  • Always use overlap (10-20% of chunk size) to avoid splitting mid-thought
  • Preserve metadata (source file, page number, section heading) on every chunk
  • Smaller chunks = more precise retrieval but less context per chunk
  • Larger chunks = more context but noisier retrieval
  • Test with your actual queries, not synthetic benchmarks
# Recursive chunking with LangChain
from langchain.text_splitter import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000,
    chunk_overlap=200,
    separators=["\n\n", "\n", ". ", " "]
)

chunks = splitter.split_documents(documents)

Retrieval Patterns

Combines vector similarity with keyword matching. Catches both semantic meaning and exact terms that vector search misses.

# Azure AI Search hybrid query
results = search_client.search(
    search_text="rate limiting Azure OpenAI",  # keyword
    vector_queries=[VectorizableTextQuery(
        text="rate limiting Azure OpenAI",     # vector
        k_nearest_neighbors=10,
        fields="content_vector"
    )],
    query_type="semantic",                      # re-rank
    semantic_configuration_name="default",
    top=5
)

Re-ranking

Initial retrieval (vector or hybrid) returns candidates. A cross-encoder re-ranker scores each candidate against the query with full attention, producing much better ordering than cosine similarity alone.

Re-ranking adds 50-200ms latency but typically improves answer quality by 15-30%.

Query transformation

The user's raw query is often not the best search query. Transform it before retrieval:

TechniqueWhat it doesWhen to use
Query rewritingLLM rephrases for better retrievalConversational queries, pronouns
HyDEGenerate hypothetical answer, embed that insteadWhen query and document language differ
Query decompositionSplit complex query into sub-queriesMulti-hop questions
Step-back promptingAsk a broader question firstSpecific questions needing general context

Evaluation

Without automated evaluation, RAG quality degrades silently as document collections grow. Implement evaluation before production deployment.

RAGAS metrics (industry standard)

MetricMeasuresRequiresTarget
FaithfulnessAre claims in the answer supported by retrieved context?Context + answer>= 0.9
Answer relevancyDoes the answer address the question?Question + answer>= 0.85
Context precisionAre retrieved chunks relevant to the question?Question + context>= 0.8
Context recallDid retrieval find all necessary information?Ground truth + context>= 0.8
from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy, context_precision

results = evaluate(
    dataset=eval_dataset,
    metrics=[faithfulness, answer_relevancy, context_precision],
    llm=eval_llm
)

print(results)
# {'faithfulness': 0.92, 'answer_relevancy': 0.87, 'context_precision': 0.83}

Evaluation pipeline

Production Failure Modes

FailureSymptomRoot causeFix
HallucinationAnswer contains facts not in contextChunks too small, insufficient contextIncrease chunk size, add overlap
Wrong answerConfident but incorrectRetrieved wrong chunksImprove query transformation, add re-ranking
"I don't know" on valid questionsRefuses to answerRetrieval threshold too strictLower similarity threshold, add keyword fallback
Stale answersOutdated informationIndex not refreshedSchedule re-indexing, track document freshness
Slow responses>5s latencyToo many chunks, large contextReduce top-K, use streaming, cache frequent queries
Cost runawayUnexpected billsEmbedding every query, large context windowsCache embeddings, limit context tokens, use smaller models for simple queries

Technology Stack (2026)

LayerOptions
OrchestrationLangGraph, LlamaIndex Workflows, Semantic Kernel
Vector storeAzure AI Search, Pinecone, Weaviate, pgvector, Databricks Vector Search
Embedding modelstext-embedding-3-large (OpenAI), Cohere embed-v4, Gemini embedding
Re-rankersCohere Rerank, cross-encoder/ms-marco, Jina Reranker
EvaluationRAGAS, Phoenix (Arize), Langfuse, Azure AI Evaluation SDK
GenerationGPT-4o, Claude Sonnet, Gemini Pro, Llama 3.3

Key Takeaways

  • Hybrid search (vector + keyword) with semantic re-ranking is the production default. Pure vector search is not enough.
  • 70% of RAG failures are retrieval or chunking problems, not LLM problems. Debug retrieval first.
  • Implement RAGAS evaluation before production. Target: faithfulness >= 0.9, relevancy >= 0.85.
  • Agentic RAG (agent decides what/when to retrieve) is the 2026 dominant pattern for complex queries.
  • Chunk size is not one-size-fits-all. Test with your actual queries and documents, measure retrieval precision.