Módulo 3: Modelos de Embeddings Comparison

OpenAI Embeddings Models: Deep Dive Comparison

Descripción de la cápsula

OpenAI ofrece 2 modelos principales de embeddings en 2026: text-embedding-3-small y text-embedding-3-large. Aunque ambos funcionan bien, tienen diferencias críticas en performance, costo, dimensiones, y casos de uso óptimos.

En esta cápsula aprenderás las diferencias técnicas entre ambos modelos, cómo comparan en benchmarks (MTEB), cuándo usar cada uno según tu caso de uso, y cómo configurar dimensiones para optimizar storage/costo. También verás código para comparar ambos modelos empíricamente.

Al final, podrás elegir el modelo OpenAI correcto para tu proyecto.


Modelos disponibles (2026)

OpenAI Embeddings Models:

ModeloDims defaultDims configMTEB ScoreCosto/1M tokensLanzamiento
text-embedding-3-small1536512-1536~62$0.0202024
text-embedding-3-large3072256-3072~64$0.1302024
text-embedding-ada-002 (legacy)15361536~61$0.1002022

Recomendación: Usa 3-small o 3-large (ada-002 es legacy).


text-embedding-3-small

Características:

Modelo: text-embedding-3-small
Dimensiones: 1536 (default), configurable 512-1536
MTEB Score: ~62
Costo: $0.020 / 1M tokens
Max tokens: 8,191

Performance (MTEB):

Benchmark         | Score | Rank
------------------|-------|------
Retrieval         | 0.55  | Bueno
Classification    | 0.68  | Muy bueno
Clustering        | 0.47  | Bueno
Semantic Similarity| 0.82 | Excelente
Reranking         | 0.60  | Bueno

MTEB Average: 0.62

Interpretación: Bueno para semantic search general, excelente para similarity tasks.


Cuándo usar 3-small:

1. Prototipado rápido

# Costo bajo = iteración rápida
# $0.02/1M tokens vs $0.13/1M tokens (6.5x más barato)

2. Presupuesto limitado

# Startup con $100/mes:
# 3-small: 5M tokens
# 3-large: 769K tokens

3. Semantic search no crítico

# FAQ search, documentation search
# No requiere máxima precisión

4. High volume (millones de queries)

# 10M queries/mes:
# 3-small: $200
# 3-large: $1,300

Código de uso:

from openai import OpenAI
import os
from dotenv import load_dotenv

load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

# Generar embedding con 3-small
response = client.embeddings.create(
    model="text-embedding-3-small",
    input="Python es un lenguaje de programación"
)

embedding = response.data[0].embedding
print(f"Modelo: text-embedding-3-small")
print(f"Dimensiones: {len(embedding)}")
print(f"Primeras 5 dims: {embedding[:5]}")

Output:

Modelo: text-embedding-3-small
Dimensiones: 1536
Primeras 5 dims: [0.0234, -0.0123, 0.0456, -0.0189, 0.0267]

text-embedding-3-large

Características:

Modelo: text-embedding-3-large
Dimensiones: 3072 (default), configurable 256-3072
MTEB Score: ~64
Costo: $0.130 / 1M tokens
Max tokens: 8,191

Performance (MTEB):

Benchmark         | Score | Rank
------------------|-------|------
Retrieval         | 0.60  | Excelente
Classification    | 0.70  | Excelente
Clustering        | 0.52  | Muy bueno
Semantic Similarity| 0.84 | Excelente
Reranking         | 0.64  | Muy bueno

MTEB Average: 0.64

Mejora vs 3-small: +2 puntos MTEB (~3% mejor).


Cuándo usar 3-large:

1. RAG production-ready

# Contexto correcto es crítico
# +3% precision = queries mejores

2. Domain crítico (legal, medical)

# Errores son costosos
# Vale la pena pagar 6.5x más

3. Low-to-medium volume

# <1M queries/mes:
# Costo total manejable ($130/mes)

4. Benchmarking de otros modelos

# Usar 3-large como "gold standard"
# Comparar open-source vs este

Código de uso:

# Generar embedding con 3-large
response = client.embeddings.create(
    model="text-embedding-3-large",
    input="Python es un lenguaje de programación"
)

embedding = response.data[0].embedding
print(f"Modelo: text-embedding-3-large")
print(f"Dimensiones: {len(embedding)}")

Output:

Modelo: text-embedding-3-large
Dimensiones: 3072

Comparación directa: 3-small vs 3-large

Experimento empírico:

import numpy as np
from openai import OpenAI
import os
from dotenv import load_dotenv

load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

def cosine_similarity(vec_a, vec_b):
    """Cosine similarity"""
    return np.dot(vec_a, vec_b) / (np.linalg.norm(vec_a) * np.linalg.norm(vec_b))

def compare_models(query, docs):
    """Comparar 3-small vs 3-large en retrieval"""
    results = {}
    
    for model in ["text-embedding-3-small", "text-embedding-3-large"]:
        # Embed query
        query_emb = client.embeddings.create(
            model=model,
            input=query
        ).data[0].embedding
        
        # Embed docs
        doc_embs = []
        for doc in docs:
            emb = client.embeddings.create(
                model=model,
                input=doc
            ).data[0].embedding
            doc_embs.append(emb)
        
        # Calculate similarities
        sims = [cosine_similarity(query_emb, doc_emb) for doc_emb in doc_embs]
        
        # Rank docs
        ranked = sorted(zip(docs, sims), key=lambda x: x[1], reverse=True)
        
        results[model] = ranked
    
    return results

# Test
query = "¿Cómo instalar Python?"

docs = [
    "Para instalar Python, descarga el instalador desde python.org",
    "JavaScript es un lenguaje de programación web",
    "Python requiere pip para instalar paquetes"
]

results = compare_models(query, docs)

print("Query:", query)
print("\n=== text-embedding-3-small ===")
for doc, sim in results["text-embedding-3-small"]:
    print(f"{sim:.4f} | {doc[:50]}...")

print("\n=== text-embedding-3-large ===")
for doc, sim in results["text-embedding-3-large"]:
    print(f"{sim:.4f} | {doc[:50]}...")

Output esperado:

Query: ¿Cómo instalar Python?

=== text-embedding-3-small ===
0.8234 | Para instalar Python, descarga el instalador d...
0.7123 | Python requiere pip para instalar paquetes...
0.5432 | JavaScript es un lenguaje de programación web...

=== text-embedding-3-large ===
0.8567 | Para instalar Python, descarga el instalador d...  ← Mejor score
0.7421 | Python requiere pip para instalar paquetes...
0.5123 | JavaScript es un lenguaje de programación web...

Observación: 3-large diferencia mejor (mayor score para doc correcto, menor para irrelevante).


Dimensiones configurables

Por qué reducir dimensiones:

# Storage:
# 1M docs × 3072 dims × 4 bytes = 12 GB (3-large)
# 1M docs × 1536 dims × 4 bytes = 6 GB (3-small)
# 1M docs × 512 dims × 4 bytes = 2 GB (3-small reducido)

# Speedup:
# 512 dims → 3x más rápido en búsqueda vs 1536 dims

Código con dimensiones reducidas:

# text-embedding-3-small con 512 dims
response = client.embeddings.create(
    model="text-embedding-3-small",
    input="Python es popular",
    dimensions=512  # Reducir de 1536 → 512
)

embedding = response.data[0].embedding
print(f"Dimensiones: {len(embedding)}")  # 512

Trade-off: Precision vs Storage

# Benchmark interno de OpenAI (retrieval@10):

Modelo: text-embedding-3-small
- 1536 dims (default): 100% precision (baseline)
- 1024 dims:           98% precision
- 512 dims:            95% precision
- 256 dims:            90% precision

Recomendación: 512-1024 dims = sweet spot

Cost analysis detallado

Escenario 1: RAG system (100K queries/mes)

# Assumptions:
# - Query: 50 tokens promedio
# - Docs retrieved: 5 docs × 200 tokens = 1000 tokens
# - Total per query: 1050 tokens

tokens_per_month = 100_000 * 1050  # 105M tokens

# 3-small:
cost_small = (tokens_per_month / 1_000_000) * 0.020
print(f"3-small: ${cost_small:.2f}/mes")  # $2.10/mes

# 3-large:
cost_large = (tokens_per_month / 1_000_000) * 0.130
print(f"3-large: ${cost_large:.2f}/mes")  # $13.65/mes

# Diferencia: $11.55/mes (~6.5x)

Decisión: Si presupuesto <$50/mes → 3-small, si >$50/mes y RAG crítico → 3-large.


Escenario 2: E-commerce search (1M queries/mes)

# Assumptions:
# - Query: 30 tokens promedio
# - Productos: 100K (embed 1 vez)
# - Queries: 1M/mes

# Embedding inicial de productos (1 vez):
initial_tokens = 100_000 * 50  # 5M tokens
initial_cost_small = (initial_tokens / 1_000_000) * 0.020  # $0.10
initial_cost_large = (initial_tokens / 1_000_000) * 0.130  # $0.65

# Queries mensuales:
query_tokens = 1_000_000 * 30  # 30M tokens
query_cost_small = (query_tokens / 1_000_000) * 0.020  # $0.60/mes
query_cost_large = (query_tokens / 1_000_000) * 0.130  # $3.90/mes

# Total mensual (después de setup):
print(f"3-small: ${query_cost_small:.2f}/mes")  # $0.60/mes
print(f"3-large: ${query_cost_large:.2f}/mes")  # $3.90/mes

Decisión: Para e-commerce, 3-small probablemente suficiente (ahorro significativo).


Decision matrix

Cuándo elegir cada modelo:

Criterio                | 3-small | 3-large
------------------------|---------|--------
Presupuesto <$100/mes   | ✅      | ❌
RAG production-critical | ❌      | ✅
Prototipo/MVP           | ✅      | ❌
Domain crítico (legal)  | ❌      | ✅
High volume (>1M/mes)   | ✅      | ❌
Máxima precisión        | ❌      | ✅

Benchmarking en código

Comparación automática:

import time

def benchmark_model(model_name, texts):
    """Benchmark latencia y costo"""
    start = time.time()
    
    response = client.embeddings.create(
        model=model_name,
        input=texts
    )
    
    latency = time.time() - start
    
    # Estimar costo (assumiendo 50 tokens/text)
    tokens = len(texts) * 50
    cost_per_1m = 0.020 if "small" in model_name else 0.130
    cost = (tokens / 1_000_000) * cost_per_1m
    
    return {
        'model': model_name,
        'latency_ms': latency * 1000,
        'cost_usd': cost,
        'texts_processed': len(texts)
    }

# Test
texts = ["Python es popular"] * 100

result_small = benchmark_model("text-embedding-3-small", texts)
result_large = benchmark_model("text-embedding-3-large", texts)

print("=== Benchmark Results ===")
print(f"3-small: {result_small['latency_ms']:.0f}ms, ${result_small['cost_usd']:.6f}")
print(f"3-large: {result_large['latency_ms']:.0f}ms, ${result_large['cost_usd']:.6f}")

Output típico:

=== Benchmark Results ===
3-small: 324ms, $0.000100
3-large: 412ms, $0.000650

Observación: 3-large es ~25% más lento (más dims).


Resumen

Qué aprendiste:

  • 2 modelos principales: 3-small (barato, bueno) y 3-large (caro, excelente)
  • MTEB scores: 62 vs 64 (~3% mejora)
  • Costos: $0.02 vs $0.13 (6.5x diferencia)
  • Dimensiones: Configurables (reducir storage)
  • Casos de uso: Prototipo vs producción

Conceptos clave:

  1. 3-small → Prototipo, high volume, presupuesto limitado
  2. 3-large → RAG crítico, domain importante, low volume
  3. Dimensiones reducidas → Ahorro de storage (~3x)

Recursos adicionales

  1. OpenAI Embeddings Guide - Oficial
  2. MTEB Leaderboard - Rankings
  3. OpenAI Pricing - Costos actualizados
  4. Embeddings Comparison - Docs

En la siguiente cápsula

Cápsula 03: Open-Source Embeddings Overview

Aprenderás:

  • Sentence-BERT (SBERT)
  • BGE Models (BAAI)
  • Instructor Embeddings
  • E5 Models
  • Cómo usar HuggingFace Sentence-Transformers

De OpenAI API a open-source self-hosted.


Módulo 3 - Embeddings Deep Dive Guide OpenAI embeddings: eligiendo entre small y large