Quand une défaillance de pipeline ne peut pas être résolue par de simples retries ou une adaptation de schéma, le niveau suivant d’auto-réparation consiste à envoyer le contexte de l’échec à un LLM et à récupérer un correctif structuré. L’architecture de Benjamin Nweke (publiée dans Towards Data Science, janvier 2026) présente une référence claire pour ce pattern.
Le pattern comporte cinq étapes :
- Le pipeline tente le traitement normalement
- En cas d’échec, il capture les “éléments de la scène de crime” : la traceback, les premières lignes des données d’entrée, et les métadonnées pertinentes
- Il envoie ce contexte à un LLM avec un schéma de sortie structuré
- Le LLM retourne des paramètres correctifs en JSON (pas des suggestions en texte libre, mais des changements de configuration actionnables)
- Le pipeline réessaie avec les corrections appliquées
Les choix de conception à chaque étape importent davantage que la forme globale du pattern.
La sortie structurée est non négociable
La décision de conception la plus importante est de forcer des réponses JSON structurées de la part du LLM. Des conseils en texte libre comme “essayez de changer le délimiteur en pipe” sont inutiles pour une remédiation automatisée. Vous avez besoin d’une réponse que le pipeline peut analyser et appliquer sans interprétation humaine.
Les modèles Pydantic définissent le schéma du correctif :
from pydantic import BaseModel
class PipelineFix(BaseModel): delimiter: str | None = None encoding: str | None = None skip_rows: int = 0 date_format: str | None = None explanation: strChaque champ de ce schéma est un paramètre que le pipeline sait comment appliquer. Le LLM ne peut pas suggérer des changements arbitraires. Il ne peut que remplir des valeurs pour des paramètres que le pipeline gère déjà. Cette contrainte prévient le problème d’hallucination où le modèle retourne des conseils plausibles mais non structurés que personne n’applique.
Le champ explanation est destiné à la journalisation, pas à l’action automatisée. Il indique à l’ingénieur d’astreinte ce que le LLM pensait être erroné, ce qui est utile pour examiner les échecs auto-remédiés après coup.
La fonction de diagnostic
La fonction de diagnostic capture le contexte de l’échec et l’envoie au LLM avec une exposition minimale des données :
def diagnose_failure(error: Exception, sample_data: str) -> PipelineFix: """Envoie le contexte d'échec à Claude, obtient un correctif structuré.""" response = client.messages.create( model="claude-sonnet-4-6", max_tokens=1024, messages=[{ "role": "user", "content": f"Le pipeline a échoué avec : {error}\n\n" f"Premières 4 lignes de l'entrée :\n{sample_data}\n\n" f"Retourne un correctif JSON." }], ) return PipelineFix.model_validate_json(response.content[0].text)N’envoyer que les quatre premières lignes d’un fichier est un choix délibéré. Cela maintient les coûts d’API bas tout en évitant d’envoyer des ensembles de données entiers (avec des PII potentiels) à des services externes. Quatre lignes suffisent généralement pour que le LLM identifie les problèmes d’encodage, les décalages de délimiteurs, ou les problèmes de format de date. Pour les données sensibles, même quatre lignes peuvent être trop. Voir la note sur la hiérarchisation des risques pour les considérations liées aux PII.
La boucle de retry
Tenacity gère une logique de retry propre avec des callbacks before_sleep pour la journalisation :
from tenacity import retry, stop_after_attempt, before_sleep
@retry(stop=stop_after_attempt(3), before_sleep=log_retry)def process_file(filepath: str, fix: PipelineFix | None = None): try: load_and_transform(filepath, fix) except Exception as e: sample = read_first_lines(filepath, n=4) fix = diagnose_failure(e, sample) raise # Tenacity réessaie avec le correctif disponibleLe pattern sépare le mécanisme de retry (Tenacity) du mécanisme de diagnostic (l’appel LLM). À chaque retry, le pipeline dispose d’un objet fix mis à jour avec les paramètres suggérés par le LLM. Si le correctif fonctionne, le traitement réussit. Sinon, l’itération suivante capture la nouvelle erreur et demande un correctif différent.
Disjoncteurs
C’est l’élément qui est souvent oublié. Si 100 000 fichiers échouent simultanément (par exemple, un système source a changé son format d’export), vous ne voulez pas 100 000 appels à l’API LLM. Un compteur simple qui se déclenche après N échecs dans une fenêtre temporelle vous évite une facture surprise.
class CircuitBreaker: def __init__(self, max_failures=10, window_seconds=300): self.failures = [] self.max_failures = max_failures self.window_seconds = window_seconds
def record_failure(self): now = time.time() self.failures = [t for t in self.failures if now - t < self.window_seconds] self.failures.append(now) if len(self.failures) >= self.max_failures: raise CircuitBreakerTripped( f"{self.max_failures} échecs en {self.window_seconds}s" )Quand le disjoncteur se déclenche, le pipeline revient à la gestion traditionnelle des défaillances : journaliser l’erreur, alerter l’équipe, arrêter le traitement. Le LLM n’est pas le bon outil pour les défaillances massives qui ont toutes la même cause profonde.
Pour une remédiation à volume élevé et à faibles enjeux où vous préférez sacrifier la précision pour le contrôle des coûts, les modèles locaux via Ollama sont une alternative aux appels API. La qualité du diagnostic est moindre, mais le coût par appel est essentiellement nul.
Implémentations en production avec Claude
Plusieurs équipes ont mis ce pattern (ou des variantes) en production spécifiquement avec Claude.
L’intégration Datadog + Claude Code de Michael Stewart (publiée sur Medium) présente une configuration complète. Les moniteurs Datadog détectent les patterns d’erreur et déclenchent des webhooks. Une API Gateway et une fonction Lambda récupèrent les journaux d’erreurs détaillés avec les stack traces, regroupent les erreurs par type, et les envoient à Claude Code en lot. Claude Code clone le dépôt, analyse les erreurs en contexte, et génère des suggestions de correctifs. L’équipe reçoit une notification Slack avec l’analyse, applique le correctif via Cursor, et Claude Code examine la PR résultante avant le déploiement. Chaque étape comprend des points de contrôle humains.
Monte Carlo utilise Claude 3.5 pour deux types d’agents. Un agent de surveillance profile les données et crée des règles de surveillance (avec un taux d’acceptation de 60 % par les premiers adoptants incluant les Texas Rangers et Roche). Un agent de dépannage explore de manière autonome les causes profondes. Les agents s’exécutent entièrement dans l’environnement de Monte Carlo, de sorte que les clients n’ont pas besoin d’abonnements LLM séparés ni de se soucier des données quittant la plateforme.
Pour les équipes construisant leur propre intégration, un bon point de départ est le on_failure_callback d’Airflow connecté à une Cloud Function qui appelle l’API Claude. Quand une tâche échoue, le callback envoie le contexte d’erreur à la Cloud Function, qui appelle Claude avec le journal d’erreur de la tâche et retourne un diagnostic structuré sur Slack. Cela ne corrige rien automatiquement. Cela donne à l’ingénieur d’astreinte une longueur d’avance pour comprendre ce qui s’est passé avant même qu’il n’ouvre son ordinateur portable.
L’échappatoire “ne peut pas corriger”
Votre schéma de sortie structuré devrait inclure un moyen pour le LLM de dire “je ne peux pas corriger cela.” Si l’entrée est vraiment corrompue, la bonne réponse est d’échouer, pas de générer une sortie qui semble plausible.
class PipelineFix(BaseModel): can_fix: bool = True delimiter: str | None = None encoding: str | None = None skip_rows: int = 0 date_format: str | None = None explanation: strQuand can_fix est False, la boucle de retry s’arrête et le pipeline revient à l’investigation humaine. Sans cette échappatoire, le LLM pourrait halluciner des données d’apparence valide à partir de données corrompues. Un fichier rempli de données binaires n’a pas de “bon” délimiteur. Un LLM forcé à en suggérer un choisira quelque chose et laissera le pipeline produire des données incorrectes.
Quand utiliser ce pattern
Le pattern Try-Heal-Retry a du sens pour les types de défaillances où trois conditions sont réunies :
- Les correctifs sont prévisibles. Changements d’encodage, modifications de délimiteurs, décalages de format de date, variations de lignes d’en-tête. Vous pouvez énumérer les correctifs possibles dans votre schéma Pydantic.
- Le risque est contenu. Obtenir le mauvais correctif produit des données incorrectes dans un contexte à faibles enjeux, pas dans un rapport financier ou un système de conformité. Voir la note sur la hiérarchisation des risques pour le cadre.
- Vous pouvez valider le correctif. Après la remédiation, vous pouvez vérifier les comptages de lignes, la conformité du schéma, et la qualité de base des données pour confirmer que le correctif a bien fonctionné.
L’ingestion de fichiers est le cas d’usage canonique. L’analyse des réponses API est un autre bon candidat. Les deux ont des modes de défaillance prévisibles, un risque contenu, et une validation facile.
Ce qui ne convient pas : les erreurs de transformation SQL, les bugs de logique métier, les migrations de schéma en production, tout ce qui touche aux données financières. Ceux-ci nécessitent un jugement humain, pas une remédiation automatisée. Le spectre de maturité des pipelines auto-réparateurs place cette distinction à la frontière entre le niveau 4 (pratique) et le niveau 5 (théorique), et cette frontière existe pour de bonnes raisons.