Vector Embeddings
Generate dense mathematical embeddings, calculate cosine similarities, and index text representations with OpenAI and Voyage.
TL;DR
- Generate dense vector embeddings using
embeddings.create()API calls. - Compute vector distance with dot product
cosineSimilarity()mathematical formulas. - Compress embedding storage costs using
dimensionsparameter reduction features.
Generating Embeddings with OpenAI SDK
Single Text Embedding RequestGenerate a dense float vector from a single user query.
import OpenAI from 'openai';
const client = new OpenAI();
const res = await client.embeddings.create({
model: 'text-embedding-3-small',
input: 'Production RAG architecture',
encoding_format: 'float',
});
const vector: number[] = res.data[0].embedding;Batched Document EmbeddingsEmbed an array of text chunks in a single efficient HTTP call.
const chunks = ['Intro paragraph', 'Body content'];
const batch = await client.embeddings.create({
model: 'text-embedding-3-small',
input: chunks,
});
const vectors = batch.data.map(d => d.embedding);Matryoshka Dimension ReductionReduce vector dimensions to save index storage and latency.
const compressed = await client.embeddings.create({
model: 'text-embedding-3-small',
input: 'Save memory',
dimensions: 512, // Down from default 1536
});
// Slashes storage by 66% with negligible recall dropVoyage AI Domain Embeddings
Code & Finance Specialized EmbeddingsUse Voyage AI for codebases and technical domain retrieval.
async function getVoyageEmbedding(text: string) {
const url = 'https://api.voyageai.com/v1/embeddings';
const auth = `Bearer ${process.env.VOYAGE_KEY}`;
const res = await fetch(url, {
method: 'POST',
headers: {
'Authorization': auth,
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'voyage-code-3',
input: [text],
}),
});
const json = await res.json();
return json.data[0].embedding;
}Input Type SpecializationSpecify query vs document input types for asymmetric retrieval.
const body = {
model: 'voyage-3',
input: ['search query'],
input_type: 'query', // vs 'document' for corpus
};Truncation EnforcementEnsure input text stays strictly within embedding model limit.
const maxTokens = 8000; // Voyage-3 context limit
function prepText(raw: string) {
const cleaned = raw.replace(/\s+/g, ' ').trim();
return cleaned.slice(0, 24000);
}Vector Mathematics & Similarity
Pure TypeScript Cosine SimilarityCalculate semantic similarity score between two normalized vectors.
function cosineSimilarity(a: number[], b: number[]) {
let dot = 0, normA = 0, normB = 0;
for (let i = 0; i < a.length; i++) {
dot += a[i] * b[i];
normA += a[i] * a[i];
normB += b[i] * b[i];
}
return dot / (Math.sqrt(normA) * Math.sqrt(normB));
}Dot Product for Unit VectorsFast dot product similarity for pre-normalized embedding arrays.
function dotProduct(a: number[], b: number[]): number {
let sum = 0;
for (let i = 0; i < a.length; i++) {
sum += a[i] * b[i];
}
return sum;
}K-Nearest Neighbors SearchRank in-memory vector database records by similarity score.
function rankTopK(
qVec: number[],
corpus: Array<{ id: string; vec: number[] }>,
k = 3
) {
return corpus
.map(c => {
const s = dotProduct(qVec, c.vec);
return { id: c.id, score: s };
})
.sort((a, b) => b.score - a.score)
.slice(0, k);
}Normalization & Storage Economics
In-Place L2 NormalizationNormalize float array in-place so dot products equal cosine similarity.
function normalizeL2(vec: number[]): number[] {
const sq = vec.reduce((s, v) => s + v * v, 0);
const norm = Math.sqrt(sq);
if (norm === 0) return vec;
return vec.map(v => v / norm);
}Batch Chunking DispatcherChunk massive document arrays into manageable API batches.
function chunkBatch<T>(arr: T[], size = 100): T[][] {
const out: T[][] = [];
for (let i = 0; i < arr.length; i += size) {
out.push(arr.slice(i, i + size));
}
return out;
}Vector Memory Footprint CalculatorEstimate RAM requirement for storing vectors in memory.
function getVectorBytes(count: number, dims = 1536) {
// 4 bytes per 32-bit float
return count * dims * 4;
}Tips
- Normalize embeddings to unit length so fast dot products equal mathematical
cosineSimilaritycalculations exactly without expensive square roots. - Batch up to 2048 text inputs per
embeddings.create()call to minimize HTTP network overhead and accelerate indexing pipelines.
Warnings
- Never compare embeddings generated by different model versions like
text-embedding-3-smalland legacyada-002due to incompatible coordinate spaces. - Strip empty strings and newlines prior to embedding generation to avoid skewed
0.0vector representations.
In Practice
Computes vector similarity across an in-memory document corpus and returns top semantic matches.
- Define sample document corpus with pre-computed vectors.
- Implement pure mathematical cosine similarity formula.
- Iterate across corpus and compute score for query vector.
- Sort matches descending and return top ranked record.
function cosine(a: number[], b: number[]) {
let dot = 0, nA = 0, nB = 0;
for (let i = 0; i < a.length; i++) {
dot += a[i] * b[i];
nA += a[i] * a[i];
nB += b[i] * b[i];
}
return dot / (Math.sqrt(nA) * Math.sqrt(nB));
}
const docs = [
{ text: 'Auth JWT guide', vec: [0.9, 0.1, 0.2] },
{ text: 'CSS layout flex', vec: [0.1, 0.8, 0.3] },
];
const q = [0.85, 0.15, 0.1];
const scored = docs.map(d => ({
...d, s: cosine(q, d.vec),
}));
scored.sort((a, b) => b.s - a.s);
console.log(scored[0].text, scored[0].s.toFixed(3));FAQ
Bi-encoders independently embed queries and documents into vectors for fast index lookup. Cross-encoders process query and document simultaneously with joint attention for higher precision.
Matryoshka models train embeddings so the most essential semantic information is concentrated in early dimensions, letting you truncate from 1536 to 512 dimensions with minimal accuracy loss.
When vectors have a magnitude of 1.0, the cosine similarity formula simplifies directly to the dot product, eliminating costly square root and division operations during search.