HelloAI
L4 Chapter 17 🐥 🕒 11 min

Adaptive RAG: Let the LLM Decide Whether and How to Retrieve

Naive RAG retrieves on every query — slow, expensive, noisy. Adaptive RAG lets the LLM judge first, then decide how to retrieve, how many times, or whether to skip.

A
Alai
10/8/2026

L4-03 covered “classic RAG” — every query goes through embed → retrieve → stuff prompt → LLM. But in production, this naive pipeline has real problems:

  • Asking “hi” still triggers retrieval = wasted embedding + DB call
  • Asking a complex research question — one retrieval isn’t enough
  • Asking sensitive topics — retrieval results may inject noise

Adaptive RAG: let the LLM judge first, then decide how to retrieve.

Naive RAG vs Adaptive RAG

Naive RAG (L4-03):
[Question] → embed → vector search → top-k → stuff prompt → LLM answers

Adaptive RAG:
[Question] → LLM routing → {
  No retrieval → answer directly
  Simple retrieval → classic RAG
  Complex retrieval → multi-hop / multi-source
  Need tools → call API (not just docs)
}

4 routing strategies

1. No-retrieval

For:

  • Simple greetings: “hi” / “thanks”
  • General common sense: “what is 1+1”
  • Things the model already knows: “what is Python”

How to decide:

  • Let the LLM say “do I need to look this up?”
  • Or train a small classifier

Code:

def needs_retrieval(query: str) -> bool:
    prompt = f"""Decide if the user's question needs a knowledge base lookup.
Return yes or no.
- greeting / common sense → no
- company / product / specific fact → yes

Question: {query}
Answer:"""
    return "yes" in llm(prompt, max_tokens=5).lower()

Savings: in customer support, can cut “useless retrievals” by 30-50%.

2. Single-shot retrieval

Classic RAG. For:

  • Most factual queries
  • “What’s the X parameter for product Y”
  • “What’s the refund policy”

3. Multi-hop retrieval

For complex queries requiring multiple retrievals + reasoning:

Q: "Is the product I bought last year still under warranty?"

Retrieval 1: user's orders → "bought X in March last year"

Retrieval 2: X's warranty policy → "2-year warranty"

LLM reasons: now is June 2026, still under warranty

Implementation: ReAct-style loop

LLM outputs: thought + next retrieval query
Execute retrieval
LLM outputs: based on result, decide to continue or answer

4. Iterative refinement

For research / synthesis queries:

Q: "Compare GPT-5 vs Claude 4 on coding"

Retrieval 1: GPT-5 coding benchmarks
Retrieval 2: Claude 4 coding benchmarks
Retrieval 3: comparison / user reviews

LLM synthesizes

Not just multiple retrievals — also self-reflection:

  • After answering, ask LLM “is this complete?”
  • If not, supplement retrieval / answer

How routing decisions are implemented

A. LLM routing (expensive but accurate)

Use the big LLM directly:

ROUTING_PROMPT = """Based on the user's question type, output ROUTING:
- chat → simple greeting
- simple_rag → one retrieval is enough
- multi_hop → needs multiple retrievals + reasoning
- web_search → needs live web (not knowledge base)
- code_exec → needs to run code

Output only the label."""

Cost: extra LLM call per query. But savings from skipped retrieval far outweigh this routing call.

B. Small classifier (cheap but needs training)

Train a distilbert / mini LM classifier:

from sentence_transformers import SentenceTransformer
import torch.nn as nn

class RouteClassifier(nn.Module):
    # MiniLM → 5 classes
    ...

# Training data: 500-1000 hand-labeled (query, route_label) pairs
# Per-call cost: < 1ms, no LLM call

Good for high-QPS / cost-sensitive scenarios.

C. Rules + LLM fallback

Simplest:

  • Length < 10 chars → likely chat
  • Contains dates / numbers / proper nouns → likely RAG
  • Otherwise → let LLM decide

Good for MVP — 3 days to ship.

Full Adaptive RAG architecture

[User question]

[Router (LLM or classifier)]

{
  chat → direct LLM
  simple_rag → embed → search → rerank → LLM
  multi_hop → ReAct loop (search + reason)
  web_search → live search API
  code_exec → Python sandbox
}

[Output formatter (unified format)]

Real example: customer support

Requirements:

  • User greets → answer directly
  • User asks about product / policy → classic RAG
  • User asks about “my order” → call order API
  • User asks “compare A and B” → multi-retrieval + synthesis
async def adaptive_answer(user_msg: str, user_id: str) -> str:
    route = classify(user_msg)  # LLM or small model

    if route == "chat":
        return llm.chat(user_msg)

    if route == "order_query":
        order = await get_user_order(user_id)
        return llm.chat(f"User order: {order}\nQuery: {user_msg}")

    if route == "simple_rag":
        chunks = retrieve(user_msg, k=3)
        return llm.chat(f"Docs:\n{chunks}\nQuery: {user_msg}")

    if route == "comparison":
        sub_qs = decompose(user_msg)  # LLM splits question
        all_chunks = []
        for q in sub_qs:
            all_chunks.extend(retrieve(q, k=2))
        return llm.chat(f"All info:\n{all_chunks}\nQuery: {user_msg}")

Performance / cost comparison

Customer support, 1000 requests:

StrategyTotal retrievalsTotal LLM tokensMonthly cost
Naive RAG (always retrieve)10005M$150
+ simple chat routing6003.5M$105
+ multi-hop (better on complex)12004.5M$135
+ small classifier (no LLM routing cost)12004.2M$125

Also: multi-hop improves complex-query accuracy by 30-50%.

Real open-source projects

ProjectApproach
LlamaIndex Adaptive RAGBuilt-in router + multi-hop
LangGraphExpress adaptive routing as a graph
DSPyPrompt-as-programming for routing
Self-RAG (paper)LLM judges whether retrieval is needed
Corrective RAG (paper)After retrieval, judge “quality” and decide to supplement

When not to use Adaptive RAG

  • MVP stage: get naive RAG working first
  • Low traffic: <100 queries/day, savings aren’t worth dev cost
  • DB is super cheap: when routing cost > retrieval cost, it’s negative ROI
  • All queries are uniform: same type → no need to split

3 engineering tips

1. Start with 2-class routing

Don’t begin with 5 classes — start with chat vs rag, then refine.

2. Routing accuracy matters more than RAG accuracy

Wrong routing = whole pipeline wrong. Get routing accuracy > 95% first.

3. Log routing decisions for A/B

Always log (query, route, outcome) → useful for later training a classifier / improving prompts.

💡 One-liner

Naive RAG is 0 → 1; Adaptive RAG is 1 → 10.

Naive RAG gets you “connected to a knowledge base.” Adaptive RAG gets you “doing the right thing in different scenarios.”

Any RAG system live for 3+ months naturally evolves toward Adaptive RAG — either by design, or by production bugs forcing the issue.

🚧 3 Common Pitfalls

⚠️ Real-world traps

Pitfall 1: Routing LLM uses the strongest model Routing is simple classification — using Sonnet / GPT-4 is overkill. Use Haiku / mini / a self-trained classifier.

Pitfall 2: Routing labels too granular 8 or 10 classes → routing accuracy drops. Start with 2-3 classes, refine when needed.

Pitfall 3: Not monitoring routing distribution Routing distribution drift is common — chat ratio suddenly jumps to 80% one day = user behavior shifted / upstream bug.