Action is proposed as structured data (tool + args).
El problema (en producción)
Quieres writes. Tu agente quiere writes. Tus clientes quieren que los writes sean correctos.
En demo: “el agente puede cerrar el ticket”. En prod: “puede” es la parte donde terminas explicando por qué 200 cosas quedaron mal.
Approvals no es “enterprise feature”. Es una válvula de seguridad cuando el que decide es probabilístico.
Por qué esto se rompe en producción
1) “Write tool” no es una categoría única
No todos los writes son iguales:
- reversible vs irreversible
- bajo impacto vs alto impacto
- idempotente vs “oops, duplicado”
Si tratas todo igual, terminas con:
- demasiadas approvals (UX muere)
- o muy pocas (prod muere)
2) Sin approval path, te vuelves autónomo por accidente
Si un write tool está en la allowlist y nadie lo frena, se va a usar. No “quizás”. Cuando sea el camino más corto.
3) Approval sin contexto no sirve
“Approve este tool call?” no basta. Necesitas evidencia:
- acción propuesta
- args (o diff)
- por qué el agente cree que es correcto
- razón de policy / riesgo
Ejemplo de implementación (código real)
Un gate mínimo:
- write tools → approval request
- approval firmado (id/key)
- tool gateway ejecuta solo si hay approval válida
from dataclasses import dataclass
from typing import Any
WRITE_TOOLS = {"ticket.close", "db.write", "email.send"}
@dataclass(frozen=True)
class Approval:
approval_id: str
approved: bool
approved_by: str
class ApprovalRequired(RuntimeError):
pass
def requires_approval(tool: str) -> bool:
return tool in WRITE_TOOLS
def tool_gateway_call(tool: str, args: dict[str, Any], *, approval: Approval | None) -> Any:
if requires_approval(tool):
if not approval or not approval.approved:
raise ApprovalRequired(f"approval_required:{tool}")
return call_tool(tool, args) # (pseudo)const WRITE_TOOLS = new Set(["ticket.close", "db.write", "email.send"]);
export class ApprovalRequired extends Error {}
export function requiresApproval(tool) {
return WRITE_TOOLS.has(tool);
}
export function toolGatewayCall(tool, args, { approval } = {}) {
if (requiresApproval(tool)) {
if (!approval || approval.approved !== true) throw new ApprovalRequired("approval_required:" + tool);
}
return callTool(tool, args); // (pseudo)
}Incidente real (con números)
Teníamos un agente para “limpiar” tickets de soporte. Un cambio de prompt interpretó “cleanup” como “close”.
Impacto:
- 63 tickets cerrados cuando no debían
- ~2 horas para reabrir + pedir disculpas
- pusimos el agente en read-only una semana hasta recuperar confianza
Fix:
- approvals para writes high-impact
- UI de approval con diff/evidence (no solo “approve?”)
- idempotency keys para evitar doble ejecución
Trade-offs
- Approvals agregan latencia. Es el costo de seguridad.
- Demasiadas approvals matan la UX → necesitas risk tiers.
- Sin audit logs, en incidente no tienes pruebas.
Cuándo NO usarlo
- No necesitas approvals para tools read-only.
- Para writes low-risk y totalmente reversibles, auto-approve bajo budgets estrictos puede ser aceptable.
- Si nadie revisa en serio: no es approval, es teatro.
Checklist (copiar/pegar)
- [ ] Identificar write tools (capability-based)
- [ ] Approvals para acciones irreversibles / high-impact
- [ ] Evidence en la UI (diff, why, provenance)
- [ ] Enforced en tool gateway (no solo frontend)
- [ ] Idempotency keys por acción aprobada
- [ ] Audit logs (who approved what)
Config segura por defecto (JSON/YAML)
approvals:
required_for:
- "db.write"
- "email.send"
- "ticket.close"
evidence:
include_args: true
include_diff: true
enforce_in: "tool_gateway"
FAQ (3–5)
Usado por patrones
Fallos relacionados
- AI Agent Infinite Loop (Detectar + arreglar, con código)
- Explosión de presupuesto (cuando un agente quema dinero) + fixes + código
- Tool Spam Loops (fallo del agente + fixes + código)
- Incidentes de exceso de tokens (prompt bloat) + fixes + código
- Corrupción de respuestas de tools (schema drift + truncation) + código
Gobernanza requerida
P: ¿Cuándo necesito approvals de verdad?
R: Cuando la acción es costosa/irreversible o modifica datos del cliente. Default: writes → approval.
P: ¿Cómo evito spam de approvals?
R: Risk tiers + escalar solo high-risk. Y mantén write tools pequeños (no RPC genérico).
P: ¿Puedo automatizar approvals?
R: Parcialmente: auto-approve low-risk bajo budgets estrictos. Pero loggea como “auto-approved”.
P: ¿Dónde enforceo approvals?
R: En el tool gateway. Si es solo UI, se va a bypass.
Páginas relacionadas (3–6 links)
- Foundations: What makes an agent production-ready · How agents use tools
- Failure: Prompt injection attacks · Cascading tool failures
- Governance: Tool permissions · Kill switch design
- Production stack: Production agent stack