Por qué fallan la mayoría de los bots de "chatea con tus documentos"

Un agente de IA para empresas es tan bueno como los documentos que encuentra cuando llega una pregunta. Un modelo de uso general nunca ha visto tu política de RR. HH., tu lista de precios ni tus informes de incidentes, así que rellena los huecos con suposiciones plausibles.

Imagina a un empleado que pregunta al asistente interno: "¿Cuántos días de vacaciones puedo pasar al año que viene?". Un modelo sin más responde "normalmente cinco días". La respuesta suena segura y razonable, y es errónea si tu política dice diez.

En soporte, ventas o trabajo legal, respuestas así cuestan dinero y confianza. La generación aumentada por recuperación (RAG) resuelve el problema recuperando primero los fragmentos relevantes y haciendo que el modelo responda a partir de ellos. Este artículo recorre el camino completo: indexación, recuperación, generación, el salto del pipeline al agente y cómo demostrar que el resultado funciona.

Qué es RAG, en pocas palabras

RAG divide el trabajo en dos pipelines: uno offline que indexa tus documentos y otro online que responde a las preguntas a partir de ese índice. La idea viene de un artículo de 2020 de Lewis et al. en Facebook AI Research. Combinaba un recuperador neuronal sobre Wikipedia con un generador de texto y superaba, en tareas intensivas en conocimiento, a los modelos que dependían solo de sus pesos (Lewis et al., 2020).

Pipeline offline (se ejecuta cada vez que cambia un documento):

  1. Tus documentos → análisis y limpieza
  2. División en fragmentos con metadatos
  3. Cálculo de embeddings y escritura en el índice (vectores + texto completo)

Pipeline online (se ejecuta con cada pregunta del usuario):

  1. Pregunta del usuario → búsqueda híbrida en el índice, filtrada por permisos de acceso
  2. Reranking de los 20 mejores candidatos
  3. Los 5–8 mejores fragmentos → el LLM redacta una respuesta con citas

La primera vía se ejecuta cada vez que cambia un documento. La segunda se ejecuta con cada pregunta y solo lee del índice, filtrado por los permisos de acceso del usuario.

El argumento de negocio es práctico, no académico. Tu conocimiento cambia cada semana, y reindexar un documento lleva segundos, mientras que hacer fine-tuning de un modelo lleva días y aun así no puede señalar una fuente. RAG también permite imponer los permisos de acceso en el momento de la recuperación, de modo que el modelo nunca ve un fragmento que el usuario no puede leer.

Paso 1: indexación (analizar, enriquecer, fragmentar)

La calidad de la recuperación se decide sobre todo en la indexación, mucho antes de que nadie escriba una pregunta. Importan tres cosas: texto limpio, metadatos útiles y fragmentos sensatos.

Análisis. Los PDF, las presentaciones y los contratos escaneados pierden su estructura al convertirlos en texto plano. Conserva los encabezados, la numeración de listas y las tablas, porque "Sección 4.2" es a menudo justo lo que hace encontrable un fragmento. Convierte las tablas a Markdown o a una frase por fila; si no, los números acaban separados de los nombres de sus columnas.

Metadatos. Cada fragmento debe llevar su fuente, la ruta de secciones, la fecha de última actualización, el responsable y el grupo de acceso. Los metadatos permiten filtros ("solo políticas vigentes en 2026"), citas y comprobaciones de permisos.

Fragmentación. Divide primero por estructura (encabezados, párrafos) y después por tamaño, con un pequeño solapamiento para que una frase cortada en el borde sobreviva en ambos vecinos. Unos cientos de tokens por fragmento con un 10–15% de solapamiento es un punto de partida razonable; ajústalo con tu conjunto de evaluación en lugar de fiarte de ningún valor por defecto.

from dataclasses import dataclass
 
@dataclass
class Chunk:
    text: str
    source: str
    section: str
    updated: str
    acl_group: str
 
def chunk_document(doc, max_chars=2000, overlap=200):
    chunks = []
    for section in doc.sections:          # split by headings first
        text, start = section.text, 0
        while start < len(text):
            end = min(start + max_chars, len(text))
            chunks.append(Chunk(
                # prepend the breadcrumb so the chunk makes sense alone
                text=f"{doc.title} > {section.path}\n\n{text[start:end]}",
                source=doc.url,
                section=section.path,
                updated=doc.updated_at,
                acl_group=doc.acl_group,
            ))
            if end == len(text):
                break
            start = end - overlap
    return chunks

Fíjate en la ruta de navegación antepuesta a cada fragmento. Un fragmento que dice "el límite es de 30 días" no sirve de nada por sí solo; precedido de "Política de reembolsos > Clientes de la UE", responde a una pregunta real.

Paso 2: recuperación (búsqueda híbrida, reranking, contexto)

La búsqueda vectorial pura no basta para documentos de empresa. Los embeddings captan bien el significado, pero difuminan los tokens exactos: códigos de producto, IDs de error, números de cláusula y nombres de productos. La clasificación por palabras clave de la familia BM25 los detecta con exactitud (Robertson y Zaragoza, 2009), así que los sistemas de producción ejecutan ambas búsquedas y fusionan los resultados.

La fusión estándar es Reciprocal Rank Fusion (RRF). Cada documento puntúa la suma de 1 / (k + posición) en las listas de resultados, con k = 60 en el artículo original (Cormack et al., 2009). RRF no necesita calibrar las puntuaciones entre los dos motores, lo que la convierte en una opción segura por defecto.

Así queda todo en PostgreSQL con la extensión pgvector. Aquí la clasificación de texto completo de Postgres sustituye a BM25; motores de búsqueda como Elasticsearch u OpenSearch usan BM25 de forma nativa.

-- $1 = query embedding, $2 = query text, $3 = user's access groups
WITH semantic AS (
  SELECT id, ROW_NUMBER() OVER (ORDER BY embedding <=> $1) AS rnk
  FROM chunks
  WHERE acl_group = ANY($3)
  ORDER BY embedding <=> $1
  LIMIT 50
),
keyword AS (
  SELECT id, ROW_NUMBER() OVER (
           ORDER BY ts_rank(tsv, plainto_tsquery('spanish', $2)) DESC) AS rnk
  FROM chunks
  WHERE tsv @@ plainto_tsquery('spanish', $2)
    AND acl_group = ANY($3)
  ORDER BY ts_rank(tsv, plainto_tsquery('spanish', $2)) DESC
  LIMIT 50
)
SELECT c.id, c.text, c.source,
       COALESCE(1.0 / (60 + s.rnk), 0)
     + COALESCE(1.0 / (60 + k.rnk), 0) AS rrf_score
FROM semantic s
FULL OUTER JOIN keyword k ON s.id = k.id
JOIN chunks c ON c.id = COALESCE(s.id, k.id)
ORDER BY rrf_score DESC
LIMIT 20;

Fíjate en que el filtro de acceso está dentro de ambas subconsultas. Los permisos los impone la base de datos, no pidiéndole al modelo que guarde secretos.

Los 20 mejores candidatos pasan después a un reranker: un cross-encoder que lee juntos la pregunta y cada fragmento y los reordena por relevancia (Nogueira y Cho, 2019). Solo los cinco a ocho mejores fragmentos llegan al modelo de lenguaje.

Otra mejora barata es el contextual retrieval. Antes de indexar, un LLM escribe un resumen de una o dos frases sobre dónde se sitúa cada fragmento dentro de su documento, y ese resumen se antepone al fragmento tanto para el embedding como para la búsqueda por palabras clave. En las pruebas de Anthropic, esto redujo la tasa de fallos de recuperación en el top 20 un 35% solo con embeddings contextuales, un 49% añadiendo BM25 contextual y un 67% con reranking encima (Anthropic, 2024).

Paso 3: generación (responder a partir de las fuentes o decir "no lo sé")

El prompt de generación tiene un único trabajo: hacer que el modelo trate los fragmentos recuperados como la única fuente de verdad. Para eso hacen falta tres reglas: fuentes numeradas, una cita por cada afirmación y permiso explícito para negarse.

You are the internal assistant for Acme Corp.
Answer ONLY from the sources below. Cite every claim as [n].
If the sources do not contain the answer, reply
"I couldn't find this in our documentation" and suggest who to ask.
If sources conflict, prefer the most recently updated one
and mention the conflict.
 
<sources>
[1] HR Policy > Leave > Carry-over (updated 2026-03-01)
    Employees may carry over up to 10 unused vacation days...
[2] HR FAQ > Leave (updated 2024-11-15)
    Up to 5 days can be carried over...
</sources>
 
Question: How many vacation days can I carry over?

Con este prompt, el modelo responde "hasta 10 días [1]" y señala que las FAQ más antiguas [2] todavía dicen cinco. Esa segunda frase es valiosa: le dice al responsable del documento qué tiene que corregir.

El orden de los fragmentos también importa. Liu et al. mostraron que los modelos aprovechan mucho mejor la información del principio y del final de un contexto largo que la del medio (Liu et al., 2023). Pon primero los fragmentos más sólidos y resiste la tentación de meter 40 fragmentos "por si acaso": más contexto a menudo significa peores respuestas, no mejores.

Las citas sirven además como funcionalidad del producto. Cuando los usuarios pueden ir con un clic al párrafo exacto, confían en las respuestas correctas y detectan ellos mismos las erróneas.

Del pipeline al agente

Un pipeline RAG responde a una pregunta con una búsqueda; un agente decide qué buscar, dónde y si ya tiene suficiente. En la práctica, el salto consiste en dar al modelo la recuperación como una herramienta que puede llamar repetidamente, junto con unas pocas más.

Un agente de negocio típico solo necesita un puñado de herramientas:

  • search_docs(query, filters): la recuperación híbrida anterior, con filtros de metadatos que rellena el propio modelo.
  • get_document(id): el documento completo, para cuando un fragmento no da suficiente contexto.
  • query_crm(customer_id): datos estructurados que nunca deberían adivinarse a partir de texto.
  • create_ticket(...): una acción con efectos secundarios, que solo se ejecuta tras la confirmación del usuario.

Así es el bucle con una pregunta de soporte real:

User:   Can customer #4471 still get a refund on the March order?
 
Agent -> query_crm(4471)
         EU customer, order placed 2026-03-12, Pro plan
Agent -> search_docs("refund window EU customers", {doc_type: "policy"})
         [1] Refund Policy > EU: refunds within 30 days of purchase
Agent -> search_docs("refund exceptions Pro plan")
         no relevant passages
 
Agent:  No. The 30-day refund window for EU customers closed
        on April 11 [1]. I found no exception for the Pro plan;
        the billing team can approve one manually.

El agente combinó datos estructurados con el texto de la política y lanzó una segunda búsqueda cuando la primera dejó un hueco. También admitió lo que los documentos no cubren en lugar de inventarse una excepción.

La investigación apunta en la misma dirección. Self-RAG entrena modelos para decidir cuándo recuperar y para criticar sus propios borradores (Asai et al., 2023). Para preguntas que abarcan todo un corpus, como "¿qué temas se repiten en todos los informes de incidentes?", GraphRAG construye un grafo de conocimiento con resúmenes por comunidades en lugar de recuperar fragmentos aislados (Edge et al., 2024). Para conectar herramientas entre sistemas sin código de pegamento a medida, el Model Context Protocol ofrece un estándar abierto.

Una regla no cambia nunca: el agente actúa con los permisos del usuario, no con los suyos. Cada llamada a una herramienta lleva la identidad del usuario y cada filtro se aplica en código.

Paso 4: mide antes de lanzar

RAG falla en silencio: una respuesta errónea con una cita parece exactamente igual que una correcta. Así que, antes del lanzamiento, construye un conjunto de referencia de 100–200 preguntas reales, cada una con la respuesta esperada y el documento que la contiene. Sácalas de tickets de soporte, hilos de chat y logs de búsqueda, no de la imaginación.

Después mide las dos capas por separado, porque una mala respuesta puede venir de cualquiera de ellas:

Capa Métrica Pregunta que responde
Recuperación Recall@k ¿Está el fragmento correcto entre los k primeros resultados?
Recuperación MRR ¿En qué posición aparece el primer fragmento correcto?
Generación Fidelidad ¿Cada afirmación está respaldada por las fuentes recuperadas?
Generación Relevancia de la respuesta ¿La respuesta aborda la pregunta real?
De extremo a extremo Precisión de los rechazos ¿Dice "no lo sé" cuando los documentos no dicen nada?

Frameworks como RAGAS automatizan la puntuación de fidelidad y relevancia con un LLM como juez (Es et al., 2023). Contrasta el juez con unas cuantas docenas de etiquetas humanas antes de fiarte de él. Vuelve a ejecutar el conjunto completo con cada cambio de chunking, embeddings, reranker o prompt, y guarda los resultados para poder comparar versiones.

Errores habituales y lista de comprobación para el lanzamiento

La mayoría de los proyectos RAG fallidos fallan por los datos y el proceso, no por el modelo. Los sospechosos habituales son documentos obsoletos o duplicados que se contradicen, tablas aplanadas hasta convertirse en ruido y permisos de acceso comprobados en el prompt en lugar de en la consulta. El más caro es no tener conjunto de referencia, de modo que cada cambio se juzga a ojo.

Antes de abrir el agente a los usuarios, comprueba que:

  • Cada documento tiene un responsable y una fecha de actualización, y las versiones obsoletas se han retirado del índice
  • Cada fragmento lleva su fuente, su ruta de secciones y su grupo de acceso
  • La búsqueda híbrida con reranking se ha probado frente a la búsqueda solo vectorial con tus propias preguntas
  • El prompt exige citas y permite explícitamente decir "no lo sé"
  • Un conjunto de referencia de más de 100 preguntas reales se ejecuta con cada cambio
  • Las preguntas, los fragmentos recuperados y el feedback de los usuarios se registran para revisarlos

Empieza en pequeño: un departamento, un conjunto de documentos, un conjunto de referencia. Un agente acotado que cita sus fuentes y admite sus lagunas genera más confianza que uno amplio que adivina, y esa confianza es lo que te permite ampliarlo después.

Guías relacionadas

Una vez que el pipeline funciona, tres temas deciden si sobrevive en producción: cómo mides la calidad (cómo evaluar aplicaciones LLM), cómo conectas el agente con los sistemas de negocio (MCP para empresas) y cuánto cuesta operarlo (optimización de costes de LLM). Los documentos recuperados también son entrada no confiable; consulta seguridad de agentes de IA.

Para profundizar en la capa de recuperación, consulta embeddings y chunking y la comparativa de bases de datos vectoriales; para decidir entre recuperación y entrenamiento, consulta fine-tuning vs RAG vs prompting.

Fuentes

  1. Lewis et al. (2020). Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks. NeurIPS 2020.
  2. Robertson y Zaragoza (2009). The Probabilistic Relevance Framework: BM25 and Beyond. Foundations and Trends in Information Retrieval.
  3. Cormack, Clarke y Büttcher (2009). Reciprocal Rank Fusion Outperforms Condorcet and Individual Rank Learning Methods. SIGIR 2009.
  4. Nogueira y Cho (2019). Passage Re-ranking with BERT.
  5. Anthropic (2024). Introducing Contextual Retrieval.
  6. Liu et al. (2023). Lost in the Middle: How Language Models Use Long Contexts.
  7. Asai et al. (2023). Self-RAG: Learning to Retrieve, Generate, and Critique through Self-Reflection.
  8. Edge et al. (2024). From Local to Global: A Graph RAG Approach to Query-Focused Summarization.
  9. Es et al. (2023). RAGAS: Automated Evaluation of Retrieval Augmented Generation.
  10. pgvector: búsqueda de similitud vectorial open source para PostgreSQL.
  11. Model Context Protocol: estándar abierto para conectar agentes de IA con herramientas y datos.