Skip to Content

RAG — Interview Q&A

RAG (Retrieval-Augmented Generation) is the most common AI topic in interviews today because it is the spine of almost every production AI product. The pattern: take a user question, retrieve relevant chunks from a knowledge base, and ask the LLM to answer using only those chunks. Sounds simple. The failure modes are not.

The strongest candidates don’t just explain the architecture. They can troubleshoot it, identify bottlenecks, isolate failures, and explain trade-offs.


Q1 — Why does a RAG system start hallucinating?

What? A “hallucination” is any LLM answer that is factually wrong or unsupported by the retrieved context. It is a symptom, not a root cause.

Why? Because interviewers ask this to learn whether you debug the data layer first or jump to “switch to a better model.” Mature engineers start with retrieval, not generation.

How? The audit ladder, in order:

  1. Chunking: chunks too big dilute the match signal; too small lose context.
  2. Metadata filters: the question is about “customer fees” but no category=fees filter is applied, so the system pulls loan content.
  3. Retrieval misses: top-k returns irrelevant chunks because the embedding model drifts from expectation.
  4. Stale documents: ingested document is from 2023, the question is about a 2025 change.
  5. Embedding mismatch: ingestion used MiniLM-L6-v2, query uses mpnet-base-v2 — vectors are 384-d vs 768-d, comparison is meaningless.
  6. Context construction: chunks were retrieved correctly but truncated to fit the prompt window.

3 Scenarios

Scenario 1 — “Works for everyone except Customer #42” (metadata bug) The user’s question was about their specific product. The retriever retrieved generic docs. Diagnosis: customer_id filter is missing from the SQL WHERE clause. Fix: add WHERE customer_id = ? to the retrieval query.

Scenario 2 — “Suddenly worse after yesterday’s deploy” (embedding drift) The team swapped embedding models from MiniLM to OpenAI text-embedding-3-small but the document embeddings remained MiniLM. Diagnosis: comparing vectors from two different models. Fix: re-ingest all documents with the new embedding model in a single blue/green index swap.

Scenario 3 — “Works at 9 AM, terrible at 9 PM” (latency / cache eviction) RAG latency rose above the SLO, retrieval returned slow or no results. The chunks are correct but only 80 of the 100 retrieved make it to the LLM. Diagnosis: the prompt context window was hit; chunks were silently dropped right-to-left. Fix: route the dropped chunk metadata to a debug log; cap top-k to fit the budget; raise number of returned chunks only after evaluating the impact on precision.


Q2 — How do you choose a chunking strategy?

What? Chunking is how you split a document into retrievable units. Each unit becomes one row in the vector DB.

Why? Because every chunking mistake compounds: one bad boundary produces one bad retrieval, which produces one bad answer, multiplied by every user query that hits it.

How? Four rules:

  1. Size: 500-1000 tokens is the sweet spot for most LLM context windows.
  2. Overlap: 10-15%. Without overlap, a sentence that straddles chunks is invisible to retrieval.
  3. Boundaries: chunk on semantic boundaries (\n\n\n. → space), not just character-count.
  4. Metadata sidecars: preserve page numbers, section headers — so the LLM can cite Page 4 without re-prompting.

3 Scenarios

Scenario 1 — FAQ PDF with bullet points Pick: RecursiveCharacterTextSplitter(separators=["\n\n", "\n", ". ", " "]). Bullets become one chunk each; each answer carries its own metadata block (“FAQ: account opening”).

Scenario 2 — 200-page regulatory document Pick: hierarchical chunking — section-level chunks (1000-3000 tokens) containing smaller paragraph chunks (300 tokens). The router picks section first, then drills down. Avoids losing context that fixed-size chunking destroys.

Scenario 3 — Streaming JSON / semi-structured data Pick: JSON-aware splitter that respects object boundaries. A simple length-based splitter would cut a JSON object in half and produce garbage embedding. Use langchain.text_splitter.RecursiveJsonSplitter or equivalent.


Q3 — Cosine vs L2 vs inner-product — when do you use each?

What? Vector databases return “nearest neighbours” using a similarity metric. Three common ones: cosine, L2 (Euclidean), inner product.

Why? Because choosing the wrong metric silently degrades retrieval quality without any error message.

How? Rule of thumb:

3 Scenarios

Scenario 1 — Mixed-length documents (FAQs, PDFs, articles) Pick: cosine. A long document and a short document embedded at the same model produce different magnitudes but the same direction. Cosine handles this cleanly.

Scenario 2 — Image embeddings, fixed length Pick: cosine. Image embeddings tend to live on a unit sphere; magnitude is meaningless.

Scenario 3 — Pre-normalised user embeddings (face recognition mirrors) Pick: inner product. After L2-normalisation, cosine = inner product; using <#> is faster because no normalisation is computed.


Q4 — How do you debug “RAG returns empty results in production”?

What? A symptom where top_k returns zero or low-similarity chunks. Often mistaken for a model bug.

Why? Because the fix is almost never “change the LLM” — it is data plumbing. Interviewers test whether you walk the layers.

How? Walk three layers, top to bottom:

  1. Row check: SELECT COUNT(*) FROM chunks WHERE embedding IS NOT NULL; — emptiness here means ingestion failed silently.
  2. Embedding sanity: pick a question you know the answer to. Embed it. Compute cosine distance to every chunk manually. Look for distance < 0.3.
  3. Query introspection: is the query getting HyDE-expanded? Is there a multi-query rewrite happening? Is the metadata filter blocking valid hits?

3 Scenarios

Scenario 1 — Index never re-built after schema change The chunks.content column was renamed to chunks.body, but the ingest.py script still writes to old column. New rows are silently dropped. Fix: idempotent ingestion with a source_hash column so re-ingestion is observable.

Scenario 2 — Filter too aggressive Production code added category IN ('faq', 'faq_extended') to filter, but the orange of queries lives in category=help. Top-k returns zero. Fix: allowlist the missing category; rebuild the test corpus to catch this.

Scenario 3 — Multi-tenant data leak / leakage filter blocks legit hits A noisy-neighbour tenant caused the team to add a tenant-isolation filter. The filter is over-eager and excludes the current customer’s chunks. Fix: the filter should be WHERE tenant_id IN (...) not WHERE NOT IN (...).


Q5 — How do you evaluate a RAG system?

What? A measurement programme that tells you whether your retrieval is good enough. Without it, you ship guessing.

Why? Because you cannot improve what you cannot measure, and interviewers love engineers who set up measurement first.

How? Three pillars:

  1. Retrieval-only metrics: precision@k, recall@k, MRR (Mean Reciprocal Rank) — does the right chunk appear in the top-k?
  2. End-to-end metrics: answer faithfulness (is the LLM using the chunks?), answer relevance (does it answer the question?).
  3. Human-in-the-loop: weekly review of 50 sampled traces to catch issues the metrics miss.

3 Scenarios

Scenario 1 — “Our LLM is great, retrieval is bad” Retrieval-only metrics show precision@5 = 0.4. You build a golden set of 200 question/chunk-code pairs, run it weekly. Iterating on chunking strategy moves precision@5 from 0.4 → 0.6 → 0.75. The LLM was never the problem.

Scenario 2 — “Users say the LLM is bad” Faithfulness score (RAGAS) = 0.65. The model is hallucinating into the chunks rather than from them. Fix: tighten the prompt with stricter grounding instructions (“Answer using ONLY the context below. Quote the source.”).

Scenario 3 — “Latency is fine, cost is exploding” Cost-per-answer rises linearly with traffic. The team is running the LLM on every retrieval, even on cache hits. Fix: add a Tier 0 cache (Redis) for popular questions with TTL 1-24h. Cached hits skip retrieval and LLM.

Advertisement