Click any words you think contain an error. Click again to unmark.
Switching `Settings.embed_model` between build and re-index silently embeds new nodes with a different model than existing vectors, either a dim-mismatch error or silent cross-space corruption.
Imagine a closet where every shirt has a number written inside the collar showing its size in inches. You sort the shirts by that number. Months later, a friend helps you add new shirts, but they wrote the numbers in centimeters without telling anyone. The new shirts slip onto the rod next to the old ones. A shirt marked 30 might be tiny or huge depending on which ruler the writer used, but the rack treats every number the same. Now nothing on the rod is truly sorted, and when you reach for a small shirt you grab whatever lands near the number, not the size. The closet looks fine. The system silently lies. That is what happens when two different rulers measure the same shelf and nobody records which ruler made which mark.
Concept explanation~2 min read
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Concept explanation~2 min read
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
This snippet is a textbook example of how convenient global state in a framework becomes a production trap. The script ran fine last week, runs without errors today, and the codebase reads like a clean refactor. The index is quietly corrupted.
The root cause is the gap between Settings.embed_model (a mutable global read at call time) and the persisted vector store (which carries no record of which embed model produced its vectors). The defect is structural, you cannot fix it by patching this script alone; you fix it by changing how corpus integrity is enforced. This explanation walks the failure modes, the underlying geometry, and the production-grade fix.
Mechanically, what happens
On line 7, the initial build sets the global embed model to OpenAI's text-embedding-3-small and constructs the index from documents. LlamaIndex resolves the embed model from Settings for each chunk, produces 1536-dimensional vectors, and writes them to ./storage along with the index structure. Crucially, the persisted storage does not include the embed model identity; only the vectors and the nodes are saved.
A week later, the script runs again. Line 12 swaps the global to BAAI/bge-small-en-v1.5, which produces 384-dimensional vectors. Line 13 loads the index from disk; the vectors come back as raw 1536-dim arrays, but no consistency check fires because the index has no idea which model produced them.
Line 14, index.insert_nodes(new_nodes), asks LlamaIndex to embed the new nodes. The framework reads Settings.embed_model, sees bge-small, and produces 384-dim vectors. The insert then attempts to add 384-dim vectors into a vector store that holds 1536-dim vectors from last week's run. What happens next depends entirely on the vector store.
A store that enforces a fixed dimension at the schema level (pgvector with vector(1536), Pinecone with a declared dim, Weaviate classes) raises a dimension-mismatch error. The bug is loud and instantly fixable. A permissive store (a default in-memory dict, a Chroma collection without explicit dim constraints, a homemade store) accepts the insert. Now the index holds two embedding spaces.
Situations where this technique stops working.
2–4 min · Everything important, quickly.
Real products, models, and research that use this idea.
- pgvector enforces a fixed dimension per column (`vector(1536)`), which would catch this bug at insert time with a hard error.
- Pinecone and Weaviate require declaring the index dimension at creation, so a dim-mismatch insert fails fast.
What an interviewer would ask next. Try answering before peeking at the approach.
QSketch the sidecar-metadata pattern you'd use to make this class of bug impossible.
When persisting, write a JSON file (or a row in your store's metadata table) with {model_id, model_provider, dim, built_at_iso, schema_version}. On load, read the runtime embed_model config, compute the expected model_id, and assert equality. Mismatch raises an error before any insert or query runs. CI test that downgrading or upgrading the embed model triggers the assertion.
Red flags & common mistakes
The phrases that signal junior thinking. Click to expand.
Red flags & common mistakes
The phrases that signal junior thinking. Click to expand.
Trusting that an index "remembers" which embed model built it. By default, LlamaIndex's `Settings.embed_model` is a global at call time, the index does not enforce consistency.
60 second bullets to scan on the way to the call.
What the Settings.embed_model global actually is and when LlamaIndex reads from it.
Two failure modes when the embed model changes between build and insert.
Primary sources. Browse if you want the original framing.
Same topic, related formats. Practice these next.