Search Tech Journey

Find topics, journeys and posts

back to blog
systemsadvanced 25m read

Designing for Scale · RAG and Vector Search

Why LLMs hallucinate, how Retrieval-Augmented Generation grounds them in reality, and the architecture required to execute semantic search over millions of documents in milliseconds.

The problem this post solves

A Large Language Model (LLM) is a reasoning engine, not a database. If you ask it a question about your company's internal HR policy, it will either refuse to answer or confidently invent a policy that sounds plausible. It cannot retrieve information it was never trained on.

You cannot solve this by retraining the model on your HR documents every night; training is too slow and too expensive. You cannot solve this by pasting your entire company's documentation into the prompt; the context window is too small and the per-token cost would be astronomical.

This post covers Retrieval-Augmented Generation (RAG). It is the architectural pattern that gives an LLM access to external knowledge by finding the exact paragraphs required to answer a question, and handing them to the model at the moment of inference.

First principles

From first principles
Start with the question
Why does standard keyword search fail for RAG?
  1. 1
    RAG requires finding the text most relevant to the user's question.
    forced by · We must inject that text into the LLM's prompt.
  2. 2
    Users ask questions conceptually, not using exact keywords.
    forced by · A user might ask 'How do I cancel my plan?', while the document says 'Subscription termination process'.
  3. 3
    Standard search (like Elasticsearch) looks for exact word matches (BM25 / TF-IDF).
    forced by · It relies on an inverted index of tokens.
  4. 4
    An exact keyword search will fail to match 'cancel' with 'termination'.
    forced by · The words are structurally different, even though they mean the same thing.
⇒ Therefore
We need a search system that understands the *meaning* of the text, not just the characters.

Semantic Search and Embeddings

To search by meaning, we convert words into mathematics.

An embedding model (like OpenAI's text-embedding-ada-002) takes a sentence and returns a vector (an array of numbers). For example, a 1536-dimensional vector.

These numbers represent the semantic meaning of the sentence. In this 1536-dimensional space, the vector for "How do I cancel my plan?" is physically very close to the vector for "Subscription termination process", even though they share no words.

Mental modelVector Space
A map of the stars. Sentences about dogs are clustered together in one galaxy. Sentences about cars are in another. If you map the user's question to a star, you just look for the documents that are physically closest to it on the map.
  • Distance equals relevance. Short distance means high semantic similarity.
  • Distance is calculated using simple math: Cosine Similarity or Dot Product.
  • The embedding model determines the map. If you change the model, all the stars move, and you must re-calculate every document.
🔔 Fires when you see
Use to explain how semantic search bypasses the limitations of keywords.

Architecture: The RAG Pipeline

A RAG system consists of two distinct pipelines: an asynchronous indexing pipeline (Data Ingestion) and a synchronous retrieval pipeline (Querying).

The Ingestion Pipeline

  1. Chunking: You cannot embed a 100-page PDF as a single vector. The semantic meaning becomes too diluted. The document must be split into chunks (e.g., paragraphs or 500-token blocks).
  2. Embedding: Each chunk is passed to the embedding model to generate a vector.
  3. Storage: The vector, along with the raw text of the chunk and metadata (document ID, access permissions), is saved to a Vector Database (like Pinecone, Milvus, or pgvector).

The Query Pipeline

  1. Embedding the Query: The user asks a question. The API sends the question to the exact same embedding model used in ingestion. It receives a query vector.
  2. Vector Search: The API asks the Vector Database: "Find the 5 vectors in your storage that are closest to this query vector."
  3. Prompt Construction: The API takes the raw text from those 5 chunks, appends them to a prompt template ("Answer the user's question using ONLY the following context: [Chunks]"), and sends it to the LLM.
  4. Generation: The LLM reads the context and generates an accurate, grounded answer.

Scaling the Vector Search (Approximate Nearest Neighbor)

At scale, the Vector Database is the bottleneck.

If you have 10 million chunks, finding the 5 closest vectors requires calculating the distance between the query vector and all 10 million stored vectors. At 1536 dimensions per vector, this is billions of floating-point operations. It takes too long to do on every query.

To achieve millisecond latency, Vector Databases do not calculate exact distances. They use Approximate Nearest Neighbor (ANN) algorithms, primarily HNSW (Hierarchical Navigable Small World).

HNSW builds a multi-layered graph of the vectors in memory. When a query arrives, it navigates the graph, leaping quickly toward the general neighborhood of the query vector, and only calculating exact distances for the vectors in that small local cluster.

The tradeoff
Exact vs Approximate Vector Search (k-NN vs ANN)
Exact Search (k-NN)
+ you gain Perfect accuracy. Guaranteed to find the absolute closest vectors.
− you pay O(N) complexity. Scans the entire database. Too slow for interactive queries on large datasets.
pick when For small datasets (under 100k vectors) or offline batch processing where latency doesn't matter.
Approximate Search (ANN / HNSW)
+ you gain O(log N) complexity. Sub-10ms latency on tens of millions of vectors.
− you pay Sacrifices slight accuracy. It might return the 2nd closest vector instead of the 1st.
pick when Mandatory for production RAG systems serving user queries.

Semantic search is brilliant for concepts, but terrible for specific identifiers. If a user asks "What is error code ERR-8092?", semantic search might return documents about general errors, because the semantic meaning of "error" dominates the vector.

Modern RAG systems use Hybrid Search. They execute a semantic vector search AND a traditional exact-keyword search (BM25) simultaneously. A scoring algorithm (like Reciprocal Rank Fusion) merges the results, returning chunks that match both the concept and the exact keywords.

Failure modes

Ignoring document permissions. If the Vector Database contains chunks from the CEO's private strategy document, and a junior employee asks a question, the vector search will happily retrieve the CEO's document and hand it to the LLM. The Vector Database must enforce row-level security (metadata filtering) before executing the ANN search, ensuring it only scans vectors the user is authorized to see.

Blindly trusting the LLM (Hallucination on Context). Even when provided with correct chunks, an LLM might ignore them or blend them with its internal training data. The prompt must strictly instruct the model to state "I do not know" if the answer is not present in the provided chunks, and the system should ideally force the LLM to cite the chunk ID it used to generate its answer.

What to carry forward

Key points
    You can now
    • Explain why fine-tuning is the wrong tool for injecting dynamic knowledge into an LLM.
    • Design a data ingestion pipeline that chunks, embeds, and stores documents.
    • Defend the use of Approximate Nearest Neighbor search against Exact search for latency-bound APIs.
    • Architect a hybrid search system that solves the weaknesses of pure semantic search.