Human-in-the-loop approvals (stopper les writes) + Code

Les approvals, c’est ennuyeux — et moins cher que d’annuler 200 writes. Un gate d’approbation pour les tool calls à risque.
Sur cette page
  1. Le problème (côté prod)
  2. Pourquoi ça casse en prod
  3. 1) “Write tool” n’est pas une catégorie unique
  4. 2) Sans chemin d’approbation, tu deviens autonome par accident
  5. 3) Approval sans contexte = inutile
  6. Exemple d’implémentation (code réel)
  7. Incident réel (avec chiffres)
  8. Compromis
  9. Quand NE PAS l’utiliser
  10. Checklist (copier-coller)
  11. Config par défaut sûre (JSON/YAML)
  12. FAQ (3–5)
  13. Pages liées (3–6 liens)
Flux interactif
Scénario:
Étape 1/3: Execution

Action is proposed as structured data (tool + args).

Le problème (côté prod)

Tu veux des writes. Ton agent veut des writes. Tes clients veulent que les writes soient corrects.

En démo : « l’agent peut juste fermer le ticket ». En prod : « juste » est la partie où tu expliques ensuite pourquoi 200 trucs sont cassés.

Les approvals ne sont pas un feature “enterprise”. C’est une soupape de sécurité quand ton décideur est probabiliste.

Pourquoi ça casse en prod

1) “Write tool” n’est pas une catégorie unique

Les writes ne se valent pas :

  • réversible vs irréversible
  • faible impact vs gros impact
  • idempotent vs “oops, duplicate”

Si tu traites tout pareil, tu fais soit :

  • trop d’approvals (UX meurt)
  • pas assez (prod meurt)

2) Sans chemin d’approbation, tu deviens autonome par accident

Si un write tool est dans l’allowlist et rien ne l’arrête, il sera utilisé. Pas “peut-être”. Dès que c’est le chemin le plus court.

3) Approval sans contexte = inutile

“Approve ce tool call ?” ne suffit pas. Il faut de l’evidence :

  • action proposée
  • args (ou diff)
  • pourquoi l’agent pense que c’est bon
  • raison de policy / risque

Exemple d’implémentation (code réel)

Un gate minimal :

  • write tools → approval request
  • approval signé (id/key)
  • tool gateway exécute seulement si approval valide
PYTHON
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)
JAVASCRIPT
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)
}

Incident réel (avec chiffres)

On avait un agent pour “nettoyer” des tickets support. Un changement de prompt a interprété “cleanup” comme “close”.

Impact :

  • 63 tickets fermés alors qu’ils devaient rester ouverts
  • ~2 heures pour rouvrir + s’excuser
  • on a mis l’agent en read-only une semaine, le temps de reconstruire la confiance

Fix :

  1. approvals sur writes high-impact
  2. UI d’approbation avec diff/evidence (pas juste “approve?”)
  3. idempotency keys pour éviter les doubles exécutions

Compromis

  • Les approvals ajoutent de la latence. C’est le prix de la sécurité.
  • Trop d’approvals tue l’UX → il faut des risk tiers.
  • Un système d’approbation sans audit logs te laisse sans preuve en incident.

Quand NE PAS l’utiliser

  • Pas besoin d’approvals pour des tools read-only.
  • Pour des writes low-risk et totalement réversibles, un auto-approve sous budgets stricts peut être OK.
  • Si personne ne review réellement : ce n’est pas un approval, c’est du théâtre.

Checklist (copier-coller)

  • [ ] Identifier les write tools (capability-based)
  • [ ] Approvals pour actions irréversibles / high impact
  • [ ] Evidence dans l’UI (diff, why, provenance)
  • [ ] Enforcement dans le tool gateway (pas seulement dans le frontend)
  • [ ] Idempotency keys par action approuvée
  • [ ] Audit logs (who approved what)

Config par défaut sûre (JSON/YAML)

YAML
approvals:
  required_for:
    - "db.write"
    - "email.send"
    - "ticket.close"
  evidence:
    include_args: true
    include_diff: true
  enforce_in: "tool_gateway"

FAQ (3–5)

Quand les approvals sont vraiment nécessaires ?
Quand l’action est coûteuse/irréversible ou modifie des données client. Par défaut : writes → approval.
Comment éviter le spam d’approvals ?
Risk tiers + escalader seulement le high-risk. Et garder les write tools petits (pas de RPC générique).
Je peux automatiser des approvals ?
Partiellement : auto-approve low-risk sous budgets stricts. Mais logge en ‘auto-approved’.
Où enforce les approvals ?
Dans le tool gateway. Si c’est seulement dans l’UI, ça sera contourné.

Q: Quand les approvals sont vraiment nécessaires ?
A: Quand l’action est coûteuse/irréversible ou modifie des données client. Par défaut : writes → approval.

Q: Comment éviter le spam d’approvals ?
A: Risk tiers + escalader seulement le high-risk. Et garder les write tools petits (pas de RPC générique).

Q: Je peux automatiser des approvals ?
A: Partiellement : auto-approve low-risk sous budgets stricts. Mais logge en “auto-approved”.

Q: Où enforce les approvals ?
A: Dans le tool gateway. Si c’est seulement dans l’UI, ça sera contourné.

Pages liées (3–6 liens)

Pas sur que ce soit votre cas ?

Concevez votre agent ->
⏱️ 5 min de lectureMis à jour 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

Cette documentation est organisée et maintenue par des ingénieurs qui déploient des agents IA en production.

Le contenu est assisté par l’IA, avec une responsabilité éditoriale humaine quant à l’exactitude, la clarté et la pertinence en production.

Les patterns et recommandations s’appuient sur des post-mortems, des modes de défaillance et des incidents opérationnels dans des systèmes déployés, notamment lors du développement et de l’exploitation d’une infrastructure de gouvernance pour les agents chez OnceOnly.