Custom vs Off-the-Shelf Embeddings

The most common mistake: fine-tuning embeddings when the real problem is bad chunking, missing metadata, or poor prompts. Use this decision tree.

Decision Tree: Do you need custom embeddings?

Have you tried off-the-shelf embeddings
(e.g., text-embedding-3-large, E5)?

Click each node to expand. Custom embeddings are valuable when domain-specific vocabulary or task mismatch causes retrieval failures, not when the real bottleneck is pipeline design.

When custom embeddings clearly win

Strong signals for custom

Domain Heavy jargon: medical codes, legal citations, protein sequences
Scale Millions of retrievals/day justify the upfront cost
Task Asymmetric retrieval: short queries against long documents
Quality Off-the-shelf Recall@10 plateaus below business needs

Fix these first (not embeddings)

Chunking Chunks too large/small, splitting mid-sentence
Query No query expansion or rewriting
Hybrid No BM25/sparse component for exact matches
Reranking No cross-encoder reranking stage

Domain Adaptation Approaches

Three strategies for adapting embeddings to your domain, from lightest to heaviest.

Continued Pretraining

Keep training the base model's masked-language objective on your domain corpus. Teaches the model new vocabulary and domain patterns.

When to use:
Domain has unique terminology (biomedical, chemistry, law) that the base model rarely saw during pretraining.
Effort: Medium Data: Unlabeled domain text

Contrastive Fine-Tuning

Train on (query, positive_doc) pairs with hard negatives. Directly optimizes the embedding space for your retrieval task.

When to use:
You have query-document relevance judgments (even a few hundred pairs can help).
Effort: Medium-High Data: Labeled pairs needed

Full Retraining

Train a new embedding model from scratch on your domain. Maximum control but extreme cost. Rarely justified unless you are building an embedding product.

When to use:
You have a non-standard language (code, DNA sequences, molecular structures) where general text models are fundamentally wrong.
Effort: Very High Data: Massive corpus needed
Off-the-shelf
baseline
->
Continued
Pretraining
domain vocab
->
Contrastive
Fine-Tuning
task-specific
->
Evaluate
on your data

Common pipeline: pretrain first for vocabulary, then fine-tune for task alignment.


Hard Negatives

The single most impactful ingredient in embedding fine-tuning. Hard negatives teach the model what "close but wrong" looks like.

Visual: Easy vs Hard Negatives

Query
Positive
Easy negatives
(obviously wrong)
Large gap
= No signal

Easy negatives: Obviously wrong. The model already knows "cat care" is not related to "quantum physics." No learning signal.

Query
Positive
Hard negatives
(close but wrong)
Small gap
= Strong signal

Hard negatives: Close but wrong. "Cat breeds" looks similar to "cat health" but is not the right answer. Forces the model to learn subtle distinctions.

Concrete example

Query
"How to treat a cat's urinary tract infection"
Positive
"Feline UTI treatment involves antibiotics prescribed by a veterinarian..."
Easy Neg
"The history of ancient Egyptian pyramids..." Trivially different
Hard Neg
"Common cat urinary tract symptoms and diagnosis..." Topically close but wrong task

How to mine hard negatives

BM25 mining

Run BM25 search for each query. Top results that aren't labeled positive are hard negatives -- keyword overlap but semantically wrong.

In-batch negatives

Other queries' positives in the same batch become negatives. Free and effective with large batch sizes.

Cross-encoder mining

Use a cross-encoder to score many candidates. Those scored medium-high but known-irrelevant are the hardest negatives.


Training Losses for Embeddings

The loss function determines what the embedding space optimizes for. Three dominant approaches.

Contrastive Loss (Pair-based)

Anchor
Pull
Push

Operates on pairs: (a, b) with a label y (1=similar, 0=dissimilar). Pulls similar pairs together, pushes dissimilar apart.

L = y*d(a,b)^2 + (1-y)*max(0, m - d(a,b))^2

Pros: Simple, works on pairs.
Cons: Needs margin tuning. No relative ranking between negatives.

Triplet Loss

A
P
N
d(A,P) + margin < d(A,N)

Triplets: (anchor, positive, negative). Requires d(a,p) + margin < d(a,n). More explicit separation constraint.

L = max(0, d(a,p) - d(a,n) + m)

Pros: Intuitive, enforces relative ordering.
Cons: Triplet mining is expensive. Many triplets are uninformative.

InfoNCE (used by most SOTA models)

A
P
Many negatives
softmax(sim/t)

One positive vs many negatives. Softmax over similarities -- the positive should get the highest probability among all candidates.

L = -log( exp(sim(a,p)/t) / [exp(sim(a,p)/t) + ∑ exp(sim(a,ni)/t)] )

Pros: Scales with batch size, no margin tuning. State of the art.
Cons: Needs large batches for enough negatives.

Key insight: InfoNCE dominates modern embedding training (CLIP, E5, GTE, Sentence Transformers). The key insight is that it naturally uses in-batch negatives, so larger batches = more negatives = better representations. Temperature t controls how sharply the model discriminates.


Long Document Strategies

Most embedding models have a 512-token limit. Documents are much longer. Three strategies to bridge the gap.

Fixed-Size Chunking

Chunk 1 (512 tok)
Chunk 2 (512 tok)
Chunk 3 (512 tok)

Split into fixed-size windows, embed each. Simple but can split thoughts mid-sentence.

Overlap: Add 50-100 token overlap between chunks to preserve context at boundaries.

Semantic Chunking

Introduction
Methods
Results

Split at natural boundaries: paragraphs, sections, headers. Each chunk is a coherent thought.

Better: Preserves meaning but chunk sizes vary widely.

Hierarchical Embeddings

Document Summary Embedding
|
Section 1
Section 2
Section 3

Create embeddings at multiple levels: doc summary + section + chunk. Search coarse-to-fine.

Best: Most accurate but complex to build and maintain.

StrategyComplexityRetrieval QualityWhen to Use
Fixed ChunkingLowModeratePrototyping, homogeneous docs
Semantic ChunkingMediumGoodStructured docs with clear sections
HierarchicalHighBestLarge corpora needing precision at scale

Multilingual Embedding Considerations

Making embeddings work across languages requires specific architectural and training choices.

Cross-Lingual Alignment

A multilingual embedding model maps "cat" (English), "gato" (Spanish), and "chat" (French) to nearby vectors because they mean the same thing.

"cat"
->
Multilingual
Encoder
->
Shared
Vector Space
"gato"
->
Same
Encoder
->
Nearby
Vector!

Key Challenges

Tokenizer mismatch: Same sentence in different scripts produces very different token counts. CJK languages often get 2-3x more tokens.
Language imbalance: English dominates training data. Low-resource languages get worse embeddings. Check MTEB benchmarks per-language.
Cultural context: Same word, different meaning across cultures. Evaluation must include native-speaker judgment, not just automated metrics.

Production tip: Models like multilingual-e5-large, BGE-M3, and Cohere's embed-multilingual-v3 are strong baselines. Always test with real queries in your target languages -- MTEB scores are averages that can hide per-language weaknesses.


Index Compression

At scale, raw float32 vectors are too expensive to store and search. Compression makes large-scale retrieval practical.

Visual: How quantization compresses vectors

Product Quantization (PQ)

Original: 768 float32 values
| Split into sub-vectors
Sub-vectors (groups of 8 dims):
| Replace with codebook IDs
Quantized: just IDs

Splits the vector into sub-vectors, then replaces each sub-vector with the ID of its nearest centroid from a learned codebook. Lossy but dramatic compression.

768-dim float32 (3072 bytes) -> 96 sub-vectors x 1 byte = 96 bytes

32x compression!

Scalar Quantization (SQ)

float32 values:
4 bytes each
| Map min/max to int8 range [-128, 127]
int8 values:
1 byte each (4x smaller!)
Reconstruction: int8 * scale + zero_point ~ original float32

Converts each float32 value to a smaller integer type (int8 or int4). Simpler than PQ, less compression but higher accuracy.

float32 (4 bytes/dim) -> int8 (1 byte/dim) = 4x compression

4x compression with minimal recall loss.

MethodCompressionRecall LossSpeed ImpactBest For
No compression (float32)1xNoneBaselineSmall datasets (<100K)
Scalar Quantization (int8)4xVery LowFaster (SIMD)Default choice for most
Product Quantization10-32xModerateFaster (smaller index)Billions of vectors
Binary Quantization32xHigherMuch faster (hamming)First-pass filtering

Similarity Threshold Tuning

The threshold at which you consider a retrieval result "relevant" directly trades precision for recall. There is no universal right answer.

Interactive: Precision/Recall Tradeoff

Drag the threshold slider. A higher threshold means fewer results but more precise; lower means more results but noisier.

0.70
Precision
82%

Of the results returned, what fraction is actually relevant?

Recall
36%

Of all relevant documents, how many were returned?

The dot on the curve tracks your current threshold setting.

High threshold (0.85+)

Use for: safety-critical retrieval (medical, legal), RAG where false positives cause hallucination. Fewer results, but each one is highly likely correct.

Low threshold (0.50-0.65)

Use for: exploratory search, creative brainstorming, when missing results is costlier than noise. More results, but includes marginal matches.

Key insight: There is no universal "good" threshold. It depends on the embedding model, the domain, and the cost of false positives vs false negatives. Always calibrate with labeled data from your actual task.


Monitoring Retrieval Drift

Embeddings work today but can degrade silently as your data, queries, or user behavior changes. Monitoring catches this before users notice.

What can go wrong over time

Day 1
Embeddings work great
->
Week 4
New topics in corpus
->
Month 3
Query patterns shift
->
Month 6
Silent quality degradation

What to Monitor

Average similarity scores - Dropping scores signal embedding-query mismatch
Recall@K on held-out queries - The gold standard; requires labeled data
Click-through / acceptance rate - Users ignoring results = quality issue
Distribution of retrieved doc ages - Old docs dominating = new content not embedded

Drift Detection Signals

Alert Top-1 similarity drops >10% from baseline
Warning New query clusters appear with no good matches
Warning User reformulation rate increases (users keep rephrasing)
Track Embedding space centroid shift over time

Embedding Migration Planning

Switching embedding models is a full data migration. Planning prevents costly downtime and silent quality regression.

Migration Pipeline

Evaluate New
Model
on your data
->
Build Shadow
Index
parallel to prod
->
A/B Test
dual-read
->
Cutover
swap primary
->
Deprecate
Old Index
after bake

Why you can't just swap models

Incompatible Different models produce different vector spaces -- they cannot be mixed
Dimensions New model may have different dimensions (768 vs 1024)
Re-embed all Every document must be re-embedded with the new model
Thresholds Similarity thresholds are model-specific -- need recalibration

Migration checklist

1 Benchmark new model on your labeled eval set
2 Calculate re-embedding time and compute cost
3 Build new index in parallel (not in-place)
4 A/B test with real traffic before full cutover
5 Keep old index for rollback (at least 1 week)
6 Recalibrate thresholds with the new model

Cost estimation: Re-embedding 10M documents at $0.00002/1K tokens (OpenAI text-embedding-3-small) with avg 200 tokens/doc = ~$40 in API costs plus compute time. The real cost is the engineering effort to run shadow indexing, A/B testing, and threshold recalibration safely.