Embeddings
LocalVectorDB features a plugin-based embedding system that supports multiple providers with a unified interface. The system is designed for flexibility, allowing easy switching between providers and custom implementations.
Overview
Embeddings are dense vector representations of text that capture semantic meaning. LocalVectorDB supports multiple embedding providers:
Ollama: Local embeddings without API costs
OpenAI: Cloud-based embeddings with high quality
JinaAI: Advanced cloud-based embedding models with more control
Google: Cloud-based Gemini Embedding
SentenceTransformers: Local inference with the sentence-transformers library
HuggingFace: Both Inference API and local transformers models
Custom Providers: Plugin system for additional providers
Embedding Providers
Ollama Provider (Recommended)
Run embeddings locally without API costs or rate limits.
Setup:
# Install Ollama
curl -fsSL https://ollama.ai/install.sh | sh
# Pull embedding models
ollama pull nomic-embed-text # 137M parameters, good quality
ollama pull mxbai-embed-large # 334M parameters, highest quality
ollama pull all-minilm # 23M parameters, fastest
Configuration:
from localvectordb import VectorDB
# Default Ollama configuration
db = VectorDB(
"my_db",
"./vector_storage",
embedding_provider="ollama",
embedding_model="nomic-embed-text",
embedding_config={
"base_url": "http://127.0.0.1:11434" # Default Ollama URL
}
)
# Custom Ollama configuration
db = VectorDB(
"my_db",
"./vector_storage",
embedding_provider="ollama",
embedding_model="mxbai-embed-large",
embedding_config={
"base_url": "http://remote-ollama:11434", # Remote Ollama
"timeout": 60 # Request timeout in seconds
}
)
Available Models:
nomic-embed-text: General-purpose, good balance of speed/qualitymxbai-embed-large: Highest quality, slowerall-minilm: Fastest, lower qualitysnowflake-arctic-embed: Optimized for retrieval tasks
OpenAI Provider
High-quality cloud embeddings with API costs.
Setup:
export OPENAI_API_KEY=your_api_key_here
Configuration:
# Using environment variable
db = VectorDB(
"my_db",
"./vector_storage",
embedding_provider="openai",
embedding_model="text-embedding-3-small"
)
# Explicit API key
db = VectorDB(
"my_db",
"./vector_storage",
embedding_provider="openai",
embedding_model="text-embedding-3-large",
embedding_config={
"api_key": "your_api_key_here"
}
)
Available Models:
text-embedding-3-small: 1536 dimensions, cost-effectivetext-embedding-3-large: 3072 dimensions, highest qualitytext-embedding-ada-002: Legacy model, still good quality
JinaAI Provider
Advanced cloud-based embedding models with extensive customization options.
Note
The JinaAI provider is built into LocalVectorDB and requires no additional dependencies. It uses the standard HTTP client already included with LocalVectorDB.
Setup:
# No additional installation required - JinaAI provider is built-in
export JINA_API_KEY=your_api_key_here
# Get your free API key at: https://jina.ai/?sui=apikey
Configuration:
# Basic configuration
db = VectorDB(
"my_db",
"./vector_storage",
embedding_provider="jina",
embedding_model="jina-embeddings-v4"
)
# Advanced configuration with task-specific optimization
db = VectorDB(
"my_db",
"./vector_storage",
embedding_provider="jina",
embedding_model="jina-embeddings-v4",
embedding_config={
"api_key": "your_api_key_here",
"task": "retrieval.passage", # Optimize for document retrieval
"requested_dimensions": 1024, # Truncate to 1024 dimensions
"truncate": True,
"late_chunking": True
}
)
# Code embeddings
db = VectorDB(
"my_db",
"./vector_storage",
embedding_provider="jina",
embedding_model="jina-code-embeddings-1.5b",
embedding_config={
"task": "code2code.passage" # Code-to-code similarity
}
)
Available Models:
jina-embeddings-v4: 2048 dimensions, multimodal/multilingualjina-embeddings-v3: 1024 dimensions, text-onlyjina-code-embeddings-1.5b: 1536 dimensions, code-specializedjina-code-embeddings-0.5b: 896 dimensions, code-specialized
Task Types for jina-embeddings-v4:
retrieval.query: For search queriesretrieval.passage: For documents being searchedtext-matching: For similarity comparisonscode.query/code.passage: For code search
Task Types for code models:
nl2code.query/nl2code.passage: Natural language to codecode2code.query/code2code.passage: Code-to-code searchcode2nl.query/code2nl.passage: Code to natural languagecode2completion.query/code2completion.passage: Code completionqa.query/qa.passage: Question-answering
Google AI Provider
Google’s Gemini embedding models with flexible configuration.
Note
The Google AI provider is built into LocalVectorDB and requires no additional dependencies. It uses the standard HTTP client already included with LocalVectorDB.
Setup:
# No additional installation required - Google AI provider is built-in
# Set one of these environment variables
export GEMINI_API_KEY=your_api_key_here
export GOOGLE_API_KEY=your_api_key_here
Configuration:
# Basic configuration
db = VectorDB(
"my_db",
"./vector_storage",
embedding_provider="google",
embedding_model="gemini-embedding-001"
)
# Advanced configuration with task optimization
db = VectorDB(
"my_db",
"./vector_storage",
embedding_provider="google",
embedding_model="gemini-embedding-001",
embedding_config={
"api_key": "your_api_key_here", # Or better yet, use GEMINI_API_KEY environment variable instead
"task_type": "retrieval_document", # Optimize for document storage
"requested_dimensions": 1536, # Control output size
"normalize": True # L2-normalize vectors
}
)
Available Models:
gemini-embedding-001: 3072 dimensions (default), stable production model
Task Types:
semantic_similarity: General text similarity (default)classification: Text classification tasksclustering: Document clusteringretrieval_document: For documents being indexedretrieval_query: For search queriescode_retrieval_query: Code search queriesquestion_answering: Q&A systemsfact_verification: Fact-checking tasks
Configuration Options:
requested_dimensions: Output size (128-3072), defaults to 3072normalize: L2-normalize vectors (recommended for non-3072 outputs)task_type: Task-specific optimization
SentenceTransformers Provider
Run any SentenceTransformer model locally. Supports Matryoshka dimension truncation.
Note
Requires the sentence-transformers optional dependency:
pip install "localvectordb[sentence-transformers]"
Configuration:
# Basic usage
db = VectorDB(
"my_db",
"./vector_storage",
embedding_provider="sentence_transformers",
embedding_model="all-MiniLM-L6-v2"
)
# With Matryoshka dimension truncation
db = VectorDB(
"my_db",
"./vector_storage",
embedding_provider="sentence_transformers",
embedding_model="all-MiniLM-L6-v2",
embedding_config={
"requested_dimensions": 128, # Truncate to 128 dims
"normalize": True,
"device": "cuda" # Use GPU (cpu/cuda/mps/auto)
}
)
HuggingFace Inference API Provider
Use HuggingFace’s hosted Inference API for embedding models.
Setup:
export HF_TOKEN=your_huggingface_token
Configuration:
# Using HuggingFace Inference API
db = VectorDB(
"my_db",
"./vector_storage",
embedding_provider="huggingface",
embedding_model="BAAI/bge-small-en-v1.5"
)
# With a custom TEI (Text Embeddings Inference) endpoint
db = VectorDB(
"my_db",
"./vector_storage",
embedding_provider="huggingface",
embedding_model="BAAI/bge-small-en-v1.5",
embedding_config={
"base_url": "http://localhost:8080", # Custom TEI endpoint
"requested_dimensions": 256,
"normalize": True
}
)
HuggingFace Local Provider
Run HuggingFace transformer models locally with full control over pooling and device.
Note
Requires the local-embeddings optional dependency:
pip install "localvectordb[local-embeddings]"
Configuration:
db = VectorDB(
"my_db",
"./vector_storage",
embedding_provider="huggingface_local",
embedding_model="BAAI/bge-small-en-v1.5",
embedding_config={
"pooling_strategy": "mean", # mean, cls, or max
"device": "cuda",
"normalize": True,
"requested_dimensions": 256
}
)
Matryoshka Dimension Support
Several providers support Matryoshka Representation Learning (MRL), which allows you to truncate embeddings to a smaller dimension while preserving most of their quality. This reduces storage and speeds up similarity search.
OpenAI (text-embedding-3-small and text-embedding-3-large only):
# Reduce OpenAI embeddings from 1536 to 256 dimensions
db = VectorDB(
"my_db",
"./vector_storage",
embedding_provider="openai",
embedding_model="text-embedding-3-small",
embedding_config={
"requested_dimensions": 256,
"normalize": True
}
)
Ollama (model-dependent):
# Reduce Ollama embeddings with client-side truncation
db = VectorDB(
"my_db",
"./vector_storage",
embedding_provider="ollama",
embedding_model="nomic-embed-text",
embedding_config={
"requested_dimensions": 256,
"normalize": True
}
)
SentenceTransformers and HuggingFace providers also support requested_dimensions
for Matryoshka truncation (see their sections above).
Custom Provider Example
from typing import List
from localvectordb.embeddings import EmbeddingProvider, EmbeddingRegistry
import numpy as np
class CustomEmbeddingProvider(EmbeddingProvider):
def __init__(self, model: str, **kwargs):
super().__init__(model, **kwargs)
self.api_endpoint = kwargs.get('api_endpoint')
@property
def provider_name(self) -> str:
return "custom"
@property
def max_batch_size(self) -> int:
return 100
def validate_model(self) -> bool:
# Check if your model/API is available
return True
def get_dimension(self) -> int:
return 768 # Your embedding dimension
async def _embed_single_batch(self, texts: List[str], **kwargs) -> List[List[float]]:
# Implement your embedding logic for a single batch
embeddings = []
for text in texts:
# Call your embedding API/model
embedding = await self._get_embedding(text)
embeddings.append(embedding)
return embeddings
async def _get_embedding(self, text: str) -> List[float]:
# Your implementation here
pass
# Register custom provider
EmbeddingRegistry.register("custom", CustomEmbeddingProvider)
# Use custom provider
db = VectorDB(
"my_db",
"./vector_storage",
embedding_provider="custom",
embedding_model="your-model",
embedding_config={
"api_endpoint": "https://your-api.com/embed"
}
)
Direct Embedding API
Use embedding providers directly without a database:
from localvectordb.embeddings import EmbeddingRegistry
# Create provider
provider = EmbeddingRegistry.create_provider(
"ollama",
"nomic-embed-text"
)
# Generate embeddings
texts = ["Hello world", "How are you?", "Goodbye"]
# Synchronous
embeddings = provider.embed_sync(texts)
print(f"Shape: {embeddings.shape}") # (3, 768)
# Asynchronous
import asyncio
embeddings = await provider.embed_batch(texts)
The async embed_batch accepts a progress_callback that is invoked as
(completed, total) after each batch — useful for progress bars on large
embedding jobs:
def on_progress(completed, total):
print(f"{completed}/{total} texts embedded")
embeddings = await provider.embed_batch(texts, progress_callback=on_progress)
The module-level helpers embed_texts() (async)
and embed_texts_sync() (synchronous) create a
provider and embed in one call, without instantiating a database.
Provider Comparison
Performance Comparison
import time
from localvectordb.embeddings import EmbeddingRegistry
def benchmark_provider(provider_name, model, texts):
provider = EmbeddingRegistry.create_provider(provider_name, model)
# Validate model
if not provider.validate_model():
print(f"{provider_name} model {model} not available")
return
# Time embedding generation
start_time = time.time()
embeddings = provider.embed_sync(texts)
duration = time.time() - start_time
dimension = embeddings.shape[1]
speed = len(texts) / duration
print(f"{provider_name}/{model}:")
print(f" Dimension: {dimension}")
print(f" Speed: {speed:.1f} texts/second")
print(f" Total time: {duration:.2f}s")
# Test different providers
test_texts = ["Example text " + str(i) for i in range(100)]
benchmark_provider("ollama", "nomic-embed-text", test_texts)
benchmark_provider("ollama", "all-minilm", test_texts)
benchmark_provider("openai", "text-embedding-3-small", test_texts)
benchmark_provider("jina", "jina-embeddings-v4", test_texts)
benchmark_provider("google", "gemini-embedding-001", test_texts)
Quality Considerations
Provider |
Model |
Dimensions |
Speed |
Cost |
|---|---|---|---|---|
Ollama |
nomic-embed-text |
768 |
Medium |
Free |
Ollama |
mxbai-embed-large |
1024 |
Medium |
Free |
Ollama |
all-minilm |
384 |
Fast |
Free |
OpenAI |
text-embedding-3-small |
1536 |
Fast |
$0.02/1M tokens |
OpenAI |
text-embedding-3-large |
3072 |
Fast |
$0.13/1M tokens |
JinaAI |
jina-embeddings-v4 |
2048 |
Fast |
Free tier |
JinaAI |
jina-embeddings-v3 |
1024 |
Fast |
Free tier |
JinaAI |
jina-code-embeddings-1.5b |
1536 |
Fast |
Free tier |
Google AI |
gemini-embedding-001 |
3072 |
Fast |
Free tier |
SentenceTransformers |
all-MiniLM-L6-v2 |
384 |
Fast |
Free (local) |
HuggingFace |
BAAI/bge-small-en-v1.5 |
384 |
Fast |
Free tier |
HuggingFace Local |
BAAI/bge-small-en-v1.5 |
384 |
Fast |
Free (local) |
Advanced Configuration
embedding_config Reference
The embedding_config dictionary is passed as keyword arguments to the embedding provider’s
constructor. All providers inherit a set of common parameters from the base EmbeddingProvider class,
plus provider-specific options.
Common parameters (all providers):
embedding_config={
"timeout": 90, # Request timeout in seconds (default: 90, Ollama default: 300)
"max_retries": 3, # Number of retries on failure (default: 3)
"retry_delay": 1.0, # Initial retry delay in seconds, with exponential backoff (default: 1.0)
"max_concurrent_requests": 5, # Max parallel batch requests (default: 5, Ollama default: 3)
}
Provider-specific parameters:
Provider |
Parameter |
Description |
|---|---|---|
Ollama |
|
Ollama server URL (default: |
Ollama |
|
Truncate output to N dims (Matryoshka/MRL) |
Ollama |
|
L2-normalize output vectors (bool) |
OpenAI |
|
API key (default: |
OpenAI |
|
Output dims (MRL, v3 models only) |
OpenAI |
|
L2-normalize output vectors (bool) |
JinaAI |
|
API key (default: |
JinaAI |
|
Task-specific optimization (see JinaAI section above) |
JinaAI |
|
Truncate output to N dimensions |
JinaAI |
|
Whether to truncate long inputs (bool) |
JinaAI |
|
Enable late chunking (bool) |
Google AI |
|
API key (default: |
Google AI |
|
Task-specific optimization (see Google AI section above) |
Google AI |
|
Output size (128-3072) |
Google AI |
|
L2-normalize output vectors (bool) |
Google AI |
|
Override the Generative Language API base URL |
SentenceTransformers |
|
Inference device (cpu/cuda/mps/auto) |
SentenceTransformers |
|
Truncate output to N dims (Matryoshka) |
SentenceTransformers |
|
L2-normalize output vectors (bool, default: True) |
SentenceTransformers |
|
Trust remote code when loading model (bool) |
HuggingFace |
|
API key (default: |
HuggingFace |
|
Custom TEI endpoint URL |
HuggingFace |
|
Truncate output to N dimensions |
HuggingFace |
|
L2-normalize output vectors (bool, default: True) |
HuggingFace Local |
|
Inference device (cpu/cuda/mps) |
HuggingFace Local |
|
Pooling method: mean, cls, or max (default: mean) |
HuggingFace Local |
|
Truncate output to N dimensions |
HuggingFace Local |
|
L2-normalize output vectors (bool, default: True) |
HuggingFace Local |
|
Trust remote code when loading model (bool) |
Retry behavior uses exponential backoff: the delay after attempt n is retry_delay * 2^n seconds.
Retries are triggered by network errors, timeouts, HTTP 429 (rate limit), and 5xx server errors.
Batch Processing
# Configure batch sizes for optimal performance.
# The DB-level ``batch_size`` controls how many texts are accumulated before
# each embedding call (capped by the provider's ``max_batch_size``). It is a
# top-level VectorDB argument -- it is NOT read from ``embedding_config``.
# ``embedding_config`` holds provider request settings such as ``timeout``.
db = VectorDB(
"my_db",
"./vector_storage",
embedding_provider="ollama",
embedding_model="nomic-embed-text",
batch_size=32, # Texts per embedding call (DB-level argument)
embedding_config={
"timeout": 120 # Longer timeout for large batches
}
)
# Manual batch processing
large_documents = ["document " + str(i) for i in range(1000)]
# Insert with custom batch size
doc_ids = db.upsert(
documents=large_documents,
batch_size=50 # Process 50 documents at a time
)
Error Handling and Retries
from localvectordb.exceptions import EmbeddingError
try:
db = VectorDB(
"my_db",
"./vector_storage",
embedding_provider="ollama",
embedding_model="nonexistent-model"
)
except EmbeddingError as e:
print(f"Embedding error: {e}")
# Fallback to different model
db = VectorDB(
"my_db",
"./vector_storage",
embedding_provider="ollama",
embedding_model="all-minilm" # Smaller, more reliable model
)
Provider Selection Strategy
def create_db_with_fallback(name, base_path, preferred_provider="ollama"):
"""Create database with provider fallback"""
providers_to_try = [
("ollama", "nomic-embed-text"),
("ollama", "all-minilm"),
("openai", "text-embedding-3-small")
]
if preferred_provider == "openai":
providers_to_try = providers_to_try[::-1] # Try OpenAI first
for provider, model in providers_to_try:
try:
# Test provider availability
test_provider = EmbeddingRegistry.create_provider(provider, model)
if test_provider.validate_model():
return VectorDB(
name,
base_path,
embedding_provider=provider,
embedding_model=model
)
except Exception as e:
print(f"Failed to use {provider}/{model}: {e}")
continue
raise Exception("No embedding providers available")
# Use with fallback
db = create_db_with_fallback("my_db", "./vector_storage", preferred_provider="ollama")
Plugin Development
Creating an Embedding Plugin
Create a Python package with entry points.
pyproject.toml:
[project]
name = "my-embedding-provider"
version = "1.0.0"
dependencies = [
"localvectordb>=0.1.0",
"requests", # Your dependencies
]
# Discovered automatically by LocalVectorDB's EmbeddingRegistry
[project.entry-points."localvectordb.embedding_providers"]
my_provider = "my_embedding_provider:MyEmbeddingProvider"
my_embedding_provider/__init__.py:
from typing import List
from localvectordb.embeddings import EmbeddingProvider
import numpy as np
import requests
class MyEmbeddingProvider(EmbeddingProvider):
def __init__(self, model: str, **kwargs):
super().__init__(model, **kwargs)
self.api_url = kwargs.get('api_url', 'https://api.example.com')
self.api_key = kwargs.get('api_key')
@property
def provider_name(self) -> str:
return "my_provider"
@property
def max_batch_size(self) -> int:
return 50
def validate_model(self) -> bool:
try:
response = requests.get(f"{self.api_url}/models/{self.model}")
return response.status_code == 200
except:
return False
def get_dimension(self) -> int:
# Return dimension for your model
return 512
async def _embed_single_batch(self, texts: List[str], **kwargs) -> List[List[float]]:
response = requests.post(
f"{self.api_url}/embed",
json={
"model": self.model,
"input": texts
},
headers={"Authorization": f"Bearer {self.api_key}"}
)
if response.status_code != 200:
raise RuntimeError(f"API error: {response.text}")
return response.json()['embeddings']
Installation and Usage:
pip install my-embedding-provider
# Now use in LocalVectorDB
python -c "
from localvectordb import VectorDB
db = VectorDB(
'test_db',
'./vector_storage',
embedding_provider='my_provider',
embedding_model='my-model-v1',
embedding_config={'api_key': 'your_key'}
)
"
Troubleshooting
Common Issues
Ollama connection errors:
# Test Ollama connection
from localvectordb.embeddings import EmbeddingRegistry
try:
provider = EmbeddingRegistry.create_provider("ollama", "nomic-embed-text")
if provider.validate_model():
print("Ollama working correctly")
else:
print("Model not available, try: ollama pull nomic-embed-text")
except Exception as e:
print(f"Ollama error: {e}")
print("Check if Ollama is running: ollama list")
OpenAI authentication errors:
import os
# Verify API key
api_key = os.getenv("OPENAI_API_KEY")
if not api_key:
print("Set OPENAI_API_KEY environment variable")
elif not api_key.startswith("sk-"):
print("Invalid OpenAI API key format")
else:
print("API key configured correctly")
Dimension mismatch errors:
# Check embedding dimensions
provider = EmbeddingRegistry.create_provider("ollama", "nomic-embed-text")
dimension = provider.get_dimension()
print(f"Model dimension: {dimension}")
# When switching models, ensure dimensions match
# or create a new database with the new model
Performance Optimization
# Optimize embedding performance
import asyncio
from localvectordb.embeddings import embed_texts
async def fast_embedding_example():
texts = ["Text " + str(i) for i in range(1000)]
# Process in parallel with optimal batch size
embeddings = await embed_texts(
texts=texts,
provider="ollama",
model="all-minilm", # Fastest model
batch_size=64 # Optimize based on your hardware
)
return embeddings
# Run async embedding
embeddings = asyncio.run(fast_embedding_example())