RAG con Enrichment LLM: De Texto Plano a Inteligencia Semántica
Teníamos un chatbot RAG funcional. Respondía preguntas, citaba fuentes, multilingüe. Pero no entendía — buscaba coincidencias de palabras, no significado. Con una inversión de $0.05 y un pipeline de enrichment con DeepSeek, la precisión mejoró un ~40%.
1 El problema: búsqueda literal, no semántica
En nuestro artículo anterior construimos un pipeline RAG completo: contenido HTML → chunks de ~150 palabras → embeddings con bge-m3 → Cloudflare Vectorize → contexto para DeepSeek. Funcionaba. Pero al analizar las respuestas, detectamos un patrón recurrente.
🔍 Queries problemáticas reales
"¿Cuánto cuesta Cadences?"
Devolvía chunks de FAQ y capacidades en vez de la sección de pricing → respuesta vaga sin cifras
"¿Cómo funciona Perspectiva Studio?"
Mezclaba chunks de Synapse Studio, CIMAD y Perspectiva → la IA confundía productos
"¿Qué hace la demo de restaurantes?"
Traía chunks de la landing genérica porque "restaurantes" aparecía en texto secundario
El problema no era el modelo de embeddings ni el vector search — ambos funcionaban correctamente. El problema era más profundo: el gap semántico entre cómo pregunta un usuario y cómo está escrito el contenido.
2 El gap semántico: por qué fallan los embeddings "crudos"
Un embedding es un vector de 1024 números que captura el significado de un texto. Pero "significado" no es lo mismo que "contenido". El usuario pregunta con intención; el documento está escrito con información. Esos dos espacios semánticos no siempre coinciden.
"¿cuánto cuesta?"
Espacio semántico: pricing, precio, plan, tarifa, coste
"Cadences ofrece tres niveles de servicio con facturación mensual. El plan Business incluye..."
Espacio semántico: servicio, niveles, facturación, business, incluye
El vector de "¿cuánto cuesta?" y el vector de "tres niveles de servicio con facturación mensual" tienen una similaridad moderada — suficiente para rankear 4º o 5º, pero no 1º. Y en un TOP_K=5, la posición importa: el LLM da más peso a los primeros chunks del prompt.
3 La solución: HyDE — Hypothetical Document Embeddings
HyDE es una técnica publicada por Gao et al. (2022) con una idea elegante: si el problema es que queries y documentos viven en espacios semánticos diferentes, genera un documento hipotético que respondería la query y usa ese texto para buscar. El documento hipotético está más cerca del espacio semántico del contenido real.
Nosotros aplicamos la variante inversa de HyDE — en vez de enriquecer la query, enriquecemos cada chunk en tiempo de indexación. La ventaja: el coste se paga una sola vez, no en cada query.
💡 Enriquecimiento por chunk (una sola vez)
Para cada chunk, un LLM genera:
- summary — 1-2 frases que capturan la esencia semántica, no un resumen extractivo
- keywords — 5-8 términos clave normalizados y en minúsculas
- questions — 2-3 preguntas que este chunk respondería (la "H" de HyDE)
- product — a qué producto pertenece (cadences, perspectiva-studio, cimad, synapse...)
- content_type — tipo de contenido (tutorial, referencia, pricing, faq, demo...)
Las questions son la clave: al incluirlas en el texto que se embediza, el vector del chunk ahora vive también en el espacio semántico de las preguntas del usuario. "¿Cuánto cuesta Cadences?" matchea directamente con la pregunta hipotética "¿Cuánto cuesta la plataforma?" generada para el chunk de pricing.
4 Antes y después: arquitectura completa
| Componente | v1 | v2 |
|---|---|---|
| Embedding input | [title | category] text | Summary + Keywords + Questions + text |
| Vectorize metadata | slug, title, category | + product, content_type |
| D1 storage | chunk_text (raw) | chunk_text + enrichment JSON |
| Context al LLM | [Source: Title (Cat)] text | [Source: Title (Cat/Product)]\nSummary: ...\nKeywords: ...\ntext |
| Coste de indexación | $0 (solo embeddings gratis) | < $0.05 (DeepSeek enrichment) |
5 Implementación: el prompt de enrichment
Cada chunk (577 en total: landing pages, demos, documentación interna) se envía a DeepSeek V3 con un system prompt diseñado para generar output JSON estructurado. Se usa temperature: 0.2 para máxima consistencia.
You are a content analysis assistant. Analyze the following content chunk and return a JSON object: { "summary": "1-2 sentence semantic summary (same language as input)", "keywords": ["5-8 key terms, lowercase, normalized"], "questions": ["2-3 questions this chunk answers (same language)"], "product": "cadences|perspectiva-studio|cimad|synapse|codex|void|general", "content_type": "tutorial|reference|feature|pricing|faq|demo|overview|guide" } Return ONLY the JSON object. No markdown formatting. Detect the language of the input and respond in that same language.
El user message incluye el título, categoría y sección del chunk para dar contexto al LLM antes de analizar el texto:
Content chunk to analyze: ─────────────── Title: Cadences Platform Overview Category: Landing Section: Hero Text: Cadences es una plataforma todo-en-uno que integra CRM, automatización, IA y storefronts profesionales...
6 El embedding enriquecido: de literal a semántico
La diferencia clave está en qué texto llega al modelo de embeddings. Con v2, el vector captura semántica, no solo palabras.
[Cadences Platform | Landing | Hero]
Cadences es una plataforma todo-en-uno
que integra CRM, automatización, IA y
storefronts profesionales... Vector captura: "plataforma", "CRM", "automatización", "storefronts"
[Cadences Platform | Landing | Hero] Summary: Cadences es una plataforma SaaS todo-en-uno que integra CRM, IA, automatización y storefronts, construida sobre Cloudflare Workers. Keywords: cadences, plataforma, saas, crm, ia, automatización, storefronts Questions: ¿Qué es Cadences? ¿Qué incluye la plataforma Cadences? ¿Sobre qué tecnología está construida? --- Cadences es una plataforma todo-en-uno que integra CRM, automatización, IA y storefronts profesionales...
Vector captura: semántica + intención del usuario + keywords normalizadas
7 Pipeline de ejecución: 577 chunks en ~3 minutos
El indexer v2 ejecuta un pipeline de 6 pasos:
Extracción de contenido
HTML → stripHtml → chunkText (~150 palabras, 50 overlap). 26 archivos HTML internos + landing pages + demos + documentación.
Enrichment LLM (DeepSeek V3)
Batches de 5 chunks en paralelo, 300ms entre lotes. Cada chunk genera ~200 tokens de output. Rate limiting automático con fallback silencioso.
Embedding enriquecido (bge-m3)
El texto original + summary + keywords + questions pasa por @cf/baai/bge-m3 (1024 dims). Batches de 50 vía Workers AI. Gratis.
Upsert a Vectorize
Vectores + metadata enriquecida (product, content_type). Mismo índice compartido con blog y CadencesLab. Namespace = idioma (es/en).
Almacenamiento en D1
chunk_text + enrichment JSON completo en SQLite. Preserva chunks de blog (slug_*) y CadencesLab (lab_*). Solo sobrescribe land_*.
Verificación y resumen
Desglose por categoría, idioma y producto (auto-detectado por LLM). Valida integridad embeddings ↔ vectores ↔ D1 rows.
8 El chatbot también mejora: contexto enriquecido
No solo mejora el retrieval. El propio contexto que recibe el LLM del chatbot es ahora más denso y estructurado:
[Source 1: Pricing (Landing) — URL]
Cadences ofrece tres niveles de servicio
con facturación mensual. El plan Business
incluye 10 agentes IA, CRM completo y
5 storefronts profesionales... [Source 1: Pricing (Landing/cadences) — URL] Summary: Planes y precios de Cadences con tres niveles: Starter, Business y Enterprise, con facturación mensual. Keywords: pricing, planes, precios, starter, business, enterprise, coste Cadences ofrece tres niveles de servicio con facturación mensual. El plan Business incluye 10 agentes IA, CRM completo y 5 storefronts profesionales...
El LLM del chatbot ahora "lee" un resumen antes del texto raw. Sabe que está leyendo sobre pricing de Cadences (no de otro producto) y tiene keywords que puede usar directamente en su respuesta. La calidad de las respuestas mejora sin cambiar el modelo ni el prompt del sistema.
9 Stack técnico y costes reales
| Componente | Tecnología | Coste |
|---|---|---|
| Enrichment LLM | DeepSeek V3 (deepseek-chat) | ~$0.03 |
| Embedding model | @cf/baai/bge-m3 (1024 dims, multilingüe) | Gratis |
| Vector search | Cloudflare Vectorize (~5ms queries) | Gratis |
| Text storage | Cloudflare D1 (SQLite edge) | Gratis |
| Chatbot LLM | DeepSeek V3 → Llama 3.1 8B (fallback) | ~$0.001/query |
| Indexer runtime | Node.js (local o CI) | $0 |
Chunks enriquecidos
Coste total
Tiempo de indexación
Mejora en precisión
10 Lecciones aprendidas y próximos pasos
1. El RAG es un pipeline, no un componente
Mejorar la calidad de un RAG no requiere cambiar el modelo de embeddings ni el LLM. A veces el mayor impacto está en qué texto se embediza, no en cómo. El enrichment es un paso previo que multiplica el efecto de todo lo que viene después.
2. HyDE inverso > HyDE en runtime
Enriquecer en tiempo de indexación en vez de en cada query tiene ventajas claras: coste fijo (una vez), latencia cero en runtime, y el resultado se puede inspeccionar y debuggear. La desventaja (rigidez) se mitiga re-indexando cuando cambia el contenido.
3. Metadata como filtro, no solo como decoración
Añadir product y content_type a la metadata de Vectorize permite hacer pre-filtrado. En v3 podremos filtrar "solo chunks de Perspectiva Studio" o "solo pricing" antes del ranking vectorial.
4. DeepSeek V3 es impresionantemente barato para esto
577 análisis de contenido por $0.03. La relación coste/calidad de DeepSeek para tareas de análisis estructurado es difícil de superar. GPT-4o costaría 20x más para el mismo resultado.
🔮 Próximos pasos (v3)
- Reranking — Usar un cross-encoder ligero (bge-reranker-v2) después del vector search para reordenar por relevancia semántica real
- Query enrichment — Expandir queries cortas del usuario con sinónimos e intención antes de buscar
- Metadata filtering en Vectorize — Filtrar por producto/tipo antes del ranking vectorial cuando la query menciona un producto específico
- Feedback loop — Trackear qué chunks se usan en respuestas positivas para ajustar el scoring
FAQ — Preguntas frecuentes
¿Qué es HyDE y por qué mejora el RAG?
HyDE (Hypothetical Document Embeddings) genera documentos hipotéticos que responderían a una query. Al incluir preguntas hipotéticas en los embeddings de cada chunk, el vector search encuentra contenido relevante por intención, no solo por coincidencia literal de palabras.
¿Cuánto cuesta implementar enrichment LLM?
Con DeepSeek V3, menos de $0.05 para ~600 chunks. El modelo de embeddings (bge-m3), el vector store (Vectorize), y la base de datos (D1) son gratuitos en Cloudflare. El coste total de mejorar un RAG completo es menor que un café.
¿Necesito cambiar el modelo de embeddings?
No. El mismo modelo (bge-m3, 1024 dimensiones) funciona mejor cuando recibe texto enriquecido. El truco no es cambiar el modelo, sino mejorar la calidad del texto que llega al modelo.
¿Funciona con otros LLMs además de DeepSeek?
Sí. El prompt de enrichment es estándar — funciona con GPT-4o, Claude, Llama, Gemini o cualquier modelo que genere JSON estructurado. DeepSeek V3 se eligió por su relación calidad/precio excepcional para tareas de análisis.
¿Con qué frecuencia hay que re-indexar?
Solo cuando cambia el contenido. El enrichment se ejecuta en tiempo de indexación (no por query), así que el coste es fijo y predecible. Un re-index completo toma ~3 minutos y cuesta ~$0.05.
Cadences Engineering
Documentación técnica del equipo de ingeniería