26 sept 2026
Pon un guardarrail tipado delante de la llamada a herramienta de un agente
Pregúntale a Jev si una llamada a herramienta propuesta coincide con la intención del usuario y cuán destructiva es, y deja que código simple decida. Un recorrido con ensamblado del estado, umbrales y una matriz de pruebas.
El modo de fallo para el que existen los guardarraíles
Los agentes fallan de una forma concreta: emiten una llamada a herramienta que parece razonable a nivel local y es errónea a nivel global. Un SELECT sobre una tabla de producción que iba destinada a staging. Un DROP TABLE donde se daba por hecho un DELETE. Preguntar a un modelo de chat con un segundo prompt — «¿esto es seguro?» — es lento, no estructurado, y convierte tu política de seguridad en texto libre que la siguiente release puede cambiar en silencio.
Un guardarrail tipado hace tres preguntas en su lugar: si esta llamada coincide con lo que pidió el usuario (noul), si un humano debería confirmarla antes de ejecutarla (noul) y cuán destructiva es si sale mal (score). Las tres viajan en una sola solicitud, y cada respuesta vuelve dentro del espacio de respuestas que definiste — tu política se queda en código, no en prosa.
Ensamblar el estado
Envía la petición del usuario y la llamada propuesta como estado. Aquí un estado objeto se lee mejor que una única cadena larga, porque cada hecho conserva su nombre y los criteria pueden referenciarlos.
{
"state": {
"user_request": "Clean up the old test data in the staging database.",
"proposed_tool_call": {
"tool": "sql.execute",
"args": { "query": "DROP TABLE customers;" },
"environment": "production"
}
},
"questions": {
"matches_intent": {
"type": "noul",
"instructions": "Does `proposed_tool_call` match what `user_request` asked for?"
},
"needs_confirmation": {
"type": "noul",
"instructions": "Should a human confirm this tool call before it runs?",
"criteria": {
"true": "Touches live data, is destructive, or the environment does not match the request",
"false": "Read-only, staging-only, and exactly what was asked"
}
},
"risk": {
"type": "score",
"instructions": "How destructive is this action if it is wrong?",
"criteria": ["Harmless", "Recoverable", "Irreversible data loss"]
}
}
}Cuerpo de la solicitud del guardarrailMantener la política en tu código
Jev solo juzga; nunca ejecuta la herramienta. Tu wrapper convierte las probabilidades en acciones:
const a = answers;
const must_confirm =
a.matches_intent.noul < 0.8 ||
a.needs_confirmation.noul > 0.7 ||
a.risk.score >= 1.5; // past "Recoverable", toward the red end
if (a.risk.score >= 2.0 && a.matches_intent.noul < 0.5) {
blockOrFlag(a.request_id); // never execute, log for review
} else if (must_confirm) {
confirmWith(a.request_id); // ask the human
} else {
execute(call);
}Política como códigoLos umbrales los pones tú. 0,8 es una línea de confianza razonable para empezar con la coincidencia de intención; ajústala en herramientas irreversibles (DROP, deploy, envío de correos) y relájala en las de solo lectura. Ejecuta diez ejemplos reales de tu propio tráfico — no casos de juguete — y mueve un umbral solo donde el modelo discrepe de lo que tú habrías decidido de todos modos.
La matriz de pruebas antes de fiarte de él
- Llamada benigna en el entorno correcto — espera riesgo bajo, alta coincidencia de intención y sin confirmación.
- Intención correcta, entorno equivocado (se pidió staging, se llamó a producción) — espera que la coincidencia de intención se mantenga alta y needs_confirmation suba. Lee el desajuste con honestidad: el modelo solo puede señalar lo que el estado le deja ver.
- Intención equivocada, llamada inofensiva — espera que needs_confirmation se mantenga bajo; inofensivo es inofensivo.
- Intención equivocada, llamada destructiva (el ejemplo anterior) — espera que se disparen todas las señales.
- Petición del usuario ambigua — espera confianza baja; envíalo a una persona en lugar de adivinar.
Si un caso sale mal dos veces, no ajustes un umbral para esconderlo — corrige la redacción de los criteria, o mete el dato que falta (como el entorno del solicitante) en el estado.
El coste en la práctica
Este cuerpo de tres preguntas pesa alrededor de 350–500 tokens, cómodamente dentro del mínimo de 1 crédito, así que poner una puerta a cada llamada a herramienta cuesta $0,0001 por llamada en Starter y proporcionalmente menos en los packs mayores. La latencia añade un viaje de ida y vuelta: 400–600 ms en mediciones típicas contra la pasarela en producción. Es aceptable en la mayoría de los bucles de agente. Si tus llamadas a herramientas son asuntos de menos de 100 ms y cada milisegundo se nota, pon puerta solo a las herramientas cuyo radio de blast lo justifique — escrituras en el sistema de archivos, SQL, pagos, correo — y deja pasar el resto.
Dónde dejan de funcionar los guardarraíles tipados
Sé claro con los límites: un modelo guardarrail no puede ver lo que no está en el estado. Si no incluyes el entorno de destino, no puede detectar el error de entorno. Tampoco reemplazará a los controles deterministas — usa allowlists, comprobaciones de rutas y ámbitos de red para aquello en lo que son buenos, y deja que la capa de decisión tipada se ocupe de la pregunta semántica: ¿este plan coincide con la petición?
¿Puede Jev ejecutar la llamada a herramienta él mismo?
No. Devuelve solo juicios — probabilidades sobre las preguntas que le hiciste. Tu código ejecuta o se niega. Esa separación es la que mantiene el rastro de auditoría en tus manos.
¿Detectará esto cada llamada peligrosa?
Ningún modelo es un sistema de seguridad completo. Usa el guardarrail como una capa más. Es más fuerte donde el peligro es semántico (desajuste de intención, confusión de entornos). Mantén reglas deterministas para allowlists y ámbitos, y mantén a un humano en el camino irreversible.
¿Tiene el playground este ejemplo?
Sí — el preset «Tool-call risk gate» de la página /playground es exactamente esta forma de solicitud, gratis para ejecutar.
Prueba el playground de Jev AI para enviar tu primera decisión gratis cuando termines esta guía.