Compiling the next screen…
Compiling the next screen…
Sun Mar 08 2026
David Bleeker, Principal Consultant

Retrieval-augmented generation has become the default answer to almost every knowledge problem in AI applications. Need enterprise search? Add a vector database. Need a chatbot over docs? Add retrieval. Need better factuality? Add retrieval again.
The public question stream tells a different story. Engineers on Stack Overflow are asking much more specific versions of the problem: should every conversational turn hit the vector store, how do you avoid irrelevant chunks poisoning the answer, and how do you know when retrieval is helping versus merely making the system more expensive and harder to debug?
That is the right framing. RAG is not a feature. It is a tradeoff. Retrieval introduces another subsystem with its own failure modes: bad chunking, stale indexes, weak query rewriting, poor filtering, duplicate context, and ranking drift. When teams add it reflexively, they often increase both cost and answer variance.
When should an AI application use retrieval, and how do you keep RAG from making answers worse?
You should use retrieval only when the answer depends on external, changing, proprietary, or high-volume information that the base model cannot reliably carry in-context by itself.
That seems obvious, but many systems violate it. They run retrieval for arithmetic, generic product explanations, or low-stakes conversation turns where the model already has enough background knowledge. In those cases retrieval adds latency and context noise without adding meaningful truth.
Retrieval is usually warranted when all three conditions are true:
If one of those is missing, retrieval may be unnecessary.
The most common RAG failure is not bad embeddings. It is bad retrieval policy. Teams often query the store on every turn, regardless of intent. That injects low-signal chunks into easy interactions and makes the model anchor on accidental matches.
The fix is to introduce a retrieval gate. Instead of "always retrieve," ask a narrower question first: does this request actually need corpus evidence? That gate can be deterministic, model-based, or hybrid. In practice, a hybrid approach works well:
A strong RAG system is boring. It retrieves a small number of highly relevant passages, attaches provenance, and declines to answer when confidence is low. It does not maximize tokens retrieved. It maximizes useful signal.
The main tradeoff is recall versus contamination. If you fetch too little, you miss the critical fact. If you fetch too much, you dilute the answer with unrelated context. Most teams err on the side of too much retrieval because it feels safer. In reality, too much context often lowers answer quality by making the model solve a ranking problem inside the prompt.
Another risk is hiding retrieval quality behind generation quality. A fluent answer can conceal a weak retrieval stage. That is why production evaluation has to separate:
If you evaluate only the final answer, you cannot tell whether the problem came from ranking, chunking, filtering, or the model.
An experienced developer insight here is that RAG quality often improves more from metadata and ranking work than from swapping embedding models. Better document boundaries, recency filters, tenant scoping, and section-aware chunking usually beat another week of model shopping.
The architecture recommendation is to make retrieval conditional, typed, and measurable.
That means:
For conversational systems, keep two parallel states:
Do not use conversation history as a substitute for retrieval relevance. A conversation summary can help query rewriting, but it should not justify pulling corpus documents for every turn.
A practical production metric set looks like this:
That metric set is more useful than generic "hallucination rate" dashboards because it maps to actual tuning work.
type RetrievalDecision =
| { mode: 'skip'; reason: string }
| { mode: 'retrieve'; query: string; filters: Record<string, string> }
export function decideRetrieval(input: {
userQuery: string
productArea: string
tenantId: string
}): RetrievalDecision {
const normalized = input.userQuery.toLowerCase()
if (/^\s*what is 2\+2\??\s*$/.test(normalized)) {
return { mode: 'skip', reason: 'general knowledge question' }
}
if (normalized.includes('our policy') || normalized.includes('my account')) {
return {
mode: 'retrieve',
query: input.userQuery,
filters: { tenantId: input.tenantId, productArea: input.productArea },
}
}
if (
normalized.includes('in the docs') ||
normalized.includes('what changed')
) {
return {
mode: 'retrieve',
query: input.userQuery,
filters: { productArea: input.productArea },
}
}
return { mode: 'skip', reason: 'no source-specific dependency detected' }
}
export async function buildPromptContext(input: {
retriever: Retriever
decision: RetrievalDecision
}) {
if (input.decision.mode === 'skip') {
return { context: [], citations: [] }
}
const results = await input.retriever.search({
query: input.decision.query,
filters: input.decision.filters,
topK: 8,
})
const filtered = results.filter((item) => item.score >= 0.78).slice(0, 4)
return {
context: filtered.map((item) => item.chunkText),
citations: filtered.map((item) => ({
sourceId: item.sourceId,
title: item.title,
})),
}
}
The point of these snippets is not the threshold value. It is the shape: retrieval is a decision, not a reflex.
retrieval-augmented-generation reflects ongoing implementation questions around RAG systemsvector-search cover the retrieval layer that often sits underneath RAG systems