Embeddings¶
OmniMemory uses vector embeddings for semantic search. This guide covers embedding configuration and best practices.
Embedder Interface¶
type Embedder interface {
Embed(ctx context.Context, text string) ([]float64, error)
EmbedBatch(ctx context.Context, texts []string) ([][]float64, error)
Dimension() int
}
OmniLLM Integration¶
The recommended embedder uses omnillm-core:
import "github.com/plexusone/omnimemory/core"
embedder, err := core.NewOmniLLMEmbedder(core.EmbedderConfig{
Provider: "openai",
APIKey: os.Getenv("OPENAI_API_KEY"),
Model: "text-embedding-3-small",
})
if err != nil {
log.Fatal(err)
}
Configuration Options¶
| Field | Type | Description |
|---|---|---|
Provider |
string |
LLM provider name |
APIKey |
string |
API key |
Model |
string |
Embedding model |
Dimension |
int |
Vector dimension (optional) |
BaseURL |
string |
Custom API endpoint (optional) |
Supported Models¶
OpenAI¶
| Model | Dimensions | Notes |
|---|---|---|
text-embedding-3-small |
1536 | Recommended for most use cases |
text-embedding-3-large |
3072 | Higher quality, more expensive |
text-embedding-ada-002 |
1536 | Legacy model |
embedder, _ := core.NewOmniLLMEmbedder(core.EmbedderConfig{
Provider: "openai",
Model: "text-embedding-3-small",
APIKey: os.Getenv("OPENAI_API_KEY"),
})
Anthropic¶
Anthropic doesn't provide embedding models directly. Use OpenAI or a local model.
Local Models (Ollama)¶
embedder, _ := core.NewOmniLLMEmbedder(core.EmbedderConfig{
Provider: "ollama",
Model: "nomic-embed-text",
BaseURL: "http://localhost:11434",
})
Using with Providers¶
PostgreSQL¶
import "github.com/plexusone/omnimemory/provider/postgres"
provider, err := postgres.NewProvider(core.ProviderConfig{
Options: map[string]any{
"connection_string": os.Getenv("DATABASE_URL"),
},
}, embedder)
In-Memory¶
import "github.com/plexusone/omnimemory/provider/memory"
provider, err := memory.NewProvider(core.ProviderConfig{}, embedder)
KVS¶
import "github.com/plexusone/omnimemory/provider/kvs"
provider, err := kvs.NewProvider(core.ProviderConfig{
Options: map[string]any{
"store": store,
},
}, embedder)
Custom Embedder¶
Implement the Embedder interface for custom embedding solutions:
type MyEmbedder struct {
dimension int
}
func (e *MyEmbedder) Embed(ctx context.Context, text string) ([]float64, error) {
// Call your embedding API
return myEmbeddingAPI(text)
}
func (e *MyEmbedder) EmbedBatch(ctx context.Context, texts []string) ([][]float64, error) {
embeddings := make([][]float64, len(texts))
for i, text := range texts {
emb, err := e.Embed(ctx, text)
if err != nil {
return nil, err
}
embeddings[i] = emb
}
return embeddings, nil
}
func (e *MyEmbedder) Dimension() int {
return e.dimension
}
Dimension Matching¶
Embedding dimensions must match across:
- Embedder output: The dimension from your embedding model
- Database schema: The vector column dimension
- Stored embeddings: Previously stored memory embeddings
// Check dimension matches
if embedder.Dimension() != 1536 {
log.Fatal("Embedder dimension must match database schema")
}
Performance Optimization¶
Batch Embedding¶
// Embed multiple texts at once
texts := []string{"text1", "text2", "text3"}
embeddings, err := embedder.EmbedBatch(ctx, texts)
Caching¶
Consider caching embeddings for frequently used queries:
type CachedEmbedder struct {
inner Embedder
cache map[string][]float64
mu sync.RWMutex
}
func (e *CachedEmbedder) Embed(ctx context.Context, text string) ([]float64, error) {
e.mu.RLock()
if emb, ok := e.cache[text]; ok {
e.mu.RUnlock()
return emb, nil
}
e.mu.RUnlock()
emb, err := e.inner.Embed(ctx, text)
if err != nil {
return nil, err
}
e.mu.Lock()
e.cache[text] = emb
e.mu.Unlock()
return emb, nil
}
Best Practices¶
- Use consistent models: Don't mix embedding models
- Normalize text: Clean input before embedding
- Handle errors: Embedding APIs can fail
- Monitor costs: Track embedding API usage
- Consider local models: For high volume or privacy