AI Engineering Playbook
Embeddings & Search

Embeddings

What embeddings are, how models produce them, dimensionality, MTEB, choosing a model.

Prerequisites

  • How LLMs Work — transformers and attention at survival depth; embedding models are the same family of encoders.
  • Tokens & Context Windows — chunking and max-sequence limits only make sense once you know how text becomes tokens.

The intuition

Imagine every document, paragraph, and query as a point on a map — not of cities, but with hundreds or thousands of axes. Similar meaning places points near each other. "Reset my password" sits close to "credential recovery procedure"; both sit far from "Q3 revenue forecast."

You do not draw the map by hand. An embedding model learns where each piece of text belongs so that distance approximates relevance. Finding documents becomes geometry: which stored points are nearest this query point?

Key insight

An embedding is not a "summary in numbers." It is a coordinate in a space the model shaped so that geometric nearness tracks semantic nearness. Everything downstream — ANN indexes, hybrid search, rerankers — is engineering on top of that geometry.

Why it exists

Keyword search answers "which documents share these tokens?" That fails the moment users paraphrase. "PTO policy" and "vacation leave rules" share almost no surface form, yet they are the same intent.

Three hard constraints force learned vectors. Exact tokens are a fragile match signal — synonyms and natural-language questions miss corporate jargon on shared words alone. You need one comparable representation at scale: a fixed-length float vector turns every document and query into the same kind of object. And you cannot hand-craft features for every domain — contrastive training on millions of pairs learns the geometry from data instead of rules you invent and maintain.

The alternatives lose on different axes. Pure keyword (BM25) is cheap and excellent on exact IDs, but blind to paraphrase. Hand-written taxonomies need constant curation. Stuffing the full corpus into an LLM context does not scale and still does not give you a reusable index. Embeddings are the representation layer that makes semantic search, RAG, and "similar items" operational.

The core idea

An embedding is a fixed-length vector of floats — typically 384 to 4096 dimensions — that places text at one point in high-dimensional space. The model is trained so that similar meanings land close together and unrelated texts land far apart. "Find relevant documents" becomes "find nearby vectors."

Those models are transformer encoders trained with contrastive learning: millions of pairs that should match (question ↔ answer, title ↔ body, paraphrase ↔ paraphrase). The loss pulls matching pairs together and pushes non-matching pairs (other batch examples) apart.

Three practical facts. The whole input compresses into one vector — a 500-token chunk and a 5-word query become the same size, which is why chunking dominates quality. Embeddings from different models are not comparable: same model and version on both sides, or re-embed everything. Choosing a model is empirical — shortlist from MTEB, then measure on your own data.

How it actually works

From raw text to a searchable vector:

Architecture. A transformer encoder (BERT-style, or increasingly an LLM decoder backbone) produces one contextual vector per token. Pooling collapses those into a single vector: mean pooling, the [CLS] token, or last-token pooling for decoder-based models. The output is usually L2-normalized to unit length — which is why cosine and dot product often rank the same way (similarity metrics).

Contrastive training. The dominant loss is InfoNCE (MultipleNegativesRankingLoss in Sentence Transformers): for a batch of (query, positive) pairs, every other positive is a negative. The model maximizes similarity of true pairs relative to all in-batch negatives. Larger batches mean more negatives per update, so batch size is a first-class training hyperparameter.

Training usually has two stages: weakly-supervised pretraining on billions of natural pairs (title/body, forum Q&A, citations), then supervised fine-tuning with hard negatives — topically similar but wrong documents mined from a first-stage retriever. Hard negatives teach fine distinctions that random negatives never force.

Asymmetry and instructions. Queries and documents differ in length and style, so many models train with prefixes (query: / passage:) or free-text task instructions. Omitting the required prefix at inference silently degrades quality — neighbors still return, with no exception.

Common misconception

"Same model family, same dimension, so vectors are interchangeable" is false. Different models — and even different versions of the same model — define different geometries. Mixing them is comparing coordinates from unrelated maps.

Dimensionality. Cost scales linearly with dims (storage ≈ dims × 4 bytes × count, before index overhead):

DimensionsTypical models (illustrative)Storage per 1M vectors (float32)
384all-MiniLM-L6-v2~1.5 GB
768–1024bge, e5, many open models~3–4 GB
1536text-embedding-3-small~6 GB
3072–4096text-embedding-3-large, LLM-based~12–16 GB

Quality gains flatten well before 4096 — dimension count is a cost knob more than a quality knob. At large N, that is why ANN indexes and quantization become non-optional.

Matryoshka embeddings (MRL). Matryoshka Representation Learning applies the loss at several prefix lengths at once (e.g. 768, 512, 256, 128), packing important information into the earliest dimensions. You can truncate to the first N dims, re-normalize, and keep most quality. OpenAI's text-embedding-3 models expose this as the dimensions API parameter; their docs report that text-embedding-3-large at 256 dims still beats older ada-002 at 1536 on MTEB — enabling adaptive retrieval (coarse short-vector search, then rescore with full vectors).

Choosing a model. Filter MTEB by language(s), max sequence length (512 vs 8k+ changes chunking), dimensions, license, and price. Shortlist 2–4 — as of mid-2026 often one API model (Gemini embedding, OpenAI text-embedding-3, Cohere embed-v4, Voyage) and one open model (Qwen3-Embedding, BGE/E5 family). MTEB has multiple boards and revisions; scores across versions are not comparable, so rankings are a shortlist, not a verdict. Evaluate on a golden set of 50–200 real queries with known relevant chunks (recall@k, nDCG@k). Domain shift routinely reorders the leaderboard.

The flows

FlowWhat it doesWhat breaks it
Offline corpus ingestparse → chunk → prefixes → embed batch → normalize → write vectors + metadataSilent truncation; wrong prefix; model version drift between batches
Online query embedsame prefix/instructions as indexing → one embed → same normalization → ANN / hybridDifferent model, version, or prefix than the index
Model migration / dual-writere-embed into a new index → dual-serve or shadow-query → atomic cutover → retire old vectorsPartial re-embed; mixing old and new vectors; no rollback
Matryoshka adaptive retrievalsearch truncated prefixes → rescore shortlist with full dimsTruncating without re-normalizing; different metric than training

On the governed enterprise platform, offline ingest is a scheduled pipeline over internal wikis and policy PDFs; online query embed is one hop before entitlement-filtered vector search. Model migrations are versioned dual-write jobs, not silent API upgrades.

A worked example

Employees ask policy questions over ~10k internal documents.

Document side (offline). A 1,200-token expense-policy section is chunked to ~400 tokens. One chunk: "International travel requires pre-approval above the threshold…" (~120 tokens). An illustrative 1024-dim API model receives it with a passage: prefix, returns 1024 L2-normalized float32s (4,096 bytes raw) plus metadata {doc_id, version, effective_date, acl}. The vector lands in HNSW; the same text also goes into BM25 for hybrid search.

Query side (online). "Does international travel still need pre-approval?" Apply the matching query: prefix, embed once (~20–40 ms via API, illustrative), retrieve ANN top-50 → optional reranker → top 5 into the LLM prompt. A cosine of 0.82 is not universally good — only meaningful relative to this model on this corpus (similarity metrics).

What each omission looks like in production

  • No chunking (whole 50-page PDF as one vector) → one point tries to represent every topic; you get a blob that mentions travel, not the clause.
  • Wrong or missing prefix → neighbors still return, ranks quietly worse; no exception.
  • Query model v2, corpus still v1 → geometrically meaningless neighbors; "confidently irrelevant" top hits.
  • Truncation past max tokens → the policy exception in the tail never enters the vector.
  • Matryoshka truncate without re-normalize → unit-norm assumptions break; rankings skew.

Production concerns

Model lock-in is structural. Vectors are useless without the exact model that made them. A provider deprecation or quality upgrade forces a full corpus re-embed — budget tokens × price, and design versioned dual-write with atomic cutover and rollback (reliability).

Cost is cheap per call and expensive at corpus scale. Illustrative OpenAI pricing as of 2026: roughly $0.02–$0.13 per 1M tokens for the text-embedding-3 tier. One query embed is nearly free; re-embedding 100M chunks is not (cost). Query latency is one embed hop (tens of ms via API); document embedding is throughput-bound (latency).

Silent failure modes dominate. Text past max tokens truncates without a hard error — enforce chunk sizes upstream (ingestion and chunking). Normalization and prefixes must match between indexing and querying; drift produces quietly-bad retrieval with no error log. Track model ID and version on every vector and query log (observability). Storage compounds as dims × 4 bytes × chunks × replicas plus index overhead; Matryoshka truncation and quantization (ANN indexes) are the levers once N grows.

Common drill-downs

Why do hard negatives beat "more random pairs"? Easy negatives only teach coarse separation (sports vs finance). Hard negatives — topically similar but wrong answers mined from a first-stage retriever — force "about the same topic" apart from "actually answers this question." Without them, ANN top-10 fills with related-but-useless chunks. A reranker can clean some of that up; hard-negative training reduces how much it must.

When to fine-tune vs switch APIs? Fine-tune when a domain golden set shows a gap that a stronger general model and a reranker do not close (jargon, legal phrasing, code). Prefer a better off-the-shelf model first: fine-tuning adds a training set, a serving path, and another version to migrate.

How do instruction-tuned embedders differ from plain bi-encoders? They accept a task string ("retrieve passages that answer this" vs "cluster by topic") that steers the same weights toward different geometries. Using the wrong instruction — or none when one was trained in — is the modern form of the prefix bug.

Test yourself

You embedded 2M support articles with model A. Product wants model B 'because MTEB rank is higher.' What is the full migration plan, and what fails if you only change the query-side model?

A teammate says 'use 3072 dimensions for maximum quality.' When is that the wrong call?

Retrieval works in staging and fails in production after a model card update that added required task instructions. Diagnose.

On the governed enterprise platform, a new embedding model is 15% better on public MTEB. Legal and medical jargon dominate the corpus. Do you adopt it?

Go deeper

Where this connects

  • Similarity metrics — once you have vectors, which distance you use (and whether they are normalized) decides ranking.
  • ANN indexes — exact scan does not scale; HNSW/IVF/quantization make "find nearby" fast.
  • The RAG pipeline — embeddings are the representation layer inside offline ingest and online retrieve.
  • Embeddings beyond RAG — classification, recsys, dedupe, and anomaly detection reuse the same vectors.
Embeddings Beyond RAG

On this page