Introducción a los Embeddings y búsqueda semántica
Cómo transformar texto en vectores numéricos y construir búsqueda semántica real. Desde similitud coseno hasta RAG, con diagramas, código TypeScript y ejercicios interactivos.
Colaboradores: Ivan Garcia Villar
Cuando alguien busca “cómo freír un huevo” y tu sistema le devuelve resultados como “técnicas de cocción básicas”, eso es la búsqueda semántica. La búsqueda semántica es”entender” el significado de lo que pides y buscar términos relacionados. No hay coincidencia de palabras exactas, pero si hay una comprensión del significado. La pieza técnica que hace posible eso se llama embedding, y en este post voy a explicar cómo funciona desde los fundamentos: qué es un vector de texto, por qué la similitud coseno es la métrica correcta, y cómo montas un pipeline completo en producción.
De texto a números: qué es un embedding
Un modelo de lenguaje no puede entender directamente la palabra “gato” o “perror”. Necesita transformarlo en algo que pueda entender. Pero no puede hacerlo de cualquier manera, necesita hacerlo de manera que esas palabras estén relacionadas de alguna manera que capture que son cosas similares (andan a cuatro patas, son mamíferos, están vivos…), y necesita hacerlo de una manera que un ordenador pueda entender con matemáticas.
Un embedding resuelve esto: transforma cada texto en un vector de cientos o miles de números, entrenado para que textos con significado similar produzcan vectores similares. “Gato” y “felino” terminan cerca en ese espacio numérico. “Gato” y “contabilidad” terminan lejos.
El proceso completo tiene tres pasos: Primero se divide el texto en trozos o “Tokens”. Los tokens no siempre son palabras completas, sino fracciones de texto con significado propio.
El modelo de embedding (una red neuronal entrenada sobre grandes conjuntos de texto) lee esos tokens y produce un vector de dimensión fija. Para el tokenizador (modelo IA) text-embedding-3-small de OpenAI, ese vector tiene 1536 dimensiones. Para text-embedding-3-large, llega a 3072.
Cada uno de esos 1536 números captura un aspecto de significado de ese texto.
La analogía que mejor me funciona: piensa en las coordenadas GPS. Una ubicación geográfica queda definida por latitud y longitud — dos números que capturan “dónde está” ese punto en el planeta. Un embedding hace lo mismo con el significado: captura “dónde está” ese texto en el espacio semántico, pero en lugar de 2 dimensiones, usa 1536.
El espacio vectorial: donde el significado se transforma en vectores
Visualizar 1536 dimensiones es imposible para el cerebro humano. Pero si comprimimos ese espacio a 2 o 3 dimensiones (técnicas como PCA o t-SNE hacen eso), el patrón que aparece nos permite ver de forma más sencilla en que consisten los embeddingsgs:
Los términos de programación se agrupan juntos. Los de cocina forman otro grupo (cluster). Los de deportes, otro. Esta distribución no se definió específicamente; emergió del entrenamiento del modelo sobre texto humano real. El modelo aprendió que “Python” y “debugging” aparecen en contextos similares, y eso se refleja en su posición vectorial.
Lo que esto implica para tus búsquedas: cuando un usuario escribe “bug en mi código”, el vector de esa consulta caerá cerca de “error en la aplicación”, “excepción no capturada”, “fallo en producción” — aunque ninguna de esas frases comparta palabras con la consulta original.
Similitud coseno: la métrica que nos permite saber cuándo dos textos son similares
Tienes dos vectores . ¿Cómo mides qué tan similares son?
Si nos imaginamos el vector como una flecha que apunta hacia el significado de ese texto, dos vectores serán similares si apuntan en la misma dirección. No nos vamos a preocupar del punto exacto, tan solo de la dirección.
Para medir si dos vectores apuntan en la misma dirección, usamos la similitud coseno. Esta es la cuenta matemática que usamos para saber si dos embeddings son similares.
La similitud coseno mide el ángulo entre dos vectores:
cos(θ) = (A · B) / (|A| × |B|)
El resultado va de -1 a 1. Dos vectores idénticos tienen similitud 1.
Vectores perpendiculares (sin relación) tienen similitud 0. Vectores opuestos tienen similitud -1. En la práctica, con embeddings de texto, los valores suelen estar entre 0 y 1 — los textos raramente son semánticamente opuestos en sentido estricto.
La intuición geométrica: dos vectores que apuntan en la misma dirección son similares, sin importar si uno es más largo que el otro. Es como comparar la orientación de dos brújulas, no la distancia entre ellas.
Aplicaciones prácticas: más allá de la búsqueda
La búsqueda semántica es el caso de uso más visible, comparamos un texto con otros para encontrar similares, pero los embeddings abren un abanico de posibilidades que va bastante más allá.
Búsqueda semántica: el usuario escribe una consulta, la conviertes en embedding, buscas los documentos más cercanos. Funciona aunque el usuario use vocabulario diferente al de tus documentos. Estamos buscando por significado, no por concordancia exacta de palabras.
Sistemas de recomendación: conviertes cada ítem (producto, artículo, película) en un embedding basado en su descripción. Para recomendar, buscas los ítems más cercanos al historial y a la descripción de los intereses del usuario. Esta descripción de sus intereseses los puedes generar con otro modelo que interprete su comportamiento (que ha dicho que le gusta, que ha buscado antes, que ha visitado…)
Agrupamiento semántico (clusitering): aplicando algoritmos como “k-means” o similares sobre los embeddings de tus documentos. k-means busca embeddings que estén cercanos y los agrupa, de manera que puedes generar “nubes de ideas”. Los clusters que emergen agrupan contenido por temas similares sin que hayas definido esos temas manualmente. Es útil para analizar grandes volúmenes de feedback de usuarios o tickets de soporte.
Detección de anomalías: cuando la mayoría del contenido es coherente, el contenido anómalo (spam, contenido fuera de tema, duplicados con variaciones) produce vectores que quedan aislados lejos de los clusters principales. Se pueden usar embeddings para detectar esas anomalías.
Embeddings en producción: bases de datos vectoriales
Cuando tienes miles o millones de documentos, comparar el vector de consulta contra cada documento uno a uno es inviable. Necesitas índices especializados que hacen búsqueda aproximada de vecinos más cercanos (ANN) en milisegundos.
Las opciones principales para bases de datos vectoriales:
| Opción | Cuándo usarla | Ventaja principal | Desventaja |
|---|---|---|---|
| pgvector | Ya tienes PostgreSQL, escala media | Sin infraestructura nueva, queries SQL normales | Más lento que soluciones dedicadas a alta escala |
| Pinecone | Quieres managed, sin ops | Cero configuración de infraestructura | Coste alto a escala, vendor lock-in |
| ChromaDB | Prototipado local, desarrollo | Instalación trivial, funciona en memoria | No apto para producción con volumen real |
Sobre el chunking: cómo divides tus documentos antes de generar embeddings importa más de lo que parece. Un documento de 50 páginas no debería convertirse en un solo embedding — perderías toda la granularidad. Pero chunks demasiado pequeños pierden contexto. En la práctica, chunks de 300-500 tokens con overlap de 50-100 tokens es un punto de partida razonable. La superposición entre chunks asegura que las ideas que cruzan un límite de chunk no se pierdan.
El modelo de embedding también tiene un límite de tokens. text-embedding-3-small acepta hasta 8191 tokens de input — texto que exceda ese límite se trunca silenciosamente si no lo manejas.
La conexión con RAG
Si llegas a este punto y piensas “esto suena como la base de los sistemas de preguntas y respuestas sobre documentos propios”, tienes razón. Los embeddings son la pieza central de RAG (Retrieval-Augmented Generation): el patrón de recuperar contexto relevante antes de generar una respuesta con el LLM.
El pipeline de RAG completo tiene más capas — chunking strategies más sofisticadas, re-ranking de resultados, manejo de consultas ambiguas, evaluación de relevancia. Si estás construyendo un sistema RAG para producción, el post RAG empresarial completo cubre esas capas en detalle.
Errores comunes
Usar embeddings para comparación exacta
Los embeddings miden similitud semántica, no identidad. “Madrid es la capital de España” y “la capital española es Madrid” tendrán alta similitud coseno — y eso es correcto. Pero si necesitas detectar si dos strings son exactamente iguales, un hash es más rápido, más barato y más preciso. Los embeddings son la herramienta equivocada para ese trabajo.
No normalizar los vectores antes de almacenarlos
Algunos modelos devuelven vectores ya normalizados (magnitud = 1). Otros no. Si mezclas vectores de diferentes fuentes o versiones del modelo sin normalizar, la similitud coseno deja de ser una comparación justa. Normaliza siempre antes de persistir — es una operación barata que evita bugs difíciles de detectar.
Chunks demasiado grandes
Vi este error en un proyecto donde alguien convertía páginas enteras de documentación en un solo embedding. El resultado: el vector promediaba demasiados conceptos distintos y la búsqueda devolvía siempre las páginas más largas, no las más relevantes. Un embedding por párrafo, con overlap entre párrafos consecutivos, resuelve esto.
Generar embeddings en tiempo de consulta para documentos estáticos
Si tienes 100.000 documentos y los re-embedes en cada búsqueda, tu latencia será inaceptable y tu factura de API también. Los embeddings de documentos se precomputan y almacenan. Solo el embedding de la consulta se genera en tiempo real.
Cambiar el modelo de embedding sin re-indexar
Los vectores de text-embedding-3-small y text-embedding-3-large viven en espacios distintos — no son comparables entre sí. Si migras a un modelo nuevo, necesitas re-generar todos los embeddings de tu índice. Guarda siempre qué modelo generó qué vector.
Checklist de implementación
-
El modelo de embedding está fijado con versión explícita (no “latest”)
-
Los documentos se dividen en chunks de 300-500 tokens con overlap de 50-100 tokens
-
Los vectores se normalizan antes de almacenarse en la base de datos
-
Los embeddings de documentos se precomputan offline, no en tiempo de consulta
-
El modelo que generó cada vector está registrado junto al vector
-
Se usa similitud coseno (no distancia euclídea) para comparar vectores
-
Los chunks que superan el límite de tokens del modelo se detectan y manejan antes de llamar a la API
-
Hay una estrategia definida para re-indexar cuando se cambia de modelo
Preguntas Frecuentes
¿Cuántas dimensiones necesita un embedding para ser útil?
Depende de la tarea. Para búsqueda semántica estándar, 384 dimensiones (modelos como all-MiniLM-L6-v2) funcionan bien y son más eficientes en almacenamiento. Los modelos de OpenAI con 1536 o 3072 dimensiones capturan matices más finos y generalmente dan mejores resultados en tareas complejas, pero el salto de calidad no siempre justifica el coste extra. La forma de saberlo es medir sobre tus datos reales.
¿Qué diferencia hay entre embeddings de palabras (Word2Vec) y embeddings de oraciones?
Word2Vec genera un vector por palabra, siempre el mismo independientemente del contexto. “Banco” (mueble) y “banco” (financiero) tienen el mismo vector. Los modelos modernos de embeddings de oraciones como los de OpenAI son contextuales: la representación de una palabra depende de las palabras que la rodean. Esto los hace mucho más precisos para búsqueda semántica real.
¿Puedo usar embeddings sin base de datos vectorial?
Sí, y tiene sentido hacerlo en fases tempranas. Si tienes menos de 10.000 documentos, puedes guardar los vectores en un array en memoria o en un archivo JSON y calcular la similitud coseno con NumPy o con JavaScript puro. El código del ejemplo en este post funciona así. La base de datos vectorial se vuelve necesaria cuando el volumen crece o cuando necesitas filtros combinados (similitud + metadatos).
¿Los embeddings capturan el idioma?
Los modelos multilingüe como text-embedding-3-small de OpenAI están entrenados en múltiples idiomas y pueden comparar textos cross-language. Una consulta en inglés puede devolver documentos relevantes en español. Los modelos monolingüe son más precisos dentro de su idioma, pero fallan en comparaciones cross-language. Para aplicaciones en español con usuarios que escriben en español, un modelo multilingüe de calidad suele ser suficiente.
¿Cuándo usar búsqueda semántica versus búsqueda por palabras clave (BM25)?
No son mutuamente excluyentes. La búsqueda por palabras clave (BM25, Elasticsearch) es muy precisa cuando el usuario sabe exactamente qué término buscar y ese término está en los documentos. La búsqueda semántica brilla cuando el usuario describe un concepto con sus propias palabras o cuando los documentos usan vocabulario diferente al de la consulta. El patrón más robusto en producción es búsqueda híbrida: ejecutar ambas en paralelo y fusionar los resultados con un algoritmo como Reciprocal Rank Fusion (RRF).