C
Contextología
RAG

Arquitectura de un pipeline RAG avanzado

4 de mayo de 2025· 5 min read

El RAG básico tiene una arquitectura lineal: recibe pregunta → busca en vectorDB → pasa fragmentos al LLM → devuelve respuesta.

Funciona para prototipos. Para producción, necesitas más capas.

El problema con RAG básico

Los fallos más comunes en sistemas RAG simples:

  • Recuperación irrelevante: La pregunta del usuario no coincide semánticamente con los documentos correctos
  • Fragmentos truncados: El chunk tiene la respuesta a medias, el contexto necesario está en otro chunk
  • Respuestas alucinadas: El modelo rellena los huecos de lo que no encontró
  • Sin verificación: No sabes si la respuesta está realmente en los documentos

Un pipeline avanzado añade capas antes y después de la recuperación para atacar cada uno de estos problemas.

La arquitectura completa

Pregunta → [Pre-retrieval] → [Retrieval] → [Post-retrieval] → [Generation] → [Validation]

Pre-retrieval: mejorar la consulta

Query expansion

Antes de buscar, reescribe o expande la pregunta para capturar más variantes:

Original: "¿Cuánto cuesta?"
Expandida: ["precio", "coste mensual", "tarifa", "plan", "cuánto vale"]

Hypothetical Document Embeddings (HyDE)

Genera una respuesta hipotética y busca documentos similares a esa respuesta (en lugar de a la pregunta):

# 1. Genera respuesta hipotética
hipotetica = llm("Si alguien pregunta X, ¿cómo sería la respuesta ideal?")
# 2. Busca documentos similares a la respuesta hipotética
resultados = vectordb.search(embed(hipotetica))

Funciona porque los documentos reales se parecen más a respuestas que a preguntas.

Query decomposition

Para preguntas compuestas, divídelas en sub-preguntas:

Pregunta: "¿Cuál es la diferencia entre RAG y fine-tuning y cuándo usar cada uno?"
Sub-preguntas:
  1. ¿Qué es RAG?
  2. ¿Qué es fine-tuning?
  3. ¿Cuándo usar RAG?
  4. ¿Cuándo usar fine-tuning?

Retrieval: recuperar mejor

Hybrid search

Combina búsqueda semántica (vectorial) con búsqueda léxica (BM25/keywords):

Score final = α × score_semántico + (1-α) × score_léxico

La búsqueda semántica es buena con sinónimos y paráfrasis. La léxica es buena con términos exactos, nombres propios y acrónimos. Juntas cubren más casos.

Multi-vector retrieval

En lugar de un solo embedding por documento, genera múltiples embeddings:

  • Embedding del resumen
  • Embedding de cada sección
  • Embeddings de hipotéticas preguntas que responde el documento

Cuando buscas, encuentras por cualquiera de estos vectores pero recuperas el documento completo.

Metadata filtering

Añade filtros por metadatos antes de la búsqueda vectorial:

resultados = vectordb.search(
    query=embedding,
    filters={"fecha": {"gte": "2024-01-01"}, "categoría": "política de precios"}
)

Reduce el espacio de búsqueda y mejora la precisión.

Post-retrieval: mejorar los resultados

Reranking

Los primeros resultados de una búsqueda vectorial no siempre son los más relevantes. Un reranker (modelo cross-encoder) recalcula la relevancia de los top-k candidatos:

Búsqueda: top-50 candidatos por similitud coseno
Reranking: modelo evalúa cada par (query, chunk) → selecciona top-10

Los rerankers de Cohere y los modelos cross-encoder de sentence-transformers son las opciones más comunes.

Contextual compression

Si los chunks recuperados contienen mucha información irrelevante, extrae solo la parte relevante:

fragmento_comprimido = llm(f"""
Del siguiente documento, extrae solo la información relevante para: {query}

Documento: {chunk}
""")

Reduce el contexto sin perder lo importante.

Parent document retrieval

Recuperas por chunk pequeño (más preciso en la búsqueda) pero pasas al modelo el documento padre completo (más contexto):

Indexas: chunks de 200 tokens
Buscas: por chunks pequeños
Pasas al modelo: el documento completo del que vienen esos chunks

Generation: controlar la respuesta

Instrucciones de grounding

El system prompt debe incluir instrucciones explícitas para mantenerse en el contexto:

Responde SOLO basándote en los documentos proporcionados.
Si la respuesta no está en los documentos, di explícitamente que no tienes
esa información. No elabores ni añadas información que no provenga de los
documentos.

Documentos:
[CONTEXTO]

Citations

Haz que el modelo cite los fragmentos que usa:

Responde con citas en formato [1], [2]... al final, indicando qué documento
respaldó cada afirmación.

Validation: verificar la respuesta

Faithfulness check

Un segundo LLM verifica que la respuesta está realmente soportada por los documentos:

check = llm(f"""
¿Está la siguiente respuesta completamente soportada por los documentos dados?
Responde: SÍ / NO + justificación

Respuesta: {respuesta}
Documentos: {contexto}
""")

Si no pasa el check, regenera o indica que no tienes suficiente información.

Métricas para evaluar tu RAG

  • Faithfulness: ¿La respuesta está soportada por los documentos? (objetivo: >0.9)
  • Answer relevance: ¿Responde la pregunta que se hizo? (objetivo: >0.85)
  • Context precision: ¿Los documentos recuperados son relevantes? (objetivo: >0.8)
  • Context recall: ¿Se recuperaron todos los documentos necesarios? (objetivo: >0.75)

Frameworks como RAGAS calculan estas métricas automáticamente.

Qué añadir primero

Si tienes un RAG básico y quieres mejorarlo, este es el orden de impacto/esfuerzo:

  1. Hybrid search — mayor impacto, implementación moderada
  2. Reranking — gran mejora en precisión, fácil de añadir
  3. Query rewriting — mejora casos donde el usuario no pregunta bien
  4. Faithfulness check — reduce alucinaciones, crítico para sistemas de confianza
  5. HyDE — mejora significativa para dominios muy específicos

No construyas todo desde el principio. Cada capa añade latencia y complejidad. Añade solo lo que resuelve un problema medido.


Recursos relacionados:

Pon en práctica lo que has aprendido

Checklist de RAG

Asegura que tu implementación RAG no tiene puntos débiles.

Abrir herramienta gratuita →

Recibe lo mejor de Contextología

Diseño de contexto, agentes y workflows de IA directamente en tu correo.