Pause et reprise des agents LangGraph avec interrupt() et Commande
Comment les fonctions interrupt() et Command de LangGraph s’appuient sur des points de contrôle et des threads pour suspendre un agent en attente d’approbation, de modifications ou d’entrée de la part de l’utilisateur, puis pour le reprendre en toute sécurité par la suite.
Un agent capable de transférer de l’argent, de supprimer des ressources ou d’être déployé en production ne devrait pas toujours être autorisé à terminer ce qu’il a commencé. Parfois, le graphe doit s’arrêter délibérément, attendre des heures qu’une personne intervienne, puis reprendre exactement là où il s’était arrêté. Cet article explique comment LangGraph y parvient grâce à interrupt() et Command, pourquoi cela dépend des points de contrôle et des threads, ainsi quelles décisions vous restent à prendre avant d’exécuter des agents avec un humain dans la boucle (HITL) en production.
Les éléments de base
HITL repose sur trois couches. Premièrement, l’exécution du graphe : l’état entre dans un nœud, et une arête sélectionne le nœud suivant.
STATE
↓
NODE
↓
EDGE
↓
NEXT NODE
Deuxièmement, la gestion de l’état : les nœuds renvoient des mises à jour, et les réducteurs les fusionnent pour former le nouvel état.
NODE
↓
STATE UPDATE
↓
REDUCER
↓
NEW STATE
Troisièmement, la persistance : un point de contrôle enregistre l’état sous forme de points de contrôle regroupés au sein d’un thread.
STATE
↓
CHECKPOINT
↓
CHECKPOINTER
↓
THREAD
↓
PERSISTENCE
Tout cela permet à un agent de fonctionner, de mémoriser et de survivre aux redémarrages. Ce qui manque, c’est un moyen de déterminer s’il doit continuer ou non.
Lorsqu’un agent ne devrait pas simplement continuer
Un utilisateur demande à un assistant de paiement : "Virez 50 000 ₹ sur ce compte." L’agent prépare la transaction, et rien techniquement ne l’empêche de s’exécuter.
User
↓
Agent
↓
Prepare Transfer
↓
Transfer ₹50,000
↓
Execute
Pour une action aussi importante, une personne doit d’abord examiner la proposition, afin que le flux suive une décision humaine.
User
↓
Agent
↓
Prepare Transfer
↓
┌─────────────────────┐
│ HUMAN APPROVAL │
└──────────┬──────────┘
│
┌───┴───┐
↓ ↓
Approve Reject
│ │
↓ ↓
Execute Cancel
Le graphique doit maintenant s’arrêter délibérément : non en cas d’erreur ou de panne, mais parce que le processus nécessite une intervention humaine à cet endroit.
Que signifie l’intervention humaine dans le flux
HITL insère des décisions humaines dans un flux automatisé. Au lieu de passer directement d’une décision à une action,
Agent
↓
Decision
↓
Action
l’agent propose, fait une pause et attend un examen.
Agent
↓
Proposed Action
↓
PAUSE
↓
Human Review
↓
Decision
↓
Continue
L’examinateur peut approuver, rejeter, modifier la proposition, fournir des données manquantes, corriger l’agent ou choisir parmi des alternatives. Cela convient à toute étape ayant des conséquences réelles.
Financial transactions
Sending emails
Deleting resources
Production deployments
Database modifications
Legal workflows
Publishing content
Access approvals
Sensitive tool calls
Ce dont a vraiment besoin une pause d’un graphique
Prenons une chaîne comportant une étape d’approbation avant le dernier nœud.
Node A
↓
Node B
↓
Human Approval
↓
Node C
Si l’examinateur répond six heures plus tard, bloquer le processus est la mauvaise solution : cela gaspille un travailleur et provoque une erreur lors du premier redémarrage.
sleep(21600)
Ce que vous souhaitez plutôt, c’est enregistrer l’état actuel et s’arrêter,
Node B
↓
SAVE STATE
↓
PAUSE EXECUTION
↓
puis le restaurer plus tard, éventuellement dans un autre processus, et reprendre à partir du nœud suivant.
Application can stop──────── 6 HOURS LATER ────────Human responds
↓
RESTORE STATE
↓
CONTINUE EXECUTION
↓
Node C
La persistance résout déjà la moitié du problème. Les points de contrôle, le mécanisme de suivi des points de contrôle, les threads et thread_id sont exactement ce dont a besoin une longue pause.
Checkpoint
Checkpointer
Thread
thread_id
Persistence
Comment interrupt() arrête l’exécution
interrupt() met en pause un graphe et demande une valeur au monde extérieur. Vous l’appeliez à l’intérieur d’un nœud avec un en-tête JSON serialisable décrivant ce que l’utilisateur doit voir. Le fragment est écrit en Python, malgré son étiquette initiale.
from langgraph.types import interrupt
def approval_node(state):
decision = interrupt({
"question": "Do you approve this transaction?",
"amount": state["amount"]
})
return {
"decision": decision
}
Lorsque l’exécution atteint cet appel,
interrupt(...)
le nœud n’atteint pas sa instruction de retour. L’exécution est suspendue et l’en-tête est renvoyé à l’appelant afin d’être affiché.
approval_node
│
↓
interrupt()
│
↓
┌─────────────────┐
│ EXECUTION PAUSED│
└─────────────────┘
Deux points importants : interrupt() nécessite un graphe compilé avec un checkpointer, car l’état en pause doit être stocké quelque part. Lors de la reprise, LangGraph exécute à nouveau le nœud interrompu depuis le début ; interrupt() renvoie alors la valeur saisie par l’utilisateur, ce qui fait que le code précédant l’appel s’exécute deux fois. Évitez les effets secondaires dans cette partie du nœud, et vérifiez le comportement correspondant pour votre version dans la documentation de LangGraph.
Qu’est-ce qui est enregistré lors d’une interruption
Considérez ce graphique.
START
↓
Prepare Transfer
↓
Human Approval
↓
Execute Transfer
↓
END
Le nœud de préparation met à jour l’état, un point de contrôle est enregistré, et le nœud d’approbation appelle interrupt().
START
↓
Prepare Transfer
↓
State Updated
↓
Checkpoint
↓
Approval Node
↓
interrupt()
L’état actuel est capturé et enregistré dans le stockage.
Current State
│
↓
Checkpoint
│
↓
Persistent Storage
Le thread contient désormais les détails du transfert, un statut en attente ainsi que la raison de l’arrêt.
THREAD: transaction-123
Checkpoint
────────────────────
amount ₹50,000
recipient Account X
status pending
────────────────────
Execution:
PAUSED
Reason:
Human approval required
C’est tout ce qui est nécessaire pour poursuivre plus tard. Sans persistance, le processus disparaîtrait simplement après l’interruption.
Agent
↓
interrupt
↓
process disappears
↓
???
Lorsque le responsable d’examen indique « Approuvé » le jour suivant, personne ne peut savoir ce qui a été approuvé, où s’est arrêté le graphique ou quel nœud vient ensuite. Avec les points de contrôle, l’état est chargé depuis le thread et restauré avant la reprise.
INTERRUPT
│
↓
CHECKPOINT
│
↓
THREAD
│
↓
PERSISTENT STORAGE
...time passes...
HUMAN INPUT
│
↓
THREAD
│
↓
LOAD CHECKPOINT
│
↓
RESTORE STATE
│
↓
RESUME
Reprise avec une commande
L’application affiche le contenu de l’interruption sous forme de question
Approve transfer of ₹50,000?
avec deux boutons,
[ APPROVE ] [ REJECT ]
et l’utilisateur en choisit un.
APPROVE
La réponse est renvoyée via Command, qui indique au graphe comment procéder. Pour reprendre, invoquez le graphe avec Command(resume=...) au lieu d’une entrée normale.
from langgraph.types import Command
graph.invoke(
Command(resume="approved"),
config=config
)
config doit utiliser le même thread que l’exécution en pause,
thread_id = transaction-123
car c’est l’ID du thread qui permet à LangGraph de savoir quelle exécution suspendue vous désignez.
Étapes du cycle de vie, une par une
graph.invoke()
elle lit son thread dans config,
thread_id = transaction-123
elle entre dans le nœud de préparation,
START
↓
Prepare Transfer
et enregistre le transfert dans l’état.
amount = ₹50,000
recipient = Account X
status = pending
Le nœud d’approbation appelle interrupt(),
Approval Node
↓
interrupt()
et l’exécution est suspendue.
EXECUTION PAUSED
Le dernier point de contrôle reste sécurisé sous le thread.
Thread
↓
Checkpoint
↓
Persistent Storage
Une personne voit la demande
Approve ₹50,000 transfer?
et y répond.
YES
L’application envoie une commande de reprise
Command(resume="approved")
au même thread.
transaction-123
LangGraph restaure l’exécution, transmet la décision au nœud d’approbation et continue jusqu’à la fin.
Restore Execution
↓
Human Decision = approved
↓
Continue Graph
↓
Execute Transfer
↓
END
Chaque schéma ci-dessous est une variation de ce cycle de vie.
Décisions humaines au-delà du oui ou non
La réponse d’un examinateur n’a pas besoin d’être binaire.
YES / NO
L’approbation exécute la proposition.
Agent Proposal
↓
Human
↓
APPROVE
↓
Execute
Le rejet l’annule.
Agent Proposal
↓
Human
↓
REJECT
↓
Cancel
La modification modifie une partie de celle-ci, comme le montant, avant que le graphe ne progresse.
Agent:
Send ₹50,000
↓
Human:
Change to ₹40,000
↓
Graph continues with
updated information
Fournir des informations manquantes transforme l’interruption en une question.
Agent
↓
Missing Account Number
↓
INTERRUPT
↓
Human provides account
↓
RESUME
Le choix permet à l’agent de proposer des alternatives et de laisser le choix à une personne.
Agent generates:
Option A
Option B
Option C
↓
Human chooses B
↓
Graph continues
HITL est un moyen général d’injecter des entrées humaines dans un graphe en cours d’exécution, et non seulement un dialogue d’approbation.
La commande en tant que flux de données et flux de contrôle
Commande peut également mettre à jour l’état et choisir la destination suivante.
Resume Execution
Update State
Choose Next Destination
Une seule commande peut définir un état et envoyer l’exécution vers un nœud spécifique ; dans LangGraph, cette forme est généralement renvoyée par un nœud.
Command(
update={
"status": "approved"
},
goto="execute"
)
Cela combine deux aspects,
DATA FLOW
+
CONTROL FLOW
car le routage appartenait auparavant uniquement aux arêtes.
Edges control where we go.
Désormais, un seul objet peut contenir à la fois le changement d’état et l’étape suivante.
Command can participate in
state updates + control decisions.
Corriger l’état avant de continuer
Supposons que l’état contienne cette somme,
amount = 50000
et que l’examinateur approuve avec une correction.
Approve, but change amount to 40000.
Le flux passe de la valeur initiale, via l’examen, à une valeur mise à jour, avant de reprendre (le deuxième extrait apparaît alors sur une seule ligne).
BEFORE
amount = 50000 ↓Human Review ↓UPDATEamount = 40000 ↓RESUME
La question passe de « Puis-je continuer ? » à « Vérifier, corriger si nécessaire, puis continuer. »
Contrôle des appels à des outils sensibles
HITL est particulièrement utile avant l’utilisation d’outils à risque.
search_web()
read_database()
send_email()
delete_resource()
transfer_money()
Une recherche sur Internet peut s’exécuter automatiquement,
search_web()
↓
Execute Automatically
alors que la suppression d’une ressource doit attendre une approbation.
delete_resource()
↓
INTERRUPT
↓
Human Approval
Chaque appel à un outil passe par une vérification de sensibilité : les appels sûrs se déroulent, tandis que ceux qui sont sensibles s’interrompent pour obtenir une approbation ou être annulés.
Agent
│
↓
Tool Call
│
↓
Sensitive Tool?
/ \
NO YES
│ │
↓ ↓
Execute INTERRUPT
│ │
│ ↓
│ Human
│ / \
│ Approve Reject
│ │ │
└─────────┘ ↓
Cancel
Pour une implémentation plus complète soutenue par un stockage, consultez les agents contrôlés par l’approbation dans LangGraph.
L’examen en tant que limite de contrôle délibérée
L’examen humain n’est pas une solution de remplacement pour un agent qui n’est pas suffisamment intelligent. C’est une limite que l’on impose intentionnellement. Les tâches à faible risque s’exécutent automatiquement,
LOW RISK
Search
Read
Summarize
↓
Automatic
et les tâches à haut risque passent par une personne.
HIGH RISKSend
Delete
Purchase
Transfer
Deploy
↓
Human Approval
Le but est de déterminer où l’autonomie est appropriée, et non de la réduire partout.
Gestion des rejets et du silence
Le rejet mérite une véritable conception.
Agent
↓
Prepare Action
↓
Interrupt
↓
Human
↓
REJECT
Enregistrez le résultat dans l’état,
status = "rejected"
puis dirigez le flux en fonction de cela à l’aide d’un bord conditionnel.
Decision
/ \
approved rejected
│ │
↓ ↓
Execute Cancel
│ │
↓ ↓
END END
Tous les concepts précédents y participent, et l’entrée humaine n’est qu’une information supplémentaire qui influence l’exécution.
State
Reducers
Conditional Routing
Checkpoints
Threads
Commands
Les examinateurs peuvent également ne jamais répondre.
Interrupt
↓
Waiting for approval
↓
1 hour
↓
1 day
↓
7 days
Un thread en pause peut attendre indéfiniment, il faut donc des politiques dans votre application.
Expiration
Timeout
Cancellation
Reminder
Escalation
Une méthode courante consiste en une attente limitée dans le temps, généralement imposée par un planificateur qui reprend les threads obsolètes après une durée définie.
Approval Requested
│
↓
Wait up to 24 hours
│
┌───┴────┐
↓ ↓
Response Timeout
│ │
↓ ↓
Resume Cancel
LangGraph fournit des primitives ; les règles métier relèvent de vous.
Plusieurs étapes et flux en continu
Un agent de déploiement peut demander l’approbation de son plan, puis à nouveau avant la mise en production.
START
↓
Analyze Code
↓
Generate Deployment Plan
↓
Human Approval #1
↓
Deploy to Staging
↓
Run Tests
↓
Human Approval #2
↓
Deploy Production
↓
END
Chaque étape pause et reprend le même thread, laissant ainsi un historique des points de contrôle et des interruptions.
Thread
│
├── CP1
│
├── CP2
│
├── INTERRUPT
│
├── RESUME
│
├── CP3
│
├── INTERRUPT
│
├── RESUME
│
└── END
C’est un flux de travail durable partagé entre les utilisateurs et un agent. Jusqu’à présent, chaque exemple utilisait une appel bloquant,
graph.invoke(...)
qui ne renvoie de résultat que lorsque l’exécution se termine ou est interrompue.
START → A → B → C → END
↓
RESULT
Les applications interactives nécessitent de suivre l’avancement en temps réel, jusqu’à la demande d’approbation.
START
↓
Planner Update ─────────→ UI
↓
Tool Call ──────────────→ UI
↓
Tool Result ────────────→ UI
↓
Approval Required ──────→ UI
Le streaming transmet ces événements afin que l’interface puisse afficher les étapes terminées ainsi que la décision en attente.
┌──────────────────────────────────┐
│ Deployment Agent │
├──────────────────────────────────┤
│ │
│ ✓ Analyzed repository │
│ │
│ ✓ Generated deployment plan │
│ │
│ ✓ Staging tests passed │
│ │
│ ⚠ Production deployment ready │
│ │
│ Human approval required │
│ │
│ [ APPROVE ] [ REJECT ] │
│ │
└──────────────────────────────────┘
Derrière cet écran, les événements sont acheminés vers le frontend et la décision est renvoyée via Command(resume=...).
LangGraph
│
↓
Streaming
│
↓
Frontend
│
↓
Human Decision
│
↓
Command(resume=...)
│
↓
LangGraph
Le modèle d’exécution complet
Dans un seul diagramme : l’utilisateur invoque le graphe sur une thread, l’état passe par des nœuds et des réducteurs, des points de contrôle sont enregistrés, le routage choisit l’étape suivante, et les actions sensibles redirigent vers une interruption à résoudre par un humain.
USER
│
↓
graph.invoke()
│
↓
THREAD
│
↓
CHECKPOINTER
│
↓
STATE
│
↓
NODE
│
↓
STATE UPDATE
│
↓
REDUCER
│
↓
NEW STATE
│
↓
CHECKPOINT
│
↓
EDGE / ROUTING
│
↓
SENSITIVE ACTION?
/ \
NO YES
│ │
↓ ↓
NEXT NODE interrupt()
│
↓
PAUSED
│
↓
HUMAN
/ | \
/ | \
Approve Edit Reject
│ │ │
└────────┼────────┘
↓
Command(resume)
│
↓
SAME thread_id
│
↓
RESTORE CHECKPOINT
│
↓
CONTINUE GRAPH
│
↓
END
En termes narratifs, une demande arrive
User Input
et l’exécution commence.
START
Les nœuds lisent l’état et retournent des mises à jour, les réducteurs les fusionnent, les points de contrôle les enregistrent au sein d’un thread, et les arêtes déterminent ce qui s’exécute ensuite. Le graphe peut se diviser, former des boucles ou appeler des outils.
BRANCH
LOOP
CALL TOOLS
Lorsqu’une intervention humaine est nécessaire, une interruption suspend l’exécution.
interrupt()
La personne répond,
APPROVE
REJECT
EDIT
PROVIDE INPUT
une commande de reprise continue depuis le thread persisté,
Command(resume=...)
et le graphe se termine.
END
La plupart des projets commencent par une seule appel à un modèle,
LLM
↓
Response
et se terminent par un graphe combinant des nœuds LLM et d’outils, des réducteurs, des points de contrôle, du routage, des interruptions et des commandes.
USER
│
↓
START
│
↓
STATE
│
↓
NODE
│
┌──────┴──────┐
│ │
LLM TOOL
│ │
└──────┬──────┘
↓
STATE UPDATE
│
↓
REDUCER
│
↓
NEW STATE
│
↓
CHECKPOINT
│
↓
THREAD
│
↓
ROUTING
/ | \
/ | \
NODE LOOP INTERRUPT
│
↓
HUMAN
/ | \
Approve Edit Reject
\ | /
\ | /
↓
COMMAND
│
↓
RESUME
│
↓
NEXT NODE
│
↓
END
Checklist de production
Garder les nœuds ciblés
Les petits nœuds à usage unique sont plus faciles à tester, à réessayer et à interrompre en toute sécurité,
Plan Node
Search Node
Validate Node
Execute Node
contrairement à un seul nœud qui fait tout.
do_everything_agent()
Concevoir délibérément l’état et les réducteurs
Ne conserver que ce dont ont besoin les nœuds, car tout est sauvegardé et peut être montré aux reviewers. Choisir soigneusement les réducteurs pour les champs qui s’accumulent.
messages
events
results
observations
Rendre les effets secondaires idempotents
Les opérations irréversibles nécessitent une attention particulière.
Send Email
Charge Card
Delete Resource
Deploy
Transfer Money
Les tentatives de réessai et la reprise ne doivent jamais les reproduire. Comme un nœud interrompu redémarre à la reprise, placer les appels irréversibles après le point d’approbation ou dans un nœud séparé, et utiliser des clés d’idempotence lorsque les API le permettent.
Utiliser une persistance durable
Les outils de sauvegarde en mémoire conviennent à l’apprentissage ; la production nécessite un stockage durable adapté aux exigences de fiabilité.
Établir des limites et des frontières
Définir explicitement ces éléments pour chaque flux de travail,
What can AI do automatically?
What requires approval?
What can humans modify?
When does approval expire?
et spécifier les conditions de terminaison des boucles.
Maximum attempts
Timeouts
Validation
Failure paths
Escalation
Quand HITL est utile
La révision humaine s’avère efficace dans des situations spécifiques.
Cost of wrong action is high
Action is irreversible
Policy requires approval
Agent confidence is insufficient
Sensitive information is involved
Human judgment adds value
Dispersée partout, elle contrecarre l’automatisation et pousse les réviseurs à cliquer sans lire.
Agent
↓
Ask Human
↓
Agent
↓
Ask Human
↓
Agent
↓
Ask Human
Un meilleur design offre à l’agent une zone autonome pour la planification et le raisonnement, avec une limite avant l’action conséquente.
AUTONOMOUS ZONE
┌───────────────────────┐
│ │
│ Plan → Search → Think │
│ │
└───────────┬───────────┘
│
↓
CONTROL BOUNDARY
│
↓
HUMAN
│
↓
APPROVED ACTION
Comment les couches s’assemblent
L’exécution du graphe couvre les nœuds, les arêtes et le routage ;
Graph
Nodes
Edges
START
END
Loops
Conditional Routing
la gestion de l’état couvre les mises à jour et les réducteurs ;
State
State Updates
Reducers
Messages
State Evolution
la persistance couvre les points de contrôle, les threads et la récupération ;
Checkpoints
Checkpointer
Threads
thread_id
State History
Recovery
et HITL ajoute des interruptions, des commandes et des modèles de révision.
interrupt()
Command
Pause
Resume
Approve
Reject
Edit
Human Control
Empilées, elles forment un seul pipeline.
GRAPH
↓
STATE
↓
NODE
↓
UPDATE
↓
REDUCER
↓
CHECKPOINT
↓
THREAD
↓
ROUTING
↓
INTERRUPT
↓
HUMAN
↓
COMMAND
↓
RESUME
↓
END
Points clés
Le vocabulaire peut sembler intimidant,
StateGraph
MessagesState
Reducers
Checkpointers
Threads
Commands
Interrupts
Mais chaque composant résout une partie d’un seul objectif : un agent qui connaît, agit, met à jour, décide, enregistre les progrès, s’arrête au bon moment, demande de l’aide à une personne et reprend en toute sécurité.
Remember what it knows
↓
Perform some work
↓
Update what it knows
↓
Decide what to do next
↓
Persist its progress
↓
Pause when necessary
↓
Ask a human
↓
Resume safely
↓
Continue until complete
- L’état correspond à ce que l’agent connaît, les nœuds à ce qu’il fait, les arêtes aux endroits où il se rend, et les réducteurs à la manière dont l’état change.
- Les points de contrôle enregistrent où se trouvait l’agent ; les threads indiquent à quel thread appartient une histoire.
interrupt()marque l’endroit où s’arrêter et demander de l’aide ;Commandindique comment continuer, toujours sur le même thread.- Les nœuds interrompus redémarrent lors de la reprise, il faut donc conserver les effets secondaires irréversibles après le point d’approbation.
- Placer les vérifications aux véritables limites de contrôle, avec des règles explicites de délai d’expiration et d’escalade.