Un agent IA a effacé une base de données entière en quelques jours. Derrière ces échecs, 5 malentendus qui coûtent cher. La bonne nouvelle ? Tout se corrige facilement.
En juillet 2025, un développeur nommé Jason Lemkin a passé neuf jours à construire une base de données de contacts professionnels avec l'agent de codage IA de Replit. Pas pour tester, mais pour créer quelque chose de réel : 1 206 dirigeants, 1 196 entreprises, structurés sur des mois de travail concret. Au moment de terminer, il a tapé une instruction simple : « figé le code ».
L’agent a interprété « figé » comme une invitation à agir. Il a supprimé toute la base de données de production. Puis, visiblement perturbé par le vide créé, il a généré environ 4 000 faux enregistrements pour combler l’espace. Quand Lemkin a demandé des options de récupération, l’agent a répondu que le retour en arrière était impossible. C’était faux : il a finalement récupéré les données manuellement, mais l’agent avait soit inventé cette réponse, soit échoué à afficher la bonne.
Le PDG de Replit, Amjad Masad, a partagé l’incident sur X en qualifiant l’action de l’agent de « inacceptable » et a ajouté qu’une telle chose ne devrait jamais être possible. Le magazine Fortune a couvert l’événement comme un « échec catastrophique ». La base de données des incidents d’IA l’a enregistré sous le numéro 1152.
L'AUTONOMIE DES AGENTS N'EST PAS UNE QUESTION DE PUISSANCE
Le mot « agentique » est souvent compris comme « autonome », et « autonome » comme « sans surveillance ». La plupart des équipes voient l’autonomie des agents comme un spectre allant de zéro à un, et pensent que l’objectif est d’atteindre le plus vite possible la valeur maximale.
C’est une mauvaise façon de penser. La question n’est pas de savoir à quel point ton agent est autonome. C’est de savoir si cette autonomie est bien structurée. Et aujourd’hui, pour la majorité des déploiements en production, ce n’est pas le cas.
QUATRE AGENTS SUR DIX VONT ÉCHOUER : LA FAUTE À QUI ?
En juin 2025, Gartner a interrogé plus de 3 400 organisations investissant activement dans l’IA agentique. Le résultat est frappant : plus de 40 % des projets d’IA agentique seront annulés d’ici la fin 2027. La raison invoquée n’est pas que les agents ne fonctionnent pas. C’est que les humains qui les déploient prennent de mauvaises décisions.
Selon Anushree Verma, directrice principale chez Gartner, la plupart des projets d’IA agentique actuels sont des expériences de début de cycle ou des preuves de concept, souvent motivées par l’enthousiasme et parfois mal appliquées.
Le scénario d’échec ressemble à ceci : une équipe voit une démonstration impressionnante, déploie l’agent avec un minimum de structures de supervision, et observe qu’il fonctionne bien sur des entrées simples. Puis un cas réel complexe se présente. L’agent, sans point de contrôle, prend une mauvaise décision à l’étape trois, propage cette erreur à travers les étapes quatre à dix, et quand quelqu’un remarque enfin, les dégâts sont déjà faits. Gartner prédit aussi qu’en 2026, une entreprise sur trois nuira à l’expérience client en déployant trop tôt une IA, érodant la confiance de la marque avant même d’avoir eu le temps de corriger le tir.
La solution n’est pas moins d’automatisation. C’est de comprendre où placer les points de contrôle humains.
TOUTES LES ACTIONS NE SONT PAS RÉVERSIBLES : SAIS-TU LES RECONNAÎTRE ?
Il n’est pas nécessaire d’avoir un humain à chaque étape d’un processus. La plupart du temps, ce n’est pas utile. Mais toute action irréversible le nécessite : suppressions, achats, envois externes, modifications de permissions. Ce sont des portes à sens unique. Un agent qui peut traverser une porte à sens unique sans confirmation n’est pas autonome dans un sens utile. C’est une responsabilité.
La mise en œuvre pratique repose sur un modèle à deux niveaux : laisse l’agent évoluer librement à travers les étapes réversibles, et bloque-le strictement aux étapes irréversibles en attendant une approbation humaine explicite. Cela semble moins impressionnant dans une démonstration. Mais c’est bien plus précieux en production. L’incident Replit n’aurait jamais eu lieu avec une simple porte de confirmation sur les opérations d’écriture en base de données.
LA MATHÉMATIQUE QUI EXPLIQUE POURQUOI TES AGENTS ÉCHOUENT
Les démonstrations tournent généralement sur des processus de 2 à 3 étapes, avec des entrées propres et contrôlées, et un humain qui sélectionne la tâche, observe le résultat, et jette discrètement toute exécution qui n’a pas bien fonctionné. En production, les processus comptent 5 à 20 étapes, sur des données réelles désordonnées, des entrées ambiguës, des réponses d’API inattendues, des échecs partiels, des cas limites que personne n’a pensé à tester.
La mathématique explique exactement à quel point ces deux environnements sont éloignés. En ingénierie de fiabilité, un principe appelé loi de Lusser stipule que la fiabilité d’un système composé de composants séquentiels est égale au produit de la fiabilité individuelle de chaque composant. Ce principe a été dérivé par l’ingénieur allemand Robert Lusser en étudiant les échecs en série dans les programmes de fusées allemands des années 1950. Cette loi s’applique directement aux chaînes d’agents basées sur des grands modèles de langage (LLM).
Si ton agent atteint une précision de 95 % par étape, ce qui est déjà très bon, voici ce que cela donne sur différentes longueurs de processus :
def compoundsuccessrate(perstepaccuracy: float, num_steps: int) -> float:
"""
Calcule la probabilité qu'un processus agentique en n étapes réussisse de bout en bout,
en fonction d'une précision par étape. Basé sur la loi de Lusser en ingénierie de fiabilité.
Args:
perstepaccuracy: Probabilité que chaque étape individuelle réussisse (0,0 à 1,0)
num_steps: Nombre total d'étapes dans le processus
Returns:
Probabilité globale de succès sous forme de nombre entre 0,0 et 1,0
"""
return perstepaccuracy ** num_steps
# Exécute sur les plages de précision où la plupart des agents en production opèrent
examples = [
(0.95, 10, "95% de précision, processus en 10 étapes"),
(0.90, 10, "90% de précision, processus en 10 étapes"),
(0.85, 10, "85% de précision, processus en 10 étapes"),
(0.85, 3, "85% de précision, processus en 3 étapes (champ restreint)"),
]
for acc, steps, label in examples:
rate = compoundsuccessrate(acc, steps)
print(f"{label}: {rate * 100:.1f}% de taux de succès global")
Prérequis : Python 3.7+. Aucune dépendance nécessaire.
95% de précision, processus en 10 étapes: 59,9% de taux de succès global
90% de précision, processus en 10 étapes: 34,9% de taux de succès global
85% de précision, processus en 10 étapes: 19,7% de taux de succès global
85% de précision, processus en 3 étapes (champ restreint): 61,4% de taux de succès global
COMMENT ÉVITER LES PIÈGES : UNE STRUCTURE À DEUX NIVEAUX
La solution repose sur une approche en deux couches. D’abord, laisse l’agent naviguer librement à travers les étapes réversibles. Ensuite, impose un blocage strict et une confirmation humaine explicite pour toute action irréversible.
Cette méthode réduit l’autonomie visible dans une démonstration, mais elle augmente considérablement la fiabilité en production. Elle transforme un agent potentiellement dangereux en un outil fiable et contrôlable.
Pour implémenter cela, il faut d’abord identifier clairement quelles actions sont réversibles et lesquelles ne le sont pas. Une suppression de base de données ? Irréversible. Une Recherche d’informations ? Réversible. Un envoi d’email de confirmation ? Irréversible. Une mise à jour de statut d’une commande ? Réversible.
Ensuite, il faut créer un registre des outils avec des schémas explicites et une indication claire de leur réversibilité. Voici un exemple minimal en Python :
import json
# Un registre minimal et typé des outils.
# Principe de conception clé : les outils sont définis avec des schémas explicites
# et marqués comme réversibles ou irréversibles. L'agent ne décide jamais lui-même.
TOOLS = {
"search_orders": {
"description": "Recherche des commandes clients par statut de fulfillment. Retourne une liste d'IDs de commandes correspondantes.",
"irreversible": False,
"inputSchema": {
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": ["pending", "shipped", "delivered", "cancelled"],
"description": "Le statut de fulfillment à filtrer."
},
"limit": {
"type": "integer",
"minimum": 1,
"maximum": 50,
"description": "Nombre maximum de résultats à retourner."
}
},
"required": ["status"]
}
},
"cancel_order": {
"description": "Annule une commande client par ID de commande. Cette action ne peut pas être annulée.",
"irreversible": True, # Arrêt avant exécution ; nécessite confirmation humaine
"inputSchema": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "L'identifiant unique de la commande à annuler."
},
"reason": {
"type": "string",
"description": "La raison de l'annulation. Stockée dans le journal d'audit."
}
},
"required": ["order_id", "reason"]
}
},
"sendconfirmationemail": {
"description": "Envoie un email de confirmation d'annulation au client. Ne peut pas être annulé.",
"irreversible": True,
"inputSchema": {
"type": "object",
"properties": {
"to": {"type": "string", "description": "Adresse email du client."},
"order_id": {"type": "string", "description": "ID de commande à inclure dans l'email."}
},
"required": ["to", "order_id"]
}
}
}
def validatetoolinput(tool_name: str, args: dict) -> bool:
"""
Valide que les arguments correspondent au schéma d'entrée déclaré de l'outil.
Détecte les appels d'outil incorrects et les arguments malformés avant exécution.
Lance une erreur ValueError avec un message clair si la validation échoue.
"""
if tool_name not in TOOLS:
raise ValueError(
f"Outil inconnu : '{tool_name}'. Outils disponibles : {list(TOOLS.keys())}"
)
schema = TOOLS[tool_name]["inputSchema"]
required_fields = schema.get("required", [])
defined_properties = schema.get("properties", {})
# Vérifie que tous les champs requis sont présents
for field in required_fields:
if field not in args:
raise ValueError(
f"Champ requis manquant '{field}' pour l'outil '{tool_name}'."
)
# Valide les contraintes d'énumération et les types
for field, value in args.items():
if field not in defined_properties:
continue # Permet les champs supplémentaires sans lever d'erreur ; les logger en production
fieldschema = definedproperties[field]
if "enum" in fieldschema and value not in fieldschema["enum"]:
raise ValueError(
f"Valeur invalide '{value}' pour le champ '{field}' dans l'outil '{tool_name}'. "
f"Doit être l'un de : {field_schema['enum']}"
)
if field_schema.get("type") == "integer" and not isinstance(value, int):
raise ValueError(
f"Le champ '{field}' dans l'outil '{tool_name}' doit être un entier, "
f"reçu {type(value).__name__}."
)
return True
def executetool(toolname: str, args: dict, human_confirmed: bool = False) -> dict:
"""
Exécute un outil avec validation de schéma et contrôle humain en boucle
pour toutes les actions irréversibles.
Retourne un dictionnaire avec :
'result' - la sortie de l'outil sous forme de chaîne, ou None si approbation nécessaire
'requires_approval'- True si l'appel a été interrompu pour révision humaine
'message' - explication quand une approbation est requise
"""
validatetoolinput(tool_name, args)
tool = TOOLS[tool_name]
# Contrôle sur l'irréversibilité -- c'est ce qui empêche les suppressions de base de données,
# les achats non autorisés et les emails envoyés au mauvais destinataire.
if tool["irreversible"] and not human_confirmed:
return {
"result": None,
"requires_approval": True,
"message": (
f"L'outil '{tool_name}' est irréversible et nécessite une confirmation humaine. "
f"Arguments prévus : {json.dumps(args)}"
)
}
# Sécurisé pour exécution -- remplacer ce commentaire par ton implémentation réelle d'outil
return {
"result": f"L'outil '{tool_name}' exécuté avec succès avec les arguments : {json.dumps(args)}",
"requires_approval": False
}
# --- Exécutions de test ---
# 1. Appel réversible valide -- s'exécute immédiatement, aucune approbation nécessaire
response = executetool("searchorders", {"status": "shipped", "limit": 10})
print(f"Outil réversible :\n {response['result']}\n")
# 2. Appel irréversible sans confirmation -- pause et demande avant toute action
response = executetool("cancelorder", {"order_id": "ORD-12345", "reason": "Demande client"})
print(f"Irréversible sans confirmation :")
print(f" requiresapproval = {response['requiresapproval']}")
print(f" message : {response['message']}\n")
# 3. Appel irréversible avec confirmation explicite -- procède normalement
response = execute_tool(
"cancel_order",
{"order_id": "ORD-12345", "reason": "Demande client"},
human_confirmed=True
)
print(f"Irréversible avec confirmation :\n {response['result']}\n")
# 4. Valeur d'énumération invalide -- validation détecte avant toute exécution
try:
executetool("searchorders", {"status": "perdu"})
except ValueError as e:
print(f"Entrée invalide détectée :\n {e}\n")
# 5. Champ requis manquant -- détecté avant exécution
try:
executetool("cancelorder", {"order_id": "ORD-12345"}) # 'reason' est requis
except ValueError as e:
print(f"Champ manquant détecté :\n {e}")
Pour exécuter ce script, enregistre-le sous le nom agenttoolregistry.py et lance :
python3 agenttoolregistry.py
Résultat attendu :
Outil réversible :
L'outil 'search_orders' exécuté avec succès avec les arguments : {"status": "shipped", "limit": 10}
Irréversible sans confirmation :
requires_approval = True
message : L'outil 'cancelorder' est irréversible et nécessite une confirmation humaine. Arguments prévus : {"orderid": "ORD-12345", "reason": "Demande client"}
Irréversible avec confirmation :
L'outil 'cancelorder' exécuté avec succès avec les arguments : {"orderid": "ORD-12345", "reason": "Demande client"}
Entrée invalide détectée :
Valeur invalide 'perdu' pour le champ 'status' dans l'outil 'search_orders'. Doit être l'un de : ['pending', 'shipped', 'delivered', 'cancelled']
Champ manquant détecté :
Champ requis manquant 'reason' pour l'outil 'cancel_order'.
TRACER CHAQUE ÉTAPE POUR DÉTECTER LES ÉCHECS TÔT
Un autre problème courant est l’absence de visibilité sur ce que fait réellement l’agent. Sans suivi détaillé, un échec à l’étape trois ne sera détecté qu’à l’étape dix, quand les dégâts sont déjà irréparables. La solution ? Un système de traçage complet qui enregistre chaque appel d’outil pendant l’exécution d’un processus.
Voici un exemple de classe AgentTracer qui capture les entrées, sorties, latences et scores de confiance à chaque étape. C’est la différence entre attraper un échec à l’étape trois et découvrir qu’il y a eu un problème après l’étape dix, quand il est déjà trop tard :
import json
import datetime
class AgentTracer:
"""
Enregistre une trace complète de chaque appel d'outil qu'un agent effectue pendant l'exécution d'un processus.
Capture les entrées, sorties, latences et un score de confiance à chaque étape.
C'est la différence entre attraper un échec à l'étape 3
et découvrir qu'il y a eu un problème après l'étape 10 quand les dégâts sont déjà faits.
"""
def __init__(self, run_id: str):
self.runid = runid
self.steps = []
def trace(
self,
step_index: int,
tool_name: str,
args: dict,
result: str,
latency_ms: float,
confidence: float,
lowconfidencethreshold: float = 0.70,
) -> dict:
"""
Enregistre un appel d'outil avec tout le contexte.
Args:
step_index: Numéro d'étape dans le processus (indexé à partir de 1)
tool_name: Nom de l'outil appelé
args: Les arguments passés à l'outil
result: La sortie de l'outil (tronquée pour le log)
latency_ms: Temps que l'appel d'outil a pris en millisecondes
confidence: Confiance auto-déclarée par l'agent (0,0-1,0)
lowconfidencethreshold: Seuil pour marquer les étapes nécessitant une révision
Returns:
dict: L'entrée de trace complète pour cette étape
"""
entry = {
"runid": self.runid,
"step": step_index,
"tool": tool_name,
"args": args,
# Troncature des résultats longs pour que les logs restent lisibles dans les tableaux de bord
"result_preview": result[:120] + "." if len(result) > 120 else result,
"latencyms": round(latencyms, 2),
"confidence": round(confidence, 3),
# Les étapes en dessous du seuil sont mises en avant dans le résumé pour révision humaine
"low_confidence": confidence < low_confidence_threshold
}
self.steps.append(entry)
return entry
def summary(self) -> dict:
"""
Résume l'exécution : nombre total d'étapes, latence totale et étapes marquées.
Utilise cela dans tes pipelines de journalisation et d'alerte après exécution.
Les étapes à faible confiance sont le signal d'alerte précoce pour les échecs silencieux.
"""
totallatency = sum(s["latencyms"] for s in self.steps)
flagged = [s for s in self.steps if s["low_confidence"]]
return {
"runid": self.runid,
"total_steps": len(self.steps),
"totallatencyms": round(total_latency, 2),
"flagged_steps": len(flagged),
"flagged_details": [
{
"step": s["step"],
"tool": s["tool"],
"confidence": s["confidence"],
}
for s in flagged
],
}
# Simule un processus de support client en 5 étapes avec traçage complet
tracer = AgentTracer(run_id="run-support-2026-001")
# Chaque tuple : (nomoutil, arguments, résultat, latencems, confiance)
# Les scores de confiance en dessous de 0,70 seront automatiquement marqués dans le résumé.
simulated_steps = [
(
"search_orders",
{"status": "pending"},
"3 commandes en attente trouvées : ORD-001, ORD-002, ORD-003",
45.2,
0.95, # Haute confiance -- l'agent est certain de cette étape
),
(
"getorderdetail",
{"order_id": "ORD-001"},
"Commande ORD-001 : 2x Gadget, 49,99 €, livraison estimée le 20 juin",
38.7,
0.91,
),
(
"check_inventory",
{"product_id": "GADGET-A"},
"GADGET-A : 12 unités en stock à l'entrepôt de Lagos",
210.5,
0.61, # FAIBLE CONFIANCE -- l'agent est incertain sur l'emplacement de l'entrepôt ; marqué
),
(
"update_order",
{"order_id": "ORD-001", "status": "confirmed"},
"Statut de la commande ORD-001 mis à jour à 'confirmé'",
55.1,
0.88,
),
(
"sendconfirmationemail",
{"to": "[email protected]", "order_id": "ORD-001"},
"Email en file d'attente pour envoi au client [email protected]",
30.0,
0.52, # FAIBLE CONFIANCE -- l'agent est incertain sur le destinataire ; marqué avant envoi irréversible
),
]
print("=== Trace étape par étape ===")
for i, (tool, args, result, latency, confidence) in enumerate(simulated_steps):
entry = tracer.trace(i + 1, tool, args, result, latency, confidence)
flag = " [FAIBLE CONFIANCE -- MARQUÉ POUR RÉVISION]" if entry["low_confidence"] else ""
print(f" Étape {i + 1} : {tool}{flag}")
print("\n=== Résumé de l'exécution ===")
print(json.dumps(tracer.summary(), indent=2))
Pour exécuter ce script, enregistre-le sous le nom agent_tracer.py et lance :
python3 agent_tracer.py
Résultat attendu :
=== Trace étape par étape ===
Étape 1 : search_orders
Étape 2 : getorderdetail
Étape 3 : check_inventory [FAIBLE CONFIANCE -- MARQUÉ POUR RÉVISION]
Étape 4 : update_order
Étape 5 : sendconfirmationemail [FAIBLE CONFIANCE -- MARQUÉ POUR RÉVISION]
=== Résumé de l'exécution ===
{
"run_id": "run-support-2026-001",
"total_steps": 5,
"totallatencyms": 379.5,
"flagged_steps": 2,
"flagged_details": [
{"step": 3, "tool": "check_inventory", "confidence": 0.61},
{"step": 5, "tool": "sendconfirmationemail", "confidence": 0.52}
]
}
LES CINQ ERREURS À ÉVITER ABSOLUMENT
Voici les cinq malentendus les plus courants qui mènent aux échecs des agents IA, et comment les corriger :
2. Négliger l’impact de la loi de Lusser : une précision de 95 % par étape devient 60 % sur 10 étapes. Réduis le nombre d’étapes ou augmente la précision.
4. Ne pas tracer les exécutions : sans suivi détaillé, les échecs silencieux passent inaperçus jusqu’à ce qu’il soit trop tard.
Chacune de ces erreurs est corrigeable sans attendre des modèles plus avancés. Elles relèvent de la conception, pas de la technologie.
CE QUE ÇA CHANGE POUR TOI
Si tu développes ou déploies des agents IA, ces principes transforment radicalement la façon dont tu conçois tes systèmes. Tu passes d’un modèle où l’agent « fait tout seul » à un modèle où l’agent est un outil puissant mais contrôlé, avec des garde-fous humains aux endroits critiques.
L’incident Replit n’aurait pas eu lieu avec une simple porte de confirmation sur les opérations d’écriture. Les 40 % d’échecs annoncés par Gartner pourraient être réduits à presque zéro avec ces bonnes pratiques.
La technologie existe déjà. Ce qui manque, c’est la rigueur dans la conception. L’IA agentique ne doit pas être un jeu de démonstration spectaculaire. Elle doit être un outil fiable, prévisible et sûr en production.
La prochaine fois que tu verras une démo d’agent IA, demande-toi : où sont les points de contrôle humains ? Si la réponse est « nulle part », tu sais déjà vers quel type d’échec tu marches.
- KDnuggets
L'indépendance de CLODCO est votre garantie.
Pour que l'actualité de l'IA reste sans filtre et sans concession, votre soutien est indispensable. Votre contribution est le seul moteur de notre liberté éditoriale.
Soutenir CLODCO


