Human Approval pour les agents IA : comment contrôler en sécurité les actions write

Flow d'approval pratique en production : approval_required, TTL, stop reasons, approval token et audit trail pour les actions write.
Sur cette page
  1. Idée en 30 secondes
  2. Problème
  3. Solution
  4. Human Approval != Manual Mode
  5. Métriques de contrôle d'approval
  6. Comment cela se place dans l'architecture
  7. Exemple
  8. Dans le code, cela ressemble à ceci
  9. Comment cela se passe pendant l'exécution
  10. Erreurs fréquentes
  11. Auto-vérification
  12. FAQ
  13. Où Human Approval se place dans le système global
  14. Pages liées

Idée en 30 secondes

Human approval est un runtime-gate pour les actions write risquées : avant exécution, l'agent reçoit approval_required et attend une confirmation humaine.

Quand c'est nécessaire : quand un agent peut modifier des données, envoyer des messages clients, ou lancer des actions irréversibles en production.

Problème

Sans approval, les actions write sont exécutées immédiatement si la policy les autorise. En demo, c'est pratique. En production, une erreur de l'agent devient un incident réel.

Le problème n'est pas seulement un modèle "mauvais". Même un bon modèle se trompe parfois sur des demandes atypiques. S'il n'y a pas de gate humain entre l'agent et l'outil write, une erreur devient immédiatement un side effect dans des systèmes réels.

Analogie : c'est comme un paiement sans 3D Secure. Tant que tout se passe bien, il n'y a pas de délai. Quand quelque chose tourne mal, les conséquences deviennent coûteuses en quelques secondes.

Solution

La solution est d'ajouter dans la policy layer un flow d'approval dédié aux actions write risquées. La policy renvoie l'une des décisions suivantes : allow, deny ou approval_required.

approval_required n'exécute pas l'action immédiatement : runtime crée une approval request, attend une décision humaine, et n'exécute le tool call qu'après approval_granted. Cette décision est prise à chaque étape, pas seulement à la fin du run.

Human Approval != Manual Mode

Ce sont des modèles différents :

  • Manual mode : un humain exécute presque chaque action à la place de l'agent.
  • Human approval : l'agent travaille de façon autonome, et l'humain confirme seulement les actions write risquées.

L'un sans l'autre n'est pas suffisant :

  • sans approval, les actions risquées passent sans contrôle supplémentaire
  • si on utilise manual mode pour tout, le système perd en vitesse et en scalabilité

Exemple :

  • sans approval : ticket.close_bulk est exécuté immédiatement
  • avec approval : la policy renvoie approval_required, et l'action attend une confirmation

Métriques de contrôle d'approval

Ces métriques et signaux travaillent ensemble à chaque étape de l'agent.

MétriqueCe qu'elle contrôleMécaniques clésPourquoi
Approval scopeQuelles actions nécessitent une confirmationwrite policy
risk tiers
Réduit le risque sur les actions irréversibles
Approval request contextCe que l'humain voit exactement avant de déciderpreview + args hash
reason + policy context
Permet une décision fondée
TTL et annulationCycle de vie de l'approval requestapproval TTL
cancel flow
Empêche qu'un run reste bloqué indéfiniment
Execution gateExécution réelle de l'action writeapproval token
gateway enforcement
Garantit que le write ne part pas sans confirmation
Approval observabilityVisibilité sur les décisions d'approvalaudit logs
alerts on timeout spikes
Ne limite pas directement l'action, mais aide à détecter les goulots du process d'approval

Comment cela se place dans l'architecture

La policy layer (tool gateway) se place entre runtime et tools et constitue le point unique de contrôle d'accès avant chaque étape. Chaque décision (allow, deny, approval_required) est journalisée dans l'audit log.

Chaque étape de l'agent passe par ce flow avant exécution : runtime n'exécute pas directement une action write — d'abord vérification policy -> approval gate -> exécution.

Résumé du flow :

  • Runtime forme un tool call
  • la policy layer vérifie le risque et peut renvoyer approval_required
  • en cas de approval_granted, le write est exécuté
  • en cas de approval_denied ou approval_timeout, le run reçoit un stop reason
  • chaque décision est écrite dans l'audit log

Dans runtime, deny est aussi converti en stop reason explicite, visible dans les logs et la réponse du run.

Une approval request contient en général :

  • tool
  • preview courte de l'action
  • args hash
  • reason / risk tier
  • TTL

Exemple

Un agent support veut exécuter email.send pour un client. La policy définit qu'une confirmation humaine est nécessaire pour ce tool.

Résultat :

  • sans approval token, le write n'est pas exécuté
  • après approval_granted, l'appel passe
  • en cas de timeout, l'agent renvoie stop("approval_timeout")

Human approval arrête l'action risquée avant le side effect, pas après l'incident.

Dans le code, cela ressemble à ceci

Dans le schéma simplifié ci-dessus, le control flow principal est montré. En pratique, vérification et exécution doivent passer par un seul policy/tool gateway.

Exemple de configuration d'approval :

YAML
approvals:
  required_for:
    - email.send
    - ticket.close_bulk
    - db.write
  ttl_seconds: 300
  fallback_when_not_approved: stop
PYTHON
decision = policy.evaluate(tool, user_context, mode="normal")

if decision.outcome == "approval_required":
    request = approvals.create_request(
        run_id=run_id,
        tool=tool,
        args_hash=hash_args(args),
        ttl_seconds=300,
    )
    audit.log(run_id, decision.outcome, reason="pending_human_review", tool=tool, pending_id=request.id)
    return stop("approval_required", pending_id=request.id)

elif decision.outcome == "deny":
    audit.log(run_id, decision.outcome, reason=decision.reason, tool=tool)
    return deny(decision.reason)

# later, in resume flow with pending_id
approval = approvals.get_decision(pending_id)
if approval.outcome != "approved":
    audit.log(run_id, "deny", reason=approval.outcome, tool=tool, pending_id=pending_id)
    return stop(approval.outcome)

audit.log(run_id, "approval_granted", reason="human_approved", tool=tool, approver=approval.approved_by)
result = tool.execute({**args, "approval_token": approval.token})
decision = Decision.allow(reason="policy_ok")
audit.log(run_id, decision.outcome, reason=decision.reason, tool=tool, result=result.status)
return result

En production, le flow d'approval est généralement asynchrone : runtime crée une request, renvoie un état pending/stop sans bloquer le worker, puis reprend le run après la décision humaine.

Comment cela se passe pendant l'exécution

TEXT
Scénario 1 : confirmé (approval granted)

1. Runtime forme un appel email.send.
2. La policy renvoie approval_required.
3. Runtime crée une approval request et renvoie un état pending/stop.
4. Un humain confirme l'action dans la TTL.
5. Runtime reprend le run, exécute le tool call et écrit `approval_granted -> allow`.

---

Scénario 2 : timeout d'approval

1. Runtime forme un appel db.write.
2. La policy renvoie approval_required.
3. Runtime crée une approval request et renvoie un état pending/stop.
4. Aucune confirmation n'est reçue avant la fin de la TTL.
5. Runtime renvoie stop (approval_timeout), l'action n'est pas exécutée.

---

Scénario 3 : policy deny sans approval

1. Runtime forme un appel write hors du scope autorisé.
2. La policy renvoie immédiatement deny.
3. Runtime renvoie un stop reason.
4. Audit : decision=deny, reason=policy_denied.
5. L'action n'est pas exécutée.

Erreurs fréquentes

  • approval uniquement dans l'UI, mais pas dans le policy/tool gateway
  • approval sans TTL ni annulation
  • même approche pour actions write low-risk et high-risk
  • absence d'approval token à l'exécution du tool
  • ne pas logguer approval_required et approval_granted
  • bloquer tous les runs en attente d'approval au lieu de renvoyer un état stop/pending explicite

Résultat : le système laisse passer des actions dangereuses, ou se bloque dans des files d'approval sans état transparent.

Auto-vérification

Vérification rapide human-approval avant lancement en production :

Progression: 0/8

⚠ Les contrôles de governance de base manquent

Avant la production, il faut au minimum le contrôle d'accès, des limites, des audit logs et un arrêt d'urgence.

FAQ

Q: Quelles actions doivent obligatoirement avoir un approval ?
A: Les actions write irréversibles ou visibles côté client : changements de données, fermetures en masse, envoi de messages, opérations financières.

Q: Comment éviter de noyer l'équipe sous l'approval-spam ?
A: Découper les actions write en risk tiers. High-risk -> approval obligatoire, low-risk -> policy séparée avec tighter limits et audit.

Q: Faut-il bloquer le worker pendant l'attente d'approval ?
A: Mieux vaut non. Retourne un état pending/stop et reprends le run après décision pour éviter files d'attente et deadlocks.

Q: Est-ce que l'approval peut remplacer RBAC et budgets ?
A: Non. Approval est un gate supplémentaire pour actions risquées. RBAC, limits et budgets restent nécessaires.

Q: Que faut-il logguer au minimum ?
A: approval_required, approval_granted|approval_denied|approval_timeout, qui a approuvé, quel tool, quel reason, et le résultat d'exécution.

Où Human Approval se place dans le système global

Human approval est une des couches d'Agent Governance. Avec allowlist/RBAC, budgets, limits et audit, il forme un système unifié de contrôle d'exécution.

Pages liées

Pour continuer :

⏱️ 8 min de lectureMis à jour 25 mars 2026Difficulté: ★★★
Implémenter dans OnceOnly
Budgets + permissions you can enforce at the boundary.
Utiliser dans OnceOnly
# onceonly guardrails (concept)
version: 1
budgets:
  max_steps: 25
  max_tool_calls: 12
  max_seconds: 60
  max_usd: 1.00
policy:
  tool_allowlist:
    - search.read
    - http.get
writes:
  require_approval: true
  idempotency: true
controls:
  kill_switch: { enabled: true }
Intégré : contrôle en productionOnceOnly
Ajoutez des garde-fous aux agents tool-calling
Livrez ce pattern avec de la gouvernance :
  • Budgets (steps / plafonds de coût)
  • Permissions outils (allowlist / blocklist)
  • Kill switch & arrêt incident
  • Idempotence & déduplication
  • Audit logs & traçabilité
Mention intégrée : OnceOnly est une couche de contrôle pour des systèmes d’agents en prod.

Auteur

Nick — ingénieur qui construit une infrastructure pour des agents IA en production.

Focus : patterns d’agents, modes de défaillance, contrôle du runtime et fiabilité des systèmes.

🔗 GitHub: https://github.com/mykolademyanov


Note éditoriale

Cette documentation est assistée par l’IA, avec une responsabilité éditoriale humaine pour l’exactitude, la clarté et la pertinence en production.

Le contenu s’appuie sur des défaillances réelles, des post-mortems et des incidents opérationnels dans des systèmes d’agents IA déployés.