RAGEngineering Hub
Chapter 5 · concept 4 of 4 · show all
  1. 1What RAG is, and why
    1. 1.1Why models need outside knowledge, and what hallucination means
    2. 1.2What RAG is: anatomy of a request
    3. 1.3RAG vs fine tuning vs long context and prompt caching
    4. 1.4Use cases and the quality, latency and cost triangle
    5. Chapter overview
  2. 2Tokens, cost and your first RAG
    1. 2.1Tokens and context windows for RAG
    2. 2.2The RAG lifecycle and your first RAG in miniature
    3. Chapter overview
  3. 3Getting documents in
    1. 3.1Content sources and file formats
    2. 3.2Parsing, layout and OCR
    3. 3.3Tables, images and mixed content
    4. 3.4Cleaning, normalization and quality gates
    5. 3.5Metadata, document identity and versioning
    6. 3.6Updates, deletes, reindexing and ingestion pipelines
    7. Chapter overview
  4. 4Chunking
    1. 4.1Why we chunk, and the main chunking strategies
    2. 4.2Structure aware chunking and tables
    3. 4.3Chunk size, overlap and token based sizing
    4. 4.4Contextual chunking and late chunking
    5. 4.5Parent child and multi representation indexing
    6. 4.6Chunk metadata, provenance and the chunking debugging playbook
    7. Chapter overview
  5. 5Embeddings
    1. 5.1Embeddings and similarity from first principles
    2. 5.2What embeddings cannot do
    3. 5.3Choosing an embedding model: size, cost, language
    4. 5.4Embedding model migration and index rebuilds
    5. Chapter overview
  6. 6Vector stores and scores
    1. 6.1Vector databases, ANN indexes and choosing a store
    2. 6.2Score calibration and thresholds
    3. 6.3Late interaction and multivector retrieval
    4. Chapter overview
  7. 7Finding the right chunks
    1. 7.1Query understanding, rewriting and expansion
    2. 7.2Dense retrieval and keyword search with BM25
    3. 7.3Hybrid retrieval and rank fusion
    4. 7.4topK, no good match, and metadata filtering
    5. 7.5Routing, diversity, deduplication and caching
    6. 7.6Reranking: two stage, cross encoder and LLM rerankers
    7. Chapter overview
  8. 8When retrieval fails
    1. 8.1Retrieval failure analysis playbook
    2. Chapter overview
  9. 9Building the answer
    1. 9.1Context selection, packing and citations
    2. 9.2Grounding prompts and abstention
    3. 9.3Lost in the middle and context management
    4. 9.4Conflicts, staleness and freshness rules
    5. 9.5Hallucination checks and answer verification
    6. 9.6Conversational RAG, answer UX and RAG APIs
    7. Chapter overview
  10. 10Measuring
    1. 10.1Why measure, and what to measure
    2. 10.2Building a golden dataset
    3. 10.3Retrieval metrics: precision, recall, MRR, nDCG
    4. 10.4Faithfulness and answer correctness
    5. 10.5LLM as judge, and judging the judge
    6. 10.6Offline and online evals, regression tests and slices
    7. Chapter overview
  11. 11Safety and operations
    1. 11.1Prompt injection and poisoned documents
    2. 11.2Access control, privacy and governance
    3. 11.3Index lifecycle operations
    4. 11.4Observability and tracing
    5. 11.5Latency, cost, caching and model routing
    6. 11.6Reliability, degraded modes and launch readiness
    7. Chapter overview
  12. 12Scale and advanced RAG
    1. 12.1Scaling, multi tenancy and enterprise architecture
    2. 12.2Choosing an architecture: naive, advanced, agentic, graph
    3. 12.3Agentic RAG and RAG as an MCP tool
    4. 12.4GraphRAG, structured data and multimodal RAG
    5. Chapter overview

Embedding model migration and index rebuilds

Changing the embedding model means re-embedding everything. We mixed an old index with a new query model of the same size; recall fell from 44 to 28 of 47 without a single error.

A real question

We found a better embedding model. Can we just start using it for new questions?

No. Every stored vector was made by the old model, and the new model's vectors live in a different space. You have to re-embed everything and switch queries and index together.

The problem

Why this matters

Two models that both output 384 numbers are compatible.
The belief

Two models that both output 384 numbers are compatible.

We searched the bge-small index with all-MiniLM query vectors. Both have 384 dimensions. Recall fell from 44 to 28 of 47, and nothing raised an error.
What really happens

We searched the bge-small index with all-MiniLM query vectors. Both have 384 dimensions. Recall fell from 44 to 28 of 47, and nothing raised an error.

Why not the simpler way

Embedding models improve every few months, and vendors retire old ones. Sooner or later you will migrate. The danger is that a half-done migration looks fine: queries return results, scores look normal, and the answers get quietly worse.

The idea

The idea in plain words

Each embedding model learns its own map of meaning. Two maps can have the same number of coordinates and still put "router" in completely different places. A migration re-draws every point on the new map before anyone navigates with it.

Two cities can both use street numbers from 1 to 400. A house number from one city does not find a house in the other.

How it works

Step by step

  1. Re-embed every chunk with the new model into a separate index. The old one keeps serving users.
    1

    Build the new index alongside

    Re-embed every chunk with the new model into a separate index. The old one keeps serving users.

  2. Same questions, same metric. Switch only if the new index wins clearly, and check slices like languages and codes.
    2

    Test both on the golden set

    Same questions, same metric. Switch only if the new index wins clearly, and check slices like languages and codes.

  3. Point queries and index at the new model in one release. Keep the old index until you are sure.
    3

    Switch together, keep a way back

    Point queries and index at the new model in one release. Keep the old index until you are sure.

In detail

What changes. Chunk vectors, query vectors, any score cut-offs (RAG-23), cached query results, and sometimes chunk size, if the new model reads more or fewer tokens.

Blue-green index. Keep two indexes, old (blue) and new (green). Re-embed into green in the background; new and changed documents go to both while it runs. Evaluate green on the golden set, then flip a single setting that moves queries and index together.

Guard rails. Store model, version, prefix and pooling in the index metadata. At query time, refuse to search if the query model does not match. Dimension mismatches fail loudly (bge-base has 768, our index 384); same-dimension mismatches fail silently, so the check must compare names.

Cost. Re-embedding is one model call per chunk. For a hosted API that is tokens times price; for a local model it is compute time. Batch it and resume from a checkpoint.

The code

Try it in Python

INDEX_META = {"model": "BAAI/bge-small-en-v1.5", "prefix": "Represent this sentence for searching relevant passages: ", "pooling": "cls"}

def search(question: str, query_model_name: str):
    if query_model_name != INDEX_META["model"]:
        raise RuntimeError(f"query model {query_model_name} does not match index model {INDEX_META['model']}")
    ...

# Migration: build a second index with the new model, run the golden set on both,
# then change INDEX_META and the query model in the same release.

See it

What we measured

Measured · evidence recall@3 by index and query model

Polder corpus, 34 recursive 512 token chunks, 47 golden questions. Index and query vectors from the named models, q8, each with its own prefix and pooling.

bge-small index, bge-small queries44 of 47 (stored vectors)
bge-small index, all-MiniLM queries (mixed)4428 of 47
e5-small index, e5-small queries4447 of 47

Measured 2026-11-04 with corpus/scripts/measure-parts-4-7.mts. The mixed run uses the same 384 dimensions on both sides, so no error is raised.

Try it on a real example

Same 34 chunks and 47 questions

Index + queries
1.bge-small index + bge-small queries · 44 of 47One model for both.✓

Today's system.

Choosing

Use it when, avoid it when

Use it when
  • A parallel index and a golden-set comparison for every model change
  • A model-name check on every query
Avoid it when
  • Re-embedding only new documents with a new model
  • Switching the query model before the index is rebuilt

What it costs · One embedding call per chunk, plus storage for two indexes during the switch.

In production

Schedule migrations like database migrations: a plan, a dry run on a copy, a measured comparison and a rollback. Run the golden set per slice, because a new model can win overall and lose on one language or on exact codes. If the corpus is large, estimate the re-embedding time and cost before you start, and keep the old index until the new one has served real traffic without regressions.

Watch out

Common mistakes

  • Same size, same space. 384 and 384 gave 28 of 47.
  • A new model only matters for new documents. Every old vector must be redone too.
  • Migrations fail loudly. Only dimension mismatches do; the rest is silent.

Check yourself

Remember this

Remember these

  • Changing the model invalidates every stored vector.
  • Same dimensions do not mean the same space: mixing gave 28 of 47.
  • Build alongside, test on the golden set, switch both sides at once.
  • Store the model name and recipe with every vector, and check it at query time.

Say it in an interview

  1. 01A model change invalidates every vector, because each model has its own space.
  2. 02On my corpus, mixing two 384-dimension models dropped recall from 44 to 28 of 47 with no error.
  3. 03I migrate blue-green: build alongside, compare on the golden set, switch both sides together.
  4. 04I store the model name and recipe in index metadata and refuse mismatched queries.
  5. 05I re-tune score cut-offs after the switch, since every model has its own score range.

Quick quiz

Three questions

Question 1

Q1

Index from bge-small, queries from all-MiniLM, both 384 numbers. What happened?

Question 2

Q2

What is the safe way to switch embedding models?

Question 3

Q3 · from RAG-12

When a document changes, which chunks need new embeddings?

Saved on this device. No account needed.