RAG vs GraphRAG: Cuando los Agentes Alucinan Respuestas

RAG vs GraphRAG: Cuando los Agentes Alucinan Respuestas

Un agent que alucina durante la ejecucion es catastrofico: podria fabricar parametros de API, inventar confirmaciones de exito tras fallos, o ejecutar acciones basadas en creencias falsas.

Este articulo explora como el Retrieval-Augmented Generation (RAG) tradicional provoca que los AI agents alucinen estadisticas y agregaciones, en contraste con GraphRAG usando knowledge graphs de Neo4j. Demostramos las diferencias a traves de un agent de reservas de viajes que compara RAG (FAISS) frente a GraphRAG sobre 300 documentos FAQ de hoteles.

Esta demo utiliza Strands Agents. Patrones similares se pueden aplicar en LangGraph, AutoGen u otros frameworks de agents.


Vision General de la Serie

Esta es la Parte 1 de una serie sobre como detener las hallucinations en AI agents:

  1. RAG vs Graph-RAG (este articulo) — Los knowledge graphs previenen agregaciones alucinadas
  2. Semantic Tool Selection — El filtrado vectorial reduce las elecciones incorrectas de tools
  3. Multi-Agent Validation — Los swarms detectan hallucinations antes de que lleguen a los usuarios
  4. AI Agent Guardrails — Reglas simbolicas que el LLM no puede eludir
  5. Runtime Guardrails — Dirigir en lugar de bloquear

El Problema: Tres Tipos de Hallucinations en RAG

La investigacion (MetaRAG: Metamorphic Testing for Hallucination Detection) identifica tres tipos de hallucination en sistemas RAG:

  1. Estadisticas fabricadas — Los sistemas RAG producen numeros estimados en lugar de valores calculados. El LLM adivina agregaciones a partir de unos pocos documentos recuperados en vez de calcularlas sobre el conjunto completo de datos.
  2. Recuperacion incompleta — La busqueda vectorial recupera los top-k fragmentos mas similares, pero los datos necesarios para una respuesta pueden estar dispersos en muchos documentos. El LLM llena los vacios con fabricaciones que suenan plausibles.
  3. Fabricacion fuera de dominio — Cuando no existen datos relevantes, RAG devuelve los resultados de apariencia mas similar de todos modos. El LLM trata estas coincidencias parciales como contexto valido y fabrica una respuesta con confianza.

La Solucion: GraphRAG con Knowledge Graphs

Los knowledge graphs resuelven estos problemas a nivel arquitectonico:

  • Las agregaciones son calculadas por el motor de base de datos (AVG, COUNT, SUM) — no adivinadas por el LLM
  • Las relaciones son aristas explicitas en el grafo — no inferidas por similitud de texto
  • Los datos faltantes devuelven resultados vacios — el LLM recibe “no se encontraron resultados” en lugar de coincidencias parciales de las cuales alucinar

La diferencia clave: RAG siempre devuelve algo. GraphRAG devuelve resultados vacios cuando los datos no existen.


Requisitos Previos

  • Python 3.9+
  • Neo4j ejecutandose localmente con el plugin APOC
  • Clave de API de OpenAI (o cualquier proveedor de modelos compatible con Strands)
git clone https://github.com/aws-samples/sample-why-agents-fail
cd stop-ai-agent-hallucinations/01-faq-graphrag-demo
uv venv && uv pip install -r requirements.txt

Implementacion

Agent 1: RAG Tradicional (FAISS)

from strands import Agent, tool

@tool
def search_faqs(query: str) -> str:
    """Search hotel FAQs using vector similarity."""
    query_embedding = embed_model.encode([query])
    distances, indices = index.search(query_embedding.astype('float32'), 3)
    return "\n".join([documents[idx]['text'][:500] for idx in indices[0]])

rag_agent = Agent(tools=[search_faqs], model=model)

El agent RAG recupera los 3 documentos mas similares y permite que el LLM los resuma. No puede agregar sobre el conjunto completo de datos, recorrer relaciones ni reconocer cuando los datos estan ausentes.

Agent 2: GraphRAG (Neo4j + Cypher)

@tool
def query_knowledge_graph(cypher_query: str) -> str:
    """Execute a Cypher query against the hotel knowledge graph.

    Node labels: Hotel, Room, Amenity, Policy, Service
    Relationships: (Hotel)-[:HAS_ROOM]->(Room), (Hotel)-[:OFFERS_AMENITY]->(Amenity),
                   (Hotel)-[:HAS_POLICY]->(Policy), (Hotel)-[:PROVIDES_SERVICE]->(Service)

    Properties:
    - Hotel: name, location, rating, price_range
    - Room: type, capacity, price_per_night
    - Amenity: name, category
    """
    with driver.session() as session:
        result = session.run(cypher_query)
        records = list(result)
        if not records:
            return "No results found."
        return f"Found {len(records)} results:\n" + "\n".join(str(dict(r.items())) for r in records[:15])

graph_agent = Agent(tools=[query_knowledge_graph], model=model)

El schema en el docstring habilita Text2Cypher — el LLM genera consultas Cypher precisas en lugar de adivinar a partir de fragmentos de texto.


Resultados: 4 Escenarios de Prueba

Prueba 1: Agregacion — “What is the average hotel rating in Paris?”

EnfoqueResultadoPor que
RAG4.7 (de solo 2 documentos)Recupero 2 documentos similares y promedio esas calificaciones
GraphRAG4.7 (a nivel de base de datos) ✅MATCH (h:Hotel {location:'Paris'}) RETURN avg(h.rating) — calculado sobre todos los hoteles

RAG tuvo suerte aqui — mismo numero, pero de 2 documentos en vez del conjunto completo de datos. Con datos diferentes, esto divergiria.

Prueba 2: Conteo — “How many hotels have a swimming pool?”

EnfoqueResultadoPor que
RAG”No tengo los datos” ❌Los 3 documentos principales no mencionaban piscinas; no pudo contar entre 300 documentos
GraphRAG”133 hoteles” ✅MATCH (h)-[:OFFERS_AMENITY]->(a {name:'pool'}) RETURN count(h)

Prueba 3: Multi-hop — “What room types does the highest-rated hotel offer?”

EnfoqueResultadoPor que
RAGIncompleto ⚠️Encontro informacion del hotel pero no pudo recorrer hasta los datos de habitaciones
GraphRAGCompleto con datos de habitaciones ✅MATCH (h:Hotel) WITH h ORDER BY h.rating DESC LIMIT 1 MATCH (h)-[:HAS_ROOM]->(r) RETURN r

Prueba 4: Fuera de dominio — “Find hotels in Antarctica”

EnfoqueResultadoPor que
RAGFabrico “Estaciones de Investigacion” como hoteles ❌Devolvio documentos de apariencia similar sobre alojamiento en clima frio
GraphRAG”No se encontraron hoteles” ✅MATCH (h:Hotel {location:'Antarctica'}) RETURN h — resultado vacio

Cuando Usar Cada Enfoque

CriterioRAGGraphRAG
Estructura de datosTexto no estructurado, documentosEstructurado, con relaciones
Tipo de consultaSimilitud semantica, busqueda difusaAgregaciones precisas, recorridos
Datos faltantesDevuelve resultados similares (riesgo de hallucination)Devuelve vacio (fallo honesto)
Complejidad de configuracionMenor (embeddings + vector store)Mayor (knowledge graph + schema)
Ideal paraBusqueda de contenido, Q&A sobre documentosAnalitica, razonamiento multi-hop, verificacion

Conclusiones Clave

  1. RAG siempre devuelve algo — incluso cuando los datos no existen, creando oportunidades de hallucination
  2. GraphRAG devuelve resultados vacios cuando los datos estan ausentes — forzando respuestas honestas de “No lo se”
  3. Las agregaciones deben ser calculadas por la base de datos, no adivinadas por el LLM
  4. El schema en el docstring del tool habilita Text2Cypher — consultas precisas en lugar de similitud de texto
  5. Ambos enfoques tienen su lugar — usa RAG para busqueda semantica, GraphRAG para recuperacion precisa de datos

Siguiente Paso

GraphRAG previene estadisticas y agregaciones alucinadas. Pero los agents aun pueden seleccionar el tool incorrecto o desperdiciar tokens procesando descripciones de tools irrelevantes.

Parte 2: Semantic Tool Selection muestra como el filtrado vectorial reduce los errores de seleccion de tools y los costos de tokens.


Pruebalo Tu Mismo

git clone https://github.com/aws-samples/sample-why-agents-fail
cd stop-ai-agent-hallucinations/01-faq-graphrag-demo
uv venv && uv pip install -r requirements.txt
# Start Neo4j with APOC plugin first
uv run test_graphrag_hallucinations.py

Puedes cambiar a cualquier proveedor compatible con Strands — consulta Strands Model Providers para la configuracion.


Referencias

Investigacion

Strands Agents

Codigo


Gracias!

🇻🇪🇨🇱 Dev.to Linkedin GitHub Twitter Instagram Youtube