Idée en 30 secondes
Agents Without Guardrails est un anti-pattern où l'agent exécute des actions sans règles runtime imposées : policy-gate, allowlist, contrôle de scope, limites de budget et stop_reason clair.
Résultat : une erreur du modèle ou un mauvais routage devient un vrai problème opérationnel : appels inutiles, actions indésirables, surconsommation de budget ou accès risqué dans le mauvais contexte.
Règle simple : les garde-fous doivent vivre dans le code et dans la couche d'execution, pas seulement dans le prompt.
Exemple d'anti-pattern
L'équipe lance un agent de support qui peut chercher des données, mettre à jour des statuts et envoyer des messages.
L'agent reçoit un accès large aux tools sans règles runtime centralisées.
decision = agent.next_action(user_message)
result = run_tool(decision.tool, decision.args)
return result
Dans ce schéma, le contrôle de base manque :
# pas d'allowlist par route
# pas de deny-by-default pour les actions risquées
# pas de tenant/env scope enforcement
# pas de limites budget/step/time
Avec cette approche, le run passe à l'execution sans policy-gate, donc les étapes risquées ne sont pas arrêtées au moment de la décision.
Dans ce schéma, l'absence de garde-fous provoque :
- des changements d'état imprévisibles
- un risque d'appels incorrects ou inutiles
- une analyse d'incident difficile sans frontière claire de responsabilité
Pourquoi ça apparaît et ce qui se passe mal
Cet anti-pattern apparaît souvent quand l'équipe optimise d'abord "pour que l'agent fasse plus", et repousse les limites de contrôle.
Causes typiques :
- confiance excessive dans les instructions du prompt au lieu de checks runtime imposés
- absence de couche gateway séparée pour les décisions policy
- rôles mélangés : l'agent planifie et exécute des actions risquées sans vérification
- personne n'est explicitement responsable des règles d'accès, des limites et de l'audit
Conséquences :
- actions risquées sans contrôle - l'agent peut exécuter une étape dangereuse dans un scénario invalide
- surconsommation de ressources - sans limites budget/step, le coût et la latence du run augmentent
- erreurs de contexte - sans scope enforcement, l'action peut viser le mauvais tenant/env
- frontières de responsabilité floues - difficile de localiser l'incident entre agent et gateway
- incidents répétitifs - l'équipe corrige les effets, pas la cause racine
Contrairement à Write Access by Default, le problème ici est plus large : il ne manque pas seulement des limites write, mais des limites d'execution globales pour tout le run.
Signaux de production typiques d'un manque de garde-fous :
- des tool-calls potentiellement dangereux passent alors que
approval_requiredoupolicy_deniedest attendu - les blocked attempts sont rares même sur des routes risquées
- les runs atteignent souvent
max_stepsou un dépassement de budget sans arrêt anticipé - les audit-logs ne montrent pas quelle règle exacte a autorisé ou bloqué l'action
- l'équipe ne peut pas expliquer rapidement pourquoi un tool-call précis a été exécuté
Chaque tool-call est une décision opérationnelle. Si les limites d'execution ne sont pas imposées, le système agentique devient imprévisible même dans des scénarios simples.
Bonne approche
Commencez avec un ensemble minimal mais strict de garde-fous runtime. Chaque étape passe la vérification policy, sinon le run s'arrête avec un stop_reason clair.
Si vous partez de zéro, n'essayez pas de tout livrer d'un coup.
Premier minimum : deny-by-default, allowlist par route, scope enforcement (tenant/env) et stop_reason explicite pour les refus policy.
Cadre pratique :
- deny-by-default pour les actions dangereuses ou inconnues
- allowlist des tools par rôle et par route
- scope obligatoire (
tenant_id,env) depuis le contexte authentifié - limites step/time/budget pour chaque run
- étape d'approval séparée pour les write-opérations risquées
- journal de décision policy pour chaque tool-call
ALLOWED_TOOLS_BY_ROUTE = {
"faq": {"kb.search"},
"refund": {"order.get", "refund.create"},
}
WRITE_TOOLS = {"refund.create", "ticket.close", "email.send"}
def execute_step(decision, ctx):
allowed = ALLOWED_TOOLS_BY_ROUTE.get(ctx["route"], set())
if decision.tool not in allowed:
return stop("policy_denied:tool_not_allowed")
if decision.tool in WRITE_TOOLS and not has_approval(ctx, decision):
return stop("approval_required")
if exceeds_budget(ctx):
return stop("budget_exceeded")
scoped_args = enforce_scope(
decision.args,
tenant_id=ctx["tenant_id"],
env=ctx["env"],
)
return run_tool(decision.tool, scoped_args)
Dans ce schéma, l'agent fonctionne dans des limites contrôlées : les actions autorisées passent, les étapes risquées ou invalides s'arrêtent de façon transparente.
Test rapide
Si la réponse à ces questions est "oui", vous avez un risque d'anti-pattern Agents Without Guardrails :
- L'agent peut-il appeler un tool sans vérification policy explicite ?
- Pour les étapes risquées,
policy_deniedouapproval_requiredapparaît-il presque jamais ? - L'équipe ne peut-elle pas expliquer rapidement pourquoi une action précise a été autorisée ?
Différence avec les autres anti-patterns
Write Access by Default vs Agents Without Guardrails
| Write Access by Default | Agents Without Guardrails |
|---|---|
| Problème principal : l'accès write est ouvert par défaut. | Problème principal : il n'y a pas de limites d'execution globales pour le run (policy, scope, budgets, approvals). |
| Quand il apparaît : quand write ne passe pas par deny-by-default et approval-gate. | Quand il apparaît : quand même les routes read/write/tool n'ont pas de règles runtime imposées. |
En bref : Write Access by Default concerne un modèle d'accès write dangereux, alors que Agents Without Guardrails concerne l'absence de limites d'execution globales.
Blind Tool Trust vs Agents Without Guardrails
| Blind Tool Trust | Agents Without Guardrails |
|---|---|
| Problème principal : un tool output non validé entre dans la décision. | Problème principal : le système ne limite pas quelles actions l'agent peut exécuter. |
| Quand il apparaît : quand la validation parse/schema/invariant manque. | Quand il apparaît : quand les décisions policy restent dans le prompt et pas dans la couche d'execution. |
En bref : Blind Tool Trust concerne la fiabilité des données avant action, alors que Agents Without Guardrails concerne les limites des actions autorisées.
No Stop Conditions vs Agents Without Guardrails
| No Stop Conditions | Agents Without Guardrails |
|---|---|
| Problème principal : la boucle n'a pas de conditions d'arrêt claires. | Problème principal : les limites système d'execution pour actions, droits et accès sont absentes. |
Quand il apparaît : quand max_steps, timeout, no_progress manquent. | Quand il apparaît : quand le run ne passe pas par policy-gate, scope-check et contrôle d'accès. |
En bref : No Stop Conditions concerne le contrôle de fin de boucle, alors que Agents Without Guardrails concerne des limites d'execution sûres plus larges.
Auto-vérification : avez-vous cet anti-pattern ?
Vérification rapide de l'anti-pattern Agents Without Guardrails.
Cochez les points pour votre système et regardez le statut ci-dessous.
Vérifiez votre système :
Progression: 0/8
⚠ Il y a des signes de cet anti-pattern
Essayez de déplacer les étapes simples dans un workflow et de garder l'agent uniquement pour les décisions complexes.
FAQ
Q : Est-ce suffisant de définir des limites dans le system prompt ?
R : Non. Le prompt aide pour l'intention, mais n'impose rien. Les limites critiques doivent être vérifiées dans la couche runtime.
Q : Par quoi commencer si les garde-fous sont presque absents ?
R : Commencez par deny-by-default, allowlist par route, scope enforcement (tenant/env) et stop_reason explicite pour les refus policy.
Q : Est-ce que les garde-fous rendent le système trop lent ?
R : Les garde-fous ajoutent un peu d'overhead. En production, ce coût est presque toujours inférieur aux mauvaises actions, à la perte de budget et au nettoyage manuel d'incidents.
Et ensuite
Anti-patterns proches :
- Write Access by Default - quand l'accès write est ouvert sans restrictions suffisantes.
- Blind Tool Trust - quand les décisions utilisent un tool output non validé.
- No Stop Conditions - quand la boucle agent n'a pas de terminaison contrôlée.
Ce qu'il faut construire à la place :
- Allowed Actions - comment limiter les actions de l'agent avec des règles explicites.
- Tool Execution Layer - où centraliser policy, scope et contrôle d'execution.
- Stop Conditions - comment terminer un run de façon transparente quand les limites sont violées.