Type-safe embedding vector generation for Go. Provider-agnostic, composable reliability, observable.
provider := openai.New(openai.Config{APIKey: os.Getenv("OPENAI_API_KEY")})
svc := vex.NewService(provider)
vec, _ := svc.Embed(ctx, "hello world")
// vec is a []float32 of length 1536go get github.com/zoobz-io/vexRequires Go 1.24 or higher.
package main
import (
"context"
"fmt"
"os"
"github.com/zoobz-io/vex"
"github.com/zoobz-io/vex/openai"
)
func main() {
ctx := context.Background()
// Create provider
provider := openai.New(openai.Config{
APIKey: os.Getenv("OPENAI_API_KEY"),
Model: "text-embedding-3-small",
})
// Create service with reliability options
svc := vex.NewService(provider,
vex.WithRetry(3),
vex.WithTimeout(30*time.Second),
)
// Embed single text
vec, err := svc.Embed(ctx, "The quick brown fox")
if err != nil {
panic(err)
}
fmt.Printf("Vector dimensions: %d\n", len(vec))
// Embed batch
texts := []string{"hello", "world", "foo", "bar"}
vecs, err := svc.Batch(ctx, texts)
if err != nil {
panic(err)
}
fmt.Printf("Embedded %d texts\n", len(vecs))
// Compare vectors
similarity := vecs[0].CosineSimilarity(vecs[1])
fmt.Printf("Similarity: %.4f\n", similarity)
}| Provider | Models | Import |
|---|---|---|
| OpenAI | text-embedding-3-small, text-embedding-3-large, ada-002 | vex/openai |
| Cohere | embed-english-v3.0, embed-multilingual-v3.0 | vex/cohere |
| Voyage | voyage-3, voyage-3-lite, voyage-large-2 | vex/voyage |
| Gemini | text-embedding-004 | vex/gemini |
Built on pipz for composable reliability:
svc := vex.NewService(provider,
vex.WithRetry(3), // Retry failed requests
vex.WithBackoff(3, 100*time.Millisecond), // Exponential backoff
vex.WithTimeout(30*time.Second), // Request timeout
vex.WithCircuitBreaker(5, time.Minute), // Circuit breaker
vex.WithRateLimit(10, 20), // Rate limiting
vex.WithFallback(backupService), // Fallback provider
)Some providers (Voyage, Cohere, Gemini) optimize embeddings differently based on intent. Use Embed for documents and EmbedQuery for search queries:
// Embedding documents for storage
docVec, _ := svc.Embed(ctx, "The quick brown fox jumps over the lazy dog")
// Embedding queries for search
queryVec, _ := svc.EmbedQuery(ctx, "animals jumping")
// Compare for retrieval
similarity := queryVec.CosineSimilarity(docVec)For providers without this distinction (OpenAI), EmbedQuery behaves identically to Embed.
Handle long texts by splitting and pooling:
chunker := &vex.Chunker{
Strategy: vex.ChunkSentence, // or ChunkParagraph, ChunkFixed
MaxSize: 512,
Overlap: 50,
}
svc := vex.NewService(provider).
WithChunker(chunker).
WithPooling(vex.PoolMean) // or PoolMax, PoolFirst// Normalise to unit vector
normalised := vec.Normalize()
// Similarity metrics
cosine := vec1.CosineSimilarity(vec2)
dot := vec1.Dot(vec2)
euclidean := vec1.EuclideanDistance(vec2)
// Generic similarity
sim := vec1.Similarity(vec2, vex.Cosine)- Provider-agnostic: Swap providers without changing application code
- Type-safe: Go generics and strong typing throughout
- Composable reliability: Mix and match retry, timeout, circuit breaker, rate limiting
- Observable: Hook signals via capitan for monitoring
- Chunking built-in: Handle long texts with configurable splitting and pooling
See CONTRIBUTING.md for development workflow.
MIT - see LICENSE