Files
semantica/docs/reference/embeddings.md
T

21 KiB

title, description, icon
title description icon
Embeddings Module Text and graph embedding generation — FastEmbed, Sentence-Transformers, OpenAI, BGE — with pooling strategies and provider-agnostic API. vector-square

semantica.embeddings converts text and graph structures into dense vectors. These vectors power semantic search, entity resolution, GraphRAG retrieval, and deduplication across every Semantica module. A single provider-agnostic API abstracts FastEmbed, Sentence-Transformers, OpenAI, and BGE behind one interface.

Why Embeddings Matter

Raw text can't be compared mathematically. Embeddings translate meaning into geometry — two semantically similar sentences produce vectors that are close together in high-dimensional space, even when they share no words.

Semantica uses embeddings for:

  • Semantic search — find knowledge graph nodes by meaning, not just keywords
  • Entity resolution — detect that "Apple Inc." and "Apple Computer" refer to the same entity
  • Deduplicationsemantic_v2 strategy measures entity similarity via embedding distance
  • GraphRAG retrieval — hybrid vector + graph traversal for grounded LLM answers
  • Semantic chunking — detect topic shift boundaries in TextSplitter(method="semantic_transformer")

Exported Classes

Class Role
EmbeddingGenerator Provider-agnostic entry point — handles batching and provider selection
TextEmbedder Text embedding with automatic batch processing; default uses FastEmbed
GraphEmbeddingManager Embed KG nodes and edges for GraphRAG and graph databases
VectorEmbeddingManager Prepare and format embeddings for vector database backends
OpenAIStore OpenAI text-embedding-3-small / text-embedding-3-large provider
BGEStore BAAI/bge models via sentence-transformers
FastEmbedStore ONNX-accelerated local embeddings — no CUDA required
LlamaStore Placeholder store — not production-ready; do not use for embeddings
MeanPooling Default pooling strategy — best for retrieval and clustering

What You Get

Main entry point — provider-agnostic, handles batching automatically across all backends. Text-specific with automatic batching and progress tracking. Default method is FastEmbed. Node and edge embeddings for graph databases — Neo4j, NetworkX, FalkorDB. Prepare, normalize, and format embeddings for FAISS, Weaviate, Qdrant, and Milvus. `OpenAIStore`, `BGEStore`, `FastEmbedStore`, and `ProviderStoreFactory`. Mean, Max, CLS, Attention, and Hierarchical — control token-to-vector aggregation.

Installation

Provider Install Command API Key Required
FastEmbed (default) pip install "semantica[fastembed]" No
Sentence-Transformers pip install semantica No
BGE pip install semantica No (uses sentence-transformers)
OpenAI pip install "semantica[llm-openai]" Yes — OPENAI_API_KEY
All providers pip install "semantica[all]" Varies

Check which providers are available in your environment:

from semantica.embeddings import check_available_providers

providers = check_available_providers()
# → {"sentence_transformers": True, "fastembed": True, "openai": False}

Getting Started

EmbeddingGenerator is the fastest path to embeddings — the default method is FastEmbed (ONNX, no GPU needed):

from semantica.embeddings import EmbeddingGenerator

# Default — FastEmbed with BAAI/bge-small-en-v1.5
generator = EmbeddingGenerator()

# Embed a single text
embedding = generator.generate_embeddings("Text about AI")

# Embed a batch
embeddings = generator.generate_embeddings(["Text about AI", "Machine learning concepts"])

# Compare two embeddings (cosine similarity — 0.0 to 1.0)
score = generator.compare_embeddings(embeddings[0], embeddings[1], method="cosine")
print(f"Similarity: {score:.3f}")

To switch provider after construction:

# Switch to a sentence-transformers model
generator.set_text_model("sentence_transformers", "all-MiniLM-L6-v2")

# Switch to BGE large
generator.set_text_model("sentence_transformers", "BAAI/bge-large-en-v1.5")

Quick Start

```python from semantica.embeddings import EmbeddingGenerator
# Default — FastEmbed, free, runs locally with no GPU
generator = EmbeddingGenerator()

# Use sentence-transformers instead
generator = EmbeddingGenerator(config={"text": {"method": "sentence_transformers", "model_name": "all-MiniLM-L6-v2"}})
```
```python # Single text → 1D array embedding = generator.generate_embeddings("Text about AI")
# Batch → 2D array (n_texts, dim)
embeddings = generator.generate_embeddings(["Text about AI", "Machine learning concepts"])
```
```python # Cosine similarity — 0.0 (unrelated) to 1.0 (identical meaning) score = generator.compare_embeddings(embeddings[0], embeddings[1], method="cosine") print(f"Similarity: {score:.3f}") ``` ```python from semantica.embeddings import VectorEmbeddingManager import numpy as np
manager = VectorEmbeddingManager()

embeddings = np.array([...], dtype=np.float32)
metadata   = [{"text": "doc 1"}, {"text": "doc 2"}]

result = manager.prepare_for_vector_db(embeddings, metadata=metadata, backend="faiss")
# result["vectors"]  → normalized float32 array
# result["ids"]      → ["vec_0", "vec_1", ...]
# result["metadata"] → formatted metadata list
```

Supported Models

Provider Model Dimension Speed Best For
fastembed BAAI/bge-small-en-v1.5 384 Very fast Default — CPU-optimised, no GPU required
sentence_transformers all-MiniLM-L6-v2 384 Fast Good balance of speed and quality
sentence_transformers all-mpnet-base-v2 768 Medium Higher retrieval quality
sentence_transformers BAAI/bge-large-en-v1.5 1024 Medium State-of-the-art retrieval accuracy
openai text-embedding-3-small 1536 API Cost-effective OpenAI embedding
openai text-embedding-3-large 3072 API Highest quality via OpenAI API

EmbeddingGenerator

```python from semantica.embeddings import EmbeddingGenerator
# Default — FastEmbed with BAAI/bge-small-en-v1.5
generator = EmbeddingGenerator()
embeddings = generator.generate_embeddings(texts)
similarity = generator.compare_embeddings(embeddings[0], embeddings[1])
```

Best for: CPU-only production, lowest latency without GPU. Default — works out of the box.
```python from semantica.embeddings import EmbeddingGenerator
generator = EmbeddingGenerator()
generator.set_text_model("sentence_transformers", "all-MiniLM-L6-v2")
embeddings = generator.generate_embeddings(texts)
```

Best for: higher-quality retrieval when GPU is available, or when fine-tuned models are needed.
```python from semantica.embeddings import OpenAIStore import os
store     = OpenAIStore(api_key=os.getenv("OPENAI_API_KEY"), model="text-embedding-3-small")
embedding = store.embed("Hello world")
```

Best for: highest quality (`text-embedding-3-large`), or matching an existing OpenAI pipeline.
```python from semantica.embeddings import EmbeddingGenerator
# Use CUDA via sentence-transformers
generator = EmbeddingGenerator(config={"text": {"method": "sentence_transformers", "device": "cuda"}})

# Apple Silicon (M1/M2/M3)
generator = EmbeddingGenerator(config={"text": {"method": "sentence_transformers", "device": "mps"}})
```

GPU is only applicable with sentence-transformers. FastEmbed uses ONNX and does not use `device`.

Constructor Parameters

Parameter Type Default Description
config dict None Config dict; config["text"] is passed to TextEmbedder
**kwargs Additional key/value config merged into config

Use generator.set_text_model(method, model_name) to switch the embedding model after construction.

TextEmbedder

Direct text embedding with batch processing:

from semantica.embeddings import TextEmbedder

# Default — FastEmbed with BAAI/bge-small-en-v1.5
embedder = TextEmbedder()

# Single text → 1D array
embedding = embedder.embed_text("A knowledge graph connects entities with typed relationships.")

# Batch → 2D array (n_texts, dim)
embeddings = embedder.embed_batch(["First text", "Second text", "Third text"])

# Per-sentence embeddings
sentence_embeddings = embedder.embed_sentences("First sentence. Second sentence.")

# Get embedding dimension
dim = embedder.get_embedding_dimension()

TextEmbedder Constructor Parameters

Parameter Type Default Description
model_name str "BAAI/bge-small-en-v1.5" Model name to load
method str "fastembed" Embedding method: "fastembed" or "sentence_transformers"
device str "cpu" Device for sentence-transformers: "cpu", "cuda", "mps". Ignored for FastEmbed.
normalize bool True L2-normalize output vectors

Key behaviours:

  • If FastEmbed or sentence-transformers is unavailable, falls back to a 128-dimensional hash-based embedding. Hash embeddings are deterministic but not semantic — do not use in production.
  • Large batches are chunked internally by the underlying library to avoid OOM.

Provider Stores

Use provider stores directly when you need fine-grained control over a single backend:

from semantica.embeddings import (
    OpenAIStore, BGEStore, FastEmbedStore,
    ProviderStoreFactory,
)
import os

# OpenAI
store     = OpenAIStore(api_key=os.getenv("OPENAI_API_KEY"), model="text-embedding-3-small")
embedding = store.embed("Hello world")

# BGE (Sentence-Transformers wrapper) — pass model_name= not model=
store     = BGEStore(model_name="BAAI/bge-large-en-v1.5")
embedding = store.embed("Hello world")

# FastEmbed — ONNX runtime, no CUDA required
store     = FastEmbedStore(model_name="BAAI/bge-small-en-v1.5")
embedding = store.embed("Hello world")
# FastEmbedStore also has an efficient batch method
embeddings = store.embed_batch(["text1", "text2", "text3"])

# Auto-select from a name string — useful in config-driven pipelines
# Supported providers: "openai", "bge", "fastembed"
store = ProviderStoreFactory.create(provider="bge", model_name="BAAI/bge-large-en-v1.5")
`LlamaStore` exists in the module but is a placeholder — it does not connect to Ollama and always raises `ProcessingError` at embed time. Do not use it in production.

Pooling Strategies

Pooling aggregates a set of embeddings into a single vector — useful when you have multiple chunk embeddings to combine:

```python from semantica.embeddings import MeanPooling
pooler = MeanPooling()
pooled = pooler.pool(token_embeddings)   # shape: (hidden_dim,)
```

Best for: retrieval, semantic search, and clustering — averages all contributions.
```python from semantica.embeddings import MaxPooling
pooler = MaxPooling()
pooled = pooler.pool(token_embeddings)
```

Best for: capturing the presence of any feature — takes the max activation per dimension.
```python from semantica.embeddings import CLSPooling
pooler = CLSPooling()
pooled = pooler.pool(token_embeddings)
```

Best for: classification-style tasks; models explicitly trained with CLS pooling (BERT).
```python from semantica.embeddings import HierarchicalPooling
pooler = HierarchicalPooling()
# chunk_size is passed at pool time, not at construction
pooled = pooler.pool(token_embeddings, chunk_size=10)
```

Best for: long documents — chunk-level mean pooling, then global mean pooling across chunks.
| Strategy | When to Use |
| -------- | ----------- |
| `mean` | Default for retrieval, semantic search, and clustering |
| `max` | When you want to capture the presence of any feature, not average presence |
| `cls` | Classification-style tasks; models explicitly trained with CLS pooling (BERT) |
| `attention` | When token importance varies significantly; slower but more accurate |
| `hierarchical` | Long documents with many chunks; combines chunk-level then global pooling |

```python
from semantica.embeddings import PoolingStrategyFactory

pooler = PoolingStrategyFactory.create(strategy="mean")
```

GraphEmbeddingManager

Embed graph nodes and edges for storage in graph databases:

from semantica.embeddings import GraphEmbeddingManager

manager = GraphEmbeddingManager()

entities = [
    {"id": "e1", "text": "Apple Inc.", "type": "Organization"},
    {"id": "e2", "text": "Tim Cook",   "type": "Person"},
]
relationships = [
    {"source": "e2", "target": "e1", "type": "CEO_OF"}
]

# Embed entities → dict of {id: np.ndarray}
node_embeddings = manager.embed_entities(entities)

# Embed relationships → dict of {id: np.ndarray}
edge_embeddings = manager.embed_relationships(relationships)

# Or prepare everything at once for a graph DB backend
result = manager.prepare_for_graph_db(entities, relationships, backend="neo4j")
# result["node_embeddings"] → {id: np.ndarray}
# result["edge_embeddings"] → {id: np.ndarray}
# result["nodes"]           → entities with "embedding" field added
# result["edges"]           → relationships with "embedding" field added

Supported backends: "neo4j", "networkx", "falkordb"

VectorEmbeddingManager

Prepare and validate embeddings for vector database storage:

from semantica.embeddings import VectorEmbeddingManager
import numpy as np

manager    = VectorEmbeddingManager()
embeddings = np.random.rand(5, 384).astype(np.float32)
metadata   = [{"text": f"doc_{i}", "category": "science"} for i in range(5)]

# Prepare for FAISS
result = manager.prepare_for_vector_db(embeddings, metadata=metadata, backend="faiss")
# result["vectors"]  → L2-normalized float32 array
# result["ids"]      → ["vec_0", "vec_1", ...]
# result["metadata"] → formatted metadata list

# Validate dimensions before insertion
is_valid = manager.validate_dimensions(embeddings, backend="milvus")

# Prepare multiple batches at once
combined = manager.batch_prepare([embeddings_a, embeddings_b], backend="qdrant")

Supported backends: "faiss", "weaviate", "qdrant", "milvus"

Common Workflows

```python from semantica.embeddings import TextEmbedder
embedder = TextEmbedder()   # default: FastEmbed

texts = [
    "Apple Inc. was founded by Steve Jobs.",
    "Microsoft was co-founded by Bill Gates.",
    "Amazon was started by Jeff Bezos.",
]

# All at once — more efficient than calling embed_text() per item
embeddings = embedder.embed_batch(texts)
print(f"Shape: {embeddings.shape}")   # (3, 384)
```
```python from semantica.embeddings import check_available_providers, EmbeddingGenerator
# Check what's installed
available = check_available_providers()
# → {"sentence_transformers": True, "fastembed": True, "openai": False}

# Use the fastest available provider
generator = EmbeddingGenerator()
if available["fastembed"]:
    generator.set_text_model("fastembed", "BAAI/bge-small-en-v1.5")
elif available["sentence_transformers"]:
    generator.set_text_model("sentence_transformers", "all-MiniLM-L6-v2")

embeddings = generator.generate_embeddings(texts)
```
```python from semantica.embeddings import GraphEmbeddingManager
manager  = GraphEmbeddingManager()
entities = [{"id": "n1", "text": "Python"}, {"id": "n2", "text": "Django"}]

node_embeddings = manager.embed_entities(entities)
# {"n1": array([...]), "n2": array([...])}
```
```python from semantica.embeddings import EmbeddingGenerator, calculate_similarity import numpy as np
generator = EmbeddingGenerator()
query     = generator.generate_embeddings("knowledge graph databases")
corpus    = generator.generate_embeddings([
    "graph databases store relationships",
    "relational databases use tables",
    "knowledge graphs model entity relationships",
])

scores = [calculate_similarity(query, doc, method="cosine") for doc in corpus]
ranked = sorted(zip(scores, range(len(scores))), reverse=True)

for score, idx in ranked:
    print(f"{score:.3f}  {['graph databases store...', 'relational databases...', 'knowledge graphs...'][idx]}")
```

Similarity Computation

from semantica.embeddings import calculate_similarity

# Cosine similarity — direction only, not magnitude; most common for text
score = calculate_similarity(embedding_a, embedding_b, method="cosine")
# → 0.0 (orthogonal / unrelated) to 1.0 (identical direction)

# Euclidean distance converted to similarity
score = calculate_similarity(embedding_a, embedding_b, method="euclidean")

Convenience Functions

from semantica.embeddings import (
    embed_text, generate_embeddings, calculate_similarity,
    pool_embeddings, check_available_providers,
)

# Single text — fastest path
emb = embed_text("Hello world", method="sentence_transformers")

# Batch
embs = generate_embeddings(["text1", "text2"], method="default")

# Pool multiple embeddings into one
pooled = pool_embeddings(embs, method="mean")

# Check which providers are installed
providers = check_available_providers()
# → {"sentence_transformers": True, "fastembed": True, "openai": False}

Tips and Common Pitfalls

**Dimension mismatch.** The dimension you pass to your vector store must exactly match your embedding model's output. `BAAI/bge-small-en-v1.5` → 384, `all-MiniLM-L6-v2` → 384, `all-mpnet-base-v2` → 768, `BAAI/bge-large-en-v1.5` → 1024. Check with `embedder.get_embedding_dimension()` before creating the store. **LlamaStore is not functional.** `LlamaStore` exists in the module but does not connect to Ollama. It always raises `ProcessingError` at embed time. Use `FastEmbedStore` for local ONNX-based embeddings or `BGEStore` for sentence-transformers-based local embeddings instead. **Sequence length limits.** Most sentence-transformers models have a 512-token limit. Text beyond that is silently truncated. Use `TextSplitter(method="hierarchical")` + `HierarchicalPooling` for long documents. **FastEmbed ignores the `device` parameter.** FastEmbed uses ONNX Runtime and manages its own execution providers — passing `device="cuda"` has no effect. Switch to `method="sentence_transformers"` if you need explicit GPU control. **Always use the same model for indexing and querying.** Vectors from different models are not comparable — they live in different vector spaces. Switching models requires re-embedding your entire corpus. **Fallback embeddings are not semantic.** If neither FastEmbed nor sentence-transformers loads successfully, TextEmbedder silently falls back to 128-dimensional SHA-256 hash embeddings. These are deterministic but carry no semantic meaning. Check `embedder.get_method()` — if it returns `"fallback"`, install your intended provider. Store and search the generated embeddings. Chunk text before embedding for better retrieval quality. Distance Intelligence uses graph embeddings for semantic neighbourhoods. Semantic deduplication uses embedding distance for entity resolution.