4 técnicas para detener las hallucinations en AI agents: Graph-RAG para recuperación precisa de datos, selección semántica de tools para elegir la herramienta correcta, guardrails neurosimbólicos para aplicar reglas de negocio, y validación multi-agent para detección de errores.
Objetivos de Aprendizaje
- Cómo Graph-RAG previene hallucinations estadísticas con datos estructurados
- Por qué la selección semántica de tools mejora la precisión y reduce costos de tokens
- Cómo los guardrails neurosimbólicos con Strands Agents bloquean operaciones inválidas
- Cómo la validación multi-agent detecta hallucinations antes de que lleguen a los usuarios
Esta demo utiliza Strands Agents. Patrones similares pueden aplicarse en LangGraph, AutoGen u otros frameworks de agents.
Repositorio y Prerequisitos
Clonar:
git clone https://github.com/aws-samples/sample-why-agents-fail
cd stop-ai-agent-hallucinations
Requisitos:
- Python 3.9+
- Acceso a un LLM (Amazon Bedrock, OpenAI, Anthropic u Ollama)
- Credenciales de AWS configuradas (si se usa Bedrock)
- Comprensión básica de AI agents y tool calling
- Bibliotecas clave: Strands Agents, Neo4j, FAISS, SentenceTransformers
Técnica 1: Graph-RAG para Recuperación Precisa de Datos
Problema: El RAG tradicional recupera fragmentos de texto en lugar de ejecutar cálculos, lo que produce tres tipos de hallucination:
- Estadísticas fabricadas a partir de agregaciones adivinadas
- Recuperación incompleta cuando los datos están dispersos
- Fabricación fuera de dominio cuando no existen datos relevantes
Solución: Los knowledge graphs proporcionan datos estructurados y verificables, donde las agregaciones son calculadas por la base de datos en lugar de ser adivinadas por los LLMs.
Código de Comparación
from strands import Agent, tool
# RAG Agent — vector similarity search
@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]])
# Graph-RAG Agent — Cypher queries on knowledge graph
@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)
"""
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])
rag_agent = Agent(tools=[search_faqs], model=model)
graph_agent = Agent(tools=[query_knowledge_graph], model=model)
Resultados de la Demo
| Tipo de Consulta | RAG | Graph-RAG |
|---|---|---|
| Agregación: "¿Calificación promedio en París?" | ⚠️ Calcula solo con 2 documentos | ✅ AVG() nativo sobre todos |
| Conteo: "¿Hoteles con piscina?" | ❌ "No tengo los datos" | ✅ Preciso: 133 |
| Multi-hop: "¿Tipos de habitación del mejor hotel?" | ❌ No puede recorrer relaciones | ✅ Recorrido Hotel → Room |
| Fuera de dominio: "Hoteles en la Antártida" | ❌ Fabrica respuestas | ✅ Honesto: "No hay hoteles" |
Hallazgo Clave: Graph-RAG reduce las hallucinations porque devuelve resultados vacíos en lugar de respuestas fabricadas cuando los datos no están disponibles.
Técnica 2: Selección Semántica de Tools para Elegir la Herramienta Correcta
Problema: "Las hallucinations en tool-calling aumentan con la cantidad de tools." Cuando los agents tienen muchas tools similares, exhiben errores de selección de función, errores de idoneidad, errores de parámetros, errores de completitud y comportamiento de evasión de tools.
Problema Dual:
- ❌ Riesgo de hallucination: Más tools = más selecciones inapropiadas
- ❌ Desperdicio de tokens: 31 tools ≈ 4,500 tokens por consulta
Solución: Filtrado Semántico de Tools
Filtra las tools antes de que el agent las vea usando similitud vectorial.
from sentence_transformers import SentenceTransformer
import faiss
# Build index once
model = SentenceTransformer('all-MiniLM-L6-v2')
tool_embeddings = model.encode([tool.description for tool in ALL_TOOLS])
index = faiss.IndexFlatL2(384)
index.add(tool_embeddings)
# Filter per query
query_embedding = model.encode([query])
distances, indices = index.search(query_embedding, k=3)
relevant_tools = [ALL_TOOLS[i] for i in indices[0]]
Intercambio Dinámico de Tools con Strands Agents
from strands import Agent
# Create agent once
agent = Agent(tools=[...], model=model)
# Swap tools per query without losing conversation history
for query in conversation:
relevant_tools = search_tools(query, top_k=3)
agent.tool_registry.registry.clear()
for tool in relevant_tools:
agent.tool_registry.register_tool(tool)
response = agent(query) # agent.messages preserved
Resultados en 29 Consultas de Viaje
Las pruebas muestran mejoras significativas:
- 86.4% de reducción en errores de selección de tools
- 89% de reducción en costos de tokens
- Precisión mantenida con menos tools visibles
Técnica 3: Guardrails Neurosimbólicos para AI Agents
Problema: Investigaciones demuestran que los agents generan hallucinations cuando las reglas de negocio se expresan únicamente en prompts de lenguaje natural. El prompt engineering no puede aplicar restricciones porque los prompts son sugerencias, no reglas ejecutables.
Solución: Usar hooks de Strands Agents para interceptar llamadas a tools antes de su ejecución y aplicar reglas simbólicas a nivel del framework.
Implementación
from strands import Agent, tool
from strands.hooks import HookProvider, HookRegistry, BeforeToolCallEvent
# Define symbolic rules
BOOKING_RULES = [
Rule(
name="max_guests",
condition=lambda ctx: ctx.get("guests", 1) <= 10,
message="Maximum 10 guests per booking"
),
]
# Create validation hook
class NeurosymbolicHook(HookProvider):
def register_hooks(self, registry: HookRegistry) -> None:
registry.add_callback(BeforeToolCallEvent, self.validate)
def validate(self, event: BeforeToolCallEvent) -> None:
ctx = {"guests": event.tool_use["input"].get("guests", 1)}
passed, violations = validate(BOOKING_RULES, ctx)
if not passed:
event.cancel_tool = f"BLOCKED: {', '.join(violations)}"
# Clean tool (no validation logic)
@tool
def book_hotel(hotel: str, guests: int = 1) -> str:
"""Book a hotel room."""
return f"SUCCESS: Booked {hotel} for {guests} guests"
# Attach hook to agent
hook = NeurosymbolicHook()
agent = Agent(tools=[book_hotel], hooks=[hook])
# Test
query = "Book hotel for 15 guests"
result = agent(query) # ✅ Hook blocks before tool executes
Por Qué los Hooks de Strands Destacan
- API sencilla: Implementar HookProvider y registrar callbacks
- Validación centralizada: Un solo hook valida todas las tools
- Tools limpias: Sin lógica de validación mezclada con lógica de negocio
- Tipado seguro: Objetos de eventos fuertemente tipados
- El LLM no puede evadir: Las reglas se aplican antes de la ejecución de la tool
Efectividad
| Escenario | Prompt Engineering | Neurosimbólico con Hooks |
|---|---|---|
| Parámetros Inválidos | ❌ Acepta | ✅ Bloquea |
| Prerequisitos Faltantes | ⚠️ A veces detecta | ✅ Siempre bloquea |
| Evasión de Reglas | ❌ Posible | ✅ Imposible |
Técnica 4: Validación Multi-Agent para Detección de Errores
Problema: Los agents individuales operan en aislamiento. Cuando generan hallucinations, no existe un mecanismo para detectar errores antes de que lleguen a los usuarios.
Solución: Múltiples agents especializados se validan mutuamente mediante debate estructurado, utilizando Strands Swarm para transferencias autónomas con contexto compartido.
Implementación
from strands import Agent
from strands.multiagent import Swarm
# Define specialized agents
executor = Agent(
name="executor",
tools=ALL_TOOLS,
system_prompt="Execute requests, then hand off to validator"
)
validator = Agent(
name="validator",
system_prompt="Check for hallucinations. Say VALID or HALLUCINATION"
)
critic = Agent(
name="critic",
system_prompt="Final review. Say APPROVED or REJECTED"
)
# Create swarm - agents hand off autonomously
swarm = Swarm(
[executor, validator, critic],
entry_point=executor,
max_handoffs=5
)
result = swarm("Book grand_hotel for John")
Comparación de Rendimiento
| Enfoque | Detección de Hallucinations | Precisión | Latencia |
|---|---|---|---|
| Agent Individual | ❌ Ninguna | ⚠️ Fabrica | ✅ Rápido |
| Multi-Agent | ✅ Detecta errores | ✅ Valida | ⚠️ Más lento |
Ejemplo: Cuando el executor intenta reservar "the_ritz_paris" (no existe), el validator detecta el hotel inválido y el critic devuelve FAILED en lugar de fabricar una alternativa.
Combinando Técnicas para Producción
Estas técnicas se complementan entre sí:
- Graph-RAG asegura la precisión de los datos
- Selección semántica de tools reduce errores de tools y costos de tokens
- Reglas neurosimbólicas aplican restricciones de negocio
- Validación multi-agent detecta las hallucinations restantes
Por Qué Strands Agents Python SDK
- Gestión dinámica de tools sin perder el estado de la conversación
- Multi-agent nativo con Swarm manejando transferencias
- Validación a nivel de tool ejecutándose antes de que el LLM vea los resultados
- Flexibilidad de modelos (Bedrock, OpenAI, Anthropic, Ollama)
- Listo para producción en despliegues AWS
Conclusiones Clave
- Las hallucinations son inevitables — enfócate en detección y mitigación, no en eliminación
- Graph-RAG para precisión cuando necesitas cálculos exactos o relaciones
- Filtrado semántico esencial con más de 10 tools similares
- Las reglas simbólicas aplican cumplimiento de negocio donde el prompt engineering falla
- La validación multi-agent detecta errores que los agents individuales no captan
- Strands Agents permite despliegues en producción con tools dinámicas y soporte nativo multi-agent
Referencias
- MetaRAG: Metamorphic Testing for Hallucination Detection
- Internal Representations as Indicators of Hallucinations in Agent Tool Selection
- Teaming LLMs to Detect and Mitigate Hallucinations
- RAG-KG-IL: Multi-Agent Hybrid Framework
- Strands Agents Documentation
Gracias!
🇻🇪🇨🇱 Dev.to Linkedin GitHub Twitter Instagram Youtube
Linktr
Top comments (0)