DEV Community

Cover image for Guardrails para Agentes de IA: Reglas Que los LLM No Pueden Evadir
Elizabeth Fuentes L for AWS Español

Posted on

Guardrails para Agentes de IA: Reglas Que los LLM No Pueden Evadir

Los agentes de IA pueden alucinar el éxito de una operación incluso cuando violan reglas de negocio. Confirman reservas sin verificación de pago, aceptan parámetros inválidos como 15 huéspedes cuando el máximo es 10, o ignoran prerrequisitos obligatorios.

El problema central: los agentes pueden confirmar reservas de hotel a pesar de que el pago nunca fue verificado, violar restricciones de capacidad, o saltarse pasos de validación obligatorios. El prompt engineering por sí solo no puede prevenir estos errores.

Este post demuestra cómo la validación neurosimbólica — combinando razonamiento del LLM con reglas simbólicas deterministas aplicadas a nivel de framework — bloquea operaciones inválidas antes de que se ejecuten.

Esta demo utiliza Strands Agents. Patrones similares pueden aplicarse en LangGraph, AutoGen u otros frameworks de agentes.


Resumen de la Serie

Esta es la Parte 3 de una serie sobre cómo detener las hallucinations en agentes de IA:

  1. RAG vs Graph-RAG — Knowledge graphs para prevenir hallucinations
  2. Semantic Tool Selection — Filtrado de tools basado en vectores
  3. AI Agent Guardrails (este post) — Reglas simbólicas que los LLM no pueden evadir
  4. Runtime Guardrails — Redirigir en lugar de bloquear
  5. Multi-Agent Validation — Detección de hallucinations basada en equipos

El Problema: Los Prompts Son Sugerencias, No Restricciones

La investigación de ATA: Autonomous Trustworthy Agents (2024) identifica tres patrones de hallucination:

  1. Errores de parámetros: El agent llama a book_hotel(guests=15) a pesar de que el docstring indica un máximo de 10
  2. Errores de completitud: El agent ejecuta reservas sin la verificación de pago requerida
  3. Comportamiento de evasión de tools: El agent confirma éxito sin llamar a los tools de validación obligatorios

Causa raíz: Los prompts son texto que el LLM interpreta. Las reglas de negocio embebidas en docstrings se convierten en sugerencias — el modelo decide si las sigue en cada llamada.


La Solución: Validación Neurosimbólica con Strands Hooks

Los hooks a nivel de framework interceptan las llamadas a tools antes de la ejecución. Usando BeforeToolCallEvent en Strands Agents, puedes:

  • Validar reglas simbólicas de forma determinista
  • Cancelar la ejecución del tool si alguna regla falla
  • Enviar un mensaje de cancelación directamente al LLM (no puede ser anulado)

Diferencia arquitectónica clave:

  • Prompts: Entrada del LLM (interpretable, anulable)
  • Hooks: Interceptores del framework (deterministas, obligatorios)

Prerrequisitos

  • Experiencia con Python y uso de tools en agentes LLM
  • Familiaridad con Strands Agents
git clone https://github.com/aws-samples/sample-why-agents-fail
cd stop-ai-agent-hallucinations/04-neurosymbolic-demo
uv venv && uv pip install -r requirements.txt
Enter fullscreen mode Exit fullscreen mode

Implementación: Reglas, Hook y Dos Agentes

Paso 1: Definir Reglas Simbólicas

from dataclasses import dataclass
from typing import Callable

@dataclass
class Rule:
    name: str
    condition: Callable[[dict], bool]
    message: str

BOOKING_RULES = [
    Rule("max_guests",   lambda ctx: ctx.get("guests", 1) <= 10,     "Maximum 10 guests per booking"),
    Rule("valid_dates",  lambda ctx: ctx["check_in"] < ctx["check_out"], "Check-in must be before check-out"),
]

CONFIRMATION_RULES = [
    Rule("payment_before_confirm", lambda ctx: ctx.get("payment_verified", False),
         "Payment must be verified before confirmation"),
]
Enter fullscreen mode Exit fullscreen mode

Las reglas son funciones Python simples — deterministas, testeables y auditables de forma independiente a cualquier agent.


Paso 2: Crear el Hook de Validación

from strands.hooks import HookProvider, HookRegistry, BeforeToolCallEvent

class NeurosymbolicHook(HookProvider):

    def register_hooks(self, registry: HookRegistry) -> None:
        registry.add_callback(BeforeToolCallEvent, self.validate)

    def validate(self, event: BeforeToolCallEvent) -> None:
        tool_name = event.tool_use["name"]
        if tool_name not in self.rules:
            return
        context = self._build_context(tool_name, event.tool_use["input"])
        passed, violations = validate(self.rules[tool_name], context)
        if not passed:
            event.cancel_tool = f"BLOCKED: {', '.join(violations)}"
Enter fullscreen mode Exit fullscreen mode

Cuando se establece event.cancel_tool, Strands reemplaza el resultado del tool con ese mensaje antes de que el LLM lo vea. El tool nunca se ejecuta.


Paso 3: Definir Tools Limpios

from strands import tool

@tool
def book_hotel(hotel: str, check_in: str, check_out: str, guests: int = 1) -> str:
    """Book a hotel room."""
    return f"SUCCESS: Booked {hotel} for {guests} guests, {check_in} to {check_out}"

@tool
def process_payment(amount: float, booking_id: str) -> str:
    """Process payment for a booking."""
    return f"SUCCESS: Processed ${amount:.2f} for {booking_id}"

@tool
def confirm_booking(booking_id: str) -> str:
    """Confirm a booking."""
    return f"SUCCESS: Confirmed {booking_id}"
Enter fullscreen mode Exit fullscreen mode

Los tools contienen solo lógica de negocio — sin validación mezclada.


Paso 4: Crear Ambos Agentes

from strands import Agent
# Using OpenAI-compatible interface via Strands SDK (not direct OpenAI usage)
from strands.models.openai import OpenAIModel

MODEL = OpenAIModel(model_id="gpt-4o-mini")

# Baseline: no hook, no validation
baseline_agent = Agent(tools=[book_hotel, process_payment, confirm_booking], model=MODEL)

# Guarded: hook intercepts every tool call
hook = NeurosymbolicHook(STATE)
guarded_agent = Agent(tools=[book_hotel, process_payment, confirm_booking], hooks=[hook], model=MODEL)
Enter fullscreen mode Exit fullscreen mode

Mismos tools, mismo modelo, mismos prompts. La única diferencia: hooks=[hook]


Resultados de las Pruebas

Prueba 1: Confirmar Reserva Sin Pago

Consulta: "Confirm booking BK001"

Agent Resultado
Baseline ❌ Ejecuta — pago nunca verificado, docstring ignorado
Guarded ✅ Bloqueado — el hook evalúa CONFIRMATION_RULES, encuentra payment_verified=False, cancela

El LLM recibe: BLOCKED: Payment must be verified before confirmation


Prueba 2: Reservar Hotel Excediendo el Límite de Huéspedes

Consulta: "Book Grand Hotel for 15 people from 2026-03-20 to 2026-03-25"

Agent Resultado
Baseline ❌ Ejecuta con 15 huéspedes — máximo en docstring ignorado
Guarded ✅ Bloqueado — max_guests_check(15 <= 10) falla, ejecución cancelada

La validación ocurre antes de la ejecución — no hay reserva que revertir.


Prueba 3: Reserva Válida

Consulta: "Book Grand Hotel for 5 guests from 2026-03-20 to 2026-03-25"

Agent Resultado
Baseline ✅ Ejecuta
Guarded ✅ Ejecuta — todas las reglas pasan, el hook no agrega fricción

Resumen de Escenarios

Escenario Baseline Guarded
Confirmar sin pago ❌ Ejecuta — hallucination ✅ Bloqueado antes de la ejecución
Reservar 15 huéspedes (máx. 10) ❌ Ejecuta — regla violada ✅ Bloqueado antes de la ejecución
Reserva válida (5 huéspedes) ✅ Ejecuta ✅ Ejecuta

Punto Clave: Dónde Se Aplica la Validación

Prompt Engineering (Insuficiente)

system_prompt = """
IMPORTANT: Never confirm bookings without payment verification.
CRITICAL: Maximum 10 guests per booking.
"""
# The LLM reads this as context. It can hallucinate compliance.
Enter fullscreen mode Exit fullscreen mode

❌ El LLM decide si sigue estas instrucciones en cada llamada.

Aplicación Basada en Hooks (Suficiente)

def validate(self, event: BeforeToolCallEvent) -> None:
    passed, violations = validate(self.rules[tool_name], context)
    if not passed:
        event.cancel_tool = f"BLOCKED: {', '.join(violations)}"
        # Tool never executes. LLM receives the cancellation.
        # There is no path to override this.
Enter fullscreen mode Exit fullscreen mode

✅ El hook se ejecuta fuera del LLM. La decisión no depende del LLM.

Diferencia arquitectónica: Los prompts son entrada del LLM (interpretable). Los hooks son interceptores del framework (deterministas).


Consideraciones para Producción

Ventajas

  • Restricciones verificables: Las reglas son código, no instrucciones
  • Centralizadas: Un solo hook valida todos los tools
  • Testeables de forma independiente: Las reglas funcionan fuera de cualquier agent o contexto de LLM
  • Auditables: Las violaciones de reglas producen eventos explícitos con nombre del tool, parámetros y razón

Desafíos

  • Las reglas deben definirse explícitamente para cada operación protegida
  • No maneja lógica difusa o probabilística — las reglas son booleanas
  • Los casos límite requieren manejo explícito en las condiciones
  • Las reglas necesitan mantenimiento a medida que evoluciona la lógica de negocio

Mejores Prácticas

  • Define hooks para operaciones críticas: reservas, pagos, cancelaciones
  • Registra todas las violaciones de reglas con nombre del tool, parámetros y razón
  • Testea las reglas de forma independiente y exhaustiva
  • Combina con semantic tool selection (Parte 2) y multi-agent validation (Parte 5) para protección en capas

Siguiente Paso

Los guardrails simbólicos bloquean violaciones de reglas a nivel de tool. Pero bloquear detiene el flujo de trabajo — el usuario debe intervenir.

Parte 4: Runtime Guardrails muestra cómo Agent Control redirige a los agentes para que se autocorrijan en lugar de bloquearlos, completando flujos de trabajo sin intervención humana.


Conclusiones Clave

  • Los prompts son sugerencias: El LLM interpreta docstrings; puede alucinar cumplimiento con cualquier instrucción
  • Los hooks son aplicación forzada: BeforeToolCallEvent intercepta antes de la ejecución a nivel de framework — el LLM no puede anular un tool cancelado
  • Todas las operaciones inválidas bloqueadas: Cero cambios en tools, cero cambios en prompts, un hook agregado
  • Separación limpia: Los tools manejan operaciones; los hooks manejan la aplicación de restricciones
  • Auditable por diseño: Las violaciones de reglas son condiciones Python explícitas — testeables, registrables, trazables
  • Un hook, todos los tools: Un solo NeurosymbolicHook valida cada llamada a tool de forma centralizada

Ejecútalo Tú Mismo

git clone https://github.com/aws-samples/sample-why-agents-fail
cd stop-ai-agent-hallucinations/04-neurosymbolic-demo
uv venv && uv pip install -r requirements.txt
uv run test_neurosymbolic_hooks.py
Enter fullscreen mode Exit fullscreen mode

Puedes cambiar a cualquier proveedor soportado por Strands — consulta Strands Model Providers para la configuración.


Referencias

Investigación

Strands Agents

Código


Gracias!

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

Top comments (0)