TL;DR: RAG (Retrieval-Augmented Generation) es la técnica que da a un LLM acceso a tu documentación propia en tiempo real. Sin RAG, el modelo inventa o usa conocimiento genérico. Con RAG bien hecho, las alucinaciones bajan del 30-40% al <5%.
El problema que resuelve RAG
Un LLM como GPT-4o o Claude sabe muchísimo del mundo, pero no sabe nada específico de tu empresa:
- No conoce tus productos exactos ni sus precios actuales
- No sabe tu política de devoluciones
- No conoce los protocolos internos de tu equipo
- No tiene acceso a información posterior a su fecha de entrenamiento
Si le preguntas algo específico, hace una de tres cosas:
- Te dice “no tengo información sobre eso” (lo bueno, raro)
- Inventa una respuesta plausible (lo malo, frecuente)
- Te responde con info genérica que puede no aplicar (lo regular)
Las opciones 2 y 3 son alucinaciones: el modelo dice cosas que suenan bien pero son incorrectas. En contexto profesional son inaceptables.
Cómo funciona RAG en 5 pasos
1. Usuario: "¿Cuáles son las horas de atención del servicio premium?"
↓
2. Sistema: convierte la pregunta a un vector (embedding) de 1.536 dimensiones
↓
3. Búsqueda: encuentra en la vector DB los 3 fragmentos más similares
(probablemente el PDF "Manual Servicio Premium 2026" sección horarios)
↓
4. Prompt aumentado: envía al LLM la pregunta + los fragmentos como contexto
"Contexto: [fragmentos]. Pregunta: ¿horas atención premium?
Responde SOLO con la información del contexto."
↓
5. LLM responde: "Según nuestra documentación, el servicio premium se atiende
de lunes a viernes de 9:00 a 19:00 y sábados de 10:00 a 14:00."
El cambio clave: el LLM no usa su conocimiento general, usa el contexto que le acabas de pasar de tu documentación.
Por qué los embeddings son la pieza central
Un embedding es una representación numérica de un texto en un espacio vectorial de alta dimensión (típicamente 768 a 3.072 dimensiones).
Dos textos con significado parecido tendrán vectores cercanos en ese espacio, incluso si usan palabras diferentes:
- “¿En qué horario atendéis?”
- “Cuándo puedo llamaros”
- “Horas de servicio al cliente”
Los tres tendrán vectores muy cercanos a “horas de atención” en tu documentación, aunque comparten muy pocas palabras literales.
Modelos de embeddings populares (2026)
| Modelo | Dimensiones | Coste por 1M tokens | Calidad |
|---|---|---|---|
| OpenAI text-embedding-3-small | 1.536 (configurable) | 0,02 $ | Muy buena |
| OpenAI text-embedding-3-large | 3.072 (configurable) | 0,13 $ | Excelente |
| Voyage AI voyage-3 | 1.024 | 0,12 $ | Excelente, mejor en multilingüe |
| Cohere embed-v3.0 multilingual | 1.024 | 0,10 $ | Excelente en español |
| BGE-M3 (open source) | 1.024 | 0 (self-hosted) | Muy buena, gratis |
Vector databases: dónde guardar los embeddings
| DB | Modelo | Pros | Contras |
|---|---|---|---|
| Pinecone | SaaS | Sin mantenimiento, escala bien | Caro a escala |
| Qdrant | Open source, self-hosted o cloud | Rápido, muchas features, gratis self-host | Requiere operar servidor |
| Weaviate | Open source, self-host o cloud | Buen schema, módulos integrados | Curva de aprendizaje |
| PostgreSQL + pgvector | Extensión PG | Si ya tienes Postgres, todo en uno | Más lento que dedicadas a gran escala |
| Chroma | Open source, embebida | Ideal para prototipos rápidos | No production-ready a gran escala |
Recomendación 2026:
- Prototipo / POC: Chroma o pgvector
- Producción pequeña-mediana (<10M vectores): Qdrant self-hosted
- Producción grande / multi-tenant: Pinecone Serverless
Pipeline de RAG paso a paso
Fase 1: ingesta (offline, ocurre una vez o periódicamente)
// 1. Cargar el documento
const text = await loadPdf("manual-premium.pdf");
// 2. Dividir en chunks (clave para retrieval de calidad)
const chunks = splitText(text, {
chunkSize: 800, // tokens
chunkOverlap: 100, // tokens (mantener contexto entre chunks)
separators: ["\n\n", "\n", ". ", " "],
});
// 3. Generar embeddings de cada chunk
const embeddings = await openai.embeddings.create({
model: "text-embedding-3-small",
input: chunks.map((c) => c.text),
});
// 4. Subir a vector DB con metadata
await qdrant.upsert("documentos", {
points: chunks.map((chunk, i) => ({
id: `${docId}-${i}`,
vector: embeddings.data[i].embedding,
payload: {
docId,
filename: "manual-premium.pdf",
page: chunk.page,
text: chunk.text,
source_url: "/documentos/manual-premium.pdf",
},
})),
});
Fase 2: query (online, cada vez que un usuario pregunta)
async function answerWithRAG(userQuestion: string) {
// 1. Embedding de la pregunta
const { data } = await openai.embeddings.create({
model: "text-embedding-3-small",
input: userQuestion,
});
// 2. Búsqueda por similitud
const results = await qdrant.search("documentos", {
vector: data[0].embedding,
limit: 4,
score_threshold: 0.75, // descartar matches débiles
});
// 3. Si no hay matches buenos, no inventar
if (results.length === 0) {
return "No tengo información sobre esa consulta. ¿Te paso con un compañero?";
}
// 4. Construir prompt con contexto
const context = results
.map((r, i) => `[Fuente ${i + 1}: ${r.payload.filename}, p.${r.payload.page}]\n${r.payload.text}`)
.join("\n\n---\n\n");
// 5. Llamar al LLM con guardrail
const response = await openai.chat.completions.create({
model: "gpt-4o",
messages: [
{
role: "system",
content:
"Eres el asistente de Acme. Responde EXCLUSIVAMENTE con la información del contexto. " +
"Si la respuesta no está en el contexto, di '\\u00a1Disculpa, no tengo esa información!' " +
"y NO inventes nada. Cita la fuente cuando sea relevante.",
},
{ role: "user", content: `Contexto:\n${context}\n\nPregunta: ${userQuestion}` },
],
temperature: 0.2, // baja para reducir creatividad
});
return response.choices[0].message.content;
}
Lo que diferencia un RAG mediocre de uno excelente
1. Chunking de calidad
Si troceas mal el documento, los embeddings no captan el contexto. Buenos chunk:
- 500-1.000 tokens (no más, no menos)
- Solapamiento de 10-15% entre chunks
- Respetar separadores naturales (párrafos, secciones)
- Para Markdown: aprovecha los headings como límite natural
2. Reranking
Después de la búsqueda vectorial, aplica un reranker (modelo especializado) sobre los top 10-20 candidatos para reordenarlos por relevancia real:
- Cohere Rerank 3.5 (excelente, ~0,002 $/query)
- Voyage Rerank-2 (gratis con plan)
- BGE-Reranker (open source)
El reranking mejora la precisión del 70% al 90%+ en casi todos los casos reales.
3. Hybrid search
Combina búsqueda vectorial con búsqueda léxica (BM25) y promedia. Útil cuando hay nombres propios, códigos o términos exactos que la vectorial puede pasar por alto.
Qdrant, Weaviate y Elasticsearch 8+ soportan hybrid search nativo.
4. Metadata filtering
Antes de la búsqueda vectorial, filtra por metadata relevante:
// Solo buscar en documentos del idioma correcto y vigentes
await qdrant.search("documentos", {
vector: queryEmbedding,
filter: {
must: [
{ key: "language", match: { value: "es" } },
{ key: "status", match: { value: "vigente" } },
],
},
});
Reduce ruido y acelera la búsqueda.
5. Query rewriting
A veces la pregunta del usuario no es óptima para retrieval. Un paso previo donde el LLM reescribe la query mejora resultados:
- “Eso de los descuentos qué” → “política de descuentos para clientes”
- “Hola q tal sabes ya?” → (descartar, no es una consulta real)
Métricas que debes monitorizar
- Recall@K: ¿el chunk correcto está en los top K resultados? (objetivo: >85%)
- Precision@1: ¿el primer resultado es el correcto? (objetivo: >70%)
- Tasa de “no encontrado”: ¿qué % de preguntas no devuelven match?
- Hallucination rate: ¿con qué frecuencia el LLM dice algo que no está en contexto? (objetivo: <5%)
- Latencia end-to-end: pregunta → respuesta (objetivo: <3s)
Herramientas: Langfuse, Phoenix Arize, Ragas para evaluación automática.
Errores frecuentes al implementar RAG
- Chunks demasiado pequeños o demasiado grandes: pierdes contexto o saturas el prompt.
- No usar threshold de similitud: devuelves resultados malos como si fueran buenos.
- Prompt sin instrucción anti-alucinación: el LLM “completa” cuando no encuentra.
- Indexar contenido obsoleto: tu RAG devuelve política de 2022 cuando ya cambió.
- Ignorar el español: muchos embeddings genéricos funcionan peor en español que en inglés. Usa modelos multilingües.
- No tener fallback humano: cuando no hay match, debes derivar a una persona.
Conclusión
RAG no es opcional para un agente IA empresarial serio: es la única forma de garantizar que tus respuestas sean precisas, actualizadas y trazables a tu documentación real.
Un agente IA sin RAG es marketing; un agente IA con RAG bien implementado es una herramienta de productividad.
En La Bahía Digital implementamos pipelines RAG completos con stack a medida (Qdrant, OpenAI/Anthropic, reranking, evaluación). Si quieres entender qué necesitarías para tu caso, pídenos consultoría gratuita de 30 min.
Lecturas relacionadas: