Build / AI /

Vector Embeddings

Generate dense mathematical embeddings, calculate cosine similarities, and index text representations with OpenAI and Voyage.

TL;DR

  1. Generate dense vector embeddings using embeddings.create() API calls.
  2. Compute vector distance with dot product cosineSimilarity() mathematical formulas.
  3. Compress embedding storage costs using dimensions parameter reduction features.

Generating Embeddings with OpenAI SDK

    Single Text Embedding Request

    Generate 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 Embeddings

    Embed 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 Reduction

    Reduce 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 drop

Voyage AI Domain Embeddings

    Code & Finance Specialized Embeddings

    Use 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 Specialization

    Specify query vs document input types for asymmetric retrieval.

    const body = {
      model: 'voyage-3',
      input: ['search query'],
      input_type: 'query', // vs 'document' for corpus
    };
    Truncation Enforcement

    Ensure 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 Similarity

    Calculate 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 Vectors

    Fast 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 Search

    Rank 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 Normalization

    Normalize 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 Dispatcher

    Chunk 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 Calculator

    Estimate RAM requirement for storing vectors in memory.

    function getVectorBytes(count: number, dims = 1536) {
      // 4 bytes per 32-bit float
      return count * dims * 4;
    }

Tips

  1. Normalize embeddings to unit length so fast dot products equal mathematical cosineSimilarity calculations exactly without expensive square roots.
  2. Batch up to 2048 text inputs per embeddings.create() call to minimize HTTP network overhead and accelerate indexing pipelines.

Warnings

  1. Never compare embeddings generated by different model versions like text-embedding-3-small and legacy ada-002 due to incompatible coordinate spaces.
  2. Strip empty strings and newlines prior to embedding generation to avoid skewed 0.0 vector representations.

In Practice

FAQ