DEV Community

Cover image for Comment arrêter de surveiller constamment les agents IA ?
Antoine Laurent
Antoine Laurent

Posted on • Originally published at apidog.com

Comment arrêter de surveiller constamment les agents IA ?

En bref

Vous cessez de surveiller les agents IA en mettant en place trois piliers : des garde-fous (empêchent les échecs critiques), de l'observabilité (journaux/métriques pour comprendre ce qui s'est passé) et des points de contrôle (pauses automatiques pour vérification humaine). Implémentez-les une fois, et vos agents pourront fonctionner de façon autonome pendant des heures. Des outils comme Apidog facilitent la définition de contrats d'API inviolables, transformant votre couche API en filet de sécurité.

Essayez Apidog dès aujourd'hui

Introduction

La semaine dernière, j'ai vu un développeur passer 4 heures à surveiller un agent IA censé lui faire gagner du temps. Toutes les quelques minutes, il devait intervenir, corriger une erreur, puis relancer l'agent. Résultat : plus de travail manuel que s'il avait tout fait lui-même.

La surveillance constante est la principale raison pour laquelle les agents IA ne tiennent pas leurs promesses. Les outils sont puissants. Les modèles sont performants. Mais la plupart des équipes restent bloquées à l'étape de supervision continue.

En réalité, la plupart des pipelines traitent le LLM comme un développeur junior, alors qu'il agit comme un stagiaire ultra-rapide : il peut halluciner, et fera des erreurs en toute confiance si vous ne fixez pas de limites claires.

💡 Si vous créez des API ou travaillez avec des agents IA qui appellent des API, Apidog vous aide à fixer ces limites. En spécifiant des schémas de requête/réponse précis, vous créez des contrats inviolables. C'est comme donner une carte à votre agent plutôt que de le laisser errer.

Définissez des contrats d'API que vos agents IA peuvent suivre.

À la fin de ce guide, vous saurez :

  • Modéliser l'autonomie des agents IA
  • Implémenter garde-fous, observabilité et points de contrôle
  • Copier/coller des exemples de code prêts à l'emploi
  • Vérifier si un agent est prêt à fonctionner sans supervision

Pourquoi les agents ont besoin d'une supervision constante

Les agents IA échouent selon des schémas prévisibles. Identifier ces modes d'échec est la première étape pour automatiser sereinement.

Mode d'échec 1 : Dérive du périmètre

Vous commandez à un agent d’« ajouter l’authentification ». Il ajoute aussi la limitation de débit, refactorise la base, supprime des fichiers "inutiles". L’agent n’a pas de notion de fin : il avance tant qu’il n’atteint pas une limite technique ou humaine.

Mode d'échec 2 : Mauvaises abstractions

Demandez « améliorer la gestion des erreurs » : il met des try-catch partout, rendant le code illisible. Il exécute la consigne littéralement, faute d’exemples qualitatifs.

Mode d'échec 3 : Défaillances en cascade

Une petite erreur à l’étape 1 devient une avalanche d’échecs invisibles jusqu’au crash final. L’agent ne réalise pas qu’il s’est trompé ; chaque étape semble correcte isolément.

Mode d'échec 4 : Épuisement des ressources

Certains agents bouclent indéfiniment : retry sans fin, génération de sous-agents illimitée, explosion de coûts. Sans limite de ressources, impossible de s’arrêter proprement.


Le cadre d'autonomie : garde-fous, observabilité, points de contrôle

Pensez ce cadre comme une pyramide :

  • Base : garde-fous (prévention)
  • Milieu : observabilité (détection)
  • Sommet : points de contrôle (récupération)

Couche 1 : Garde-fous (prévention)

Implémentez des contraintes dans le code, jamais seulement dans les invites.

Contraintes sur le système de fichiers :

# À éviter : Faire confiance à l'agent pour suivre les instructions
agent.run("Only modify files in the src/ directory")

# À faire : Appliquer les contraintes dans le code
import os
from pathlib import Path

ALLOWED_DIRECTORIES = {"src", "tests", "docs"}

def validate_file_path(path: str) -> bool:
    """L'agent ne peut pas écrire en dehors des répertoires autorisés."""
    abs_path = Path(path).resolve()
    return any(
        str(abs_path).startswith(str(Path(d).resolve()))
        for d in ALLOWED_DIRECTORIES
    )

def agent_write_file(path: str, content: str):
    if not validate_file_path(path):
        raise ValueError(f"Impossible d'écrire dans {path} : en dehors des répertoires autorisés")
    with open(path, 'w') as f:
        f.write(content)
Enter fullscreen mode Exit fullscreen mode

Contraintes de schéma d'API avec Apidog :

Définissez des schémas stricts pour chaque endpoint.

// apidog-schema.ts
export const CreateUserSchema = {
  type: 'object',
  required: ['email', 'name'],
  properties: {
    email: { type: 'string', format: 'email' },
    name: { type: 'string', minLength: 1, maxLength: 100 },
    role: { type: 'string', enum: ['user', 'admin', 'guest'] }
  },
  additionalProperties: false
}

// L'agent doit valider avant d'appeler l'API
function validateRequest(schema: object, data: unknown): void {
  const valid = ajv.validate(schema, data)
  if (!valid) {
    throw new Error(`Requête invalide : ${JSON.stringify(ajv.errors)}`)
  }
}
Enter fullscreen mode Exit fullscreen mode

Contraintes budgétaires :

import time
from dataclasses import dataclass

@dataclass
class AgentBudget:
    max_steps: int = 50
    max_tokens: int = 100000
    max_time_seconds: int = 600  # 10 minutes
    max_api_calls: int = 100

class BudgetEnforcer:
    def __init__(self, budget: AgentBudget):
        self.budget = budget
        self.start_time = time.time()
        self.steps = 0
        self.tokens_used = 0
        self.api_calls = 0

    def check(self) -> bool:
        elapsed = time.time() - self.start_time

        if self.steps >= self.budget.max_steps:
            raise RuntimeError(f"Limite d'étapes atteinte : {self.steps}")
        if self.tokens_used >= self.budget.max_tokens:
            raise RuntimeError(f"Limite de jetons atteinte : {self.tokens_used}")
        if elapsed >= self.budget.max_time_seconds:
            raise RuntimeError(f"Limite de temps atteinte : {elapsed:.0f}s")
        if self.api_calls >= self.budget.max_api_calls:
            raise RuntimeError(f"Limite d'appels API atteinte : {self.api_calls}")

        return True

    def record_step(self, tokens: int, api_calls: int = 0):
        self.steps += 1
        self.tokens_used += tokens
        self.api_calls += api_calls
        self.check()
Enter fullscreen mode Exit fullscreen mode

Couche 2 : Observabilité (détection)

Permettez-vous de suivre l’agent sans micro-surveillance.

Journalisation structurée :

import json
from datetime import datetime
from typing import Any

class AgentLogger:
    def __init__(self, log_file: str = "agent_trace.jsonl"):
        self.log_file = log_file
        self.entries = []

    def log(self, event: str, data: dict[str, Any] | None = None):
        entry = {
            "timestamp": datetime.utcnow().isoformat(),
            "event": event,
            "data": data or {}
        }
        self.entries.append(entry)
        with open(self.log_file, 'a') as f:
            f.write(json.dumps(entry) + '\n')

    def log_decision(self, decision: str, reasoning: str, confidence: float):
        self.log("decision", {
            "decision": decision,
            "reasoning": reasoning,
            "confidence": confidence
        })

    def log_action(self, action: str, params: dict, result: str):
        self.log("action", {
            "action": action,
            "params": params,
            "result": result[:200]
        })

    def log_error(self, error: str, context: dict):
        self.log("error", {
            "error": error,
            "context": context
        })

# Exemple d'utilisation
logger = AgentLogger()
logger.log_decision(
    decision="Ajouter la limitation de débit à l'API",
    reasoning="Le point de terminaison actuel n'a aucune protection contre les abus",
    confidence=0.85
)
logger.log_action(
    action="écrire_fichier",
    params={"chemin": "src/middleware/rate-limit.ts"},
    result="45 lignes écrites avec succès"
)
Enter fullscreen mode Exit fullscreen mode

Tableau de bord des métriques :

from collections import Counter
from dataclasses import dataclass, field

@dataclass
class AgentMetrics:
    actions_taken: Counter = field(default_factory=Counter)
    files_modified: list[str] = field(default_factory=list)
    api_calls: dict[str, int] = field(default_factory=dict)
    errors: list[str] = field(default_factory=list)
    decisions_by_confidence: dict[str, int] = field(default_factory=lambda: {
        "élevée (>0.9)": 0,
        "moyenne (0.7-0.9)": 0,
        "faible (<0.7)": 0
    })

    def record_action(self, action: str):
        self.actions_taken[action] += 1

    def record_file_modification(self, path: str):
        if path not in self.files_modified:
            self.files_modified.append(path)

    def record_api_call(self, endpoint: str):
        self.api_calls[endpoint] = self.api_calls.get(endpoint, 0) + 1

    def record_error(self, error: str):
        self.errors.append(error)

    def record_decision(self, confidence: float):
        if confidence > 0.9:
            self.decisions_by_confidence["élevée (>0.9)"] += 1
        elif confidence >= 0.7:
            self.decisions_by_confidence["moyenne (0.7-0.9)"] += 1
        else:
            self.decisions_by_confidence["faible (<0.7)"] += 1

    def summary(self) -> str:
        return f"""
Résumé des métriques de l'agent
=====================
Actions : {dict(self.actions_taken)}
Fichiers modifiés : {len(self.files_modified)}
Appels API : {self.api_calls}
Erreurs : {len(self.errors)}
Décisions par confiance : {self.decisions_by_confidence}
"""
Enter fullscreen mode Exit fullscreen mode

Couche 3 : Points de contrôle (récupération)

Créez des pauses automatiques pour validation humaine.

from enum import Enum
from typing import Callable
from dataclasses import dataclass

class CheckpointTrigger(Enum):
    BEFORE_FILE_WRITE = "before_file_write"
    BEFORE_API_CALL = "before_api_call"
    BEFORE_GIT_COMMIT = "before_git_commit"
    BEFORE_DELETE = "before_delete"
    AFTER_N_STEPS = "after_n_steps"

@dataclass
class Checkpoint:
    trigger: CheckpointTrigger
    description: str
    data: dict
    requires_approval: bool = True

class CheckpointManager:
    def __init__(self, auto_approve: set[CheckpointTrigger] | None = None):
        self.auto_approve = auto_approve or set()
        self.pending: list[Checkpoint] = []

    def create_checkpoint(
        self, 
        trigger: CheckpointTrigger, 
        description: str, 
        data: dict
    ) -> bool:
        if trigger in self.auto_approve:
            return True
        checkpoint = Checkpoint(
            trigger=trigger,
            description=description,
            data=data
        )
        self.pending.append(checkpoint)
        # Dans un système réel, notifier l'humain et attendre
        return False

    def approve(self, checkpoint_id: int) -> None:
        if 0 <= checkpoint_id < len(self.pending):
            self.pending.pop(checkpoint_id)

    def reject(self, checkpoint_id: int) -> None:
        raise RuntimeError(f"Point de contrôle rejeté : {self.pending[checkpoint_id]}")

# Utilisation dans l'agent
checkpoints = CheckpointManager(
    auto_approve={CheckpointTrigger.BEFORE_FILE_WRITE}
)

# Avant une action destructrice
if not checkpoints.create_checkpoint(
    trigger=CheckpointTrigger.BEFORE_DELETE,
    description="Sur le point de supprimer le répertoire src/legacy/",
    data={"chemin": "src/legacy/", "fichiers": ["old_handler.ts", "deprecated.ts"]}
):
    agent.pause("En attente d'approbation pour supprimer des fichiers")
Enter fullscreen mode Exit fullscreen mode

Construire des agents autonomes avec Apidog

Quand un agent IA interagit avec des API, le risque majeur est l’envoi de requêtes malformées. Apidog permet d’appliquer des schémas d’API stricts.

Procédure :

  1. Importez ou écrivez votre OpenAPI dans Apidog
  2. Générez un client avec validation intégrée
  3. Donnez ce client à l’agent (et non un accès HTTP brut)
// Mauvais : accès direct, aucune validation
const response = await fetch('/api/users', {
  method: 'POST',
  body: JSON.stringify(data)
})

// Bon : client validé
import { UsersApi } from './generated/apidog-client'

const usersApi = new UsersApi()
const response = await usersApi.createUser({
  email: 'user@example.com',
  name: 'Test User',
  role: 'user'  // Valeur d'énumération validée
})
Enter fullscreen mode Exit fullscreen mode

Votre couche API devient un garde-fou : impossible d’envoyer une requête invalide.

Générez des clients API validés pour vos agents IA.


Modèles éprouvés et erreurs courantes

Modèle 1 : Le sandwich d'approbation

Pour les opérations risquées, exigez une validation humaine avant et après.

def risky_operation(agent, operation):
    # Pré-approbation
    if not agent.checkpoint(f"Sur le point de : {operation.description}"):
        return "Annulé par l'utilisateur"

    # Exécuter l'opération
    result = operation.execute()

    # Post-approbation
    if not agent.checkpoint(f"Vérifier le résultat de : {operation.description}"):
        operation.rollback()
        return "Annulé par l'utilisateur"

    return result
Enter fullscreen mode Exit fullscreen mode

Modèle 2 : Seuils de confiance

N’autorisez pas l’action automatique si la confiance est faible.

MIN_CONFIDENCE = 0.75

def agent_decide(options: list[dict]) -> dict:
    best = max(options, key=lambda x: x.get('confidence', 0))

    if best['confidence'] < MIN_CONFIDENCE:
        return {
            'action': 'escalate',
            'reason': f"La meilleure option a une confiance de {best['confidence']:.2f} < {MIN_CONFIDENCE}",
            'options': options
        }

    return best
Enter fullscreen mode Exit fullscreen mode

Modèle 3 : Opérations idempotentes

Rendez chaque action reproductible sans effet de bord.

import hashlib
import os

def idempotent_write(path: str, content: str) -> bool:
    """Écrit uniquement si le contenu a changé."""
    content_hash = hashlib.sha256(content.encode()).hexdigest()

    existing_hash = None
    if os.path.exists(path):
        with open(path, 'r') as f:
            existing_hash = hashlib.sha256(f.read().encode()).hexdigest()

    if content_hash == existing_hash:
        logger.log_action("écrire_fichier", {"chemin": path}, "Ignoré - pas de modifications")
        return False

    with open(path, 'w') as f:
        f.write(content)
    logger.log_action("écrire_fichier", {"chemin": path}, f"Écrit {len(content)} octets")
    return True
Enter fullscreen mode Exit fullscreen mode

Erreurs courantes à éviter

  • Faire confiance aux invites comme contraintes : les permissions de fichiers sont des vraies contraintes, une invite "ne pas supprimer" ne l'est pas.
  • Pas de plan de retour arrière : sans Git ou sauvegarde, toute erreur est définitive.
  • Ignorer les scores de confiance : pausez ou escaladez à l’humain si la confiance est basse.
  • Sur-surveillance : si vous surveillez tout, vous n’automatisez rien.
  • Sous-spécification du succès : donnez des critères de fin précis à l’agent.

Alternatives et comparaisons

Approche Autonomie Risque Idéal pour
Codage manuel Nulle Faible Travail complexe et critique
Programmation en binôme avec l'IA Faible Faible Apprentissage, exploration
Agents supervisés Moyenne Moyenne Tâches routinières
Agents autonomes avec garde-fous Élevée Contrôlé Opérations en masse, migrations
Agents entièrement autonomes Très élevée Élevée Workflows fiables et bien testés

La plupart des équipes devraient viser l'« autonomie avec garde-fous » : 80% du gain, 10% du risque.


Cas d'utilisation réels

  • Migration de codebase : migration de 200 endpoints REST → GraphQL avec agents autonomes ; garde-fous sur le schéma, points de contrôle sur la suppression. 3 jours au lieu de 3 semaines, aucun incident.
  • Génération de documentation : agent qui génère automatiquement la doc API depuis le code ; garde-fous sur la lecture, points de contrôle avant la publication. Révision hebdo, plus de rédaction manuelle.
  • Couverture de test : agent qui écrit les tests manquants ; contraintes budgétaires pour éviter les excès, seuils de confiance pour l’escalade humaine. Couverture passée de 60% à 85% en un mois.

En résumé

Points-clés à retenir :

  • Les agents IA échouent selon des modes connus : dérive, mauvaises abstractions, cascades, épuisement.
  • Trois couches pour fiabiliser : garde-fous (prévention), observabilité (détection), points de contrôle (récupération).
  • Les garde-fous sont dans le code. Appliquez vos contraintes programmatique­ment.
  • L’observabilité = journaux structurés + métriques, pas surveillance manuelle.
  • Les points de contrôle automatisent la validation humaine.
  • Les schémas d’API d’Apidog rendent votre API inviolable par l’agent.

Vos prochaines étapes :

  1. Identifiez votre tâche IA la plus répétitive
  2. Définissez les garde-fous : ce que l’agent ne doit jamais faire
  3. Ajoutez de la journalisation structurée
  4. Créez des points de contrôle pour les opérations risquées
  5. Lancez un run de 30 minutes et analysez les logs

L’objectif n’est pas de retirer l’humain de la boucle, mais de le replacer au bon endroit : la décision, pas la correction d’erreurs triviales.

Construisez vos garde-fous API pour agents IA – gratuit.


FAQ

Quelle est la différence entre un agent IA et un assistant IA ?

Un assistant répond à vos requêtes et attend la suivante. Un agent prend un objectif et planifie/exécute les étapes pour y parvenir – il fonctionne jusqu’à un point de contrôle ou la fin.

Comment savoir si mon agent est prêt à fonctionner de manière autonome ?

Testez-le 10 fois en mode supervisé. Si vous intervenez moins de 2 fois par session, et uniquement pour des détails mineurs, il est prêt. Sinon, ajoutez des garde-fous.

Quel est le plus grand risque avec les agents autonomes ?

Les défaillances en cascade non détectées. Un point de contrôle bien placé casse ces cascades.

Puis-je utiliser ces modèles avec n'importe quel LLM ?

Oui, ces concepts sont agnostiques : GPT-4, Claude, Gemini, etc. Seule l’implémentation technique varie.

À quel point l'observabilité ralentit-elle l'agent ?

Quasiment pas. L’écriture de logs est négligeable. Les pauses viennent des points de contrôle, à placer seulement sur les actions à risque.

Que se passe-t-il si l'agent prend une décision erronée ?

Les points de contrôle permettent de rejeter l’action et d’annuler ou modifier le résultat. Ajoutez vos préférences à l’agent pour affiner son comportement.

Dois-je commencer par des agents supervisés ou autonomes ?

Toujours commencer supervisé, puis lever progressivement les points de contrôle sur les tâches routinières et sûres.

Comment Apidog aide-t-il pour les agents IA ?

Apidog génère des clients API validés à partir de vos schémas. L’agent utilisant ces clients ne peut pas envoyer de requêtes malformées, éliminant ce type d'échec en amont.

Top comments (0)