RAG & Retrieval Systems Series — Presentation 05

Agentic RAG Patterns — From Single-Shot to Multi-Step

HyDE, query decomposition, Self-RAG, CRAG, iterative retrieval, query routing, and tool-using RAG with code and web.

HyDE Self-RAG CRAG Query Decomposition Iterative Retrieval Query Routing Tool-Using RAG
Query → Route / Decompose → HyDE / Rewrite → Retrieve → Grade → Re-retrieve? → Generate
00

Topics We'll Cover

01

From Single-Shot to Multi-Step Retrieval

Naive RAG is a single-pass pipeline: embed query → retrieve top-k → stuff into context → generate. This fails for compound questions (multiple sub-questions needing separate retrievals), ambiguous queries (query expansion helps), and unreliable corpora (retrieved docs may be irrelevant or outdated).

Naive RAG failure modes

  • "Compare the architecture of GPT-4 and Llama-3" → single embedding averages both → poor recall on either
  • "What was Apple's revenue in Q3 2025?" → corpus is 2023 vintage → retrieves stale data; no hallucination warning
  • "How does X work?" on a sparse corpus → top-k docs are marginally relevant → LLM hallucinates with apparent confidence

Agentic RAG capabilities

  • Decide whether to retrieve at all (Self-RAG)
  • Decompose a compound question into sub-queries, retrieve separately, merge answers
  • Grade retrieved docs and fall back to web search if quality is low (CRAG)
  • Iterate retrieval when the first pass was insufficient
  • Route different query types to the best index or tool
Complexity budget

Agentic patterns add latency and cost. Every additional LLM call adds 200–600 ms and ~0.5–2 k tokens. Design the loop so the “happy path” (good retrieval first try) is fast. Reserve multi-step patterns for queries that actually need them — query classification at the entry point lets you route simple queries to single-pass RAG and complex ones to the agentic loop.

02

HyDE — Hypothetical Document Embeddings

HyDE (Gao et al. 2022) addresses the query–document embedding gap: a short question and a long passage have very different embedding distributions even when semantically aligned. The fix: use an LLM to generate a hypothetical answer document, then embed that for retrieval.

User query
"What causes transformer vanishing gradients?"
→
LLM generates
hypothetical doc
(~150 tokens)
→
Embed
hypothetical doc
→
ANN search
in corpus
→
Rerank + generate
HyDE with OpenAI + sentence-transformers
from openai import OpenAI
from sentence_transformers import SentenceTransformer

llm = OpenAI()
embedder = SentenceTransformer("BAAI/bge-large-en-v1.5")

def hyde_retrieve(query: str, k: int = 10) -> list:
    # 1. Generate hypothetical answer
    hyp = llm.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user",
                   "content": f"Write a 100-word technical answer to: {query}"}],
        max_tokens=150,
    ).choices[0].message.content

    # 2. Embed the hypothetical answer (not the query!)
    vec = embedder.encode(hyp, normalize_embeddings=True)

    # 3. Retrieve against corpus
    return vector_db.search(vec, limit=k)
HyDE gains and limitations

On BEIR benchmarks, HyDE improves NDCG@10 by 5–15% over direct embedding of the query, especially for short keyword queries. It fails when the LLM hallucinates a factually incorrect hypothetical — the embedding then points to plausible-sounding but wrong documents. Mitigate by running HyDE in parallel with direct-query retrieval and using RRF to fuse both lists.

03

Query Decomposition for Compound Questions

Compound questions contain multiple independent sub-questions that each require separate retrieval. Embedding the full compound question produces an averaged vector that may not retrieve well for any single sub-question.

Sequential decomposition

Generate sub-queries one at a time; each may depend on the answer to the previous (step-back decomposition). Useful for multi-hop questions: "Who founded the company that acquired Slack?" → Q1: "Who founded Salesforce?" → Q2: "Did Salesforce acquire Slack?"

Parallel decomposition

Generate all sub-queries at once; retrieve independently; merge results before generation. Faster but sub-queries can't depend on each other. Good for multi-facet questions: "Compare X and Y on dimensions A, B, C." → retrieve A(X), A(Y), B(X), B(Y), C(X), C(Y) in parallel.

LangChain multi-query retriever (parallel decomposition)
from langchain.retrievers.multi_query import MultiQueryRetriever
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
retriever = MultiQueryRetriever.from_llm(
    retriever=vector_store.as_retriever(search_kwargs={"k": 5}),
    llm=llm,
    # Generates 3 alternative phrasings + the original
)

# Retrieves for all generated queries, deduplicates, returns union
docs = retriever.invoke("What are the limitations of RLHF for alignment?")
Step-back prompting

Step-back prompting (Zheng et al. 2023) is a related technique: before decomposing, ask the model for the more general “step-back” question that encompasses the specific query. Embed both the specific and the step-back question; retrieve for both; fuse. This improves recall for highly specific queries by also retrieving background context. Effective for technical documentation RAG where specific questions need conceptual background.

04

Self-RAG — Training the Model to Decide When to Retrieve

Self-RAG (Asai et al. 2023) fine-tunes a model to emit special reflection tokens that control retrieval dynamically. Unlike pipeline-controlled retrieval, the model itself decides whether retrieval is needed, whether retrieved docs are relevant, and whether its own output is grounded.

Token typeTokenMeaning
Retrieve[Retrieve] / [No Retrieve]Should retrieval be triggered for this generation step?
IsREL[Relevant] / [Irrelevant]Is the retrieved passage relevant to the query?
IsSUP[Fully supported] / [Partially supported] / [No support]Is the generated claim supported by the retrieved passage?
IsUSE[Utility:1–5]How useful is the overall response? Used for beam-search scoring.
Self-RAG vs pipeline RAG — when to choose each

Self-RAG requires a fine-tuned model. The original paper fine-tuned Llama-2-7B and 13B; Llama-3 variants exist on HuggingFace. If you're using a proprietary API (Claude, GPT-4), you cannot use Self-RAG directly — you must approximate it with a separate LLM classifier or use pipeline-controlled retrieval (CRAG). Self-RAG is most valuable when retrieval is expensive (large corpus, high reranker cost) and most queries don't need it. On knowledge-heavy tasks, Self-RAG with Llama-2-13B matches or beats GPT-3.5 + vanilla RAG.

05

Corrective RAG (CRAG) — Quality Classifier + Fallback

CRAG (Yan et al. 2024) adds a retrieval-quality classifier between the retrieval stage and the generation stage. If retrieved documents are classified as low-quality or irrelevant, the system falls back to a web-search augmented retrieval pass.

Query → First-stage retrieval (vector DB)
↓
Relevance classifier (cross-encoder or LLM-as-judge)
Each retrieved doc scored: {Correct, Incorrect, Ambiguous}
↓
Decision: ≥1 Correct? → proceed  |  All Incorrect? → web search  |  Mixed? → both
↓
Web search retrieval (Tavily, Bing API, SerpAPI)
Strip and reformat web results into passages
↓
Generate answer from corpus + web passages
LangGraph CRAG implementation

LangGraph (LangChain's agent orchestration framework) has a canonical CRAG tutorial. The graph has nodes: retrieve, grade_documents, transform_query, web_search, generate. Conditional edges route based on the grader's output. The relevance grader is typically a zero-shot GPT-4o-mini call with a binary yes/no schema (structured output). The web search node uses Tavily's TavilySearchResults tool. Full CRAG adds ~400–800 ms to the happy path but prevents the model from confabulating when the corpus is stale.

06

Iterative Retrieval Loops

Some questions cannot be answered from a single retrieval pass because the answer requires synthesising information across multiple documents, or because the initial query is underspecified and needs refinement based on what was found.

Retrieve-Read-Retrieve (RRR)

Retrieve an initial set of documents. Read them to identify what information is still missing. Formulate a second retrieval query targeting the gaps. Repeat until the model declares the context sufficient or a step limit is reached. Effective for multi-hop reasoning tasks (HotpotQA, MuSiQue). Maximum 2–3 iterations in production to contain latency.

IRCoT (Interleaved Retrieval & Chain of Thought)

Interleave chain-of-thought generation with retrieval: generate one reasoning step, retrieve a passage relevant to that step, continue generating the next step conditioned on the retrieved passage. Achieves state-of-the-art on 2WikiMultiHopQA. Cost: O(reasoning_steps) LLM calls + O(reasoning_steps) retrieval passes. Suitable only when answer quality outweighs latency.

Preventing infinite loops

Always enforce a maximum iteration count (typically 3) and a redundancy check: if the current retrieval query is semantically close to a previous one (cosine similarity > 0.95 of their embeddings), skip retrieval and proceed to generation. LangGraph add_conditional_edges with a counter check is the standard implementation pattern. Without these guards, an agentic loop on a poorly-populated corpus can call the LLM and retriever indefinitely.

07

Query Routing — Which Index for Which Question

A production RAG system may have multiple indexes: a dense vector index for prose, a BM25 index for code, a structured SQL database for factual lookups, and a web search tool for current events. Query routing selects the best retrieval path without trying all of them on every query.

Router types
LLM router (zero-shot)
Embedding classifier
Rule-based (regex, keyword)
Trained classifier (logistic regression)
Destinations
Internal vector DB
Code index (CodeBERT)
SQL / structured DB
Web search (Tavily)
Direct LLM (no retrieval)
Calendar / API tool
LlamaIndex semantic router (embedding-based)
from llama_index.core.selectors import LLMSingleSelector
from llama_index.core.tools import ToolMetadata

selector = LLMSingleSelector.from_defaults()

choices = [
    ToolMetadata(description="technical documentation", name="docs"),
    ToolMetadata(description="source code repository",     name="code"),
    ToolMetadata(description="current news and web",         name="web"),
]

result = selector.select(choices, query="How do I fix NullPointerException in Java 21 records?")
# Returns: SelectionOutput(index=1, reason="code-related query")
08

Tool-Using RAG — Retrieval + Code + Web

The most capable production RAG systems combine vector retrieval with other tools: code execution for numerical reasoning, web search for current events, SQL for structured data, and external APIs for live lookups. The model orchestrates which tools to call and in what order.

ToolPurpose in RAGLibrary/APIOutput type
Vector retrievalSemantic document lookupQdrant, pgvector, WeaviateRanked passage list
BM25 / keywordExact-match fallbackElasticsearch, BM25s Python libRanked passage list
Web searchCurrent events, out-of-corpus queriesTavily, Bing Search API, SerpAPISnippets + URLs
Code interpreterNumerical calculations, data transformationClaude Code, OpenAI Code InterpreterExecution result + stdout
SQL / text-to-SQLStructured factual lookups over tablesLangChain SQLDatabaseChain, vanna.aiTabular data
Citation lookupResolve DOI/arXiv IDs to abstract textSemantic Scholar API, CrossRef APIPaper metadata + abstract
ReAct + retrieval pattern

ReAct (Yao et al. 2022) interleaves reasoning (Thought) with action (Act) traces. For RAG, the model emits: Thought: I need to find the release date of GPT-4. Action: retrieval("GPT-4 release date"). Observation: GPT-4 was released March 2023. Thought: Now I can answer. This gives an auditable trace of retrieval decisions. LangChain's create_react_agent and LlamaIndex's ReActAgent both implement this. Claude and GPT-4-class models perform ReAct natively without fine-tuning.

09

What to Take Away

Where to next

Deck 06 covers GraphRAG and knowledge graphs: Microsoft GraphRAG communities, KG construction, property graphs (Neo4j, Memgraph, KuzuDB), hybrid graph + vector retrieval, and Cypher in agent loops.