RAG & Vector Search Interview Questions — AI Engineering Practice
Reviewed by Mark Dickie · Last updated
Retrieval-augmented generation (RAG) is a pattern where a language model pulls context from an external knowledge store before producing an answer, and vector search is the mechanism most often used to find that context. In an AI engineering interview, you should know how embeddings represent text as high-dimensional vectors, how approximate nearest neighbor (ANN) algorithms trade recall for speed, how chunking strategy affects retrieval quality, and how to evaluate whether your pipeline is actually returning useful context. You will also be asked about re-ranking, hybrid search, metadata filtering, and failure modes like stale indices or embedding drift.
| Concept | What interviews test | Common follow-up |
|---|---|---|
| Embeddings | Dimensionality, distance metrics (cosine vs L2) | "When does cosine outperform dot product?" |
| ANN indexing | HNSW, IVF, PQ trade-offs | "How does HNSW balance recall and latency?" |
| Chunking | Fixed-size, semantic, sentence-window | "What happens if chunks are too large?" |
| Re-ranking | Cross-encoder vs bi-encoder | "Why re-rank if the retriever already scores?" |
| Evaluation | Recall@k, MRR, faithfulness | "How do you know retrieval failed vs generation?" |
What does a RAG interview question typically cover?
Most questions fall into one of these areas:
- Retrieval design — choosing the right index type, distance metric, and top-k value for a given dataset size and latency budget.
- Chunking and preprocessing — deciding how to split documents so that each chunk carries enough context without diluting relevance.
- Hybrid and filtered search — combining dense vector retrieval with sparse methods (BM25) or metadata filters to improve precision.
- Re-ranking — applying a heavier cross-encoder model to the top retrieved candidates to reorder them by true relevance.
- Pipeline evaluation — measuring retrieval quality (recall@k, nDCG) and generation quality (faithfulness, answer relevance) separately so you can localise failures.
How should I prepare for vector search questions?
Start by building a small RAG pipeline end to end — ingest a few hundred documents, embed them, store in a vector database like FAISS or pgvector, and run queries. The hands-on gaps you hit (poor recall on short queries, slow ANN at scale, chunks that split mid-sentence) are exactly what interviewers probe. Pair that with reading on index internals: understand why HNSW builds a graph, why product quantization compresses vectors at a recall cost, and why brute-force flat search still wins on small datasets.
The quiz below pulls from real interview questions on these topics. Work through them to find where your understanding holds up and where it needs another pass.
Key facts
- Tarmac has 29 AI Engineering interview questions on this topic, 25 of them on this page, at difficulty 1–5 of 5.
- Tarmac tracked 4,175 job postings asking for AI Engineering in August 2026.
- Roles asking for AI Engineering advertise a median base salary of US$180,000, across 773 job postings as of August 2026.
- Tarmac last reviewed these AI Engineering interview questions on 31 August 2026.
At a glance
| Questions | 25 shown · 29 in the bank |
|---|---|
| Difficulty | 1–5 of 5 |
| Formats | True / false, Fill in the blank, Flashcard, Code output, Short answer, Ordering, Multiple choice, Multiple answer, Find the bug, Design exercise |
What you'll review
- vector search
- rag
- embeddings
- rag basics
Practice questions
Try one before you open the answer. Pick an option and press Check; it's marked on the spot.
AI Engineering/rag/vector-search
An HNSW or IVF vector index run with typical production settings returns the mathematically exact top-k nearest neighbors for every query, the same result a brute-force scan would give.#
Options
Show answer
False. HNSW and IVF are both approximate nearest-neighbor (ANN) structures, not exact ones. HNSW's greedy graph traversal can settle into a local optimum and miss a true neighbor reachable only through an unexplored path, and IVF only searches the clusters closest to the query, which can exclude a true neighbor sitting just across a cluster boundary. Both trade a small, tunable amount of recall for search that's orders of magnitude faster than brute force. Only a flat, brute-force index that compares the query against every vector is guaranteed exact.
HNSW and IVF are both approximate nearest-neighbor (ANN) structures: HNSW's greedy graph traversal can settle into a local optimum and miss a true neighbor reachable only through a path it didn't explore, and IVF only searches the nprobe clusters closest to the query, which can exclude a true neighbor sitting just across a cluster boundary. Both trade a small, tunable amount of recall (often 90-99%+ at reasonable settings) for search that's orders of magnitude faster than brute force at scale. Only a flat/brute-force index, which compares the query against every vector, is guaranteed exact — and that's exactly the cost ANN indexes exist to avoid.
AI Engineering/rag
The acronym RAG stands for _____-Augmented Generation, a technique that supplements a language model's parametric knowledge with externally retrieved information at inference time.#
Show answer
The acronym RAG stands for Retrieval-Augmented Generation, a technique that supplements a language model's parametric knowledge with externally retrieved information at inference time.
RAG stands for Retrieval-Augmented Generation. The retrieval step fetches relevant passages from an external knowledge source (e.g., a vector database) and includes them in the prompt context so the model can ground its answer in up-to-date, source-specific information.
AI Engineering/rag/vector-search
Vector search ranks documents by similarity to the query embedding. The most common metric, which measures the angle between two vectors and ignores their magnitude, is _____ similarity.#
Show answer
Vector search ranks documents by similarity to the query embedding. The most common metric, which measures the angle between two vectors and ignores their magnitude, is cosine similarity.
Cosine similarity measures the angle between vectors, so it is invariant to vector length — useful because embedding magnitude often carries little semantic meaning. When embeddings are L2-normalized, cosine similarity, dot product, and (inverse) Euclidean distance rank results identically, which is why many vector stores normalize on ingest and then use a plain dot product internally.
AI Engineering/rag/vector-search
What is HNSW, and why is it a popular choice for vector search indexes?#
Show answer
HNSW (Hierarchical Navigable Small World) is an approximate-nearest-neighbor structure built as a multi-layer proximity graph: sparse, long-range links in the top layer let a query jump close to the right neighborhood quickly, and progressively denser layers below refine the search down to the exact nearest vectors. It's popular because it gives a strong recall/latency tradeoff — roughly logarithmic query cost — without a training/clustering step (unlike IVF's k-means), handles incremental inserts well, and its recall is tunable at query time via ef_search with no rebuild required.
HNSW's graph-of-graphs structure is what most production vector databases (Qdrant, Weaviate, Pinecone, pgvector's HNSW mode, FAISS) default to or offer, because it consistently lands near the top of ANN recall/latency benchmarks and is comparatively simple to operate: no offline clustering pass and reasonable behavior even as the dataset grows.
AI Engineering/rag
In a basic RAG (Retrieval-Augmented Generation) pipeline, source documents are first split into smaller passages through a process called _____. Each passage is then converted into a numerical vector using an _____ model and stored in a vector database so that relevant passages can be found via similarity search at query time.#
Show answer
In a basic RAG (Retrieval-Augmented Generation) pipeline, source documents are first split into smaller passages through a process called chunking. Each passage is then converted into a numerical vector using an embedding model and stored in a vector database so that relevant passages can be found via similarity search at query time.
The two foundational preprocessing steps in a RAG pipeline are chunking (dividing documents into manageable passages) and embedding (converting each passage into a dense vector). These vectors are what the vector database indexes and compares against the query vector at retrieval time.
AI Engineering/rag
In a RAG system, cosine similarity is commonly used to rank document chunks against a user query. Trace the following Python code that computes cosine similarity between a document vector and a query vector. What is printed?#
import numpy as np
def cosine_similarity(a, b):
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
doc = np.array([3, 4, 0])
query = np.array([3, 0, 0])
print(round(cosine_similarity(doc, query), 4))Show answer
0.6
The dot product of [3,4,0] and [3,0,0] is 33 + 40 + 0*0 = 9. The norm of the doc vector is sqrt(3²+4²+0²) = sqrt(25) = 5, and the norm of the query vector is sqrt(3²+0²+0²) = 3. Cosine similarity = 9 / (5 * 3) = 9/15 = 0.6. Rounding to 4 decimal places gives 0.6.
AI Engineering/llm-foundations/embeddings
This computes the cosine similarity between two embedding vectors and prints it rounded to 4 decimals. What does it print?#
import math
a = [1, 2, 2]
b = [2, 0, 1]
dot = sum(x * y for x, y in zip(a, b))
norm_a = math.sqrt(sum(x * x for x in a))
norm_b = math.sqrt(sum(x * x for x in b))
print(round(dot / (norm_a * norm_b), 4))Show answer
0.5963
Cosine similarity is dot(a, b) / (||a|| * ||b||). The dot product is 1*2 + 2*0 + 2*1 = 4; ||a|| = sqrt(1+4+4) = 3 and ||b|| = sqrt(4+0+1) = sqrt(5) ≈ 2.2360679.... So 4 / (3 * 2.236...) ≈ 0.59628..., which rounds to 0.5963. This is the core ranking primitive behind vector search — the actual embeddings just have hundreds or thousands of dimensions, but the arithmetic is identical.
AI Engineering/llm-foundations/embeddings
Walk through what happens to a piece of text when you 'embed' it for semantic search, and explain why a search index built with one model cannot be queried using a different model's output.#
Show answer
The text is tokenized, then run through an embedding model that maps it to a fixed-length vector of floating-point numbers — a point in a high-dimensional space where semantically similar texts land close together (measured by cosine similarity or distance). At index time you store each document's vector; at query time you embed the query the same way and find the nearest vectors. Two different models can't be mixed because each learns its own space: they often differ in dimensionality, and even at the same size the axes and geometry are arbitrary and model-specific, so a vector from model A has no meaningful distance to a vector from model B. The query must use the exact same model (and version) that built the index.
Embedding maps text → tokens → a single fixed-length vector that positions the text in a high-dimensional space, where proximity (cosine similarity / nearest-neighbour distance) approximates semantic similarity. Indexing stores those vectors; search embeds the query identically and finds the closest ones. The incompatibility is the key gotcha: each model trains its own space — different dimensionality and arbitrary, model-specific axes — so a query vector from one model has no meaningful geometric relationship to documents embedded by another. Always embed queries with the exact model + version used to build the index.
AI Engineering/rag/rag-basics
Order the stages of building and serving a retrieval-augmented generation (RAG) pipeline, from raw documents to a grounded answer.#
Put these in order
Show answer
Ingestion runs first, then serving at query time:
- Chunk the documents into retrievable passages
- Embed each chunk into a vector
- Store the vectors (and metadata) in a vector index
- Retrieve the top-k chunks for the user's query
- Generate the answer with the retrieved context in the prompt
Ingestion runs first — documents are chunked, each chunk is embedded, and the vectors plus metadata are stored in the index. At query time you retrieve the most similar chunks for the question, then generate the answer with that context injected into the prompt. (A reranking step often sits between retrieve and generate, but the ingest-then-serve order is fixed.)
AI Engineering/rag/vector-search
A vector database advertises "HNSW indexing" for approximate nearest-neighbor search over embeddings. Structurally, what is HNSW?#
Options
Show answer
HNSW (Hierarchical Navigable Small World) is a multi-layer graph where each vector is a node linked to its approximate nearest neighbors, with sparser long-range links in the upper layers so a query can navigate coarse-to-fine. A query starts at the top layer and greedily walks toward the nearest node, dropping a layer at each local optimum, giving roughly logarithmic search cost instead of scanning every vector. It is not a hash table (that describes locality-sensitive hashing), not a B-tree (which needs a single sort key and breaks down in high dimensions), and not a flat linearly-scanned array (that is exact brute-force search, not HNSW).
HNSW (Hierarchical Navigable Small World) builds a proximity graph in layers: the top layer has very few nodes and long-range edges for fast coarse traversal, and each layer below is progressively denser, down to a bottom layer containing every vector. A query starts at the top layer and greedily walks toward the nearest node, dropping down a layer at each local optimum, which gives roughly logarithmic search cost without scanning the whole dataset. Option (b) describes locality-sensitive hashing (LSH), a different ANN family that buckets by hash rather than traversing a graph. Option (c) describes a B-tree, which is built for one-dimensional ordered lookups and breaks down in high-dimensional space because there is no single sort key that preserves proximity. Option (d) describes a flat/brute-force index — exact, but linear in the number of vectors, which is exactly what HNSW exists to avoid at scale.
AI Engineering/rag/vector-search
Which of these are legitimate reasons to configure a vector index with Euclidean (L2) distance instead of cosine similarity? Select all that apply.#
Options
Pick every one that applies.
Show answer
The legitimate reasons are: the embeddings are not normalized and their magnitude carries real signal, the index's internal machinery (e.g. certain quantization or clustering schemes) is built around squared L2 distance, and a downstream step like k-means clustering over the same vectors already minimizes squared Euclidean distance so keeping the retrieval metric consistent avoids two different notions of "close" in one system. L2 distance is not categorically cheaper than cosine — on normalized vectors, dot product (what cosine reduces to) is usually the cheaper comparison — and cosine similarity runs efficiently on GPU hardware; neither is a real constraint.
Euclidean distance earns its place when magnitude is meaningful (a) — normalizing away magnitude on purpose throws away a real signal your model actually encoded. It also matters when the index's internal machinery is built around L2 (b): several ANN structures and quantization schemes (e.g. product quantization) are formulated to minimize squared L2 error directly, so mixing in a different metric at query time can be inconsistent with what was optimized at index time. And it matters for consistency with other L2-native algorithms downstream (e) — if you're already clustering the same vectors with k-means, which minimizes within-cluster squared Euclidean distance, using a different metric for retrieval means "close" means two different things in the same system. (c) is false as a categorical claim: on L2-normalized vectors, dot product (which cosine reduces to) is typically the cheapest comparison, not L2. (d) is simply untrue — cosine similarity, like any dot-product-based metric, runs efficiently on GPUs; it is not a hardware limitation.
AI Engineering/rag/vector-search
Raising HNSW's ef_search parameter (or IVF's nprobe) at query time generally increases recall at the cost of higher query latency, without requiring the index itself to be rebuilt.#
Options
Show answer
True. ef_search (HNSW) and nprobe (IVF) are query-time parameters, not index-build-time ones. ef_search controls how many candidates HNSW keeps in its search frontier while traversing the graph, and nprobe controls how many IVF clusters get scanned; raising either explores more of the index per query and recovers true nearest neighbors the search would otherwise miss, at the cost of more distance computations and higher latency. Because both are read-time parameters, they can be tuned per query or per workload against the same already-built index, with no rebuild required.
Both ef_search (HNSW) and nprobe (IVF) are query-time knobs, not index-build-time ones: ef_search controls how many candidates HNSW keeps in its search frontier while traversing the graph, and nprobe controls how many IVF clusters get scanned. Raising either explores more of the index per query — more graph neighbors visited, or more clusters searched — which recovers true nearest neighbors the search would otherwise have missed, at the direct cost of more distance computations and higher latency per query. Because they're read-time parameters, they can be tuned per query or per workload (e.g. higher ef_search for a batch/offline job, lower for a latency-sensitive live endpoint) against the same already-built index.
AI Engineering/llm-foundations/embeddings
Documents were indexed with one embedding model, but retrieval returns near-random results. Which line is the bug?#
const DOC_MODEL = "text-embedding-3-large";
async function indexDocs(docs: string[]) {
const res = await openai.embeddings.create({ model: DOC_MODEL, input: docs });
await store.upsert(res.data.map((d, i) => ({ id: i, vector: d.embedding, text: docs[i] })));
}
async function search(query: string) {
const res = await openai.embeddings.create({ model: "text-embedding-3-small", input: query });
return store.query(res.data[0].embedding, { topK: 5 });
}Show answer
The bug is on line 9.
Line 9 embeds the query with text-embedding-3-small while the documents were indexed with text-embedding-3-large (line 1/4). Different embedding models produce vectors in different, incompatible spaces — they have different dimensionalities and geometry, so cosine similarity between a small-model query vector and large-model document vectors is meaningless. The query must be embedded with the exact same model (and version) used to build the index. The fix is to reuse DOC_MODEL on line 9.
AI Engineering/rag/vector-search
An IVF (inverted file) vector index partitions the corpus into nlist clusters with k-means, then at query time only searches the nprobe clusters whose centroids are closest to the query. What happens if nprobe is set to 1?#
Options
Show answer
Setting nprobe = 1 minimizes query latency but sharply drops recall for queries whose true nearest neighbors sit in a different cluster than the single one closest to the query's centroid — a common case for vectors near a cluster boundary, since k-means partitions space with hard boundaries that don't line up with any individual query's actual neighbors. Raising nprobe searches more clusters and recovers those neighbors at the cost of scanning more vectors and higher latency; this is IVF's runtime recall/latency knob and does not require rebuilding the index. K-means does not guarantee a vector's true nearest neighbors share its cluster, IVF has no automatic exhaustive-scan fallback, and nprobe has no effect on insert throughput.
IVF only searches inside the nprobe clusters closest to the query, so any true nearest neighbor sitting in cluster #2 or #3 (by centroid distance) is invisible to the search when nprobe = 1. That happens routinely for vectors near a cluster boundary, since k-means partitions space with hard boundaries that don't line up with any individual query's actual nearest neighbors. Raising nprobe searches more clusters and recovers those neighbors, at the cost of scanning more vectors and higher latency — this is IVF's core recall/latency knob, and it's a runtime query parameter, not something requiring a rebuild. Option (b) is wrong because k-means cluster boundaries are approximate partitions, not a guarantee that a vector's true nearest neighbors share its cluster. Option (c) invents behavior IVF doesn't have — a low nprobe degrades recall silently, it doesn't trigger a fallback. Option (d) confuses a query-time parameter with an insert-time one; nprobe has no effect on indexing/insert throughput.
AI Engineering/rag/vector-search
Your embedding model's output vectors are L2-normalized (scaled to unit length) before being written to the vector store. Given that, which statement about choosing cosine similarity vs. dot product (inner product) as the index's distance metric is correct?#
Options
Show answer
Cosine similarity and dot product produce identical rankings on L2-normalized (unit-length) vectors, so many vector stores default to the cheaper dot-product metric and skip normalizing at query time. Cosine similarity is dot(a, b) divided by the product of the two norms, and once every vector has norm 1, that denominator is always 1 — so cosine collapses to a plain dot product. That is why normalizing once at ingest and then using dot product as the index metric is common practice: it is a cheaper comparison with an identical ranking. Dot product remains well-defined on normalized vectors, neither metric is inherently more relevant independent of normalization, and normalizing is what makes the two metrics converge, not diverge.
Cosine similarity is dot(a, b) / (||a|| * ||b||). Once every vector has ||v|| = 1, that denominator is always 1, so cosine similarity collapses to a plain dot product — the two metrics rank candidates identically. That's why it's common practice to normalize vectors once at ingest time and then configure the index's metric as dot product (inner product), which is a cheaper single multiply-accumulate than cosine's extra division and norm lookups at every comparison. Option (b) is backwards: dot product is always defined, it's just numerically equal to cosine here. Option (c) is a category error — neither metric is inherently "more relevant"; correctness depends on whether the vectors are normalized and matches the model the embeddings were trained/evaluated with. Option (d) has the relationship backwards: normalizing is exactly what makes the two metrics converge, not diverge.
AI Engineering/rag/vector-search
You're deciding between a 1536-dimension embedding model and a 256-dimension option (e.g. a smaller model, or Matryoshka truncation of a larger one) for a vector search system serving billions of vectors. What is the primary engineering tradeoff?#
Options
Show answer
Lower embedding dimensionality cuts index memory footprint and per-comparison search latency roughly linearly, at some cost to retrieval quality — worth it when the smaller representation still separates your domain's semantics well. Each stored vector's memory and each distance computation's cost scale with dimension count, so a 6x cut in width shrinks the index and speeds every comparison roughly 6x, which matters at billion-vector scale where memory is often the binding constraint. The tradeoff is representational: a narrower vector has less room to preserve fine-grained semantic distinctions. Dimensionality does affect both memory and per-comparison latency (it is not free), lower dimensionality does not universally improve quality, and higher dimensionality does not guarantee better recall — computing a distance is itself work proportional to dimension count, so wider vectors make every graph traversal step more expensive too.
Each stored vector's memory cost and each distance computation's cost scale with dimension count, so cutting 1536 dimensions to 256 shrinks the index roughly 6x and speeds up every similarity comparison in proportion — a meaningful win at billion-vector scale, where memory is often the binding constraint. The cost is representational: a narrower vector has less room to separate fine-grained semantic distinctions, so recall/quality typically degrades somewhat, and how much depends on whether the smaller model (or truncated Matryoshka prefix) was actually trained to preserve the semantics you need in fewer dimensions. Option (b) is false — both memory and the cost of each distance computation scale with dimensionality, independent of vector count. Option (c) overgeneralizes a real but narrow effect (some dimensionality reduction can denoise) into a universal law; past a point, cutting dimensions removes real signal, not just noise. Option (d) is also false: computing a distance is itself O(dimensions) work per comparison, so wider vectors make every graph traversal step more expensive, not free.
AI Engineering/rag/vector-search
This ranks two candidate vectors against a query using Euclidean distance and, separately, cosine similarity — the vectors are not normalized. What does it print?#
import math
def euclidean(a, b):
return math.sqrt(sum((x - y) ** 2 for x, y in zip(a, b)))
def cosine(a, b):
dot = sum(x * y for x, y in zip(a, b))
norm_a = math.sqrt(sum(x * x for x in a))
norm_b = math.sqrt(sum(x * x for x in b))
return dot / (norm_a * norm_b)
query = [1, 0]
cand_a = [5, 0]
cand_b = [1, 1]
nearest_euclidean = "A" if euclidean(query, cand_a) < euclidean(query, cand_b) else "B"
nearest_cosine = "A" if cosine(query, cand_a) > cosine(query, cand_b) else "B"
print(nearest_euclidean, nearest_cosine)Show answer
B A
cand_a = [5, 0] points in the exact same direction as query = [1, 0] but has 5x the magnitude, while cand_b = [1, 1] points in a different direction but is close by raw distance. Euclidean: dist(query, cand_a) = sqrt((1-5)^2 + 0^2) = 4, dist(query, cand_b) = sqrt(0^2 + (0-1)^2) = 1 — cand_b is closer (1 < 4), so nearest_euclidean = "B". Cosine: cos(query, cand_a) = 5 / (1 * 5) = 1.0 (identical direction, maximal similarity), cos(query, cand_b) = 1 / (1 * sqrt(2)) ≈ 0.707 — cand_a wins (1.0 > 0.707), so nearest_cosine = "A". The two metrics disagree because cand_a's large magnitude penalizes it under Euclidean distance but is invisible to cosine similarity, which only measures angle. This is exactly why the choice of distance metric isn't cosmetic: on unnormalized embeddings where magnitude carries no intended meaning, Euclidean distance can rank a semantically-aligned but larger-magnitude vector as farther away than a smaller, differently-directed one.
AI Engineering/rag/vector-search
This endpoint should return the 5 most relevant published documents for a query, but for tenants with only a handful of published documents it often returns fewer than 5, sometimes zero, even though the corpus clearly has enough matches overall. Which line is the bug?#
async function searchPublished(query: string) {
const queryVector = await embed(query);
const candidates = await index.query(queryVector, { topK: 5 });
const published = candidates.filter((c) => c.metadata.status === "published");
return published;
}Show answer
The bug is on line 3.
Line 3 queries the ANN index for only the top 5 candidates without the status = "published" filter, and line 4 then filters that fixed-size, already-final pool afterward (classic post-filtering). If most of the 5 nearest vectors happen to be unpublished, there's nothing left after filtering — the code never goes back to fetch more candidates. The fix is either to over-fetch a much larger unfiltered pool before filtering (e.g. topK: 200 before line-4's filter) so enough published matches survive to reach 5, or, better, to pass the filter into the index query itself (index.query(queryVector, { topK: 5, filter: { status: "published" } })) if the store supports native pre-filtering, so the ANN search only considers eligible vectors in the first place.
AI Engineering/rag/vector-search
Explain what hybrid search (dense + sparse) is in a RAG system, why a team would add it on top of pure vector search, and how the two ranked result lists are typically combined.#
Show answer
Dense vector search embeds the query and documents and ranks by semantic similarity, which is great at paraphrase and conceptual matches but can miss queries that hinge on exact tokens — product SKUs, error codes, acronyms, rare proper nouns — because those specific tokens can get diluted in a dense embedding. Sparse search (classically BM25) ranks by literal term overlap/frequency and catches exactly those exact-match cases, but misses semantic paraphrases. Hybrid search runs both retrievers in parallel over the same query and fuses their ranked candidate lists into one, most commonly with Reciprocal Rank Fusion (RRF): each document's fused score is the sum, across the lists it appears in, of 1/(k + rank), which combines two very differently-scaled ranking signals (cosine similarity vs. BM25 score) using rank position instead of requiring the scores to be normalized or calibrated against each other.
The core insight is that dense and sparse retrieval fail in complementary ways: dense embeddings generalize across paraphrases but blur exact identifiers, while sparse/BM25 nails exact terms but has no notion of meaning. Hybrid search runs both and combines the result lists rather than picking one. Reciprocal Rank Fusion is the standard combiner precisely because it sidesteps the score-normalization problem — cosine similarity and BM25 scores live on unrelated scales, so summing raw scores is meaningless, but summing 1/(k + rank) per list only needs each list's internal ordering, which is always comparable. A strong answer should land on: two complementary failure modes, running both retrievers, and a rank-based (not score-based) fusion method.
AI Engineering/rag/vector-search
Many production retrieval systems run a fast ANN vector search to pull the top ~100 candidates, then a separate, slower reranker to pick the final top ~5, instead of just returning the ANN results directly. Explain why the second stage earns its cost.#
Show answer
The embedding model used for ANN search is a bi-encoder: it encodes the query and each document into vectors independently, with no interaction between them, which is exactly what makes it cheap enough to precompute document vectors once and search millions to billions of them at query time — but that independence also caps its precision, since the model never actually looks at the query and a specific document together. A cross-encoder reranker instead feeds the query and one candidate document into the model jointly, so attention can directly model how the two interact, producing a much more accurate relevance score. It's too slow and too expensive to run over the whole corpus, since nothing about it can be precomputed or indexed — the score only exists for a specific query-document pair. Running it over just the ANN stage's ~100 candidates gets both properties: cheap high-recall retrieval narrows the field, then expensive high-precision reranking sorts just that shortlist.
This is the standard two-stage retrieval architecture, and the reasoning an interviewer is probing for is the bi-encoder/cross-encoder distinction: bi-encoders trade precision for the ability to precompute and index document vectors once, which is required to search at scale; cross-encoders trade scalability for precision by letting the query and document attend to each other, which is only affordable over a small shortlist. A strong answer explains why the cross-encoder can't just replace the ANN stage outright (it has no fixed per-document representation to index) rather than just asserting that reranking 'improves quality.'
AI Engineering/rag/vector-search
When combining a metadata filter (e.g. status = "published") with an ANN vector query, what's the difference between pre-filtering and post-filtering, and what can go wrong with each?#
Show answer
Post-filtering runs the ANN search first, ignoring the filter, then discards non-matching results from that fixed candidate set afterward. It's simple to implement but can silently return fewer than k results — or zero — when the filter is selective, because the candidate pool the ANN search returned may contain few or no matches. Pre-filtering applies the filter during the search itself (either by restricting the graph/cluster traversal to eligible vectors, or by over-fetching a much larger unfiltered pool before filtering), so the result set is filled correctly even under a selective filter, at the cost of being harder for the index to implement efficiently (a naive pre-filter can degrade to a near-linear scan if the index isn't filter-aware).
This is one of the most common production vector-search bugs: a team adds a metadata filter, sees good recall in testing against a broad filter, then watches recall silently collapse for a narrow one — because a fixed-size post-filtered pool starves once the filter's selectivity is high enough that few of the top candidates pass it.
AI Engineering/rag/vector-search
Order the stages of a hybrid-search-plus-reranking retrieval pipeline, from the user's raw query to the final passages handed to the model.#
Put these in order
Show answer
A hybrid-search-plus-reranking pipeline runs in this order:
- Embed the user's query with the same model used to embed the indexed documents
- Run dense (vector) ANN search and sparse (BM25) keyword search in parallel over the corpus
- Fuse the two ranked candidate lists into one, e.g. with Reciprocal Rank Fusion
- Rerank the fused top-N candidates with a cross-encoder for a more precise relevance score
- Truncate to the final top-k passages and assemble them into the model's context
The query is embedded first, matching the index's embedding model. Dense and sparse search run in parallel against the same query — one over vectors, one over terms — producing two independently-ranked candidate lists. Those lists are fused into a single ranking, most commonly with Reciprocal Rank Fusion, which combines rank positions rather than requiring the two very differently-scaled scores to be normalized against each other. Only then does the (expensive) cross-encoder reranker run, and only over that fused shortlist rather than the whole corpus, since it can't be precomputed or indexed. Finally the pipeline truncates to the top-k passages that actually fit the model's context budget.
AI Engineering/rag
You are tuning a production RAG pipeline that uses HNSW (Hierarchical Navigable Small World) as the ANN index in your vector database (e.g., FAISS HNSW, Qdrant, pgvector with HNSW). During evaluation you observe that recall@10 is too low but query latency is well within budget. Which HNSW parameter should you increase to directly improve query-time recall at the cost of higher latency?#
Options
Show answer
Increase ef_search. In HNSW, ef_search controls the size of the dynamic candidate list explored during layer traversal at query time — a larger value improves recall by examining more neighbors at the cost of additional distance computations and higher latency. ef_construction and M are build-time parameters that shape the graph structure, and ml governs layer-assignment probability; none of them can be tuned at query time to trade recall for speed.
ef_search (called ef in FAISS) is the parameter that controls how many candidates HNSW explores in the dynamic list during each layer traversal at query time. Increasing it widens the search frontier, improving recall at the cost of more distance computations and higher latency. ef_construction affects index build quality and the resulting graph structure, but once the index is built it does not change query-time behavior. M (max connections per node per layer) also affects graph connectivity but is set at build time; while a low M can limit achievable recall, the parameter you tune at query time to trade recall for latency is ef_search. ml (the level normalization factor) controls the exponential probability distribution for layer assignment and is not a query-time tunable.
AI Engineering/rag/vector-search
Your vector index has 99% recall@10 when queried without a filter. After adding a metadata filter (tenant_id = X, matching only 2% of the corpus) that's applied by post-filtering a fixed top-20 ANN candidate pool, recall for filtered queries collapses to near zero for some tenants. What's the most direct fix that doesn't require re-architecting the index?#
Options
Show answer
The direct fix is to over-fetch a much larger unfiltered candidate pool (e.g. top-2,000) before applying the metadata filter, so enough matching candidates survive to fill the final top-10, or to use the index's native pre-filtering / filtered-search support if it has one. Post-filtering a fixed top-20 pool against a filter that only 2% of the corpus passes leaves an expected survivor count of about 0.4, so recall collapses structurally regardless of how good the underlying ANN search is. A mild ef_search or nprobe increase does not multiply survivors by the roughly 50x needed to compensate for a 2%-selective filter on a fixed pool, and switching the distance metric or reducing embedding dimensionality has no bearing on why a fixed unfiltered pool starves under a selective filter.
Post-filtering a fixed top-20 pool against a filter that only 2% of the corpus passes means the expected number of surviving candidates is about 20 * 0.02 = 0.4 — recall collapses because there's structurally almost nothing left to return, independent of how good the underlying ANN search is. The direct fix is to make the pre-filter pool large enough relative to the filter's selectivity that the expected survivor count comfortably exceeds k (here, a few thousand candidates for a 2%-selective filter and k=10), or to use pre-filtering / filtered ANN search if the index supports traversing the graph while respecting the filter directly, which avoids over-fetching altogether. Option (b) treats this as a plain recall/latency knob, but a mild ef_search/nprobe bump does not multiply the survivor count by the ~50x needed to compensate for a 2%-selective filter on a fixed-size pool — the shortfall is structural, not a small recall gap. Options (c) and (d) address unrelated properties (metric choice, vector width) that have no bearing on why a fixed unfiltered pool starves under a selective filter.
AI Engineering/rag
Design a production RAG system for a multinational law firm with the following requirements:#
Show answer
We would build a multi-stage RAG pipeline with the following components:
Chunking & Citation Provenance: Documents are parsed into a hierarchical structure (document → section → paragraph). Each paragraph becomes a chunk with metadata: {doc_id, doc_version, paragraph_id, section_path, jurisdiction, matter_id, client_id, language, effective_date}. Chunks are embedded using a legal-domain-tuned embedding model. At generation time, the LLM is prompted to include [doc_id, paragraph_id] citations for every claim. A post-processing validation step checks that every cited chunk was actually in the retrieved context set and is accessible to the user—if a citation references a chunk not in the retrieved set, the answer is flagged for review.
Access Control: Access control is enforced at the vector store level using metadata pre-filters. Each query includes the user's authorized matter_id and client_id list as filter predicates on the ANN search (supported by Pinecone, Weaviate, Milvus via metadata filtering). We use a single HNSW index with metadata filtering rather than separate indexes per matter, since the matter count is large and many matters share reference documents (e.g., public statutes). Unauthorized documents are never returned by the search—they are excluded by the filter before the ANN traversal produces candidates.
Document Versioning: When a document is updated, new chunks are embedded and inserted with an incremented version number and a new effective_date. Old version chunks are soft-deleted (marked with tombstone=true and superseded_by= new_version) rather than immediately removed, preserving the audit trail. At query time, a metadata filter (tombstone=false AND version=latest) ensures only current versions are retrieved. A background compaction job periodically rebuilds index shards to physically remove tombstoned chunks and reclaim memory.
Scale & Retrieval Quality: At 50M+ documents, we shard the index by jurisdiction (reducing per-shard size and enabling jurisdiction-aware routing—queries specifying a jurisdiction hit only the relevant shard). Retrieval uses hybrid search: dense HNSW retrieval (top-100) fused with BM25 sparse retrieval (top-100) via reciprocal rank fusion. A legal-domain fine-tuned cross-encoder re-ranks the fused top-50 down to the final top-10 chunks passed to the LLM. HNSW parameters (M=32, ef_construction=400, ef_search=64) are tuned against a held-out recall@10 benchmark set of 5,000 annotated legal queries, with ef_search adjusted dynamically based on shard size.
Multi-Jurisdiction & Multilingual: We use a multilingual embedding model (e.g., multilingual-e5-large) so queries in one language retrieve documents in another without a translation step. Jurisdiction is stored as chunk metadata and used as an optional explicit filter when the user specifies a jurisdiction. For cross-jurisdiction comparison queries (e.g., 'Compare force-majeure clauses in NY and German law'), the query is routed to multiple jurisdiction shards in parallel; results from each jurisdiction are fetched separately (top-k per jurisdiction) and merged before cross-encoder re-ranking, ensuring balanced representation from each jurisdiction in the final context.
This rubric evaluates whether the candidate can architect a RAG system that addresses the five hardest production concerns in a legal-domain setting: citation provenance, pre-retrieval access control, document versioning, retrieval quality at scale, and cross-lingual/multi-jurisdiction handling. Each criterion tests a distinct architectural decision; an answer that omits any one leaves a critical production gap. The sample answer satisfies all five: hierarchical chunking with paragraph metadata (c1), metadata pre-filtering at the vector store (c2), version increment with tombstoning and query-time filtering (c3), hybrid search + cross-encoder re-ranking + jurisdiction sharding + HNSW parameter tuning (c4), and multilingual embeddings with parallel multi-jurisdiction routing (c5).
Related interview questions
Job market
See ai-engineering salaries and hiring demand from live job postings.
The other 4 questions
This page shows 25 and marks what you pick. That's as far as a page can go. A free account opens the other 4 and keeps every answer. What you miss comes back until it's right: after a day, then at longer gaps.
Free · the whole bank · 100 marked answers per 30 days · written feedback on the paid plan