AI Quality & Evaluation

Aplicaciones RAG en la práctica: conocimiento estructurado, mejor recuperación y evaluaciones reales

Una guía práctica para ingenieros y PMs que diseñan aplicaciones RAG sobre conocimiento bien estructurado y conectado: cómo dividir en chunks, recuperar, reranquear, citar, evaluar y mejorar con evidencia en lugar de intuiciones.

33 min de lectura Actualizado el 15 jun 2026

Resumen

  • RAG no es “subir documentos y hacer preguntas”. Un sistema RAG en producción es un sistema de conocimiento: ingesta, chunking, metadatos, recuperación, reranking, síntesis de respuestas, citas, evaluación, monitoreo y corrección.
  • El mayor error de diseño es tratar el conocimiento bien estructurado como texto plano. Las políticas, los tickets, las especificaciones, los contratos, los manuales y los documentos de arquitectura suelen necesitar jerarquía, metadatos, IDs estables, chunks padre-hijo y recuperación que tenga en cuenta las relaciones.
  • Los benchmarks siguen mostrando la misma verdad incómoda: el RAG básico ayuda, pero no es suficiente. CRAG reporta que los LLMs avanzados por sí solos responden como máximo el 34% de sus preguntas factuales, el RAG sencillo llega al 44% y los sistemas RAG avanzados de la industria alcanzan el 63% sin alucinar.
  • Evalúa la cadena, no solo la respuesta final. Mide el recall de recuperación, la precisión del contexto, el sustento o la fidelidad a las fuentes, la relevancia de la respuesta, el comportamiento de rechazo, la calidad de las citas, la latencia, el costo y la deriva en producción.
  • El mejor patrón actual es híbrido: ingesta estructurada + recuperación semántica y léxica + filtros de metadatos + reranking + generación que tenga en cuenta las fuentes + evaluaciones automatizadas + revisión humana en casos de alto riesgo.
  • Para conocimiento conectado, considera la recuperación jerárquica, los chunks contextualizados, los resúmenes al estilo GraphRAG o la recuperación basada en grafos de conocimiento. Úsalos cuando la pregunta requiera relaciones, agregación, razonamiento multi-hop o síntesis a nivel de corpus.
  • Un stack predeterminado sólido incluye Postgres para metadatos y datos de evaluación, Qdrant o pgvector para recuperación híbrida, embeddings de OpenAI o Voyage, un reranker dedicado, LlamaIndex o una capa ligera de orquestación personalizada y evaluaciones al estilo RAGAS/LangSmith/LangWatch.
  • Si quieres una implementación full-stack centrada en Python, Agno puede cubrir gran parte de la aplicación: bases de conocimiento, integraciones con bases de datos vectoriales, RAG agéntico, salidas estructuradas, herramientas, APIs de AgentOS, sesiones, trazas, RBAC, integración de UI y evaluaciones integradas.

Qué aprenderás aquí

  • Cómo pensar en RAG como una cadena de decisiones y no como una sola llamada de búsqueda vectorial.
  • Qué dicen los benchmarks recientes de RAG sobre la recuperación básica, las alucinaciones, los datos dinámicos y las preguntas multi-hop.
  • Cómo diseñar chunks para conocimiento estructurado y conectado.
  • Qué métricas de evaluación importan a ingenieros y PMs.
  • Una arquitectura de referencia práctica que puedes adaptar para aplicaciones en producción.
  • Un ejemplo concreto de un asistente de políticas de soporte con IDs de fuente, flujo de recuperación, salida JSON y verificaciones de evaluación.
  • Un stack tecnológico RAG recomendado para MVPs, equipos de producto consolidados y sistemas de conocimiento empresariales.
  • Cómo armar el mismo tipo de aplicación RAG full-stack con Agno y sus funcionalidades integradas.
  • Un pequeño ejemplo al estilo Python para verificar la recuperación y las respuestas sustentadas en las fuentes.

Este artículo está dirigido a ingenieros y PMs que crean aplicaciones de IA sobre documentación de producto, bases de conocimiento internas, historiales de soporte, políticas, especificaciones, contratos, runbooks, registros de clientes u otro conocimiento empresarial.

Una advertencia amistosa: RAG es uno de los patrones de IA más fáciles de demostrar y también uno de los más fáciles de medir mal.

RAG es una cadena, no una funcionalidad

La idea original de RAG es simple: recuperar conocimiento externo, incluirlo en el contexto del modelo y generar una respuesta sustentada en ese conocimiento. Ese sigue siendo el principio central.

Pero, en la práctica, una aplicación RAG es una cadena:

User question
     |
     v
Intent + query understanding
     |
     v
Retriever selection + filters
     |
     v
Hybrid search over structured chunks
     |
     v
Reranking + deduplication + context packing
     |
     v
Answer generation with citations
     |
     v
Post-checks: grounding, policy, format, refusal
     |
     v
Telemetry + evals + dataset updates

Cada paso puede fallar.

Si el chunking rompe una tabla, la recuperación puede pasar por alto la respuesta. Si la recuperación devuelve la página correcta, pero la sección equivocada, el modelo puede hacer una suposición. Si la respuesta es correcta, pero los IDs de las citas no son estables, nadie puede auditarla. Si las evaluaciones solo califican el estilo de la respuesta final, el equipo podría no notar que el recall de recuperación empeoró después de una actualización del corpus.

Así que la pregunta de diseño no es:

¿Qué base de datos vectorial deberíamos usar?

Es:

¿Cómo preservamos la estructura de conocimiento necesaria para responder las preguntas que realmente hacen los usuarios?

Qué nos dicen los benchmarks

Los benchmarks no son tu producto. Aun así, son útiles porque revelan modos de falla que vuelven a aparecer en producción.

1. El RAG básico mejora las respuestas, pero deja una brecha importante

El benchmark CRAG se diseñó en torno a preguntas y respuestas factuales con datos dinámicos, entidades de larga cola, múltiples dominios y APIs simuladas de web y grafos de conocimiento. Su resultado principal invita a la cautela: los LLMs avanzados por sí solos alcanzan como máximo un 34% de exactitud, el RAG sencillo mejora hasta el 44% y los sistemas RAG avanzados de la industria responden el 63% de las preguntas sin alucinar.

La conclusión no es “RAG falló”. La conclusión es que la recuperación top-k simple es solo el primer escalón. Las preguntas reales suelen requerir datos actualizados, desambiguación de entidades, razonamiento temporal, síntesis de múltiples fuentes y un rechazo cuidadoso cuando falta evidencia.

2. RAG necesita algo más que exactitud en las respuestas

RGB evalúa los sistemas RAG en cuatro capacidades:

CapacidadSignificado práctico
Robustez frente al ruido¿Puede el modelo ignorar el texto irrelevante recuperado?
Rechazo ante ausencia de evidencia¿Puede decir “no lo sé” cuando no hay evidencia?
Integración de información¿Puede combinar múltiples fragmentos relevantes?
Robustez frente a información contrafactual¿Puede evitar confiar en información incorrecta recuperada?

Esto se corresponde casi a la perfección con los incidentes en producción. Muchas aplicaciones RAG no fallan porque la recuperación no haya devuelto nada. Fallan porque devolvió una mezcla confusa de contexto verdadero, desactualizado, parcial e irrelevante.

3. La evaluación debe diagnosticar los componentes

Tanto RAGBench como RAGChecker impulsan una evaluación orientada a la explicabilidad y al diagnóstico por componente. Esto importa porque “mala respuesta” no basta para saber qué hacer.

Una respuesta final puede fallar por diferentes razones:

  • El chunk correcto nunca se indexó.
  • El chunk existe, pero no se recuperó.
  • El chunk se recuperó, pero quedó demasiado abajo en el ranking.
  • El contexto recuperado era correcto, pero contenía demasiado ruido.
  • El modelo ignoró la evidencia.
  • El modelo respondió correctamente, pero citó la fuente equivocada.
  • La fuente estaba desactualizada o había sido reemplazada.

Son bugs diferentes. Necesitan soluciones diferentes.

La regla de diseño: preserva los límites que aportan significado

La mayor parte del conocimiento interno no es una secuencia uniforme de párrafos. Tiene estructura.

Ejemplos:

  • Una política tiene secciones, excepciones, fechas de entrada en vigor, responsables y estado de aprobación.
  • Un artículo de soporte tiene síntomas, causas, soluciones, versiones afectadas y tickets relacionados.
  • Un registro de decisión de arquitectura tiene contexto, decisión, consecuencias y sistemas vinculados.
  • Un contrato tiene cláusulas, definiciones, dependencias, jurisdicciones e historial de modificaciones.
  • Una especificación de producto tiene objetivos, lo que queda fuera de su alcance, requisitos, flujos, analítica y preguntas abiertas.

Si aplanas todo eso en chunks de 800 tokens con superposición, a menudo destruyes justo la estructura que necesita el modelo.

Es mejor que los chunks se comporten como pequeñas fichas de conocimiento:

Chunk ID: policy.refunds.2026.section_4.exception_2
Document: Refund Policy
Version: 2026-04-10
Section path: Refund Policy > Exceptions > Chargebacks
Audience: Support agents
Applies to: US, CA
Status: Approved
Parent: policy.refunds.2026.section_4
Related: policy.payments.chargebacks, macro.support.refund_denied
Text: ...

Este tipo de metadatos permite al sistema recuperar información tanto por significado como por estructura.

Una arquitectura práctica para RAG estructurado

Esta es la arquitectura en la que confío para la mayoría de las aplicaciones RAG en producción:

                    +-----------------------+
                    | Source systems        |
                    | Docs, CMS, tickets, DB|
                    +-----------+-----------+
                                |
                                v
                    +-----------------------+
                    | Structured ingestion  |
                    | parse, clean, version |
                    +-----------+-----------+
                                |
              +-----------------+-----------------+
              v                                   v
   +-----------------------+           +-----------------------+
   | Retrieval units       |           | Source graph / links  |
   | chunks, parents, refs |           | entities, relations   |
   +-----------+-----------+           +-----------+-----------+
               |                                   |
               v                                   v
   +-----------------------+           +-----------------------+
   | Hybrid indexes        |           | Metadata filters      |
   | vector + BM25         |           | tenant, date, status  |
   +-----------+-----------+           +-----------+-----------+
               +-----------------+-----------------+
                                 v
                    +-----------------------+
                    | Rerank + context pack |
                    | diversify, cite, trim |
                    +-----------+-----------+
                                |
                                v
                    +-----------------------+
                    | Grounded generation   |
                    | answer + citations    |
                    +-----------+-----------+
                                |
                                v
                    +-----------------------+
                    | Evaluation + tracing  |
                    | offline + production  |
                    +-----------------------+

Lo importante no son los bloques del diagrama, sino la separación de responsabilidades. Las unidades de recuperación, el grafo de fuentes, los filtros de metadatos y las trazas de evaluación deben ser conceptos de primera clase, no cadenas de texto incidentales dentro de un prompt.

Chunking: empieza por la pregunta del usuario, no por el tamaño en tokens

El tamaño del chunk importa, pero “¿cuál es el mejor tamaño de chunk?” suele ser la primera pregunta equivocada.

En cambio, pregunta:

  1. ¿Qué preguntas debería responder este chunk por sí solo?
  2. ¿Qué contexto del elemento padre necesita?
  3. ¿Por qué metadatos debe poder filtrarse?
  4. ¿Qué chunks relacionados deberían ser fáciles de consultar?
  5. ¿Qué no debería dividirse nunca?

Esta es una regla práctica:

Tipo de conocimientoMejor límite para el chunk
FAQUn par de pregunta y respuesta
PolíticaUna sección o excepción
Documentación de APIUn endpoint, grupo de parámetros, código de error o ejemplo
ADRUna decisión, consecuencia o sistema relacionado
Legal/contractualUna cláusula, definición o modificación
Ticket de soporteUn síntoma, diagnóstico, resolución o entorno
TablasUn grupo de filas con los encabezados preservados
Documentación de códigoUna función o clase con su firma y ejemplos

Para conocimiento bien estructurado, me gusta la recuperación padre-hijo:

Embed small child chunks for precision
        |
        v
Retrieve child chunks
        |
        v
Expand to parent section for context
        |
        v
Rerank parent + child evidence together

Esto te da precisión sin privar al modelo de contexto.

El patrón de recuperación contextual de Anthropic apunta en una dirección similar: enriquecer cada chunk con contexto a nivel de documento antes de generar embeddings y realizar la indexación léxica. La reducción de fallas de recuperación que reportan es lo suficientemente grande como para tomarla en serio, especialmente cuando se combina con reranking. La lección más general es simple: un chunk debe llevar suficiente significado de su entorno para que pueda recuperarse correctamente fuera de su documento original.

Cuando el conocimiento está conectado, recupera la cadena

Algunas preguntas no se responden con un solo chunk.

Ejemplo:

¿Puede un cliente empresarial en Canadá obtener un reembolso si renovó a través de un revendedor e inició un contracargo?

Eso puede requerir:

  • la política regional de reembolsos
  • los términos del revendedor
  • las excepciones del contrato empresarial
  • la política de contracargos
  • la macro de soporte más reciente
  • los metadatos de la cuenta del cliente

Una búsqueda semántica plana podría recuperar una o dos piezas y pasar por alto la cadena.

Una mejor estrategia es la recuperación por etapas:

Question
   |
   v
Extract entities and constraints
   |
   +--> country = Canada
   +--> customer_type = enterprise
   +--> channel = reseller
   +--> event = renewal
   +--> dispute = chargeback
   |
   v
Retrieve policy candidates with filters
   |
   v
Follow related links and parent sections
   |
   v
Rerank evidence set
   |
   v
Answer only if the chain supports it

Los enfoques al estilo GraphRAG, la recuperación jerárquica al estilo RAPTOR y los sistemas más recientes basados en grafos, como LightRAG, responden a la misma limitación: los chunks planos no son buenos para responder preguntas sobre conexiones, agregaciones o relaciones multi-hop.

No necesitas un grafo de conocimiento para cada aplicación RAG. Pero deberías considerar uno cuando los usuarios hacen preguntas como:

  • “¿Qué cambió entre estas versiones?”
  • “¿Qué equipos se ven afectados por esta política?”
  • “¿Cuál es la relación entre estos incidentes?”
  • “Resume los temas presentes en todas las quejas de clientes”.
  • “Encuentra excepciones que dependan de la región, el plan y el tipo de contrato”.

Esas son preguntas sobre relaciones, no solo sobre similitud.

Recuperación: primero lo híbrido, después lo sofisticado

Para muchos sistemas en producción, el stack de recuperación que más impacto aporta es:

metadata filters
   +
BM25 / keyword search
   +
vector search
   +
reranker
   +
context packing

¿Por qué híbrido?

La búsqueda vectorial es buena para encontrar similitud semántica. La búsqueda por palabras clave es buena para términos exactos, nombres de productos, IDs, códigos de error, números de cláusula y lenguaje interno peculiar. El conocimiento empresarial tiene mucho lenguaje interno peculiar.

El reranking importa porque la recuperación top-k suele contener ruido. Un cross-encoder o un reranker basado en LLM puede examinar la consulta y los chunks candidatos en conjunto y luego reordenar la lista antes de que la vea el generador.

La organización del contexto importa porque un modelo puede perder la respuesta entre demasiado contexto irrelevante. Más tokens recuperados pueden reducir la calidad si ocultan la evidencia entre el ruido.

Generación: haz que el modelo muestre su evidencia

El prompt de generación debe hacer explícito el contrato de evidencia:

Use only the provided sources.
Answer the user's question directly.
Include citations for every factual claim.
If the sources conflict, name the conflict.
If the sources do not contain the answer, say what is missing.
Do not infer policy from similar but non-applicable sources.

Para los PMs, este es el contrato de producto: los usuarios deben saber si el sistema sabe, no sabe o encontró evidencia contradictoria.

Para los ingenieros, este es el contrato de depuración: cada respuesta debe apuntar a IDs de fuente que puedan recuperarse.

Ejemplo práctico: un asistente de políticas de soporte

Hagamos esto menos abstracto.

Imagina que una empresa SaaS quiere un asistente interno para agentes de soporte. El asistente responde preguntas sobre políticas antes de que un agente responda a un cliente.

Las fuentes de conocimiento son:

  • páginas de políticas de reembolso
  • términos de revendedores
  • plantillas de contratos empresariales
  • macros de soporte
  • notas de incidentes
  • metadatos de planes de producto

La pregunta más difícil no es “¿Cuál es la política de reembolso?”. Es una pregunta que conecta varias políticas:

El cliente ACME tiene el plan Enterprise, renovó a través de un revendedor, está en Canadá e inició un contracargo. ¿Puede soporte emitir un reembolso?

Un flujo RAG práctico se vería así:

User question
   |
   v
Extract constraints
   - customer = ACME
   - plan = Enterprise
   - region = Canada
   - sales_channel = reseller
   - event = renewal
   - dispute = chargeback
   |
   v
Fetch account metadata from app DB
   |
   v
Retrieve policy chunks with metadata filters
   - status = approved
   - effective_date <= today
   - region in [Canada, Global]
   - audience = support
   |
   v
Hybrid search
   - vector: "reseller renewal refund chargeback enterprise"
   - keyword: reseller, chargeback, renewal, Enterprise
   |
   v
Rerank top 40 candidates down to top 8
   |
   v
Expand child chunks to parent sections
   |
   v
Generate answer with citations and a decision state

El asistente no debería devolver una respuesta vaga como:

Depende. Revisa las políticas de revendedores y contracargos.

Una mejor respuesta es estructurada:

{
  "decision": "do_not_refund_without_escalation",
  "confidence": "medium",
  "answer": "Support should not issue the refund directly. The customer renewed through a reseller, and the chargeback policy requires finance escalation before refund approval.",
  "required_escalation": "finance",
  "citations": [
    "policy.refunds.2026.reseller_terms.section_2",
    "policy.payments.2026.chargebacks.section_4",
    "macro.support.refund_escalation.2026"
  ],
  "missing_information": [
    "The current reseller agreement ID was not available in retrieved sources."
  ]
}

Observa lo que esto aporta al producto:

  • El agente de soporte recibe una recomendación directa.
  • La respuesta se sustenta en IDs de fuente estables.
  • El sistema expone la información faltante en lugar de ocultar la incertidumbre.
  • La decisión puede auditarse más adelante.
  • La respuesta puede evaluarse automáticamente.

El modelo de ingesta detrás de esto puede seguir siendo simple:

chunk = {
    "id": "policy.payments.2026.chargebacks.section_4",
    "text": "Chargeback-related refunds require finance review before approval...",
    "parent_id": "policy.payments.2026.chargebacks",
    "section_path": "Payments > Chargebacks > Refund approval",
    "source_url": "https://internal.example.com/policies/payments#chargebacks",
    "status": "approved",
    "effective_date": "2026-04-01",
    "owner": "finance-ops",
    "audience": "support",
    "regions": ["global"],
    "entities": ["refund", "chargeback", "finance review"],
    "related_ids": [
        "policy.refunds.2026.reseller_terms.section_2",
        "macro.support.refund_escalation.2026"
    ],
}

Y tu función de recuperación debería devolver evidencia, no solo texto:

def retrieve_policy_evidence(question: str, account: dict) -> list[dict]:
    filters = {
        "status": "approved",
        "audience": "support",
        "regions": ["global", account["country"]],
        "effective_date_lte": "2026-06-15",
    }

    dense_hits = vector_search(question, filters=filters, top_k=30)
    keyword_hits = keyword_search(question, filters=filters, top_k=30)
    fused_hits = reciprocal_rank_fusion([dense_hits, keyword_hits], limit=40)
    reranked = rerank(question, fused_hits, top_k=8)

    return expand_with_parent_sections(reranked)

La evaluación de este ejemplo debería verificar:

VerificaciónResultado esperado
Recall de recuperaciónLos términos del revendedor y la política de contracargos están entre los 8 primeros resultados
Cobertura de citasLa respuesta final cita ambas secciones de políticas requeridas
Corrección de la decisióndecision = do_not_refund_without_escalation
Información faltanteMenciona el ID del acuerdo con el revendedor si no está disponible
Sustento en las fuentesNo aparece ninguna afirmación sin respaldo en las fuentes
Comportamiento del productoEscala el caso a finanzas en lugar de inventar una aprobación

Ese es el ciclo práctico: diseñar los IDs de fuente, recuperar la cadena de evidencia, obligar a que la respuesta tenga una forma auditable y evaluar cada paso.

Un stack tecnológico recomendado

No existe un stack RAG universalmente superior, pero sí hay opciones predeterminadas razonables. Yo elegiría el stack según el tamaño del equipo, la estructura de los datos y el nivel de control operativo que necesites.

Stack predeterminado para la mayoría de los equipos de producto

CapaRecomendaciónPor qué
App/APIFastAPI, Node.js o tu backend existenteMantén RAG cerca de la autenticación, el manejo de tenants y los logs del producto.
IngestaLlamaIndex o un pipeline personalizado con parsers para contenido no estructuradoBuenas abstracciones para parsing, metadatos, nodos y patrones de recuperación.
AlmacenamientoPostgres para metadatos de fuentes y datasets de evaluaciónTu producto ya confía en él; es excelente para IDs, versiones, permisos y registros de auditoría.
Índice de recuperaciónQdrant, pgvector, Weaviate, Pinecone u OpenSearchElige según la escala y las preferencias operativas del equipo; exige filtros de metadatos.
Búsqueda híbridaVectores densos + BM25/vectores dispersosMejor para nombres de productos, IDs, números de cláusula y preguntas en lenguaje natural.
EmbeddingsOpenAI text-embedding-3-small por costo, text-embedding-3-large para búsquedas donde la calidad es prioritariaLa documentación oficial indica 1536 dimensiones para small y 3072 para large, con reducción de dimensiones disponible.
RerankingCohere Rerank, rerankers de Voyage, bge-reranker o rerank nativo del proveedorLos rerankers suelen mejorar la precisión antes de que el LLM vea el contexto.
GeneraciónUn modelo de la clase GPT-4.1/GPT-5, de la clase Claude Sonnet o tu modelo empresarial aprobadoElige según los resultados de las evaluaciones, no por preferencia de marca.
EvaluaciónRAGAS o DeepEval localmente; LangSmith, LangWatch, TruLens o Arize Phoenix para trazas gestionadasNecesitas métricas de recuperación y generación, además de depuración de trazas.
ObservabilidadOpenTelemetry + analítica de producto + dashboards de evaluaciónConecta la calidad del modelo con los resultados para el usuario, la latencia y el costo.

Mi implementación predeterminada para un producto consolidado, pero no enorme, sería:

Backend:        FastAPI or existing Node.js service
Metadata DB:    Postgres
Vector search:  Qdrant with dense + sparse hybrid search
Embeddings:     text-embedding-3-large for quality, small for cost-sensitive paths
Reranker:       Cohere Rerank or Voyage reranker
Orchestration:  LlamaIndex for ingestion/retrieval, thin custom app logic
Evaluation:     RAGAS + LangSmith/LangWatch traces
Monitoring:     OpenTelemetry + dashboards for latency, cost, retrieval recall, faithfulness

¿Por qué este stack?

  • Qdrant tiene consultas híbridas de primera clase con recuperación densa, dispersa y multivectorial, además de fusión de puntuaciones.
  • pgvector es excelente cuando quieres menos componentes y ya usas Postgres; combínalo con la búsqueda de texto completo de Postgres y reciprocal rank fusion para obtener búsqueda híbrida.
  • LlamaIndex es útil para la ingesta estructurada, la recuperación basada en metadatos y los patrones RAG para producción.
  • LangSmith, LangWatch, TruLens, RAGAS y DeepEval ayudan a separar la calidad de la recuperación de la calidad de la respuesta.
  • La API de rerank de Cohere y otros rerankers similares están diseñados para reordenar los documentos candidatos por relevancia antes de la generación.

Stack ligero para un MVP

Úsalo cuando necesites aprender rápido:

Postgres + pgvector
Postgres full-text search
OpenAI embeddings
One reranker
RAGAS or DeepEval test set
Simple trace table in Postgres

Esto es aburrido en el mejor sentido. Mantiene el sistema comprensible. La principal compensación es que tendrás que construir más lógica de integración para la recuperación por tu cuenta.

Stack más robusto para conocimiento empresarial

Úsalo cuando el conocimiento es extenso, está sujeto a permisos, tiene vínculos cruzados y se audita:

Document pipeline: LlamaParse, Unstructured, or custom parsers
Metadata system: Postgres
Search: OpenSearch/Elasticsearch + vector DB, or Qdrant/Weaviate with hybrid search
Graph layer: Neo4j, Kuzu, or graph tables in Postgres
Reranking: dedicated reranker
LLM gateway: LiteLLM or internal provider gateway
Eval/observability: LangSmith, LangWatch, Arize Phoenix, TruLens, OpenTelemetry
Human review: annotation queue for failed and high-risk answers

Este stack es más robusto porque el RAG empresarial rara vez es solo búsqueda. Son permisos, actualización, responsables, auditabilidad y respuesta a incidentes disfrazados de búsqueda.

RAG full-stack con funcionalidades integradas de Agno

Si tu equipo trabaja principalmente con Python y quiere lanzar un producto RAG sin ensamblar a mano cada pieza del runtime, Agno es una opción sólida.

Al June 15, 2026, la documentación actual de Agno describe tres capas útiles:

CapaFuncionalidad de AgnoQué te ofrece
ConocimientoKnowledge, integraciones con bases de datos vectoriales, base de datos de contenidoDocumentos, metadatos, embeddings y conocimiento que se puede consultar.
Runtime de agentesAgent, herramientas, salida estructurada, equipos, workflowsLa capa de razonamiento y acción que responde o delega.
Runtime de productoAgentOS, Agent API, AG-UI, AgentUI, trazas, evaluaciones, RBACLa API, la UI, las sesiones, las trazas, la autenticación y la superficie operativa.

Una decisión de diseño importante de Agno es que el conocimiento puede asociarse directamente a un agente. Cuando tiene conocimiento asociado, Agno usa RAG agéntico por defecto: el agente puede decidir cuándo buscar en la base de conocimiento. Si quieres RAG clásico, donde las referencias relevantes siempre se agregan al contexto según el mensaje del usuario, Agno también ofrece ese modo.

Así implementaría con Agno el asistente de políticas de soporte de la sección anterior.

1. Almacena el conocimiento en Postgres + PgVector

Para un producto consolidado, empieza con Postgres porque puede almacenar metadatos de fuentes, sesiones, trazas, datasets de evaluación y vectores mediante PgVector.

from agno.db.postgres.postgres import PostgresDb
from agno.knowledge.embedder.openai import OpenAIEmbedder
from agno.knowledge.knowledge import Knowledge
from agno.vectordb.pgvector import PgVector, SearchType

db_url = "postgresql+psycopg://ai:ai@localhost:5532/ai"

db = PostgresDb(db_url=db_url)

policy_knowledge = Knowledge(
    name="support_policy_knowledge",
    description="Approved support policies, reseller terms, chargeback rules, and support macros.",
    contents_db=db,
    vector_db=PgVector(
        table_name="support_policy_vectors",
        db_url=db_url,
        embedder=OpenAIEmbedder(),
        search_type=SearchType.hybrid,
    ),
)

Las piezas importantes:

  • contents_db le da a AgentOS un lugar para gestionar el contenido subido y los metadatos.
  • PgVector almacena embeddings y admite operaciones de Postgres adecuadas para producción.
  • SearchType.hybrid mantiene los términos exactos de las políticas, los IDs y el significado semántico en la misma ruta de recuperación.
  • Puedes cambiar PgVector por Qdrant, Weaviate, Pinecone, LanceDB, Chroma, Redis u otros almacenes vectoriales compatibles sin reescribir la lógica del agente.

2. Inserta documentos con metadatos

Agno puede incorporar contenido a la base de conocimiento, pero aún necesitas tratar los metadatos como parte del diseño del producto.

await policy_knowledge.ainsert(
    name="Refund Policy 2026",
    url="https://internal.example.com/policies/refunds-2026.pdf",
    metadata={
        "status": "approved",
        "audience": "support",
        "owner": "finance-ops",
        "effective_date": "2026-04-01",
        "regions": ["global", "CA", "US"],
        "source_type": "policy",
    },
)

No te quedes en “subir un PDF”. Agrega los metadatos que necesita tu política de recuperación: estado, responsable, región, producto, plan, fecha de entrada en vigor, tipo de fuente y alcance de los permisos.

3. Agrega herramientas de producto alrededor de la base de conocimiento

El conocimiento responde preguntas sobre políticas. Las herramientas responden preguntas sobre el estado del producto.

from agno.tools import tool


@tool
def get_customer_account(customer_name: str) -> dict:
    """Fetch account facts needed for policy decisions."""
    return {
        "customer": customer_name,
        "plan": "Enterprise",
        "country": "CA",
        "sales_channel": "reseller",
        "renewal_date": "2026-05-12",
        "chargeback_open": True,
    }

Esta es la separación correcta:

Knowledge base -> "What do the policies say?"
Product tools  -> "What is true about this customer right now?"
Agent          -> "Given both, what decision is supported?"

4. Exige una salida de decisión estructurada

Para los workflows de producto, no devuelvas prosa sin una estructura definida. Usa una salida estructurada para que el frontend, el registro de auditoría y las evaluaciones puedan depender de campos estables.

from pydantic import BaseModel, Field


class PolicyDecision(BaseModel):
    decision: str = Field(description="refund_allowed, deny, or escalate")
    confidence: str = Field(description="low, medium, or high")
    answer: str
    required_escalation: str | None = None
    citations: list[str]
    missing_information: list[str] = []

Agno admite salidas estructuradas respaldadas por Pydantic, así que esto se convierte en un contrato de API en lugar de un ejercicio de parsing.

5. Construye el agente RAG

from agno.agent import Agent
from agno.models.openai import OpenAIResponses

policy_agent = Agent(
    name="support_policy_agent",
    model=OpenAIResponses(id="gpt-5.2"),
    knowledge=policy_knowledge,
    tools=[get_customer_account],
    output_schema=PolicyDecision,
    instructions=[
        "Answer only from approved policy knowledge and account tool data.",
        "Search the knowledge base before making policy claims.",
        "Cite source IDs for every policy claim.",
        "If required sources are missing or conflict, escalate instead of guessing.",
        "Never approve a refund when chargeback rules require finance review.",
    ],
)

Esto ya te da el comportamiento central de la aplicación:

  • búsqueda en el conocimiento
  • uso de herramientas
  • generación de respuestas sustentadas en las fuentes
  • salida tipada
  • uso trazable de fuentes

6. Publícalo con AgentOS

AgentOS convierte el agente en una API para producción. La documentación actual de Agno describe REST y SSE como interfaces de API predeterminadas, con opciones para AG-UI, WebSocket, MCP, A2A, Slack y otras interfaces.

from agno.os import AgentOS
from agno.os.interfaces.agui import AGUI

agent_os = AgentOS(
    name="Support Policy OS",
    agents=[policy_agent],
    interfaces=[AGUI(agent=policy_agent)],
    tracing=True,
)

app = agent_os.get_app()

if __name__ == "__main__":
    agent_os.serve(app="support_policy_os:app", reload=True)

Eso te da:

  • runtime de FastAPI
  • endpoints REST
  • streaming compatible con SSE
  • APIs de sesión
  • APIs de ejecución
  • captura de trazas
  • conectividad con AgentOS UI
  • integración de frontend compatible con AG-UI

En otras palabras, tu frontend puede ser una aplicación Astro/React/Next.js, pero no necesitas construir el runtime RAG desde cero.

7. Usa las evaluaciones integradas antes del lanzamiento

Agno tiene dimensiones de evaluación integradas para exactitud, criterios de agente como juez, rendimiento y confiabilidad. Para este asistente RAG, ejecutaría al menos dos tipos de evaluación:

Accuracy eval:
  Input: "ACME renewed through reseller in Canada and has an open chargeback. Can support refund?"
  Expected: decision = escalate, required_escalation = finance

Reliability eval:
  Expected tool calls:
    - get_customer_account
    - search_knowledge_base

El criterio de lanzamiento no debería ser “la respuesta se vio bien una vez”. Debería ser:

Golden set passes
   +
required tool calls happen
   +
citations are present
   +
structured output validates
   +
trace shows the right knowledge was retrieved

8. Usa AgentOS para el ciclo operativo

Una vez desplegada la aplicación, usa las funcionalidades de runtime respaldadas por la base de datos de Agno como tu ciclo de mejora:

Production run
   |
   v
AgentOS stores session + trace + tool calls
   |
   v
Review bad or low-confidence answers
   |
   v
Promote failures into eval examples
   |
   v
Improve metadata, policies, tools, prompt, or model
   |
   v
Rerun evals before release

Aquí es donde más importan las funcionalidades “integradas” de Agno. AgentOS no es solo una forma de exponer un agente como API. Te da los registros del runtime necesarios para depurar, evaluar y mejorar continuamente la aplicación RAG.

Cuándo Agno es una buena opción

Usa Agno para RAG cuando:

  • tu equipo de backend se siente cómodo con Python
  • quieres RAG agéntico sin escribir desde cero el contrato de la herramienta de búsqueda
  • quieres sesiones, trazas, memoria, conocimiento, evaluaciones y APIs en un solo runtime
  • necesitas exponer el mismo agente mediante REST, streaming, AG-UI u otras interfaces
  • quieres mantener el control de tus datos, con sesiones, conocimiento y trazas en tu base de datos

Ten más cautela cuando:

  • tu empresa ya tiene un runtime de IA maduro que usa solo TypeScript
  • necesitas una orquestación de recuperación muy personalizada que no encaja bien con el framework
  • tu principal desafío es la infraestructura de búsqueda, no el runtime de agentes

Mi recomendación práctica: usa Agno para gestionar la capa de agente y runtime, pero mantén explícito el modelo de conocimiento. Los IDs estables, los metadatos, las pruebas de recuperación y la asignación de responsables de las fuentes siguen siendo tu responsabilidad.

Evaluación: mide toda la cadena RAG

Una buena evaluación de RAG tiene al menos cuatro capas.

CapaPreguntaEjemplo de métrica
Recuperación¿Recuperamos la evidencia correcta?recall@k, precisión del contexto, MRR
Contexto¿Pasamos contexto útil y sin ruido?relevancia del contexto, redundancia, actualización
Generación¿La respuesta usó correctamente la evidencia?fidelidad a las fuentes, sustento en las fuentes, relevancia de la respuesta
Producto¿Esto satisfizo al usuario de forma segura?éxito de la tarea, tasa de escalamiento, CSAT, revisión humana

RAGAS, TruLens, DeepEval, LangSmith y herramientas similares giran en torno a la misma idea central: evaluar la recuperación y la generación por separado y luego evaluar la experiencia de extremo a extremo.

Aquí hay un pequeño esquema de evaluador:

from dataclasses import dataclass


@dataclass
class RagExample:
    question: str
    required_source_ids: set[str]
    expected_answer_facts: set[str]


@dataclass
class RagRun:
    retrieved_source_ids: list[str]
    answer: str
    cited_source_ids: set[str]


def recall_at_k(example: RagExample, run: RagRun, k: int = 5) -> float:
    retrieved = set(run.retrieved_source_ids[:k])
    if not example.required_source_ids:
        return 1.0
    return len(example.required_source_ids & retrieved) / len(example.required_source_ids)


def citation_coverage(example: RagExample, run: RagRun) -> float:
    if not example.required_source_ids:
        return 1.0
    return len(example.required_source_ids & run.cited_source_ids) / len(example.required_source_ids)


def unsupported_fact_count(answer_claims: set[str], supported_claims: set[str]) -> int:
    return len(answer_claims - supported_claims)

Esto es intencionalmente simple. En un sistema real, answer_claims y supported_claims podrían provenir de un LLM que actúe como juez, un extractor de afirmaciones o etiquetas humanas. El punto es que no solo debes preguntar: “¿La respuesta fue agradable?”. Pregunta si se recuperaron, citaron y usaron las fuentes requeridas.

El conjunto de evaluación que PMs e ingenieros pueden compartir

Un conjunto de evaluación RAG útil debe incluir más que preguntas del caso ideal.

Tipo de casoPor qué importa
Respuesta conocidaCorrección básica
Respuesta ausenteRechazo e incertidumbre
Fuentes contradictoriasManejo de conflictos
Fuente desactualizadaActualización y control de versiones
Pregunta multi-hopCadena de evidencia
Ambigüedad de entidadDesambiguación
Identificador exactoRecuperación por palabras clave y metadatos
Respuesta con muchas tablasCalidad del parser y de los chunks
Excepción de políticaLógica para casos límite
Error tipográfico o consulta vaga del usuarioReformulación de consultas

Un conjunto inicial práctico es de 50 a 100 ejemplos:

  • 30 preguntas comunes de usuarios
  • 20 casos límite de logs de producción o tickets de soporte
  • 20 casos adversariales o con fuentes desactualizadas
  • 10 casos sin respuesta disponible
  • 10 preguntas multi-hop o sobre relaciones

Luego agrega fallas de producción cada semana.

Cómo diagnosticar fallas

Cuando falle una respuesta RAG, no empieces cambiando el prompt. Usa la traza.

Bad answer
   |
   v
Was the needed source indexed?
   | no -> ingestion/parser/versioning bug
   v yes
Was it retrieved in top-k?
   | no -> query, embeddings, filters, chunking, hybrid search
   v yes
Was it ranked high enough?
   | no -> reranker, scoring, metadata boost
   v yes
Was it included in final context?
   | no -> context packing, dedupe, token budget
   v yes
Did the model use it correctly?
   | no -> prompt, model, citation rules, post-check
   v yes
Is the expected label wrong?
       -> update dataset

Aquí es donde los PMs pueden ayudar mucho. Muchas fallas no son fallas del modelo. Son fallas en la gestión del conocimiento: documentos desactualizados, políticas poco claras, ausencia de una fuente de verdad o páginas contradictorias.

Mejores prácticas que usaría en 2026

Esta es la versión breve que incluiría en una lista de verificación para el equipo.

  1. Diseña el corpus antes de ajustar el modelo.
  2. Mantén IDs de fuente estables y fáciles de citar.
  3. Preserva la jerarquía de documentos y las rutas de las secciones.
  4. Agrega metadatos de tenant, producto, región, versión, estado, responsable y fecha de entrada en vigor.
  5. Usa recuperación híbrida en producción, a menos que tengas evidencia de que solo con vectores es suficiente.
  6. Aplica reranking antes de la generación.
  7. Recupera chunks pequeños y responde con el contexto del elemento padre.
  8. Agrega reformulación de consultas solo después de poder ver las trazas de recuperación.
  9. Trata las tablas, imágenes, diagramas y bloques de código como casos especiales de ingesta.
  10. Exige respuestas sustentadas en las fuentes y con citas.
  11. Enseña al sistema a decir “no se encontró” y “las fuentes están en conflicto”.
  12. Evalúa por separado la recuperación, el contexto, la generación y el éxito del producto.
  13. Mantén actualizado un conjunto de evaluación a partir de fallas reales.
  14. Monitorea la deriva en producción a medida que cambian los documentos, las preguntas de los usuarios y los modelos.
  15. Incluye revisión humana en decisiones sobre políticas, asuntos legales, médicos, financieros o de alto impacto.

Una guía sencilla para decidir

Usa RAG simple cuando:

  • las preguntas son principalmente de un solo salto
  • los documentos están limpios y ya estructurados
  • las necesidades de actualización son moderadas
  • las citas son útiles, pero no críticas desde el punto de vista legal

Usa RAG estructurado o jerárquico cuando:

  • los usuarios preguntan sobre políticas, especificaciones, procedimientos, contratos o manuales
  • los chunks necesitan el contexto del elemento padre
  • las secciones, versiones, responsables y excepciones importan
  • los límites de tablas y código importan

Usa GraphRAG o recuperación que tenga en cuenta las relaciones cuando:

  • las preguntas requieren razonamiento multi-hop
  • las respuestas agregan información de muchos documentos
  • las relaciones entre entidades importan
  • el corpus es narrativo, desordenado o tiene vínculos cruzados
  • los usuarios preguntan “por qué”, “qué cambió”, “qué depende de esto” o “qué temas aparecen en todo el corpus”

Usa fine-tuning cuando:

  • el modelo tiene el contexto correcto, pero usa repetidamente el estilo, formato o política de decisión equivocados
  • necesitas un comportamiento consistente más que conocimiento nuevo
  • tienes un conjunto de entrenamiento representativo y de alta calidad

No uses RAG como sustituto de corregir la base de conocimiento. Si el material de origen es contradictorio, está desactualizado o no tiene responsables, la recuperación principalmente hará que esos problemas sean visibles más rápido.

Brechas pendientes y temas para profundizar

Este artículo se centra en el diseño y la evaluación. Hay tres áreas que merecen un tratamiento más profundo:

  • Seguridad: prompt injection a través de documentos recuperados, permisos de las fuentes, aislamiento de tenants y registros de auditoría.
  • RAG multimodal: PDFs con tablas, capturas de pantalla, diagramas, manuales con muchas imágenes y confianza del OCR.
  • Ingeniería de costos: estrategia de actualización de embeddings, caché, costo de los rerankers, presupuestos de contexto y SLOs de latencia.

No son temas secundarios. Suelen ser lo que determina si una aplicación RAG sobrevive al tráfico en producción.

Lista de fuentes