What is the core mechanism that distinguishes Self-RAG (Asai et al. 2023) and Corrective-RAG (CRAG, 2024) from a standard single-shot retrieve then generate pipeline?
Same topic, related formats. Practice these next.
Same topic, related formats. Practice these next.
Both add a self-reflective quality check on retrieval and act on it: Self-RAG via reflection tokens, CRAG via a lightweight evaluator. Standard RAG just trusts whatever came back.
Imagine you ask a friend to look something up in a library. Standard RAG is a friend who grabs the first books off the shelf and reads from them no matter what. Self-RAG and CRAG are friends who pause and ask themselves: are these books actually about the question? If not, they go back, try a different shelf, or search online. Self-RAG was trained to spend extra effort emitting little check mark words as it works, like 'do I even need a book here?' and 'does the book actually answer this?' CRAG is simpler: it has a small helper that scores how relevant the books look, and if the score is low, it switches strategies. Both share one big idea: do not blindly trust the first results.
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example.
Everything important, quickly.
8 min: explain the shared insight, walk Self-RAG's four reflection tokens, walk CRAG's three-grade evaluator, contrast with multi-query, and close with the 2026 tool-use reproduction.
# CRAG-style corrective gate.
from enum import Enum
class Grade(Enum):
CORRECT = "correct"
AMBIGUOUS = "ambiguous"
INCORRECT = "incorrect"
async def crag_answer(query: str) -> str:
chunks = await retrieve(query, top_k=8)
grade = await evaluator.grade(query, chunks) # T5-style classifier
if grade == Grade.CORRECT:
context = await knowledge_refinement(chunks) # strip level filter
elif grade == Grade.INCORRECT:
rewritten = await rewrite_query(query)
context = await web_search(rewritten)
else: # AMBIGUOUS
web = await web_search(query)
context = await knowledge_refinement(chunks) + web
return await generator.complete(query, context)| Aspect | Standard RAG | Self-RAG | CRAG |
|---|---|---|---|
| Quality gate | none | reflection tokens in generator | external evaluator model |
| Decides when to retrieve | always retrieves | [Retrieve] token per segment | always retrieves, then grades |
| Corrective action | none | self-critique, skip, refuse | web search, query rewrite |
| Generator requirement | any frozen LLM | fine-tuned on reflection data | any frozen LLM |
| Extra inference cost | 1x | 1.2-1.5x (reflection tokens) | 1.1-1.3x (one evaluator call) |
| 2026 adoption | default everywhere | via tool-use on frontier models | common in LangChain / LlamaIndex |
Real products, models, and research that use this idea.
What an interviewer would ask next. Try answering before peeking at the approach.
Red flags and common mistakes that signal junior thinking. Click to expand.
Conflating these with multi-query retrieval. Multi-query expands the question into paraphrases and runs them in parallel; Self-RAG and CRAG inspect the results and react to quality.
The night-before-the-interview bullets. Scan these on the way to the call.
Primary sources. Skim if you want the original framing.