Choosing a Provider

View Source

This guide helps you select the right embedding provider for your use case.

Quick Decision Tree

Need image embeddings?
  └─ Yes → CLIP
  └─ No ↓

Need sparse vectors for hybrid search?
  └─ Yes → SPLADE
  └─ No ↓

Need token-level matching?
  └─ Yes → ColBERT
  └─ No ↓

Can use cloud API?
  └─ No → Local (Ollama, Local, or FastEmbed)
  └─ Yes ↓

Need EU data residency?
  └─ Yes → Mistral or Azure (EU region)
  └─ No ↓

Need domain-specific models?
  └─ Yes → Voyage (code, law, finance) or Bedrock (Cohere)
  └─ No ↓

Need enterprise compliance?
  └─ Yes → Azure, Bedrock, or Vertex
  └─ No ↓

Need best retrieval quality?
  └─ Yes → Voyage or Cohere
  └─ No → OpenAI (general purpose)

Local only?
  └─ Have Ollama → Ollama (recommended)
  └─ Need lightweight → FastEmbed (~100MB)
  └─ Need any HF model → Local (~2GB)

Provider Comparison

Cloud Providers

ProviderQualityBest ForDimensionsEU Residency
OpenAI★★★★★General purpose256-3072No
Cohere★★★★★Input type optimization384-1024No
Voyage★★★★★Retrieval, domain-specific512-1536No
Jina★★★★☆Long context (8K), multilingual768-1024No
Mistral★★★★☆EU data residency1024Yes
Azure★★★★★Enterprise compliance1536-3072Yes (regional)
Bedrock★★★★★AWS ecosystem1024-1536Yes (regional)
Vertex★★★★☆GCP ecosystem768Yes (regional)

Local Providers

ProviderQualitySpeedInstall SizeDependenciesOffline
Ollama★★★★☆Fast~2GB (model)Ollama serverYes
Local★★★★☆Medium~2GBPython, PyTorchYes
FastEmbed★★★★☆Fast~100MBPython, ONNXYes

Specialized Providers

ProviderTypeOutputBest For
SPLADESparse{indices, values}Hybrid search, keyword expansion
ColBERTMulti-vector[[float]] per tokenFine-grained semantic matching
CLIPCross-modal[float]Image-text search

When to Use Each Provider

OpenAI

Best for: Production systems requiring highest quality

{openai, #{model => <<"text-embedding-3-small">>}}

✅ Use when:

  • Quality is the top priority
  • You have budget for API costs
  • Low latency to OpenAI servers
  • Don't need offline capability

❌ Avoid when:

  • Data privacy is critical (data sent to API)
  • Need offline/air-gapped operation
  • High volume with tight budget

Cohere

Best for: Production with input type optimization

{cohere, #{
    model => <<"embed-english-v3.0">>,
    input_type => <<"search_document">>  % or search_query
}}

✅ Use when:

  • Need separate document vs query embeddings
  • Want classification/clustering optimization
  • Building production search systems
  • Need multilingual support

❌ Avoid when:

  • Don't need input type distinction
  • Tight budget (comparable to OpenAI pricing)

Voyage AI

Best for: Best-in-class retrieval, domain-specific models

{voyage, #{model => <<"voyage-3">>}}
% Or domain-specific:
{voyage, #{model => <<"voyage-code-3">>}}    % code search
{voyage, #{model => <<"voyage-law-2">>}}     % legal
{voyage, #{model => <<"voyage-finance-2">>}} % financial

✅ Use when:

  • Building RAG systems (top MTEB scores)
  • Need domain-specific models (code, law, finance)
  • Retrieval quality is critical

❌ Avoid when:

  • Budget constrained
  • Don't need specialized retrieval

Jina AI

Best for: Long context, multilingual

{jina, #{model => <<"jina-embeddings-v3">>}}

✅ Use when:

  • Processing long documents (8K context)
  • Need multilingual with free tier
  • Budget conscious (free 1M tokens/month)

❌ Avoid when:

  • Need highest retrieval quality
  • Processing only short texts

Mistral

Best for: EU data residency

{mistral, #{model => <<"mistral-embed">>}}

✅ Use when:

  • EU data residency required
  • GDPR compliance important
  • Already using Mistral for LLMs

❌ Avoid when:

  • Don't need EU residency
  • Need domain-specific models

Azure OpenAI

Best for: Enterprise with Azure ecosystem

{azure, #{
    endpoint => <<"https://your-resource.cognitiveservices.azure.com">>,
    deployment => <<"text-embedding-3-small">>
}}

✅ Use when:

  • Need enterprise compliance (SOC 2, HIPAA)
  • Already in Azure ecosystem
  • Need VNet integration
  • Regional data residency required

❌ Avoid when:

  • Don't need enterprise features
  • Simpler setup preferred

AWS Bedrock

Best for: AWS ecosystem integration

{bedrock, #{
    model => <<"amazon.titan-embed-text-v2:0">>,
    region => <<"us-east-1">>
}}

✅ Use when:

  • Already in AWS ecosystem
  • Need IAM/VPC integration
  • Want choice of models (Titan, Cohere)
  • Need enterprise compliance

❌ Avoid when:

  • Don't use AWS
  • Need batch API (not supported)

Google Vertex AI

Best for: GCP ecosystem integration

{vertex, #{
    project => <<"my-project">>,
    model => <<"text-embedding-004">>
}}

✅ Use when:

  • Already in GCP ecosystem
  • Need BigQuery integration
  • Need VPC-SC, CMEK

❌ Avoid when:

  • Don't use GCP
  • Access token refresh is problematic

Ollama

Best for: Local deployment without Python complexity

{ollama, #{url => <<"http://localhost:11434">>, model => <<"nomic-embed-text">>}}

✅ Use when:

  • Want local inference without Python
  • Already using Ollama for LLMs
  • Need good quality with simple setup
  • Want to avoid API costs

❌ Avoid when:

  • Can't install Ollama
  • Need embedded solution (no server)
  • Memory constrained (models loaded in RAM)

Local (sentence-transformers)

Best for: Full control, access to any HuggingFace model

{local, #{model => "BAAI/bge-base-en-v1.5"}}

✅ Use when:

  • Need specific HuggingFace models
  • Already have PyTorch environment
  • Want maximum model flexibility
  • Need fine-tuning capability

❌ Avoid when:

  • Disk space is limited (~2GB install)
  • PyTorch dependency is problematic
  • Need fastest possible inference

FastEmbed

Best for: Lightweight local inference

{fastembed, #{model => "BAAI/bge-small-en-v1.5"}}

✅ Use when:

  • Need local inference with small footprint
  • Don't want PyTorch dependency
  • Deploying to resource-constrained environments
  • Quality similar to sentence-transformers is acceptable

❌ Avoid when:

  • Need models not supported by FastEmbed
  • Need absolute maximum quality

SPLADE

Best for: Hybrid lexical-semantic search

{splade, #{model => "prithivida/Splade_PP_en_v1"}}

✅ Use when:

  • Building hybrid search (BM25 + semantic)
  • Need keyword expansion (synonyms, related terms)
  • Want efficient inverted index storage
  • Combining with dense embeddings

❌ Avoid when:

  • Only need dense vector search
  • Memory constrained (sparse→dense is expensive)
  • Don't have hybrid search infrastructure

Example use case: E-commerce search where users type product names (lexical) but also want semantic matches.


ColBERT

Best for: Fine-grained passage retrieval

{colbert, #{model => "colbert-ir/colbertv2.0"}}

✅ Use when:

  • Single-vector similarity isn't precise enough
  • Building QA or passage retrieval systems
  • Need token-level relevance signals
  • Documents have varying relevant sections

❌ Avoid when:

  • Storage is limited (multiple vectors per doc)
  • Simple semantic similarity is sufficient
  • Real-time latency is critical

Example use case: Legal document search where specific clauses matter more than overall document similarity.


CLIP

Best for: Image and cross-modal search

{clip, #{model => "openai/clip-vit-base-patch32"}}

✅ Use when:

  • Searching images with text queries
  • Finding visually similar images
  • Building multi-modal applications
  • Need zero-shot image classification

❌ Avoid when:

  • Only working with text
  • Don't need image capabilities

Example use case: Stock photo search, content moderation, visual product search.

Combining Providers

Provider Chain (Fallback)

Use multiple providers for high availability:

#{embedder => [
    {ollama, #{url => <<"http://localhost:11434">>}},
    {openai, #{}},
    {local, #{}}
]}

If Ollama fails → try OpenAI → fall back to local Python.

Hybrid Search (SPLADE + Dense)

Combine sparse and dense for best retrieval:

%% Sparse for lexical matching
{ok, SpladeState} = barrel_embed:init(#{embedder => {splade, #{}}}).

%% Dense for semantic matching
{ok, DenseState} = barrel_embed:init(#{embedder => {ollama, #{...}}}).

%% Query both and combine scores
SparseScore = search_sparse(Query, SpladeState),
DenseScore = search_dense(Query, DenseState),
FinalScore = 0.3 * SparseScore + 0.7 * DenseScore.

Performance Benchmarks

Approximate performance on typical hardware (results vary):

ProviderFirst RequestSubsequentBatch (100 texts)
OpenAI200ms100ms500ms
Ollama2s (model load)50ms2s
Local5s (model load)100ms3s
FastEmbed3s (model load)50ms2s

Summary Table

Use CaseRecommended Provider
Production, general purposeOpenAI
Best retrieval qualityVoyage AI
Domain-specific (code/law/finance)Voyage AI
Long context (8K tokens)Jina AI
EU data residencyMistral
Enterprise + AzureAzure OpenAI
Enterprise + AWSAWS Bedrock
Enterprise + GCPGoogle Vertex AI
Input type optimizationCohere
Local, simple setupOllama
Local, any HF modelLocal
Local, lightweightFastEmbed
Hybrid searchSPLADE + Dense
Passage retrieval, QAColBERT
Image searchCLIP
High availabilityProvider chain