Módulo 1: ¿Qué son Embeddings?
Casos de Uso Reales de Embeddings
Descripción de la cápsula
Los embeddings no son solo un concepto matemático abstracto—son la tecnología subyacente de las aplicaciones de AI más usadas en producción hoy.
En esta cápsula aprenderás los 5 casos de uso principales de embeddings en sistemas reales: semantic search, RAG (Retrieval-Augmented Generation), recommendation systems, document classification, y clustering. Verás ejemplos concretos de empresas que usan embeddings en producción y entenderás por qué son críticos para AI Engineering.
También aprenderás a identificar cuándo usar embeddings vs otras técnicas (keyword search, reglas, etc.).
Caso de Uso #1: Semantic Search
Qué es:
Búsqueda por significado, no por keywords exactas.
Ejemplo tradicional (keyword search):
Usuario busca: "cómo resetear mi laptop"
Sistema keyword (BM25):
✅ Encuentra: "resetear laptop", "reset laptop"
❌ NO encuentra: "reiniciar computadora", "reboot PC", "restaurar portátil"
Con embeddings (semantic search):
Usuario busca: "cómo resetear mi laptop"
Sistema semantic:
✅ Encuentra: "resetear laptop"
✅ Encuentra: "reiniciar computadora" (sinónimo)
✅ Encuentra: "reboot PC" (traducción conceptual)
✅ Encuentra: "restaurar portátil" (paráfrasis)
Por qué funciona: Embeddings capturan que "resetear", "reiniciar", "reboot", "restaurar" son conceptualmente similares.
Arquitectura típica:
1. Indexación (fase offline):
Documentos → Embed cada doc → Guardar en vector DB
2. Query (fase online):
Usuario query → Embed query → Buscar top-K similares → Retornar docs
Código conceptual:
from openai import OpenAI
import numpy as np
client = OpenAI()
# Paso 1: Indexación (una vez)
documents = [
"Cómo resetear tu laptop Windows",
"Reiniciar computadora Mac",
"Reboot PC después de actualización",
"Restaurar portátil a configuración de fábrica"
]
# Generar embeddings de documentos
doc_embeddings = []
for doc in documents:
response = client.embeddings.create(
model="text-embedding-3-small",
input=doc
)
doc_embeddings.append(response.data[0].embedding)
# Paso 2: Query (cada vez que usuario busca)
query = "cómo resetear mi laptop"
query_response = client.embeddings.create(
model="text-embedding-3-small",
input=query
)
query_embedding = query_response.data[0].embedding
# Paso 3: Calcular similaridades
def cosine_similarity(vec_a, vec_b):
return np.dot(vec_a, vec_b) / (
np.linalg.norm(vec_a) * np.linalg.norm(vec_b)
)
similarities = []
for i, doc_emb in enumerate(doc_embeddings):
sim = cosine_similarity(query_embedding, doc_emb)
similarities.append((i, sim))
# Ordenar por similaridad
similarities.sort(key=lambda x: x[1], reverse=True)
# Retornar top-3
print("Resultados más relevantes:")
for rank, (doc_id, sim) in enumerate(similarities[:3], 1):
print(f"{rank}. {documents[doc_id]} (score: {sim:.4f})")
Output esperado:
Resultados más relevantes:
1. Cómo resetear tu laptop Windows (score: 0.92)
2. Restaurar portátil a configuración de fábrica (score: 0.88)
3. Reiniciar computadora Mac (score: 0.85)
Empresas usando semantic search:
| Empresa | Aplicación | Escala |
|---|---|---|
| Notion | Buscar en workspace (docs, notas) | Millones de usuarios |
| Slack | Buscar mensajes/archivos | Millones de mensajes/día |
| GitHub | Code search (buscar código por función) | Millones de repos |
| Shopify | Product search (buscar productos por descripción) | Millones de productos |
| Intercom | Help center search | Cientos de miles de artículos |
Ventaja competitiva: Usuarios encuentran lo que buscan incluso con queries imprecisas.
Caso de Uso #2: RAG (Retrieval-Augmented Generation)
Qué es:
Darle a un LLM acceso a conocimiento externo mediante búsqueda semántica.
Problema sin RAG:
Usuario: "¿Cuál es la política de vacaciones de mi empresa?"
LLM sin RAG:
"No tengo información sobre las políticas específicas de tu empresa.
Generalmente, las empresas ofrecen 15-20 días..." ❌ Generic
Solución con RAG:
Usuario: "¿Cuál es la política de vacaciones de mi empresa?"
Sistema RAG:
1. Busca en docs internos con embeddings
2. Encuentra: "Política de vacaciones 2026: 25 días hábiles..."
3. LLM responde con ese contexto:
"Según la política de tu empresa (2026), tienes 25 días hábiles..." ✅ Específico
Flujo completo de RAG:
1. INDEXACIÓN (offline):
Documentos empresa → Chunking → Embed chunks → Vector DB
2. RETRIEVAL (online):
Usuario query → Embed query → Top-K chunks similares
3. AUGMENTATION (online):
Construir prompt: "Contexto: [chunks]\n\nQuestion: [query]"
4. GENERATION (online):
LLM genera respuesta usando contexto
Código conceptual:
from openai import OpenAI
import numpy as np
client = OpenAI()
# Paso 1: Indexar documentos (empresa interna)
knowledge_base = [
"Política de vacaciones 2026: Los empleados tienen derecho a 25 días hábiles de vacaciones por año.",
"Horario de trabajo: Lunes a viernes 9am-6pm. Viernes flexibles (home office).",
"Beneficios médicos: Seguro de salud cubierto 100% para empleado y 50% para familia."
]
kb_embeddings = []
for doc in knowledge_base:
response = client.embeddings.create(
model="text-embedding-3-small",
input=doc
)
kb_embeddings.append(response.data[0].embedding)
# Paso 2: Usuario hace pregunta
user_question = "¿Cuántos días de vacaciones tengo?"
# Paso 3: Retrieval (buscar contexto relevante)
query_response = client.embeddings.create(
model="text-embedding-3-small",
input=user_question
)
query_embedding = query_response.data[0].embedding
# Encontrar top-1 más relevante
similarities = [
(i, cosine_similarity(query_embedding, kb_emb))
for i, kb_emb in enumerate(kb_embeddings)
]
similarities.sort(key=lambda x: x[1], reverse=True)
most_relevant_idx = similarities[0][0]
context = knowledge_base[most_relevant_idx]
print(f"Contexto recuperado: {context}\n")
# Paso 4: Augmented prompt
augmented_prompt = f"""Contexto: {context}
Pregunta: {user_question}
Responde usando SOLO la información del contexto proporcionado."""
# Paso 5: Generation
chat_response = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": augmented_prompt}]
)
answer = chat_response.choices[0].message.content
print(f"Respuesta RAG: {answer}")
Output:
Contexto recuperado: Política de vacaciones 2026: Los empleados tienen derecho a 25 días hábiles de vacaciones por año.
Respuesta RAG: Según la política de vacaciones 2026, tienes derecho a 25 días hábiles de vacaciones por año.
Empresas usando RAG:
| Empresa | Aplicación | Datos |
|---|---|---|
| Notion AI | Q&A sobre workspace del usuario | Docs privados |
| ChatGPT (GPTs) | Custom GPTs con conocimiento específico | PDFs, sitios web |
| Perplexity | Search con citations | Web crawl |
| Intercom Fin | Customer support automation | Help center |
| Glean | Enterprise search con AI | Confluence, Google Drive, Slack |
Valor: LLMs responden con información actualizada y específica del contexto.
Caso de Uso #3: Recommendation Systems
Qué es:
Sugerir contenido similar basándote en embeddings de items.
Ejemplo: Netflix
Usuario está viendo: "Stranger Things"
Sistema:
1. Embed descripción de "Stranger Things"
2. Buscar shows con embeddings similares
3. Recomendar: "Dark", "The Umbrella Academy", "Black Mirror"
Por qué funciona: Embeddings capturan temas (sci-fi, supernatural, drama).
Arquitectura típica:
1. Embed todos los items (películas, productos, artículos)
2. Usuario consume item X
3. Buscar items con embeddings similares a X
4. Recomendar top-K más similares
Código conceptual:
# Paso 1: Indexar productos (e-commerce)
products = [
{"id": 1, "name": "Laptop Dell XPS 13", "desc": "Laptop ultrabook compacta para desarrollo"},
{"id": 2, "name": "Laptop MacBook Pro", "desc": "Laptop premium para creativos y developers"},
{"id": 3, "name": "Mouse Logitech MX Master", "desc": "Mouse ergonómico para productividad"},
{"id": 4, "name": "Teclado mecánico", "desc": "Teclado mecánico para gaming y programación"},
{"id": 5, "name": "Monitor 4K", "desc": "Monitor ultra HD para diseño y edición"}
]
# Embed productos
product_embeddings = {}
for product in products:
response = client.embeddings.create(
model="text-embedding-3-small",
input=product["desc"]
)
product_embeddings[product["id"]] = response.data[0].embedding
# Paso 2: Usuario vio producto X
user_viewed_product_id = 1 # Laptop Dell XPS 13
user_viewed_embedding = product_embeddings[user_viewed_product_id]
# Paso 3: Encontrar productos similares
similarities = []
for prod_id, prod_emb in product_embeddings.items():
if prod_id == user_viewed_product_id:
continue # No recomendar el mismo
sim = cosine_similarity(user_viewed_embedding, prod_emb)
similarities.append((prod_id, sim))
similarities.sort(key=lambda x: x[1], reverse=True)
# Paso 4: Recomendar top-3
print("Productos recomendados:")
for rank, (prod_id, sim) in enumerate(similarities[:3], 1):
product = next(p for p in products if p["id"] == prod_id)
print(f"{rank}. {product['name']} (score: {sim:.4f})")
Output:
Productos recomendados:
1. Laptop MacBook Pro (score: 0.88)
2. Teclado mecánico (score: 0.72)
3. Monitor 4K (score: 0.68)
Empresas usando recommendations con embeddings:
| Empresa | Aplicación | Método |
|---|---|---|
| Netflix | Movie/show recommendations | Embeddings de descripciones + user behavior |
| Spotify | Song/playlist recommendations | Audio embeddings + metadata |
| Amazon | Product recommendations | Product description embeddings |
| Medium | Article recommendations | Article content embeddings |
| YouTube | Video recommendations | Video title/description embeddings |
Caso de Uso #4: Document Classification
Qué es:
Clasificar documentos en categorías usando embeddings + clasificador simple.
Ejemplo: Email routing
Email: "Mi factura tiene un error en el monto..."
Sistema:
1. Embed email
2. Comparar con embeddings de categorías:
- Billing (facturación)
- Technical Support
- Sales
3. Clasificar como "Billing"
4. Rutear a equipo correcto
Arquitectura típica:
1. Entrenar (crear embeddings de categorías):
- Embed ejemplos de cada categoría
- Calcular "embedding promedio" por categoría
2. Clasificar (runtime):
- Embed documento nuevo
- Calcular similaridad a cada categoría
- Asignar a categoría más similar
Código conceptual:
# Paso 1: Definir categorías con ejemplos
categories = {
"Billing": [
"Mi factura tiene un error",
"Quiero cancelar mi suscripción",
"No reconozco este cargo"
],
"Technical Support": [
"La app no carga",
"Error al hacer login",
"No puedo acceder a mi cuenta"
],
"Sales": [
"Quiero información sobre el plan empresarial",
"¿Cuál es el precio del plan Pro?",
"Necesito una demo del producto"
]
}
# Paso 2: Crear embedding promedio por categoría
category_embeddings = {}
for category, examples in categories.items():
# Embed cada ejemplo
embeddings = []
for example in examples:
response = client.embeddings.create(
model="text-embedding-3-small",
input=example
)
embeddings.append(response.data[0].embedding)
# Promedio
category_embeddings[category] = np.mean(embeddings, axis=0)
# Paso 3: Clasificar nuevo documento
new_email = "No puedo pagar mi factura del mes pasado"
email_response = client.embeddings.create(
model="text-embedding-3-small",
input=new_email
)
email_embedding = email_response.data[0].embedding
# Paso 4: Encontrar categoría más similar
similarities = []
for category, cat_emb in category_embeddings.items():
sim = cosine_similarity(email_embedding, cat_emb)
similarities.append((category, sim))
similarities.sort(key=lambda x: x[1], reverse=True)
print(f"Email: '{new_email}'")
print(f"\nClasificado como: {similarities[0][0]} (score: {similarities[0][1]:.4f})")
Output:
Email: 'No puedo pagar mi factura del mes pasado'
Clasificado como: Billing (score: 0.89)
Empresas usando classification:
| Empresa | Aplicación | Categorías |
|---|---|---|
| Zendesk | Ticket routing | 10-50 categorías (billing, tech, sales...) |
| Gmail | Smart categorization | Primary, Social, Promotions, Updates |
| Superhuman | Email triage | Important, Later, Archive |
| Content moderation | Spam, Hate speech, Safe |
Caso de Uso #5: Document Clustering
Qué es:
Agrupar documentos similares automáticamente sin categorías predefinidas.
Ejemplo: Organizar tickets de soporte
1000 tickets sin etiquetar
Sistema clustering:
1. Embed todos los tickets
2. Aplicar clustering (K-Means)
3. Resultado automático:
- Cluster 1: Problemas de login (~250 tickets)
- Cluster 2: Errores de facturación (~180 tickets)
- Cluster 3: Bugs de la app (~320 tickets)
- Cluster 4: Preguntas sobre features (~200 tickets)
- Cluster 5: Otros (~50 tickets)
Arquitectura típica:
1. Embed todos los documentos
2. Aplicar algoritmo de clustering:
- K-Means (si sabes # de clusters)
- DBSCAN (si NO sabes # de clusters)
3. Analizar clusters resultantes
4. Etiquetar clusters manualmente (opcional)
Código conceptual:
from sklearn.cluster import KMeans
import numpy as np
# Paso 1: Documentos a clusterizar
documents = [
"No puedo hacer login en mi cuenta",
"Error al iniciar sesión",
"Mi factura tiene un monto incorrecto",
"Cargo duplicado en mi tarjeta",
"La app se cierra inesperadamente",
"Crash al abrir la app",
"¿Cómo funciona la feature X?",
"Documentación sobre feature Y"
]
# Paso 2: Generar embeddings
doc_embeddings = []
for doc in documents:
response = client.embeddings.create(
model="text-embedding-3-small",
input=doc
)
doc_embeddings.append(response.data[0].embedding)
doc_embeddings_array = np.array(doc_embeddings)
# Paso 3: Clustering con K-Means (4 clusters)
kmeans = KMeans(n_clusters=4, random_state=42)
clusters = kmeans.fit_predict(doc_embeddings_array)
# Paso 4: Mostrar resultados
from collections import defaultdict
clustered_docs = defaultdict(list)
for doc, cluster_id in zip(documents, clusters):
clustered_docs[cluster_id].append(doc)
print("Clustering automático:")
for cluster_id, docs in clustered_docs.items():
print(f"\nCluster {cluster_id}:")
for doc in docs:
print(f" - {doc}")
Output esperado:
Clustering automático:
Cluster 0:
- No puedo hacer login en mi cuenta
- Error al iniciar sesión
Cluster 1:
- Mi factura tiene un monto incorrecto
- Cargo duplicado en mi tarjeta
Cluster 2:
- La app se cierra inesperadamente
- Crash al abrir la app
Cluster 3:
- ¿Cómo funciona la feature X?
- Documentación sobre feature Y
Empresas usando clustering:
| Empresa | Aplicación | Escala |
|---|---|---|
| Zendesk | Identificar temas comunes en tickets | Millones de tickets |
| Agrupar tweets trending | Miles de tweets/segundo | |
| Google News | Agrupar noticias del mismo evento | Miles de artículos/día |
| Agrupar posts similares | Millones de posts |
Comparación: Cuándo usar embeddings
Embeddings vs Keyword Search:
| Aspecto | Keyword Search (BM25) | Embeddings (Semantic) |
|---|---|---|
| Búsqueda exacta | ✅ Excelente | ⚠️ Puede sobre-generalizar |
| Sinónimos | ❌ No encuentra | ✅ Encuentra |
| Paráfrasis | ❌ No encuentra | ✅ Encuentra |
| IDs, códigos | ✅ Perfecto | ❌ Puede confundir |
| Búsqueda multiidioma | ❌ Difícil | ✅ Funciona (si modelo multiidioma) |
| Velocidad | ✅ Muy rápida | ⚠️ Más lenta (requiere index especial) |
| Costo | ✅ Gratis (Elasticsearch) | ⚠️ API calls (o GPU local) |
Mejor approach: Híbrido (keyword + semantic).
Embeddings vs Rules:
| Caso de Uso | Rules | Embeddings |
|---|---|---|
| Email routing | Reglas: if "factura" → Billing | ✅ Mejor: Captura variaciones |
| Spam detection | Reglas: Blacklist keywords | ✅ Mejor: Generaliza |
| Product matching | Reglas: Match SKU exacto | ⚠️ Depends: SKU exacto = rules mejor |
| Content moderation | Reglas: Lista de palabras prohibidas | ✅ Mejor: Detecta contexto |
Regla general: Si hay variabilidad lingüística → Embeddings. Si es exacto (IDs, códigos) → Rules.
Casos de uso avanzados
1. Cross-lingual search (búsqueda multiidioma):
# Usuario busca en español, encuentra docs en inglés:
query_es = "cómo instalar Python"
doc_en = "How to install Python on Windows"
# Con modelo multiidioma (OpenAI, multilingual-SBERT):
emb_query_es = embed(query_es)
emb_doc_en = embed(doc_en)
similarity = cosine_similarity(emb_query_es, emb_doc_en) # → ~0.90 ✅
Aplicación: Soporte multiidioma sin traducir todo el contenido.
2. Duplicate detection:
# Detectar tickets duplicados:
ticket_1 = "No puedo hacer login"
ticket_2 = "Error al iniciar sesión"
emb_1 = embed(ticket_1)
emb_2 = embed(ticket_2)
if cosine_similarity(emb_1, emb_2) > 0.90:
print("Tickets duplicados") # ✅
Aplicación: Reducir trabajo redundante en customer support.
3. Personalization:
# Perfil de usuario = embedding promedio de items que le gustaron:
user_liked_items = [item_1, item_2, item_3]
user_profile_emb = np.mean([embed(item) for item in user_liked_items], axis=0)
# Recomendar items similares al perfil:
for item in catalog:
sim = cosine_similarity(user_profile_emb, embed(item))
if sim > 0.80:
recommend(item)
4. Anomaly detection:
# Detectar logs anómalos:
normal_logs = ["User login successful", "Payment processed", ...]
normal_embeddings = [embed(log) for log in normal_logs]
avg_normal_emb = np.mean(normal_embeddings, axis=0)
# Nuevo log:
new_log = "Database connection failed 50 times"
new_log_emb = embed(new_log)
# Si muy diferente del promedio → Anomalía
sim = cosine_similarity(new_log_emb, avg_normal_emb)
if sim < 0.60:
alert("Log anómalo detectado")
Ejercicios
Ejercicio 1: Semantic search simple
Implementa búsqueda semántica en 3 documentos:
documents = [
"Python es un lenguaje de programación",
"El gato duerme en el sofá",
"JavaScript es usado en web development"
]
query = "Lenguaje para programar"
# Encuentra el documento más relevante
Ver solución
from openai import OpenAI
import numpy as np
import os
from dotenv import load_dotenv
load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
def get_embedding(text):
response = client.embeddings.create(
model="text-embedding-3-small",
input=text
)
return np.array(response.data[0].embedding)
def cosine_similarity(vec_a, vec_b):
return np.dot(vec_a, vec_b) / (np.linalg.norm(vec_a) * np.linalg.norm(vec_b))
documents = [
"Python es un lenguaje de programación",
"El gato duerme en el sofá",
"JavaScript es usado en web development"
]
query = "Lenguaje para programar"
# Embed documentos
doc_embeddings = [get_embedding(doc) for doc in documents]
# Embed query
query_embedding = get_embedding(query)
# Calcular similaridades
similarities = [
(i, cosine_similarity(query_embedding, doc_emb))
for i, doc_emb in enumerate(doc_embeddings)
]
# Ordenar
similarities.sort(key=lambda x: x[1], reverse=True)
# Resultado
print("Resultados:")
for rank, (doc_id, sim) in enumerate(similarities, 1):
print(f"{rank}. {documents[doc_id]} (score: {sim:.4f})")
Output esperado:
Resultados:
1. Python es un lenguaje de programación (score: 0.87)
2. JavaScript es usado en web development (score: 0.75)
3. El gato duerme en el sofá (score: 0.58)
Ejercicio 2: Clasificador simple
Clasifica un email en 2 categorías (Technical o Billing):
categories = {
"Technical": ["La app no funciona", "Error al hacer login"],
"Billing": ["Mi factura está mal", "Quiero cancelar suscripción"]
}
new_email = "No puedo acceder a mi cuenta"
# Clasifica el email
Ver solución
# Embed categorías (promedio de ejemplos)
category_embeddings = {}
for category, examples in categories.items():
embeddings = [get_embedding(ex) for ex in examples]
category_embeddings[category] = np.mean(embeddings, axis=0)
# Embed nuevo email
email_embedding = get_embedding(new_email)
# Encontrar categoría más similar
similarities = []
for category, cat_emb in category_embeddings.items():
sim = cosine_similarity(email_embedding, cat_emb)
similarities.append((category, sim))
similarities.sort(key=lambda x: x[1], reverse=True)
print(f"Email: '{new_email}'")
print(f"Clasificado como: {similarities[0][0]} (score: {similarities[0][1]:.4f})")
Output:
Email: 'No puedo acceder a mi cuenta'
Clasificado como: Technical (score: 0.92)
Ejercicio 3: Recommendations
Recomienda 2 productos similares:
products = [
"Laptop para programación",
"Mouse inalámbrico",
"Teclado mecánico",
"Monitor 4K"
]
user_viewed = "Laptop para programación"
# Recomienda 2 productos similares (excluyendo el visto)
Ver solución
# Embed productos
product_embeddings = {
prod: get_embedding(prod) for prod in products
}
# Embedding del producto visto
viewed_embedding = product_embeddings[user_viewed]
# Calcular similaridades
similarities = []
for prod, prod_emb in product_embeddings.items():
if prod == user_viewed:
continue # Excluir el mismo
sim = cosine_similarity(viewed_embedding, prod_emb)
similarities.append((prod, sim))
# Ordenar y tomar top-2
similarities.sort(key=lambda x: x[1], reverse=True)
print("Recomendaciones:")
for rank, (prod, sim) in enumerate(similarities[:2], 1):
print(f"{rank}. {prod} (score: {sim:.4f})")
Output esperado:
Recomendaciones:
1. Teclado mecánico (score: 0.76)
2. Monitor 4K (score: 0.72)
Resumen
Qué aprendiste:
- ✅ Semantic Search: Buscar por significado, no keywords
- ✅ RAG: Darle conocimiento externo a LLMs
- ✅ Recommendations: Sugerir items similares
- ✅ Classification: Categorizar documentos automáticamente
- ✅ Clustering: Agrupar documentos sin supervisión
Casos de uso reales:
- Notion, Slack → Semantic search
- ChatGPT, Perplexity → RAG
- Netflix, Spotify → Recommendations
- Zendesk, Gmail → Classification
- Google News, Reddit → Clustering
Cuándo usar embeddings:
- ✅ Variabilidad lingüística (sinónimos, paráfrasis)
- ✅ Búsqueda semántica
- ⚠️ Híbrido con keywords para mejor resultado
Recursos adicionales
- RAG Explained - Guía completa
- Semantic Search Tutorial - SBERT
- Recommendations with Embeddings - OpenAI
- Document Clustering - Scikit-learn
- Hybrid Search - Elasticsearch
En la siguiente cápsula
Cápsula 06: Embeddings vs Keywords
Aprenderás:
- BM25 (keyword matching) en detalle
- Cuándo embeddings > keywords
- Cuándo keywords > embeddings
- Hybrid search (mejor de ambos mundos)
- Implementación práctica de comparación
De casos de uso a decisiones de arquitectura.
Módulo 1 - Embeddings Deep Dive Guide Aplicaciones reales que transforman industrias