Embeddings
Embeddings
The library provides multi-vendor text embeddings and Google Gemini Embedding 2 multimodal embeddings through one API. Text, image, audio, video, and document inputs can share one vector space for semantic search, RAG, clustering, classification, and similarity matching.
Basic Usage
// Documentation check: complete example
import { Connector, Embeddings, Vendor } from 'oneringai';
// Setup connector
Connector.create({
name: 'openai',
vendor: Vendor.OpenAI,
auth: { type: 'api_key', apiKey: process.env.OPENAI_API_KEY! },
});
// Create embeddings instance
const embeddings = Embeddings.create({ connector: 'openai' });
// Embed a single text
const result = await embeddings.embed('Hello world');
console.log(result.embeddings[0].length); // 1536
console.log(result.usage.promptTokens); // 2
// Embed multiple texts (batch)
const batch = await embeddings.embed([
'The quick brown fox',
'A lazy dog sleeps',
'Machine learning is powerful',
]);
console.log(batch.embeddings.length); // 3
Matryoshka Representation Learning (MRL)
Models that support MRL (marked with matryoshka: true in the registry) allow you to request fewer output dimensions. This produces smaller vectors; measure retrieval quality and latency on your own corpus.
// Full dimensions (default)
const full = await embeddings.embed('Hello world');
console.log(full.embeddings[0].length); // 1536
// Reduced dimensions — 3x smaller vectors; evaluate retrieval quality
const compact = await embeddings.embed('Hello world', { dimensions: 512 });
console.log(compact.embeddings[0].length); // 512
// Even smaller — great for large-scale approximate search
const tiny = await embeddings.embed('Hello world', { dimensions: 128 });
console.log(tiny.embeddings[0].length); // 128
Models with MRL support include text-embedding-3-small, text-embedding-3-large, gemini-embedding-2, gemini-embedding-001, codestral-embed, embeddinggemma, all qwen3-embedding variants, and nomic-embed-text.
Default Dimensions
You can set default dimensions at creation time:
// All embeddings from this instance use 512 dimensions
const embeddings = Embeddings.create({
connector: 'openai',
model: 'text-embedding-3-small',
dimensions: 512,
});
const result = await embeddings.embed('Hello');
console.log(result.embeddings[0].length); // 512
// Override per-call
const full = await embeddings.embed('Hello', { dimensions: 1536 });
console.log(full.embeddings[0].length); // 1536
OpenAI Embeddings
// text-embedding-3-small (recommended — cost-efficient, MRL)
const result = await embeddings.embed('search query', {
model: 'text-embedding-3-small',
dimensions: 1536, // default, can reduce to 512 or 256
});
// text-embedding-3-large (higher quality, more dimensions)
const large = await embeddings.embed('search query', {
model: 'text-embedding-3-large',
dimensions: 3072, // default, can reduce
});
Google Embeddings
Connector.create({
name: 'google',
vendor: Vendor.Google,
auth: { type: 'api_key', apiKey: process.env.GOOGLE_API_KEY! },
});
const googleEmb = Embeddings.create({ connector: 'google' });
// gemini-embedding-2 is the current Google default (3072 dimensions).
const result = await googleEmb.embed('search query');
console.log(result.embeddings[0].length); // 3072
// Task-aware text embedding with dimension reduction.
const compact = await googleEmb.embed('search query', {
dimensions: 512,
vendorOptions: {
taskType: 'RETRIEVAL_QUERY',
title: 'Product documentation query',
},
});
// Multimodal content is exposed directly by the high-level API.
const mixed = await googleEmb.embedMultimodal([
{ type: 'text', text: 'Find assets similar to this launch brief' },
{ type: 'image', data: './campaign.png', mimeType: 'image/png' },
{ type: 'document', data: './brief.pdf', mimeType: 'application/pdf' },
], {
dimensions: 1024,
vendorOptions: { taskType: 'RETRIEVAL_DOCUMENT' },
});
embedMultimodal() currently requires gemini-embedding-2; the provider
rejects multimodal content for text-only models. Buffer, local-path, data-URI,
and arbitrary HTTP(S) inputs are sent inline; HTTP(S) content is fetched first
with a 30-second default timeout and a streaming size guard. One request has a
100 MB aggregate inline-media budget; an individual PDF is limited to 50 MB.
Content-Length is rejected before reading when present, and chunked responses
are stopped as soon as they cross the budget. Configure a different positive
timeout with vendorOptions.mediaDownloadTimeoutMs; the provider size ceilings
remain fixed to Google's API contract. Only gs:// and Gemini Files API URIs
are emitted as provider-hosted fileData references. Data URIs are strictly
validated as base64, checked against the remaining byte budget before decoding,
and re-encoded canonically before transmission.
mimeType is optional. Explicit values take precedence; otherwise the provider
inspects common JPEG/PNG/BMP/WebP, WAV/AIFF/MP3/AAC/FLAC/Ogg/WebM/MP4, MOV/MP4/
AVI/WebM/MPEG/3GP, and PDF signatures before falling back to the path extension.
This keeps JPEG buffers out of image/png, MP3 buffers out of audio/wav, and
MOV files out of video/mp4.
Ollama Embeddings (Local)
Run embedding models locally with Ollama — free, private, no API key required.
Connector.create({
name: 'ollama-local',
vendor: Vendor.Ollama,
auth: { type: 'none' },
baseURL: 'http://localhost:11434/v1',
});
const local = Embeddings.create({ connector: 'ollama-local' });
// embeddinggemma (default) — compact multilingual model, 768 dims
const result = await local.embed('semantic search query');
console.log(result.embeddings[0].length); // 768
// Use smaller model for constrained environments
const light = await local.embed('query', {
model: 'qwen3-embedding:0.6b', // ~400MB, 1024 dims
});
// Use nomic-embed-text for 768-dim vectors
const nomic = await local.embed('query', {
model: 'nomic-embed-text',
});
Illustrative local-model sizing (verify memory use on your workload):
| RAM | Model | Size | Dimensions | Quality |
|---|---|---|---|---|
| < 12 GB | qwen3-embedding:0.6b |
~400 MB | 1024 | Good |
| 12-24 GB | qwen3-embedding:4b |
~2.5 GB | 4096 | Very good |
| 24+ GB | qwen3-embedding |
~5 GB | 4096 | Largest of these variants; evaluate on your corpus |
Available Models
The table summarizes checked-in embedding registry records. Availability and prices are registry metadata, not a live account probe. Use the active selectors; retired records remain available for lookup and migration.
| Vendor | Model | Default Dims | Max Dims | MRL | Max Tokens | Price/1M Tokens |
|---|---|---|---|---|---|---|
| OpenAI | text-embedding-3-small |
1536 | 1536 | Yes | 8,191 | $0.02 |
| OpenAI | text-embedding-3-large |
3072 | 3072 | Yes | 8,191 | $0.13 |
| OpenAI | text-embedding-ada-002 |
1536 | 1536 | No | 8,191 | $0.10 (legacy) |
gemini-embedding-2 |
3072 | 3072 | Yes | 8,192 | $0.20 text; modality-specific media rates | |
gemini-embedding-001 |
3072 | 3072 | Yes | 2,048 | $0.15 text | |
| Mistral | mistral-embed |
1024 | 1024 | No | 8,192 | $0.10 |
| Mistral | codestral-embed |
3072 | 3072 | Yes | 8,192 | $0.15 |
| Ollama | embeddinggemma |
768 | 768 | Yes | 2,048 | Free (local) |
| Ollama | all-minilm |
384 | 384 | No | 512 | Free (local) |
| Ollama | qwen3-embedding |
4096 | 4096 | Yes | 8,192 | Free (local) |
| Ollama | qwen3-embedding:4b |
4096 | 4096 | Yes | 8,192 | Free (local) |
| Ollama | qwen3-embedding:0.6b |
1024 | 1024 | Yes | 8,192 | Free (local) |
| Ollama | nomic-embed-text |
768 | 768 | Yes | 8,192 | Free (local) |
| Ollama | mxbai-embed-large |
1024 | 1024 | No | 512 | Free (local) |
Model Introspection
import {
getEmbeddingModelInfo,
getEmbeddingModelsByVendor,
getActiveEmbeddingModels,
getEmbeddingModelsWithFeature,
EMBEDDING_MODELS,
Vendor,
} from 'oneringai';
// Get model information
const info = getEmbeddingModelInfo('text-embedding-3-small');
if (!info) throw new Error('Embedding model is not registered');
console.log(info.capabilities.maxDimensions); // 1536
console.log(info.capabilities.maxTokens); // 8191
console.log(info.capabilities.features.matryoshka); // true
console.log(info.capabilities.features.multilingual); // true
console.log(info.capabilities.limits.maxBatchSize); // 2048
// List models by vendor
const ollamaModels = getEmbeddingModelsByVendor(Vendor.Ollama);
console.log(ollamaModels.map(m => m.name));
// ['embeddinggemma', 'all-minilm', 'qwen3-embedding', 'qwen3-embedding:4b', ...]
// Find MRL-capable models
const mrlModels = getEmbeddingModelsWithFeature('matryoshka');
console.log(mrlModels.map(m => `${m.name} (${m.capabilities.maxDimensions}d)`));
// Find multilingual models
const multilingualModels = getEmbeddingModelsWithFeature('multilingual');
// Use model constants for type safety
const modelName = EMBEDDING_MODELS[Vendor.OpenAI].TEXT_EMBEDDING_3_SMALL;
// 'text-embedding-3-small'
Cost Estimation
import { calculateEmbeddingCost } from 'oneringai';
// OpenAI text-embedding-3-small
const cost = calculateEmbeddingCost('text-embedding-3-small', 1_000_000);
console.log(`$${cost} per 1M tokens`); // $0.02
// OpenAI text-embedding-3-large
const largeCost = calculateEmbeddingCost('text-embedding-3-large', 1_000_000);
console.log(`$${largeCost} per 1M tokens`); // $0.13
// Ollama (free, returns null for no pricing)
const localCost = calculateEmbeddingCost('qwen3-embedding', 1_000_000);
console.log(localCost); // null (free, local)
// Gemini Embedding 2 mixed-modality accounting plus the 50% batch discount.
const googleCost = calculateEmbeddingCost('gemini-embedding-2', 1_000_000, {
images: 10,
audioSeconds: 60,
videoFrames: 30,
batch: true,
});
console.log(googleCost); // 0.11725
Common Use Cases
Semantic Search (RAG):
// Embed documents at ingestion time
const docs = ['Document 1 text...', 'Document 2 text...', 'Document 3 text...'];
const docEmbeddings = await embeddings.embed(docs, { dimensions: 512 });
// Store docEmbeddings.embeddings in your vector database
// At query time, embed the query with the same model and dimensions
const queryResult = await embeddings.embed('user search query', { dimensions: 512 });
const queryVector = queryResult.embeddings[0];
// Use queryVector for vector similarity search
Text Classification:
// Embed labeled examples and new text
const categories = await embeddings.embed([
'sports news about football',
'financial market analysis',
'cooking recipe instructions',
]);
const newText = await embeddings.embed('The team scored in the final minute');
// Compare newText vector to category vectors using cosine similarity