Embeddings y Similitud
Los embeddings convierten texto en vectores de tamaño fijo donde la similitud semántica corresponde a la cercanía geométrica. Potencian la búsqueda semántica, la agrupación y la recuperación en RAG.
Receta
Tarjeta de receta de referencia rápida, lista para copiar y pegar.
from openai import OpenAI
import numpy as np
client = OpenAI()
emb = client.embeddings.create(model="text-embedding-3-small", input=["texto de consulta"])
vec = np.array(emb.data[0].embedding)
# similitud del coseno
def cosine(a, b):
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))Cuándo usar esto:
- Búsqueda semántica sobre documentos, código o artículos de soporte.
- Agrupación o deduplicación de contenido de texto.
- Paso de recuperación de RAG antes de la generación de LLM.
- Sistemas de recomendación basados en similitud de texto.
Ejemplo de Trabajo
"""embeddings_similarity.py - generar embeddings, indexar y buscar documentos."""
from __future__ import annotations
import numpy as np
from openai import OpenAI
client = OpenAI()
MODEL = "text-embedding-3-small"
documents = [
"FastAPI es un framework web moderno de Python para construir APIs.",
"PyTorch es un framework de aprendizaje profundo con grafos de cómputo dinámicos.",
"pandas 2.2 proporciona operaciones de DataFrame para el análisis de datos tabulares.",
"pytest es el framework de pruebas estándar para proyectos de Python.",
]
def embed_texts(texts: list[str]) -> np.ndarray:
response = client.embeddings.create(model=MODEL, input=texts)
vectors = [item.embedding for item in response.data]
arr = np.array(vectors, dtype=np.float32)
norms = np.linalg.norm(arr, axis=1, keepdims=True)
return arr / norms # Normalización L2 para similitud del coseno mediante producto punto
doc_embeddings = embed_texts(documents)
query = "¿Cómo pruebo mi código de Python?"
query_vec = embed_texts([query])[0]
scores = doc_embeddings @ query_vec # similitud del coseno (normalizada)
ranked = sorted(zip(scores, documents), reverse=True)
for score, doc in ranked:
print(f"{score:.3f} {doc}")Lo que esto demuestra:
- Generación de embeddings por lotes con OpenAI
text-embedding-3-small. - Normalización L2 para que el producto punto sea igual a la similitud del coseno.
- Clasificación de documentos por relevancia a una consulta en lenguaje natural.
- Coincidencia semántica: "probar código de Python" clasifica pytest en primer lugar.
Inmersión Profunda
Cómo Funciona
- Modelo de embedding codifica texto en un vector de dimensión fija (p. ej., 1536).
- Textos similares producen vectores con alta similitud del coseno.
- Normalización (L2) hace que el producto punto sea equivalente a la similitud del coseno.
- Índice vectorial (FAISS, pgvector) permite una búsqueda rápida de vecinos más cercanos a escala.
- Se debe usar el mismo modelo para indexar y consultar.
Modelos de Embedding
| Modelo | Dims | Proveedor | Uso |
|---|---|---|---|
| text-embedding-3-small | 1536 | OpenAI | Propósito general, rentable |
| text-embedding-3-large | 3072 | OpenAI | Mayor calidad |
| all-MiniLM-L6-v2 | 384 | Local (sentence-transformers) | Sin conexión, rápido |
| voyage-3 | 1024 | Voyage AI | Optimizado para recuperación |
Notas de Python
# Embeddings locales con sentence-transformers
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("all-MiniLM-L6-v2")
vectors = model.encode(documents, normalize_embeddings=True)Trampas Comunes
- Mezclar modelos de embedding - diferentes modelos producen espacios vectoriales incompatibles. Solución: un modelo por índice; volver a generar los embeddings de todos los documentos al cambiar de modelo.
- No normalizar vectores - el producto punto sin normalización no es similitud del coseno. Solución: normalizar L2 antes de indexar y buscar.
- Generar embeddings de textos muy largos - los modelos tienen límites de tokens; los documentos largos se truncan. Solución: dividir los documentos en fragmentos antes de generar los embeddings.
- Comparar entre diferentes dimensiones - los vectores de 384 dimensiones vs 1536 dimensiones no se pueden comparar. Solución: modelo y dimensión consistentes.
- Ignorar el costo de los embeddings a escala - generar embeddings para millones de documentos suma. Solución: cachear embeddings; agrupar solicitudes; usar modelos más pequeños.
- Expectativa de búsqueda por palabras clave - los embeddings no encuentran coincidencias exactas de palabras clave. Solución: búsqueda híbrida (embeddings + BM25).
Alternativas
| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
| Embeddings de API (OpenAI) | Sin GPU, alta calidad | Los datos no pueden salir de su red |
| sentence-transformers | Local/sin conexión, gratis | Necesita la máxima calidad de recuperación |
| Búsqueda por palabras clave BM25 | Coincidencia exacta de términos | Se necesita coincidencia semántica/parafraseada |
| Híbrido (BM25 + denso) | RAG en producción | Prototipo simple con pocos documentos |
Preguntas Frecuentes
¿Qué es la similitud del coseno?
- Mide el ángulo entre dos vectores: rango [-1, 1], típicamente [0, 1] para texto.
- 1.0 = dirección idéntica; 0 = ortogonal (no relacionado).
¿Cuántas dimensiones necesito?
- 384-1536 para la mayoría de las aplicaciones.
- Dimensiones más altas capturan matices pero cuestan más almacenamiento y cómputo.
- Coincidir con la configuración de su base de datos vectorial.
¿Debo generar embeddings para consultas y documentos de la misma manera?
- Sí - mismo modelo, mismo preprocesamiento.
- Algunos modelos tienen prefijos diferentes para consulta vs documento (p. ej., prefijo "query: ").
¿Cómo almaceno los embeddings?
- PostgreSQL con la extensión pgvector.
- Chroma, Qdrant, Pinecone para almacenes vectoriales dedicados.
- Ver Bases de Datos Vectoriales.
¿Cuál es un buen umbral de similitud?
- Depende del modelo y del dominio; típicamente 0.7-0.85 para coincidencias relevantes.
- Calibrar en pares de consulta-documento etiquetados.
¿Cómo reduzco las dimensiones de los embeddings?
client.embeddings.create(model="text-embedding-3-small", input=texts, dimensions=512)- OpenAI admite la reducción de dimensiones Matryoshka.
¿Puedo generar embeddings para código?
- Los embeddings de texto general funcionan para la búsqueda de código.
- Modelos especializados (CodeBERT, voyage-code) pueden mejorar los resultados.
¿Cómo agrupo las solicitudes de embedding?
- OpenAI acepta hasta 2048 entradas por solicitud.
- Agrupar para eficiencia de costos en corpus grandes.
¿Qué es la búsqueda híbrida?
- Combina puntuaciones de recuperación densas (embedding) y dispersas (BM25).
- Reciprocal Rank Fusion fusiona listas clasificadas.
¿Cómo se relacionan los embeddings con RAG?
- Generar embeddings de documentos en la ingesta; generar embedding de consulta en la recuperación.
- Los fragmentos más similares (top-k) alimentan al LLM como contexto.
- Ver Conceptos Básicos de RAG.
¿Cómo actualizo los embeddings cuando cambian los documentos?
- Volver a generar los embeddings de los documentos modificados y actualizarlos en el índice vectorial.
- Rastrea la versión/hash del documento para evitar embeddings obsoletos.
¿Son deterministas los embeddings?
- El mismo modelo y entrada producen el mismo vector (pequeña varianza de punto flotante).
- Cachea los embeddings por hash de contenido para idempotencia.
Relacionado
- Conceptos Básicos de RAG - pipeline de recuperación
- Bases de Datos Vectoriales - almacenamiento y búsqueda
- Fragmentación e Ingesta - división de documentos
- SDK de OpenAI y Otros - API de embeddings
- Recuperación y Reclasificación - búsqueda híbrida
Versiones de Stack: Esta página fue escrita para Python 3.14.0 (estable 3.14, mantenimiento 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, y uv 0.6+.