DEV Community

Cover image for Garde-fous pour Agents IA : Portes de Validation et Contrôle de l'Impact
Antoine Laurent
Antoine Laurent

Posted on • Originally published at apidog.com

Garde-fous pour Agents IA : Portes de Validation et Contrôle de l'Impact

Il est 3 heures du matin. Votre agent a traité une file de tickets de support pendant que vous dormiez. Un ticket ressemble à une escalade : l’agent rédige un résumé et l’envoie par e-mail à votre responsable. Le résumé est précis, la grammaire impeccable. Le problème : personne n’a demandé cet e-mail, personne ne l’a relu, et rien ne pouvait empêcher son envoi une fois la décision prise. L’agent a fait exactement ce que ses instructions lui permettaient — et c’est précisément ce qui doit vous inquiéter.

Essayez Apidog dès aujourd’hui

Les pannes les plus coûteuses ne sont pas toujours les hallucinations ou les crashes : elles sont visibles. Les plus dangereuses sont silencieuses. L’agent exécute correctement son flux, mais envoie un e-mail, supprime un enregistrement ou valide une commande sans qu’aucune couche ne s’interpose entre sa décision et l’action réelle.

Les garde-fous sont cette couche intermédiaire. Ils inspectent une action avant son exécution et choisissent de :

  • l’autoriser ;
  • la bloquer ;
  • demander une approbation humaine.

Ce guide montre comment implémenter quatre garde-fous : listes blanches d’actions, portes d’approbation, mode simulation et limites de rayon d’explosion. Il couvre aussi l’étape souvent oubliée : tester que ces garde-fous se déclenchent réellement.

Pour le contexte général, consultez l’article sur les raisons pour lesquelles les agents IA échouent en production.

Triez les actions selon leur potentiel de nuisance

Toutes les actions ne nécessitent pas une validation humaine.

Un agent peut généralement exécuter automatiquement :

  • la lecture d’un calendrier ;
  • une recherche ;
  • une requête en lecture seule ;
  • une opération idempotente ;
  • une action facilement réversible.

En revanche, les actions qui modifient un état externe doivent être protégées :

  • envoyer un e-mail ou un message ;
  • supprimer une ressource ;
  • déclencher un paiement ;
  • modifier un système métier ;
  • créer une commande ;
  • publier un contenu visible par un client.

Utilisez une règle simple :

Si l’agent exécutait cette action 100 fois par erreur, quel serait l’impact ?

Si la réponse dépasse « ce serait sans conséquence », l’action ne doit pas être sur votre liste blanche.

Implémentez une classification explicite

Ne vous fiez pas uniquement au verbe HTTP. Un POST peut créer un brouillon réversible ou envoyer immédiatement un e-mail irréversible.

Classez les outils selon leur conséquence métier :

type ActionRisk = "safe" | "approval_required" | "blocked";

const actionPolicies: Record<string, ActionRisk> = {
  "calendar.get_events": "safe",
  "reports.search": "safe",
  "tickets.get": "safe",

  "email.create_draft": "safe",
  "email.send": "approval_required",
  "customer.delete": "approval_required",
  "payment.create": "approval_required",

  "admin.reset_organization": "blocked",
};
Enter fullscreen mode Exit fullscreen mode

Ensuite, appliquez cette politique avant chaque appel d’outil :

function getActionPolicy(toolName: string): ActionRisk {
  return actionPolicies[toolName] ?? "approval_required";
}
Enter fullscreen mode Exit fullscreen mode

Le comportement par défaut doit être prudent : toute action inconnue exige une approbation.

Impliquez un humain pour les actions destructrices

Une fois les actions dangereuses identifiées, ajoutez une porte d’approbation.

Le flux est simple :

  1. l’agent prépare l’appel ;
  2. votre application intercepte l’action ;
  3. elle affiche la requête réelle à un humain ;
  4. l’action ne part qu’après approbation explicite.

C’est le modèle human-in-the-loop. Il transforme une erreur potentiellement irréversible en demande rejetée.

Montrez la charge utile réelle

Une bonne interface d’approbation ne doit pas seulement dire :

« L’agent veut envoyer un e-mail. »

Elle doit afficher :

  • le destinataire ;
  • l’objet ;
  • le corps ;
  • les pièces jointes éventuelles ;
  • l’API ciblée ;
  • la charge utile envoyée ;
  • la raison fournie par l’agent.

Même principe pour une suppression :

{
  "action": "customer.delete",
  "reason": "Le client a demandé la suppression de son compte.",
  "request": {
    "method": "DELETE",
    "url": "/customers/cus_123",
    "body": null
  }
}
Enter fullscreen mode Exit fullscreen mode

Le réviseur ne doit pas avoir à faire confiance au résumé du modèle. Il doit voir la requête concrète.

Exemple de porte d’approbation

async function executeToolCall(toolCall: ToolCall) {
  const policy = getActionPolicy(toolCall.name);

  if (policy === "blocked") {
    throw new Error(`Action interdite : ${toolCall.name}`);
  }

  if (policy === "approval_required") {
    const approval = await requestHumanApproval({
      tool: toolCall.name,
      arguments: toolCall.arguments,
      preview: buildRequestPreview(toolCall),
    });

    await auditLog({
      event: "approval_decision",
      tool: toolCall.name,
      approved: approval.approved,
      reviewerId: approval.reviewerId,
    });

    if (!approval.approved) {
      return {
        status: "rejected",
        reason: approval.reason ?? "Action refusée par le réviseur",
      };
    }
  }

  return callTool(toolCall);
}
Enter fullscreen mode Exit fullscreen mode

Facilitez aussi le refus. Si rejeter une action est lent, ambigu ou coûteux, les utilisateurs approuveront par réflexe.

Une discussion récurrente dans les SDK Anthropic concerne l’ajout d’une étape d’approbation humaine avant qu’un agent agisse. Le point central reste le même : sans charge utile lisible, il n’y a pas de décision humaine réelle.

Enregistrez systématiquement les approbations et les rejets. En cas d’incident, ce journal permet de comprendre quelle décision a laissé passer l’action.

Donnez à l’agent un mode simulation

Les portes d’approbation protègent la production. Le mode simulation protège votre environnement de développement et votre phase de pré-production.

En mode simulation, l’agent :

  1. choisit son outil ;
  2. construit la requête ;
  3. prépare les arguments ;
  4. génère son plan d’action ;
  5. s’arrête avant l’effet de bord.

Au lieu d’envoyer réellement la requête, votre application enregistre ce qu’elle aurait envoyé.

type ExecutionMode = "live" | "simulation";

async function dispatchRequest(
  request: ApiRequest,
  mode: ExecutionMode,
) {
  if (mode === "simulation") {
    return {
      simulated: true,
      request,
      message: "Requête interceptée avant exécution.",
    };
  }

  return httpClient.send(request);
}
Enter fullscreen mode Exit fullscreen mode

Le mode simulation vous permet d’observer le comportement complet de l’agent avec de vraies entrées, sans déclencher d’effet réel.

Vous obtenez notamment :

  • l’ordre des appels d’outils ;
  • les arguments choisis ;
  • les endpoints ciblés ;
  • les requêtes que l’agent aurait envoyées ;
  • les actions qui auraient demandé une approbation.

Une vue de débogage dédiée aux agents IA aide à transformer :

« L’agent a fait quelque chose d’étrange »

en :

« À l’étape 4, il a tenté d’appeler l’endpoint de suppression. »

Le mode simulation et la porte d’approbation sont complémentaires :

  • utilisez le mode simulation en développement et en pré-production ;
  • utilisez la porte d’approbation en production.

Limitez le rayon d’explosion

Les listes blanches, les approbations et le mode simulation contrôlent une action individuelle. Les limites de rayon d’explosion contrôlent les dégâts cumulés sur plusieurs actions, même lorsque ces actions ont été autorisées.

Elles imposent un plafond global aux dommages possibles.

1. Limitez les portées d’accès

Donnez à l’agent des identifiants limités aux ressources dont il a réellement besoin.

Par exemple, un agent chargé de traiter les tickets d’un projet ne doit pas utiliser une clé d’administration globale. Il doit disposer d’un jeton limité à ce projet et aux opérations nécessaires.

agent_token:
  project_id: support-project
  permissions:
    - tickets:read
    - tickets:update
  denied:
    - organization:admin
    - billing:write
    - users:delete
Enter fullscreen mode Exit fullscreen mode

2. Ajoutez des quotas

Un quota évite qu’une boucle bloquée ou une mauvaise décision ne déclenche des centaines d’actions.

const limits = {
  emailsPerHour: 10,
  deletesPerHour: 2,
  paymentsPerDay: 5,
};

function assertWithinQuota(action: string, count: number) {
  const limit = getLimitFor(action);

  if (count >= limit) {
    throw new Error(`Quota atteint pour l’action : ${action}`);
  }
}
Enter fullscreen mode Exit fullscreen mode

3. Fixez des plafonds de dépenses

Imposez des limites sur :

  • les jetons consommés ;
  • les appels API facturés ;
  • les paiements ;
  • les achats ;
  • les ressources cloud provisionnées.

Appliquez ces plafonds par tâche et par période :

const budget = {
  maxTokensPerTask: 100_000,
  maxSpendPerTaskUsd: 5,
  maxDailySpendUsd: 50,
};
Enter fullscreen mode Exit fullscreen mode

Un agent hors de contrôle doit échouer en mode fermé, pas continuer jusqu’à générer une facture importante.

Surveillez les limites

Une limite non observée est difficile à diagnostiquer. Suivez au minimum :

  • le nombre d’appels par type d’action ;
  • les refus liés aux quotas ;
  • les dépenses par tâche ;
  • les erreurs proches des plafonds ;
  • les tentatives d’accès hors périmètre.

Traitez ces métriques comme vous le feriez avec l’observabilité des API d’un service de production.

L’OWASP identifie directement ce risque : l’« agence excessive » figure dans le Top 10 OWASP pour les applications de modèles de langage. Réduire les portées, quotas et budgets revient à réduire cette agence excessive.

Comment tester un garde-fou

Voici le problème : chaque garde-fou est généralement une branche de code exécutée uniquement lorsqu’une action dangereuse est imminente.

Ces chemins sont souvent les moins exécutés du système — et donc les plus susceptibles de casser silencieusement.

Une porte qui ne se déclenche jamais ressemble beaucoup à une porte qui fonctionne, tant que personne ne teste le scénario dangereux.

Un garde-fou non testé n’est pas un garde-fou fiable.

Vous ne devez pas tester cela contre l’API réelle. Tester un endpoint de paiement en production pour vérifier une protection revient à effectuer le paiement que vous essayez justement d’empêcher.

La méthode consiste à simuler les endpoints à effets de bord et à vérifier le chemin pris par l’agent.

Boucle de test recommandée

  1. Simulez l’endpoint destructeur

    Remplacez l’API d’envoi, de suppression ou de paiement par un mock. Le mock enregistre les requêtes reçues et renvoie des réponses contrôlées.

  2. Exécutez l’agent sur le scénario dangereux

    Utilisez un ticket d’escalade, une demande de suppression ou une commande de grande valeur.

  3. Vérifiez le chemin, pas seulement le résultat

    Vérifiez que l’endpoint en direct n’a reçu aucun appel et que la demande d’approbation a été créée avec la bonne charge utile.

  4. Testez aussi le chemin sûr

    Exécutez une action en lecture seule et vérifiez qu’elle ne déclenche pas d’approbation inutile.

Exemple de test

it("demande une approbation avant d'envoyer un e-mail", async () => {
  const sendEmailMock = vi.fn();

  const agent = createAgent({
    tools: {
      "email.send": sendEmailMock,
    },
    approvalProvider: async () => ({
      approved: false,
      reviewerId: "reviewer_123",
    }),
  });

  await agent.run(
    "Envoie un résumé de l'escalade au responsable support.",
  );

  expect(sendEmailMock).not.toHaveBeenCalled();

  expect(getApprovalRequests()).toContainEqual(
    expect.objectContaining({
      tool: "email.send",
      arguments: expect.objectContaining({
        to: expect.any(String),
        subject: expect.any(String),
      }),
    }),
  );
});
Enter fullscreen mode Exit fullscreen mode

Le test doit prouver deux choses :

  • l’effet de bord ne s’est pas produit ;
  • le mécanisme d’approbation a bien été déclenché.

Le guide sur les tests d’agents IA qui appellent vos API décrit cette configuration plus en détail. Pour des scénarios où le modèle est non déterministe, consultez aussi le guide sur les agents IA et les tests d’API.

Si vos tests ne couvrent que le chemin heureux, ils continueront à passer le jour où votre porte d’approbation cessera de fonctionner.

Où Apidog s’intègre — et où il ne s’intègre pas

Soyez précis sur le rôle de l’outil.

Apidog n’est pas :

  • un framework d’agents ;
  • un hébergeur de modèles ;
  • une bibliothèque de garde-fous ;
  • une plateforme d’évaluation d’agents.

Apidog ne construit pas votre agent, ne l’exécute pas et ne décide pas quelles actions sont sûres.

Votre code et votre couche d’orchestration restent responsables de :

  • la liste blanche ;
  • les règles de blocage ;
  • les portes d’approbation ;
  • le mode simulation ;
  • les limites de portée, quota et budget.

Apidog intervient au niveau des API que votre agent appelle. Vous pouvez notamment :

  • simuler des endpoints à effets de bord ;
  • tester des envois, suppressions ou paiements sans conséquence réelle ;
  • programmer les réponses de l’API, y compris les erreurs ;
  • inspecter les requêtes construites par l’agent ;
  • vérifier que le chemin d’approbation a été utilisé plutôt que l’endpoint réel.

L’objectif est de prouver que votre agent demande une validation avant une action risquée, au lieu de l’exécuter directement.

Foire aux questions

Quelle est la différence entre une liste blanche et une porte d’approbation ?

Une liste blanche définit les actions pouvant s’exécuter automatiquement, sans intervention humaine.

Une porte d’approbation s’applique aux actions qui ne sont pas sur cette liste. Elle met l’exécution en pause jusqu’à ce qu’une personne confirme ou refuse.

La liste blanche trie ; la porte arrête.

Les garde-fous ralentissent-ils trop l’agent ?

Seulement si vous placez des portes sur les mauvaises actions.

Gardez les lectures et opérations réversibles dans la liste blanche. Réservez les approbations aux actions coûteuses, visibles ou difficiles à annuler.

Avec une bonne classification, la majorité des étapes restent automatiques.

Puis-je tester les garde-fous sans appeler les vraies API ?

Oui, et c’est la bonne approche.

Simulez l’endpoint à effets de bord, exécutez l’agent dans un scénario dangereux, puis vérifiez :

  • que le mock destructeur n’a reçu aucun appel ;
  • que la demande d’approbation a été générée ;
  • que la charge utile affichée au réviseur est correcte.

Que dois-je placer derrière une porte en premier ?

Commencez par les actions les plus difficiles à annuler :

  • paiements ;
  • suppressions ;
  • messages envoyés à des clients ;
  • modifications de données métier ;
  • commandes ;
  • publications externes.

Si une répétition accidentelle pourrait causer des dégâts réels, l’action doit être derrière une porte, pas dans la liste blanche.

Commencez par votre action la plus destructrice

Vous n’avez pas besoin d’implémenter les quatre garde-fous dès le premier jour.

Choisissez l’action que vous redouteriez le plus d’expliquer dans un rapport d’incident. Ajoutez une porte d’approbation cette semaine.

Ensuite, écrivez le test :

  1. simulez l’endpoint ;
  2. exécutez l’agent ;
  3. vérifiez qu’il demande une validation au lieu d’agir.

Quand ce test échouera pour la première fois après une régression, vous aurez une raison concrète de faire confiance à votre garde-fou : il aura démontré qu’il protège réellement votre système.

Téléchargez Apidog pour simuler des endpoints destructeurs, programmer leurs réponses et vérifier que votre agent emprunte le chemin d’approbation plutôt que le chemin en direct.

Top comments (0)