Inicio / Artículos

Diseñar una tubería RAG para que los agentes de IA razonen, no solo realicen consultas.

Un pipeline RAG para agentes de IA debe mostrar el nivel de confianza, la diversidad de fuentes y el grado de cobertura, de modo que el agente pueda detectar lagunas, realizar nuevas consultas y explicar cómo llegó a sus conclusiones.

Editor: REACTAPP.TOP5 min de lectura1252 palabras

Fuentes: How to Design a RAG Pipeline So AI Agents Reason, Not Just Query It

Un agente llama a un pipeline RAG y recibe una lista de documentos. ¿Qué sucede a continuación?

En la mayoría de las configuraciones de agentes, RAG se trata como un cuadro de búsqueda: se envía una consulta, se toma lo que devuelve y se continúa. El agente no puede saber si los resultados son buenos, si abarcan todas las partes de la pregunta o si un segundo intento con una hipótesis más precisa habría revelado algo importante. Funciona a ciegas.

Eso es importante porque los agentes actúan con información parcial. Un detector de alucinaciones puede detectar hechos inventados, pero un punto ciego en la recuperación es mucho más difícil de identificar. El agente razona con confianza basándose en una imagen incompleta, y nadie se entera de lo que se le pasó por alto. El típico flujo de desarrollo, que consiste en ingresar datos, luego recuperar información y finalmente generar resultados, no incluye ninguna señal de retroalimentación.

Hacer visible la recuperación de información para el agente

La solución consiste en un arnés delgado alrededor del pipeline RAG que expone señales estructuradas sobre las cuales el agente puede razonar y no solo consumirlas.

En lugar de devolver una lista simple de documentos, el arnés devuelve un objeto más rico. Este contiene los documentos, una puntuación de confianza, una medida de la diversidad de fuentes (cuántos dominios distintos y qué rango de fechas), señales de cobertura que indican qué aspectos de la pregunta fueron abordados y cuáles faltan, además de metadatos de recuperación como el modelo de embedding, el tamaño de los fragmentos, el parámetro top-k y si se ejecutó un reranker.

{
  "results": [Document, Document, Document],
  "confidence_score": 0.87,
  "source_diversity": {"domains": 3, "timestamps": ["2024-01", "2023-11", "2023-09"]},
  "coverage_signals": {
    "question_aspects_covered": ["technical", "cost"],
    "question_aspects_missing": ["compliance", "deployment"]
  },
  "retrieval_metadata": {
    "embedding_model": "text-embedding-3-large",
    "chunk_size": 512,
    "top_k": 5,
    "reranker_applied": true
  }
}

Con eso, el agente cuenta con un canal de retroalimentación. Puede observar que la cobertura es parcial y que las fuentes son limitadas. Puede decidir realizar una nueva consulta desde un ángulo diferente, elevar el asunto a otra persona o registrar la laguna en su razonamiento.

Tres capas

Capa 1: recuperación de instrumentos

Se comienza capturando lo que el sistema ya calcula. Las bases de datos vectoriales devuelven puntuaciones de similitud, los reclasificadores indican el nivel de confianza y los fragmentos contienen marcas de tiempo y URLs de las fuentes. Esta primera capa recopila esos valores sin alterar la lógica de recuperación: ejecuta la consulta habitual, obtiene las puntuaciones, fuentes y marcas de tiempo, promedia las puntuaciones para obtener una cifra aproximada de confianza y cuenta las fuentes distintas.

def retrieve_with_signals(query: str, top_k: int = 5):
    # Standard retrieval
    results = vector_db.query(query, top_k=top_k)

    # Capture raw signals
    similarity_scores = [r.score for r in results]
    sources = [r.metadata.get("source") for r in results]
    timestamps = [r.metadata.get("timestamp") for r in results]

    # Compute confidence as mean similarity
    confidence = sum(similarity_scores) / len(similarity_scores)

    return {
        "results": results,
        "confidence_score": confidence,
        "source_diversity": {
            "domains": len(set(sources)),
            "timestamps": sorted(set(timestamps))
        }
    }

Es no invasivo, ya que solo se leen los datos que ya estaban allí.

Capa 2: detección de cobertura

A continuación viene una capa que relaciona el contenido recuperado con la pregunta original. Basta con una comparación semántica sencilla; no es necesario realizar un reordenamiento completo.

Divida la pregunta en aspectos. Para “¿Cómo despliego un modelo con restricciones de costo?”, los aspectos podrían ser el despliegue, el costo y las restricciones. Luego verifique cuáles de ellos aparecen en el texto recuperado. Un LLM o una extracción simple de palabras clave puede generar la lista de aspectos, y la verificación puede ser tan básica como buscar cada aspecto en el texto del documento combinado. La función indica qué aspectos fueron cubiertos, cuáles faltan y un porcentaje de cobertura.

def detect_coverage(query: str, documents: list) -> dict:
    # Extract query aspects (simple approach: use an LLM or keyword extraction)
    aspects = extract_query_aspects(query)  # ["deployment", "cost"]

    # Check document coverage
    doc_text = " ".join([d.content for d in documents])
    covered = [a for a in aspects if a.lower() in doc_text.lower()]
    missing = [a for a in aspects if a not in covered]

    return {
        "question_aspects_covered": covered,
        "question_aspects_missing": missing,
        "coverage_ratio": len(covered) / len(aspects) if aspects else 1.0
    }

Aquí es donde el agente recibe retroalimentación con la que puede actuar. Los aspectos faltantes deberían generar una nueva consulta. Para mejorar el enfoque, se deben etiquetar cada documento con sus aspectos durante la ingestión y comparar esas etiquetas al momento de la recuperación.

Capa 3: entregarlo al agente

Finalmente, se le proporciona al agente una herramienta que devuelve el resultado del proceso. Esta herramienta toma una consulta y, opcionalmente, un aspecto en el que centrarse, ejecuta la recuperación con señales específicas, agrega información sobre el grado de cobertura y adjunta una recomendación: volver a realizar la consulta cuando la tasa de cobertura sea inferior a 0.7, de lo contrario, continuar.

tools = [
    {
        "name": "search_with_reasoning",
        "description": "Search the knowledge base and receive coverage signals",
        "parameters": {
            "query": "str",
            "aspect_focus": "optional str (e.g., 'deployment' or 'cost')"
        }
    }
]

def search_with_reasoning(query: str, aspect_focus: str = None) -> dict:
    retrieval_output = retrieve_with_signals(query, top_k=5)
    coverage = detect_coverage(query, retrieval_output["results"])

    return {
        **retrieval_output,
        "coverage_signals": coverage,
        "recommendation": (
            "re-query" if coverage["coverage_ratio"] < 0.7 else "proceed"
        )
    }

El agente recibe esa recomendación y puede seguirla o anularla utilizando su conocimiento del dominio.

Verifique que las señales sean fiables

El sistema solo vale la pena si sus señales son precisas, por lo que pruebe tres aspectos.

  • Precisión de las señales. ¿El puntaje de confianza realmente predice la calidad de la recuperación? Ejecute unas veinte consultas, califique los resultados manualmente del uno al cinco y relacione esas calificaciones con el puntaje. Un valor de correlación superior a aproximadamente 0.75 es un objetivo razonable.
  • Detección de cobertura. Marque a mano qué aspectos de cada pregunta responden los documentos, luego comparelo con el detector en unas diez consultas diferentes. Busque una precisión superior al 85%.
  • Comportamiento del agente. Registre cada decisión de realizar una nueva consulta. Si, la mayoría de las veces, un ratio de cobertura inferior a 0.7 conduce a una nueva consulta, el agente está prestando atención a la señal.

Costos y límites

Hay una latencia adicional. La cobertura requiere un segundo proceso semántico, y en una recuperación de cinco documentos se pueden observar 50 a 100 milisegundos extra. Si eso es demasiado, se deben almacenar en caché las señales o calcularlas de forma asíncrona.

El sistema también asume que la capa de recuperación está lo suficientemente estable como para ser utilizada. Si el almacén de vectores no devuelve puntuaciones o los fragmentos no contienen metadatos, primero es necesario implementar la instrumentación.

Además, las señales son heurísticas. Una alta puntuación de confianza no garantiza un razonamiento correcto. El sistema proporciona al agente entradas mejores, pero no perfectas, por lo que siguen siendo necesarias verificaciones para detectar alucinaciones posteriores.

Por qué vale la pena

Los agentes que pueden ver el interior del proceso de recuperación de información son más transparentes y fiables. Pueden explicar por qué realizan búsquedas adicionales, señalar la incertidumbre y pasarle el caso a un humano cuando la cobertura es baja. Esa es la diferencia entre un motor de búsqueda y un asistente de investigación: uno solo devuelve resultados, mientras que el otro devuelve resultados y indica en qué aspectos no está seguro.

Comenzando

  1. Haga la Capa 1 esta semana. Muestre el nivel de confianza y la diversidad de fuentes, registre esos datos durante un día y observe cualquier patrón.
  2. Agregue detección de cobertura para los tipos de consultas más comunes y verifique manualmente en diez ejemplos.
  3. Intégrelo al agente y mida si realiza nuevas búsquedas cuando la cobertura es baja y si su razonamiento mejora.

Una vez que existe el arnés, es más fácil integrar más señales: detección de desviación semántica, verificaciones de actualidad y mecanismos de verificación de hechos. Cada una de ellas proporciona al agente más elementos con los que razonar. Comience con algo sencillo, cree el canal de retroalimentación y deje que el agente aprenda a prestarle atención.