Versioning

Semantic Versioning for Embeddings

9 min readVersioning

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
Most teams handle this by reindexing everything when models update. But this is expensive, slow, and doesn't solve the underlying problem.

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
Semantic versioning for embeddings solves these problems by:
  • 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
If you're using embeddings in production, implement semantic versioning now. The cost of not versioning is:
  • Expensive full reindexes on every model update
  • Inconsistent search results
  • No rollback capability
  • Difficult debugging
The future of embedding management isn't disposable vectors—it's versioned, traceable, and maintainable embeddings.

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