DEV Community

Cover image for Salvaguardas para agentes IA: Filtros de aprobación y control del radio de impacto
Roobia
Roobia

Posted on • Originally published at apidog.com

Salvaguardas para agentes IA: Filtros de aprobación y control del radio de impacto

Son las 3 de la mañana. Tu agente procesa una cola de tickets de soporte mientras duermes. Detecta una posible escalada, redacta un resumen y se lo envía por correo a tu jefe. El resumen es correcto y está bien escrito, pero nadie solicitó ese correo, nadie lo revisó y nada pudo detenerlo cuando decidió enviarlo. El agente hizo exactamente lo que sus instrucciones le permitían hacer. Ese es el problema.

Prueba Apidog hoy

Los fallos más costosos no siempre son alucinaciones ni bloqueos visibles. Esos errores hacen ruido y suelen detectarse. Los peligrosos son silenciosos: el agente ejecuta correctamente una acción que nunca debió realizar, como enviar un email, eliminar un registro o crear un pedido.

Las barreras de seguridad (guardrails) se interponen entre la decisión del modelo y la acción real. Inspeccionan una acción y deciden si deben permitirla, bloquearla o solicitar aprobación humana. En esta guía implementarás cuatro controles:

  1. Listas blancas de acciones.
  2. Puertas de aprobación humana.
  3. Modo de prueba en seco.
  4. Límites de radio de explosión.

También aprenderás a probar que esos controles funcionan. Para más contexto, consulta por qué los agentes de IA fallan en producción, donde la ausencia de barreras de seguridad aparece como uno de los cinco modos de fallo principales.

Clasifica las acciones según su impacto

No todas las acciones requieren aprobación. Un agente puede leer un calendario, consultar el clima o recuperar un informe de solo lectura sin intervención humana. Poner una puerta de aprobación delante de cada lectura solo entrena a las personas a pulsar “aprobar” sin revisar nada.

Empieza clasificando las herramientas y endpoints de tu agente en dos grupos:

Grupo Ejemplos Comportamiento
Lista blanca Lecturas, búsquedas, consultas idempotentes y acciones reversibles Ejecutar automáticamente
Acciones restringidas Envíos, eliminaciones, pagos, escrituras o acciones visibles para clientes Requerir una puerta

Usa esta prueba para decidir:

Si el agente ejecutara esta acción cien veces por error, ¿qué tan grave sería?

Si la respuesta es peor que “no pasa nada”, esa acción no debería estar en la lista blanca.

No clasifiques solo por el verbo HTTP. Clasifica por consecuencia:

  • Un POST /drafts que crea un borrador puede ser reversible.
  • Un POST /drafts/{id}/send que entrega un correo no lo es.
  • Dos solicitudes POST pueden requerir políticas completamente distintas.

Puedes expresar esa clasificación directamente en tu capa de herramientas:

type RiskLevel = "allow" | "approval";

const actionPolicy: Record<string, RiskLevel> = {
  "calendar.getEvents": "allow",
  "weather.getForecast": "allow",
  "tickets.search": "allow",
  "email.createDraft": "allow",
  "email.send": "approval",
  "records.delete": "approval",
  "payments.createCharge": "approval",
};
Enter fullscreen mode Exit fullscreen mode

Antes de ejecutar una herramienta, consulta la política:

function requiresApproval(action: string): boolean {
  return actionPolicy[action] === "approval";
}
Enter fullscreen mode Exit fullscreen mode

La clasificación debe vivir fuera del prompt. El modelo puede sugerir una acción, pero tu código debe decidir si puede ejecutarla.

Añade aprobación humana a las acciones destructivas

Una vez identificadas las acciones peligrosas, implementa una puerta de aprobación. El flujo debe detenerse antes del efecto secundario, mostrar la solicitud real y esperar una decisión humana.

El patrón básico es:

Modelo propone una acción
        ↓
La política la clasifica como restringida
        ↓
Crear solicitud de aprobación
        ↓
Humano aprueba o rechaza
        ↓
Ejecutar o cancelar la acción
Enter fullscreen mode Exit fullscreen mode

No muestres descripciones vagas como:

“El agente quiere enviar un correo”.

Muestra los datos que una persona necesita para tomar una decisión:

  • Destinatario.
  • Asunto.
  • Cuerpo.
  • Adjuntos.
  • Endpoint y método HTTP.
  • Motivo proporcionado por el agente.
  • Payload exacto que se enviará.

Por ejemplo:

{
  "action": "email.send",
  "reason": "El ticket parece una escalada de prioridad alta",
  "request": {
    "method": "POST",
    "url": "/emails/send",
    "body": {
      "to": "manager@example.com",
      "subject": "Posible escalada: ticket #4821",
      "text": "Resumen del incidente..."
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Una implementación mínima podría verse así:

async function executeAgentAction(action: string, payload: unknown) {
  if (!requiresApproval(action)) {
    return executeAction(action, payload);
  }

  const approval = await createApprovalRequest({
    action,
    payload,
    createdAt: new Date().toISOString(),
  });

  if (approval.status !== "approved") {
    await logAuditEvent({
      action,
      payload,
      result: "rejected",
      approvalId: approval.id,
    });

    return { status: "blocked", approvalId: approval.id };
  }

  const result = await executeAction(action, payload);

  await logAuditEvent({
    action,
    payload,
    result: "executed",
    approvalId: approval.id,
  });

  return result;
}
Enter fullscreen mode Exit fullscreen mode

Haz que rechazar sea rápido y explícito. Si una persona no entiende qué aprobará, aprobará por reflejo. La discusión sobre añadir un paso de aprobación humana antes de que un agente actúe vuelve repetidamente al mismo punto: el revisor debe ver el payload concreto para tomar una decisión real.

Registra cada aprobación y rechazo. Cuando ocurra un incidente, el registro de auditoría te permitirá responder:

  • ¿El agente pidió aprobación?
  • ¿Quién aprobó la acción?
  • ¿Qué payload se aprobó?
  • ¿La solicitud ejecutada coincidió con la aprobada?
  • ¿La puerta se omitió por un error de configuración?

Implementa un modo de prueba en seco

Las aprobaciones protegen producción. El modo de prueba en seco (dry run) protege tu proceso de desarrollo y puesta en escena.

En una prueba en seco, el agente debe:

  1. Elegir la herramienta.
  2. Construir la solicitud.
  3. Resolver los argumentos.
  4. Validar la política.
  5. Detenerse antes del efecto secundario.
  6. Devolver o registrar lo que habría ejecutado.

No debes limitarte a simular una respuesta final. Debes inspeccionar el plan completo de llamadas.

async function executeAction(
  action: string,
  payload: unknown,
  options: { dryRun?: boolean } = {}
) {
  if (options.dryRun) {
    return {
      status: "dry_run",
      action,
      payload,
      message: "La acción no se ejecutó.",
    };
  }

  return performLiveAction(action, payload);
}
Enter fullscreen mode Exit fullscreen mode

En un flujo de orquestación, activa el modo de prueba en seco para todas las herramientas con efectos secundarios:

const agentRun = await runAgent({
  input: ticket,
  toolExecution: {
    dryRun: true,
  },
});
Enter fullscreen mode Exit fullscreen mode

Una salida útil incluye las acciones en orden:

{
  "status": "dry_run",
  "plannedActions": [
    {
      "step": 1,
      "tool": "tickets.get",
      "arguments": { "id": "4821" }
    },
    {
      "step": 2,
      "tool": "email.send",
      "arguments": {
        "to": "manager@example.com",
        "subject": "Posible escalada"
      }
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Esto te permite detectar un plan incorrecto antes de que llegue a producción. Una vista de depurador de agente de IA dedicado convierte “el agente hizo algo raro” en una observación verificable:

Intentó llamar al endpoint de eliminación en el paso cuatro.

No confundas prueba en seco con aprobación humana:

  • Prueba en seco: desarrollo, staging y depuración; no hay efectos reales.
  • Aprobación humana: producción; la acción existe, pero requiere confirmación.

Necesitas ambas.

Limita el radio de explosión

Las listas blancas, las puertas y el modo de prueba en seco deciden qué ocurre con una acción individual. Los límites de radio de explosión controlan el daño total que el agente puede causar a través de muchas acciones.

Implementa al menos estos tres límites.

1. Alcances mínimos

Entrega al agente credenciales con los permisos mínimos necesarios.

Un agente que gestiona incidencias de un proyecto no debería recibir una clave de administrador para toda la organización. Debe usar un token limitado al proyecto, repositorio, workspace o cuenta que necesita.

Mal: token_admin_global
Bien: token_project_support_read_write
Enter fullscreen mode Exit fullscreen mode

2. Cuotas de acciones

Limita cuántas veces puede ejecutar una acción en una ventana de tiempo. Así, un bucle defectuoso no enviará mil correos antes de que alguien lo detecte.

const limits = {
  "email.send": { max: 10, windowMs: 60 * 60 * 1000 },
  "records.delete": { max: 3, windowMs: 24 * 60 * 60 * 1000 },
};
Enter fullscreen mode Exit fullscreen mode

Comprueba el límite antes de ejecutar:

async function assertQuota(action: string, agentId: string) {
  const limit = limits[action];

  if (!limit) return;

  const count = await getActionCount(agentId, action, limit.windowMs);

  if (count >= limit.max) {
    throw new Error(`Cuota superada para ${action}`);
  }
}
Enter fullscreen mode Exit fullscreen mode

3. Límites de gasto

Define topes por tarea y por día para:

  • Tokens del modelo.
  • Llamadas a APIs de pago.
  • Pedidos.
  • Reembolsos.
  • Cargos.
  • Recursos de infraestructura.
const budget = {
  maxTokensPerTask: 50_000,
  maxDailySpendUsd: 25,
  maxChargePerTaskUsd: 100,
};
Enter fullscreen mode Exit fullscreen mode

Estos límites funcionan como red de seguridad. Incluso si una puerta falla, el agente no debería poder escapar de su alcance, superar una cuota o gastar sin control.

Observa las métricas que alimentan cada límite:

  • Llamadas por acción.
  • Gasto por tarea.
  • Gasto diario.
  • Errores cerca del límite.
  • Rechazos por cuota.
  • Acciones bloqueadas por permisos.

Trátalo como observabilidad de la API para cualquier servicio de producción.

OWASP describe este riesgo como “agencia excesiva” en el Top 10 de OWASP para aplicaciones de modelos de lenguaje grandes (LLM). Cada límite reduce la capacidad del agente para causar daño cuando toma una mala decisión.

Cómo probar una barrera de seguridad

Cada barrera de seguridad es una rama de código que suele ejecutarse solo cuando algo peligroso está a punto de ocurrir. Por eso es una de las rutas menos ejercitadas y más propensas a romperse en silencio.

Una puerta que nunca se activa puede parecer idéntica a una puerta que se activa y se ignora.

Una barrera de seguridad que no has probado es una barrera de seguridad que no tienes.

No pruebes este comportamiento contra una API real. Si tu prueba llama al endpoint real de envío, eliminación o pago, estarás creando exactamente el efecto secundario que quieres evitar.

En su lugar, simula el endpoint destructivo y prueba la ruta que toma el agente.

1. Simula el endpoint con efectos secundarios

Configura un mock para el envío, eliminación o pago. El mock debe registrar las solicitudes recibidas y devolver respuestas controladas.

const sendEmailMock = vi.fn().mockResolvedValue({
  status: 202,
  body: { id: "email_123" },
});
Enter fullscreen mode Exit fullscreen mode

2. Ejecuta un escenario peligroso

Usa una entrada que debería activar la barrera:

  • Un ticket que parece una escalada.
  • Una solicitud de eliminación.
  • Un pedido de alto valor.
  • Un reembolso fuera de política.
const result = await runAgent({
  input: "Elimina el registro del cliente 4821",
  tools: {
    deleteRecord: deleteRecordMock,
  },
});
Enter fullscreen mode Exit fullscreen mode

3. Afirma la ruta, no solo el resultado

Tu prueba debe verificar dos cosas:

  1. El endpoint destructivo no recibió llamadas.
  2. La solicitud de aprobación se creó con el payload correcto.
expect(deleteRecordMock).not.toHaveBeenCalled();

expect(createApprovalRequest).toHaveBeenCalledWith(
  expect.objectContaining({
    action: "records.delete",
    payload: expect.objectContaining({
      recordId: "4821",
    }),
  })
);
Enter fullscreen mode Exit fullscreen mode

La condición correcta es:

El agente preguntó antes de actuar.

No:

El agente terminó sin errores.

4. Prueba también el camino permitido

Una barrera que bloquea todo también está rota. Ejecuta una acción segura y confirma que no generó una aprobación innecesaria.

await runAgent({
  input: "Consulta el estado del ticket 4821",
});

expect(createApprovalRequest).not.toHaveBeenCalled();
expect(getTicketMock).toHaveBeenCalled();
Enter fullscreen mode Exit fullscreen mode

Consulta cómo probar agentes de IA que llaman a tus APIs para una configuración completa. También puedes revisar la guía sobre agentes de IA y pruebas de API para patrones de aserción que toleran el comportamiento no determinista de los modelos.

El punto clave es simple: verifica que el efecto secundario no ocurrió y que la aprobación sí ocurrió. Una prueba que solo cubre el camino feliz seguirá pasando incluso cuando la puerta deje de funcionar.

Dónde encaja Apidog y dónde no

Sé preciso sobre el rol de cada herramienta. Apidog no es:

  • Un framework de agentes.
  • Un host de modelos.
  • Una biblioteca de barreras de seguridad.
  • Una plataforma de evaluación.
  • Un sistema que decide qué acciones son seguras.

Tu código y tu capa de orquestación deben controlar:

  • La lista blanca.
  • Las reglas de aprobación.
  • El modo de prueba en seco.
  • Los límites de alcance, cuota y gasto.

Apidog encaja en la capa de API que esas barreras protegen. Puedes simular endpoints destructivos —envíos, eliminaciones o cargos— para que el agente practique acciones peligrosas sin consecuencias reales.

El flujo de prueba es:

  1. Simula el endpoint destructivo.
  2. Configura respuestas exitosas y fallidas.
  3. Ejecuta el agente contra el mock.
  4. Verifica que no hubo tráfico hacia la API real.
  5. Verifica que se creó una solicitud de aprobación.
  6. Valida el payload que el agente intentó enviar.

Ese es el encaje práctico: Apidog prueba las APIs que llama tu agente y simula las acciones destructivas para que puedas demostrar que el agente toma la ruta de aprobación en lugar de la ruta en vivo.

Preguntas frecuentes

¿Cuál es la diferencia entre una lista blanca y una puerta de aprobación?

La lista blanca define qué acciones pueden ejecutarse automáticamente sin intervención humana. La puerta de aprobación se aplica a las acciones fuera de esa lista: el agente se detiene hasta que una persona confirme. La lista blanca clasifica; la puerta detiene.

¿Las barreras de seguridad ralentizan demasiado al agente?

Solo si bloqueas las acciones equivocadas. Mantén en la lista blanca las lecturas y acciones reversibles. Reserva las puertas para pagos, eliminaciones, envíos y operaciones costosas o difíciles de deshacer.

¿Puedo probar las barreras sin llamar a APIs reales?

Sí, y deberías hacerlo. Simula el endpoint con efectos secundarios, ejecuta el escenario peligroso y verifica que el mock no recibió llamadas mientras la ruta de aprobación sí se activó.

¿Qué debería poner primero detrás de una puerta?

La acción más difícil de revertir: pagos, eliminaciones y cualquier operación que llegue a clientes o compañeros. Si una repetición accidental produciría daño real, no pertenece a la lista blanca.

Empieza por la acción más destructiva

No necesitas implementar las cuatro barreras de seguridad el primer día.

Elige la acción que más te preocuparía explicar durante una revisión de incidentes. Añade una puerta de aprobación esta semana. Después, escribe la prueba:

  1. Simula el endpoint.
  2. Ejecuta el agente.
  3. Confirma que solicita aprobación.
  4. Confirma que no ejecuta la acción real.

La primera vez que rompas intencionadamente la puerta y veas fallar esa prueba, tendrás una razón real para confiar en ella.

Descarga Apidog para simular endpoints destructivos, configurar respuestas y verificar que tu agente toma la ruta de aprobación en lugar de la ruta en vivo.

Top comments (0)