Skip to content

Embeddings

Generate vector embeddings for semantic search, similarity comparison, and RAG applications.

import { embedding } from '@providerprotocol/ai';
import { openai } from '@providerprotocol/ai/openai';
const embedder = embedding({
model: openai('text-embedding-3-small'),
});
const result = await embedder.embed('What is machine learning?');
console.log(result.vector.length); // 1536
console.log(result.tokens); // Token count
console.log(result.dimensions); // 1536

Embed multiple texts efficiently:

const documents = [
'Machine learning is a subset of artificial intelligence.',
'Neural networks are inspired by biological brains.',
'Deep learning uses multiple layers of neural networks.',
];
const results = await embedder.embed(documents);
for (const result of results.embeddings) {
console.log(`Document ${result.index}:`, result.vector.length);
}
console.log('Total tokens:', results.usage.totalTokens);
import { embedding } from '@providerprotocol/ai';
import { openai } from '@providerprotocol/ai/openai';
const embedder = embedding({
model: openai('text-embedding-3-large'),
params: {
dimensions: 1024, // Reduce dimensions (default: 3072)
},
});

Models:

  • text-embedding-3-small - 1536 dimensions, fast
  • text-embedding-3-large - 3072 dimensions, higher quality
import { embedding } from '@providerprotocol/ai';
import { google } from '@providerprotocol/ai/google';
const embedder = embedding({
model: google('text-embedding-004'),
});
import { embedding } from '@providerprotocol/ai';
import { ollama } from '@providerprotocol/ai/ollama';
const embedder = embedding({
model: ollama('nomic-embed-text'),
config: {
baseUrl: 'http://localhost:11434',
},
});
import { embedding } from '@providerprotocol/ai';
import { openrouter } from '@providerprotocol/ai/openrouter';
const embedder = embedding({
model: openrouter('openai/text-embedding-3-small'),
});

For large datasets, use chunked mode to get progress updates:

const documents = loadLargeDataset(); // Thousands of documents
const stream = embedder.embed(documents, { chunked: true });
let processed = 0;
for await (const chunk of stream) {
processed += chunk.embeddings.length;
console.log(`Processed ${processed}/${documents.length}`);
}
// Get final results
const results = await stream.results;

Some models optimize differently for documents vs queries:

// Embedding documents for storage
const docResult = await embedder.embed(documents, {
inputType: 'document',
});
// Embedding queries for search
const queryResult = await embedder.embed('search query', {
inputType: 'query',
});
// String
await embedder.embed('Simple text');
// Text block
await embedder.embed({ type: 'text', text: 'Text block' });
// Array of strings
await embedder.embed(['Text 1', 'Text 2', 'Text 3']);

Compare embeddings using cosine similarity:

function cosineSimilarity(a: number[], b: number[]): number {
let dotProduct = 0;
let normA = 0;
let normB = 0;
for (let i = 0; i < a.length; i++) {
dotProduct += a[i] * b[i];
normA += a[i] * a[i];
normB += b[i] * b[i];
}
return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
}
// Embed documents and query
const docs = ['Paris is in France', 'Tokyo is in Japan', 'NYC is in USA'];
const docEmbeddings = await embedder.embed(docs);
const query = 'What is the capital of France?';
const queryEmbedding = await embedder.embed(query);
// Find most similar document
const similarities = docEmbeddings.embeddings.map((doc, i) => ({
text: docs[i],
score: cosineSimilarity(queryEmbedding.vector, doc.vector),
}));
similarities.sort((a, b) => b.score - a.score);
console.log('Most relevant:', similarities[0]);
// { text: 'Paris is in France', score: 0.89 }

Use embeddings for Retrieval-Augmented Generation:

import { llm, embedding } from '@providerprotocol/ai';
import { openai } from '@providerprotocol/ai/openai';
const embedder = embedding({ model: openai('text-embedding-3-small') });
const gpt = llm({ model: openai('gpt-4o') });
// Index documents
const documents = [
'UPP supports Anthropic, OpenAI, Google, xAI, Ollama, and OpenRouter.',
'Use llm() for chat, embedding() for vectors, image() for generation.',
'Thread is an optional utility for managing conversation history.',
];
const docEmbeddings = await embedder.embed(documents);
// Search function
async function findRelevant(query: string, topK = 3) {
const queryEmbed = await embedder.embed(query);
const scored = documents.map((doc, i) => ({
text: doc,
score: cosineSimilarity(queryEmbed.vector, docEmbeddings.embeddings[i].vector),
}));
return scored.sort((a, b) => b.score - a.score).slice(0, topK);
}
// RAG query
async function askWithContext(question: string) {
const relevant = await findRelevant(question);
const context = relevant.map(r => r.text).join('\n');
return gpt.generate([
{ type: 'text', text: `Context:\n${context}\n\nQuestion: ${question}` },
]);
}
const turn = await askWithContext('What providers does UPP support?');
console.log(turn.response.text);
ModelProviderDimensionsMax Input
text-embedding-3-smallOpenAI15368191 tokens
text-embedding-3-largeOpenAI30728191 tokens
text-embedding-004Google7682048 tokens
nomic-embed-textOllama7688192 tokens
  1. Batch when possible - Embedding multiple texts is more efficient
  2. Match models - Use the same model for documents and queries
  3. Normalize vectors - Most similarity functions assume unit vectors
  4. Consider dimensions - Lower dimensions = faster search, less storage
  5. Use input types - Specify document vs query when supported
// Efficient batching
const BATCH_SIZE = 100;
const allEmbeddings = [];
for (let i = 0; i < documents.length; i += BATCH_SIZE) {
const batch = documents.slice(i, i + BATCH_SIZE);
const results = await embedder.embed(batch);
allEmbeddings.push(...results.embeddings);
}