Semantic Versioning for Embeddings
Semantic Versioning for Embeddings
Embedding models update constantly. New versions promise better accuracy, lower costs, or improved performance. But without proper versioning, these updates break your vector database. This article shows you how to implement semantic versioning for embeddings and maintain consistency across model changes.
The Versioning Problem
When you update an embedding model, everything breaks:
- New embeddings don't match old ones: Different model versions produce different vector spaces
- Search quality degrades: Mixing embeddings from different models creates inconsistent results
- No rollback path: Once you update, you can't go back
- Inconsistent results: Queries return unpredictable results
What is Semantic Versioning for Embeddings?
Semantic versioning for embeddings extends the concept of semantic versioning (used in software) to vector embeddings. It provides:
- Version identification: Track which model version generated each embedding
- Compatibility rules: Understand which embeddings can be used together
- Migration paths: Plan transitions between model versions
- Rollback capability: Revert to previous versions when needed
Version Format
Embedding versions follow semantic versioning: MAJOR.MINOR.PATCH
- MAJOR: Incompatible changes (different vector space)
- MINOR: Compatible additions (same vector space, new features)
- PATCH: Bug fixes (same vector space, same features)
Example
text-embedding-ada-002-v1.0.0
text-embedding-ada-002-v2.0.0 (MAJOR - incompatible)
text-embedding-3-small-v2.1.0 (MINOR - compatible)
text-embedding-3-small-v2.1.1 (PATCH - bug fix)
Why Versioning Matters
1. Model Compatibility
Different embedding models produce incompatible vector spaces. Embeddings from text-embedding-ada-002 can't be compared with embeddings from text-embedding-3-small—they exist in different dimensions and spaces.
Versioning makes this explicit:
# Without versioning - dangerous
embedding_v1 = generate_embedding("query", model="ada-002")
embedding_v2 = generate_embedding("document", model="text-embedding-3")
These can't be compared!
similarity = cosine_similarity(embedding_v1, embedding_v2) # Meaningless
With versioning - safe
if embedding_v1.version != embedding_v2.version:
raise IncompatibleVersionError("Cannot compare different versions")
2. Gradual Migration
Versioning enables gradual migration strategies:
- Dual indexing: Maintain both old and new versions during transition
- A/B testing: Compare model versions before full migration
- Rollback capability: Revert if new version performs worse
3. Reproducibility
Versioning ensures reproducibility:
- Consistent results: Same inputs produce same outputs
- Debugging: Trace issues to specific model versions
- Auditing: Track which version was used for each query
4. Cost Management
Versioning helps manage costs:
- Selective updates: Only reindex what's necessary
- Version comparison: Test new versions before full deployment
- Rollback savings: Avoid expensive full reindexes when new versions fail
Implementing Semantic Versioning
1. Version Metadata
Store version information with each embedding:
{
"id": "doc_123",
"vector": [0.1, 0.2, ...],
"metadata": {
"model": "text-embedding-3-small",
"version": "2.1.0",
"dimensions": 1536,
"created_at": "2025-01-15T10:00:00Z"
}
}
2. Version Validation
Validate version compatibility before operations:
def validate_version_compatibility(embedding1, embedding2):
if embedding1.metadata.version.major != embedding2.metadata.version.major:
raise IncompatibleVersionError(
f"Major version mismatch: {embedding1.metadata.version} vs {embedding2.metadata.version}"
)
return True
3. Version Filtering
Filter embeddings by version in queries:
def search(query, version="2.1.0"):
query_embedding = generate_embedding(query, version=version)
results = vector_db.search(
query_embedding,
filter={"metadata.version": version}
)
return results
4. Migration Strategies
Implement migration strategies:
#### Strategy 1: Dual Indexing
Maintain separate indexes for each version:
# Old version index
old_index = VectorDB(index_name="embeddings_v1")
New version index
new_index = VectorDB(index_name="embeddings_v2")
During migration, query both and merge results
#### Strategy 2: Gradual Rollout
Migrate documents gradually:
def migrate_document(doc_id, target_version):
# Generate new embedding
new_embedding = generate_embedding(
doc.content,
version=target_version
)
# Update with version metadata
vector_db.upsert(doc_id, new_embedding, metadata={
"version": target_version
})
#### Strategy 3: Version Aliases
Use aliases to abstract version details:
# Alias points to current version
current_version = "2.1.0"
vector_db.set_alias("current", current_version)
Queries use alias
results = vector_db.search(query, index="current")
Best Practices
1. Version All Embeddings
Every embedding should have a version. No exceptions.
2. Document Breaking Changes
When you introduce a MAJOR version change, document:
- What changed
- Why it changed
- Migration path
- Compatibility notes
3. Test Before Migrating
Always test new versions before full migration:
- Generate sample embeddings
- Compare search quality
- Measure performance impact
- Validate cost changes
4. Maintain Version History
Keep a version history:
- Track which versions were used when
- Document migration timelines
- Maintain rollback procedures
5. Automate Version Checks
Automate version compatibility checks:
- Validate on insert
- Check on query
- Alert on mismatches
The Bottom Line
Without versioning, embeddings are disposable. Every model update requires a full reindex, and you have no way to:
- Test new versions safely
- Roll back if updates fail
- Maintain consistency
- Debug issues
- Identifying versions: Know which model generated each embedding
- Enforcing compatibility: Prevent mixing incompatible embeddings
- Enabling migration: Plan and execute version transitions
- Supporting rollback: Revert to previous versions when needed
- Expensive full reindexes on every model update
- Inconsistent search results
- No rollback capability
- Difficult debugging
Ready to Simplify Your Vector Infrastructure?
SimpleVector helps you manage embeddings, keep data fresh, and scale your RAG systems without the operational overhead.
Get Started