MinhVo

Minh Vo

rss feed

Slaying code & making it lit fr fr 🔥 tagline

Hey there 👋 I'm an AI Engineer with 7 years of experience building scalable web and mobile applications. Currently at Neurond AI (May 2025 — present), architecting an Enterprise AI Assistant Platform with multi-tenant RAG on pgvector, multi-provider LLM orchestration, and Azure-native infrastructure. Previously spent 5+ years at SNAPTEC (Sep 2019 — Apr 2025), leading SaaS themes, admin dashboards, and e-commerce platforms — earned the Hero of the Year award in 2021. I specialize in TypeScript, React, Next.js, and AI-Native engineering with Claude Code and Cursor.bio

Back to blogs

AI Embeddings: Understanding Vector Representations

Understand embeddings: text, image, and multimodal representations for search and classification.

AIEmbeddingsVectorsMachine Learning

By MinhVo

Introduction

Embeddings are the invisible infrastructure powering modern AI applications. Every time you use semantic search, get personalized recommendations, see relevant ads, or interact with a chatbot that understands context, you're benefiting from embeddings — dense vector representations that capture meaning in a way machines can process. Understanding embeddings is no longer optional for developers building AI-powered applications; it's the foundational knowledge that separates competent AI integration from truly effective implementation.

Vector embeddings visualized in high-dimensional space

At their core, embeddings transform complex data — text, images, audio, or any structured information — into fixed-size arrays of numbers (vectors) that preserve semantic relationships. Words with similar meanings cluster together in vector space. Sentences expressing similar ideas point in similar directions. Images containing similar objects occupy nearby regions. This mathematical representation of meaning enables machines to perform tasks that previously required human understanding: finding similar documents, classifying content, detecting anomalies, and answering questions based on context.

The practical applications are transformative. E-commerce platforms use embeddings to power "customers who bought this also bought" recommendations. Search engines use them to understand that "how to fix a leaky faucet" should match a document titled "repairing dripping taps." RAG (Retrieval-Augmented Generation) systems use embeddings to find relevant context for LLM responses. Music streaming services use them to create personalized playlists. The technology is everywhere, and understanding how to use it effectively is a superpower for modern developers.

Understanding Embeddings: Core Concepts

What Are Vector Embeddings?

An embedding is a mathematical function that maps data from one space to another — typically from a high-dimensional, discrete space (like words or pixels) to a lower-dimensional, continuous space (like a vector of 1536 floating-point numbers). The key property that makes embeddings useful is that similar inputs produce similar vectors.

For text, this means "The cat sat on the mat" and "A kitten rested on the rug" will have vectors that are close together in the embedding space, because they express similar meanings despite using different words. This semantic similarity is what makes embeddings far more powerful than keyword matching.

Dimensionality and Information Density

Modern embedding models produce vectors of varying dimensionality: OpenAI's text-embedding-3-small produces 1536-dimensional vectors, while text-embedding-3-large produces 3072 dimensions. Higher dimensionality can capture more nuanced relationships but requires more storage and computation for similarity search.

The choice of dimensionality involves a tradeoff between accuracy and efficiency. For most applications, 768-1536 dimensions provide excellent results. Specialized applications (medical text, legal documents, multilingual content) may benefit from higher dimensions.

Understanding embedding dimensions and similarity

Similarity Metrics

Once you have vectors, you need a way to measure how similar they are. The three most common metrics are:

  • Cosine Similarity: Measures the angle between vectors. Ranges from -1 (opposite) to 1 (identical). Best for text embeddings where magnitude doesn't matter.
  • Euclidean Distance (L2): Measures straight-line distance between vector endpoints. Lower values mean more similar. Sensitive to magnitude.
  • Dot Product: Simple multiplication of corresponding dimensions and summation. Fastest to compute. Works well when vectors are normalized.

For text embeddings, cosine similarity is almost always the right choice. Most embedding models normalize their outputs, making cosine similarity and dot product equivalent.

The Embedding Model Landscape

The embedding model landscape has evolved rapidly. OpenAI's text-embedding-3-small offers excellent quality at low cost. Open-source models like all-MiniLM-L6-v2 from Sentence Transformers provide strong performance for free. Cohere's embed-v3 excels at multilingual content. Google's Gecko model achieves state-of-the-art performance on the MTEB benchmark. Each model has different strengths, and the right choice depends on your language, domain, and latency requirements.

Architecture and Design Patterns

The Embedding Pipeline

A production embedding pipeline follows this flow: Raw Data → Preprocessing → Embedding Model → Vector Store → Query Interface. Each stage has design decisions that affect quality and performance.

Batch vs. Real-Time Embedding

For static content (product catalogs, document archives), batch embedding during ingestion is more efficient. For dynamic content (user queries, real-time chat), you need real-time embedding with low latency. Most applications need both: batch embedding for the corpus and real-time embedding for queries.

Vector Database Architecture

Storing embeddings requires specialized databases optimized for high-dimensional similarity search. Traditional databases can't efficiently search through millions of 1536-dimensional vectors. Vector databases like Pinecone, Weaviate, Qdrant, and pgvector use algorithms like HNSW (Hierarchical Navigable Small World) to perform approximate nearest neighbor search in milliseconds.

Hybrid Search Architecture

Production search systems typically combine embedding-based semantic search with traditional keyword search. This hybrid approach catches both semantic matches ("fixing a dripping tap" matches "leaky faucet repair") and exact matches (product codes, proper nouns, technical identifiers).

Step-by-Step Implementation

Generating Embeddings with OpenAI

import OpenAI from 'openai';
 
const openai = new OpenAI();
 
interface EmbeddingResult {
  text: string;
  embedding: number[];
  tokenCount: number;
}
 
async function generateEmbedding(text: string): Promise<EmbeddingResult> {
  const response = await openai.embeddings.create({
    model: 'text-embedding-3-small',
    input: text,
  });
 
  return {
    text,
    embedding: response.data[0].embedding,
    tokenCount: response.usage.total_tokens,
  };
}
 
// Batch embedding for efficiency
async function generateBatchEmbeddings(texts: string[]): Promise<EmbeddingResult[]> {
  const response = await openai.embeddings.create({
    model: 'text-embedding-3-small',
    input: texts,
  });
 
  return response.data.map((item, index) => ({
    text: texts[index],
    embedding: item.embedding,
    tokenCount: 0, // Shared across batch
  }));
}

Storing and Querying with Pinecone

import { Pinecone } from '@pinecone-database/pinecone';
 
const pinecone = new Pinecone({ apiKey: process.env.PINECONE_API_KEY! });
const index = pinecone.index('my-embeddings');
 
// Upsert embeddings
async function storeEmbeddings(embeddings: EmbeddingResult[]): Promise<void> {
  const vectors = embeddings.map((e, i) => ({
    id: `doc-${i}`,
    values: e.embedding,
    metadata: { text: e.text, timestamp: Date.now() },
  }));
 
  // Pinecone accepts batches of 100
  for (let i = 0; i < vectors.length; i += 100) {
    await index.upsert(vectors.slice(i, i + 100));
  }
}
 
// Query similar embeddings
async function searchSimilar(query: string, topK: number = 5): Promise<string[]> {
  const queryEmbedding = await generateEmbedding(query);
  
  const results = await index.query({
    vector: queryEmbedding.embedding,
    topK,
    includeMetadata: true,
  });
 
  return results.matches.map(match => ({
    text: match.metadata?.text as string,
    score: match.score,
  }));
}

Implementing Cosine Similarity from Scratch

Understanding the math helps you debug issues and optimize performance:

function cosineSimilarity(a: number[], b: number[]): number {
  if (a.length !== b.length) {
    throw new Error('Vectors must have the same dimensions');
  }
 
  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));
}
 
// Find the most similar documents to a query
function findSimilar(
  queryEmbedding: number[],
  documentEmbeddings: { id: string; embedding: number[] }[],
  topK: number = 5
): { id: string; similarity: number }[] {
  return documentEmbeddings
    .map(doc => ({
      id: doc.id,
      similarity: cosineSimilarity(queryEmbedding, doc.embedding),
    }))
    .sort((a, b) => b.similarity - a.similarity)
    .slice(0, topK);
}

Building semantic search with embeddings

Real-World Use Cases

The most common application of embeddings is semantic search — finding documents by meaning rather than keywords. A user searching for "how to handle errors gracefully" should find articles about try-catch patterns, error boundaries, and exception handling, even if none of those exact words appear in the query.

RAG (Retrieval-Augmented Generation)

RAG systems use embeddings to find relevant context for LLM responses. When a user asks a question, the system embeds the query, finds the most similar documents in the knowledge base, and includes them in the LLM prompt. This grounds the model's response in factual, up-to-date information.

Recommendation Systems

Embeddings power recommendation engines by representing users and items in the same vector space. When a user's embedding (derived from their interaction history) is close to an item's embedding, that item is a good recommendation.

Anomaly Detection

By embedding normal behavior patterns and measuring distance from the centroid, you can detect anomalies in real-time. This applies to fraud detection, system monitoring, and quality assurance.

Best Practices for Production

  1. Choose the right embedding model for your domain — General-purpose models work well for general content, but domain-specific models (medical, legal, code) produce dramatically better results for specialized content.

  2. Chunk documents thoughtfully — Don't embed entire documents as single vectors. Split into semantic chunks (paragraphs, sections) of 200-500 tokens. Overlap chunks by 50-100 tokens to avoid losing context at boundaries.

  3. Normalize your vectors — If your embedding model doesn't normalize by default, do it yourself. Normalized vectors make cosine similarity equivalent to dot product, enabling faster search.

  4. Use appropriate vector dimensions — Higher isn't always better. 768-1536 dimensions work well for most applications. Test with your specific data to find the optimal dimensionality.

  5. Implement caching for repeated queries — Cache embedding results for common queries to reduce API calls and latency. Embeddings are deterministic — the same text always produces the same vector.

  6. Monitor embedding quality over time — Track metrics like retrieval precision, user click-through rates on search results, and RAG answer accuracy. Degrading metrics may indicate domain drift.

  7. Use batch operations — Embedding APIs support batch processing. Sending 100 texts in one API call is far more efficient than 100 individual calls.

  8. Implement hybrid search — Combine semantic search with keyword search for best results. Use semantic search for conceptual queries and keyword search for exact matches.

Common Pitfalls and Solutions

PitfallImpactSolution
Embedding entire documentsPoor retrieval granularityChunk into 200-500 token segments
Using wrong similarity metricInaccurate resultsUse cosine similarity for text embeddings
Not normalizing vectorsInconsistent similarity scoresNormalize all vectors before storage
Ignoring token limitsAPI errors, truncated textSplit inputs to stay within model limits
Stale embeddingsOutdated search resultsRe-embed when content changes
Wrong chunk overlapLost context at boundariesUse 50-100 token overlap between chunks
Ignoring multilingual needsPoor results for non-English contentUse multilingual embedding models

Debugging Poor Retrieval Quality

When your embedding-based search returns irrelevant results, the debugging process starts with examining the actual vectors. Compare the embedding of your query with the embeddings of expected results — if they're not close in vector space, the issue is with the embedding model or your chunking strategy, not the search algorithm.

// Diagnostic tool for debugging retrieval quality
async function diagnoseRetrieval(query: string, expectedDocIds: string[]): Promise<void> {
  const queryEmb = await generateEmbedding(query);
  const results = await searchSimilar(query, 20);
  
  console.log(`Query: "${query}"`);
  console.log(`Expected documents: ${expectedDocIds.join(', ')}`);
  console.log(`\nTop 20 results:`);
  
  results.forEach((r, i) => {
    const isExpected = expectedDocIds.includes(r.id);
    console.log(`${i + 1}. [${isExpected ? '✓' : '✗'}] ${r.id} (score: ${r.score.toFixed(4)})`);
  });
  
  const recall = expectedDocIds.filter(id => 
    results.slice(0, 10).some(r => r.id === id)
  ).length / expectedDocIds.length;
  
  console.log(`\nRecall@10: ${(recall * 100).toFixed(1)}%`);
}

Performance Optimization

Embedding generation is the primary bottleneck in most embedding pipelines. A single API call to OpenAI's embedding endpoint takes 50-200ms. For applications embedding thousands of documents, this latency is unacceptable without optimization.

Batch processing is the most impactful optimization. OpenAI's API accepts up to 2048 inputs per batch, reducing per-text latency by orders of magnitude. For a corpus of 10,000 documents, batch processing reduces total embedding time from 30 minutes to under 2 minutes.

Vector quantization reduces storage and search costs by compressing 32-bit float vectors to 8-bit integers. This reduces storage by 4x with minimal accuracy loss (typically <2% degradation in retrieval quality). Most vector databases support this natively.

// Quantization: float32 to int8
function quantizeVector(vector: number[]): Int8Array {
  const maxAbs = Math.max(...vector.map(Math.abs));
  const scale = 127 / maxAbs;
  return Int8Array.from(vector.map(v => Math.round(v * scale)));
}
 
// Dequantization for comparison
function dequantizeVector(quantized: Int8Array, scale: number): number[] {
  return Array.from(quantized).map(v => v / scale);
}

Comparison with Alternatives

ApproachSemantic UnderstandingSpeedCostSetup ComplexityBest For
Embedding SearchExcellentFast (ms)Per-tokenMediumSemantic search, RAG
Keyword Search (BM25)PoorVery fastFreeLowExact match, established corpora
Hybrid SearchExcellentFastPer-tokenHighProduction search systems
Knowledge GraphsStructuredFastFree/PaidVery highEntity relationships
Full-text Search (Elastic)GoodFastSelf-hostedMediumTraditional search
Regex/Pattern MatchNoneInstantFreeLowKnown patterns

Advanced Patterns

Multimodal Embeddings

Modern embedding models like CLIP can embed both text and images into the same vector space. This enables powerful applications like image search by text description, automatic image captioning, and cross-modal recommendations.

// Using CLIP for multimodal search
interface MultimodalEmbedding {
  type: 'text' | 'image';
  embedding: number[];
  source: string;
}
 
// A text query can find similar images
// "a sunset over the ocean" → finds images with similar visual content

Embedding Caching and Invalidation

For dynamic content that changes over time, implement a caching strategy that invalidates embeddings when the source content changes. Store a hash of the original content alongside the embedding, and re-embed when the hash changes.

Dimensionality Reduction for Visualization

Use techniques like t-SNE, UMAP, or PCA to reduce high-dimensional embeddings to 2D or 3D for visualization. This helps you understand the structure of your embedding space and identify clusters or outliers.

// Simple PCA for visualization (2D projection)
function projectTo2D(embeddings: number[][]): [number, number][] {
  // Use first two principal components
  // In production, use a library like ml-pca
  const pca = new PCA(embeddings);
  const projected = pca.predict(embeddings, { nComponents: 2 });
  return projected.data.map(row => [row[0], row[1]] as [number, number]);
}

Testing Strategies

Testing embedding-based systems requires measuring retrieval quality, not just correctness. Use standard information retrieval metrics: precision@k (what fraction of top-k results are relevant), recall@k (what fraction of all relevant results appear in top-k), and mean reciprocal rank (average inverse rank of the first relevant result).

describe('Embedding Search Quality', () => {
  it('should retrieve relevant documents with > 90% precision@5', async () => {
    const testCases = [
      { query: 'how to authenticate users', expectedTopics: ['auth', 'jwt', 'oauth'] },
      { query: 'database connection pooling', expectedTopics: ['postgres', 'pool', 'connection'] },
      { query: 'react component lifecycle', expectedTopics: ['hooks', 'useEffect', 'mount'] },
    ];
 
    for (const testCase of testCases) {
      const results = await searchSimilar(testCase.query, 5);
      const relevantCount = results.filter(r => 
        testCase.expectedTopics.some(topic => 
          r.metadata?.tags?.includes(topic)
        )
      ).length;
      
      expect(relevantCount / 5).toBeGreaterThanOrEqual(0.9);
    }
  });
});

Future Outlook

The embedding landscape is evolving toward larger, more capable models that capture finer semantic distinctions. We're also seeing the emergence of task-specific embeddings — models optimized not for general similarity but for specific applications like code search, medical literature retrieval, or legal document matching.

The most exciting development is learned embeddings — systems that automatically learn the optimal embedding model for your specific data and use case through fine-tuning. Instead of choosing from a menu of pre-trained models, you'll provide your data and evaluation criteria, and the system will produce a custom embedding model that outperforms any general-purpose alternative.

For developers, the practical implication is that embedding technology is becoming more accessible and more powerful simultaneously. The barrier to building sophisticated semantic search and RAG applications is dropping rapidly, while the quality ceiling continues to rise.

Conclusion

Embeddings are the bridge between human meaning and machine computation. They transform the fuzzy, contextual nature of language, images, and data into precise mathematical representations that enable search, classification, recommendation, and generation.

Key takeaways:

  1. Embeddings capture semantic meaning — similar inputs produce similar vectors regardless of exact wording
  2. Choose your embedding model based on your content domain, language requirements, and latency needs
  3. Chunk documents into 200-500 token segments with overlap for best retrieval quality
  4. Use cosine similarity for text embeddings and normalize your vectors
  5. Combine semantic search with keyword search (hybrid) for production search systems
  6. Vector databases (Pinecone, Weaviate, Qdrant) are essential for efficient similarity search at scale
  7. Monitor retrieval quality metrics and re-embed when content changes

Start by embedding a small corpus of your own data and experimenting with similarity search. This hands-on experience will build intuition for how embeddings capture meaning and help you identify the right applications for your projects.