Engineering the Agentic Stack · Partie 5

Runtime d’AI agents longue durée : sessions et checkpoints

Traduction automatique Cet article a été traduit automatiquement depuis la version originale en anglais.

Une exécution d’agent peut durer plusieurs heures, tandis que son processus worker peut redémarrer à tout moment. Le modèle choisit toujours l’action suivante, mais le runtime doit préserver l’état, contrôler l’exécution et récupérer après une panne survenue au milieu d’un tool call. Cet article définit la frontière du runtime. La partie 6 ouvre ensuite le composant qui prend les décisions — le harness, là où la mémoire, les contrats des outils et les contrôles de permissions cessent d’être trois sujets distincts pour devenir un seul programme.

En bref : un agent longue durée a besoin de cinq éléments explicitement séparés : un journal de session durable, le harness qui pilote la boucle, une sandbox, un store de checkpoints et une trace. Pour la plupart des équipes, le bon choix par défaut est une queue avec un worker et un checkpointer PostgreSQL. Si vous ne pouvez pas identifier le composant responsable de chacun de ces cinq éléments, votre agent est encore un prototype.

Qu’est-ce qu’un runtime d’AI agent ?

Un runtime d’AI agent est la couche d’infrastructure qui maintient un agent utilisant des outils en fonctionnement, isolé, observable et reprenable une fois l’appel au modèle terminé. Il gère l’état de session, l’exécution des outils, les checkpoints, les secrets, les traces, les plafonds de coût et la forme du déploiement. Le modèle choisit l’action suivante ; le runtime détermine où cette action s’exécute, comment elle est enregistrée et comment l’exécution reprend après une panne. La décision d’autoriser ou non l’action revient au harness. Le harness n’est pas une couche de stockage : c’est le programme qui s’appuie sur ces composants et figure donc dans le tableau ci-dessous, car il faut également lui attribuer une place.

Primitive à positionnerRôle en productionImplémentation courante
SessionPréserver le journal d’exécution après un redémarrage du processusJournal d’événements en ajout seul, thread ID, store de conversations
HarnessPiloter les tours modèle/outils jusqu’à la fin de la tâcheGraphe LangGraph, runner Agents SDK, boucle personnalisée
SandboxIsoler le code, les fichiers, le réseau et les outilsConteneur renforcé, VM, browser sandbox, workspace géré
CheckpointReprendre sans rejouer toute l’exécutionPostgres, Redis, état de workflow durable
TraceDéboguer et auditer les exécutions longues a posterioriSpans OpenTelemetry, LangSmith, traces du fournisseur

Quatre de ces cinq primitives — session, sandbox, checkpoint et trace — stockent l’état ou confinent l’exécution. Le harness est celui qui décide ; c’est là que convergent les décisions relatives à la mémoire, aux contrats des outils et aux permissions. Cet article le traite comme un bloc unique et décrit les composants sur lesquels il repose. La partie 6 ouvre ce bloc et réorganise les mêmes cinq éléments entre le composant décisionnel et les quatre composants qui le supportent.


Les longues exécutions remettent en cause les hypothèses des processus sans état

Un endpoint de chat sans état peut conserver l’état de la requête dans un processus et le supprimer après la réponse. Une exécution longue d’agent traverse des redémarrages de workers, des déploiements, des réinitialisations du contexte et des pauses en attente d’approbation. Le processus worker ne peut donc plus être la source de vérité.

L’équipe OpenAI Codex indique la durée que peuvent atteindre ces exécutions dans son article sur le harness engineering :

« Nous voyons régulièrement des exécutions Codex travailler sur une seule tâche pendant plus de six heures, souvent pendant que les humains dorment. »

L’équipe d’ingénierie d’Anthropic décrit le problème d’état correspondant dans Effective harnesses for long-running agents :

« Le défi central des agents longue durée est qu’ils doivent travailler au sein de sessions discrètes, et que chaque nouvelle session commence sans mémoire de ce qui s’est passé auparavant. »

Ces deux observations impliquent la même conception du runtime : persister l’état en dehors du worker et rendre les workers remplaçables.

La session doit vivre en dehors du processus worker. Un store durable enregistre les appels au modèle, les tool results et les approbations afin qu’un autre worker puisse reprendre au dernier point sûr après un crash. Les checkpoints permettent également au runtime de démarrer une nouvelle session de modèle lorsque la fenêtre de contexte est pleine, sans rejouer tout l’historique. Pour reprendre les termes d’Anthropic, les instances du harness deviennent jetables et redémarrables ; l’état durable est stocké ailleurs.


Cinq primitives à positionner avant la mise en production

L’article d’Anthropic Scaling Managed Agents fournit un vocabulaire utile pour décrire cinq responsabilités du runtime. Le harness fait progresser l’agent, tandis que la session enregistre ce qu’il a fait et que la sandbox exécute les commandes. Le checkpoint fournit au worker suivant un point de reprise ; la trace conserve les éléments nécessaires au débogage ultérieur. Une implémentation peut fusionner certains composants, mais les responsabilités et les frontières de panne doivent toujours être nommées.

Les cinq primitives du runtimeLes cinq primitives du runtime

Session. Un journal en ajout seul de tout ce qui s’est produit : appels au modèle, tool calls, résultats, erreurs et approbations.

Le terme étant ambigu, distinguons trois portées appelées session. Un thread est la conversation d’un utilisateur sur plusieurs jours. C’est la plus longue durée des trois, et LangGraph le suit avec un thread_id.

Une model session est la plus courte : une séquence continue de contexte du modèle. La compaction — l’étape qui résume la fenêtre afin que le travail puisse continuer — prolonge une model session au lieu d’y mettre fin. Un redémarrage ou un nouveau départ explicite la termine. La partie 6 emploie « model session » dans ce sens.

Dans cet article, « session » désigne le journal durable d’une exécution. Elle se situe entre les deux autres notions : plusieurs model sessions écrivent dans un même journal, et un thread accumule plusieurs journaux. La récupération est wake(sessionId) → getSession(id) → resume from last event.

Dans LangGraph, la récupération utilise un thread_id ainsi qu’un checkpointer Postgres (voir LangGraph persistence). L’OpenAI Agents SDK fournit dix backends de session intégrés, notamment SQLiteSession, RedisSession, SQLAlchemySession, MongoDBSession et EncryptedSession (voir la documentation Sessions).

Harness. La boucle d’orchestration, et la seule primitive présentée ici qui prend des décisions. Elle assemble le prompt à partir de la mémoire, appelle le modèle, vérifie le tool call proposé au regard de ses règles de permissions, distribue l’appel autorisé, réécrit les résultats dans la session, applique les règles de retry et décide si la tâche est terminée. Chacune de ces étapes encode une hypothèse sur ce que le modèle ne peut pas faire seul. Anthropic le souligne directement — la citation figure dans la section consacrée aux modes de panne ci-dessous, qui traite principalement des conséquences de l’obsolescence de ces hypothèses.

L’équipe Codex d’OpenAI appelle cela harness engineering : écrire un logiciel demande toujours des efforts d’ingénierie, mais une part croissante de ces efforts est consacrée au scaffolding plutôt qu’au code lui-même. Le CompiledStateGraph de LangGraph, Deep Agents de LangChain et son point d’entrée create_deep_agent, ainsi que Claude Code, sont tous des harnesses au sens décrit ici.

Sandbox. L’environnement d’exécution isolé dans lequel les commandes s’exécutent réellement. La page sandbox concepts de l’OpenAI Agents SDK établit clairement la distinction :

« Le runtime externe reste responsable des approbations, du tracing, des handoffs et de la gestion de la reprise. La session de sandbox gère les commandes, les modifications de fichiers et l’isolation de l’environnement. »

Ici, « runtime externe » désigne le harness avec ses stores d’état. Dans le vocabulaire de cette série, les approbations et les handoffs sont des décisions du harness (partie 4 et partie 6) ; le tracing et la gestion de la reprise relèvent des primitives session et checkpoint.

Les sandboxes diffèrent par leur durée de vie et par ce qu’elles mémorisent entre deux exécutions. La forme la plus simple est la sandbox fresh ephemeral : en créer une pour une seule tâche, la détruire à la fin de la tâche et payer le coût de cold start à chaque exécution.

Les sandboxes persistent paused conservent le système de fichiers et un snapshot mémoire entre les exécutions. La reprise suivante peut ainsi éviter un démarrage complet. La variante snapshot or fork crée une branche à partir d’une image parent préparée en copy-on-write ; de nombreuses tâches peuvent partager les dépendances installées et les caches chauds sans partager leur état modifiable.

Les sandboxes per-worktree fournissent à chaque tâche son propre workspace et sa propre stack d’observabilité. Des logs, métriques et traces séparés permettent de déboguer une exécution sans que son état ne déborde sur une autre. Le tableau des fournisseurs plus loin compare le cold start et la persistance.

Checkpoint. Un état reprenable.

Le PostgresSaver de LangGraph écrit un Checkpoint à chaque frontière de super-step. Un super-step est un tour du graphe, constitué soit d’un nœud unique, soit d’un lot exécuté en parallèle. Les écritures par tâche sont envoyées à checkpoint_writes ; les sorties de nœuds réussis ne sont donc pas recalculées lorsqu’un nœud frère échoue.

Un checkpoint est un simple dict (v, id, ts, channel_values, channel_versions, versions_seen, updated_channels). LangGraph le sérialise avec son JsonPlusSerializer basé sur msgpack, et non avec JSON. datetime, set, Decimal et les dataclasses sont tous correctement restaurés après un aller-retour. Le format est documenté sur la page PyPI langgraph-checkpoint-postgres et dans la référence des checkpoints LangGraph.

StateSnapshot est la vue distincte et plus riche que graph.get_state() construit au-dessus d’un checkpoint. C’est l’objet dont le .values est ensuite exporté par le bundle de débogage.

Trace. La surface de replay et de débogage. Chaque appel au modèle, tool call et étape de sous-agent devient un span contenant les durées, les entrées, les sorties, le nombre de tokens et le coût. Lorsqu’une exécution de six heures échoue, c’est la trace que vous consultez pour comprendre ce qui s’est passé. La sortie du terminal a disparu depuis longtemps. Les conventions sémantiques GenAI d’OpenTelemetry normalisent les noms d’attributs — modèle, fournisseur, nombre de tokens, conversation et workflow. Pour une destination compatible OTLP prenant en charge ces conventions, la même instrumentation peut exporter la trace vers des systèmes tels que Tempo, Jaeger, Honeycomb ou LangSmith, même si des adapters de backend ou une configuration propre à la destination peuvent rester nécessaires.

Les policies et les secrets traversent les primitives

Deux frontières traversent les cinq primitives. Elles constituent la version runtime de l’argument de sécurité présenté dans la partie 4. La décision de permission elle-même appartient au harness ; la suite décrit où se trouvent physiquement les mécanismes qui l’appliquent et l’alimentent.

Enforcement des permissions

La matrice de permissions de la partie 4 doit être exécutée quelque part. Le contrôle est effectué avant chaque tool call et décide si celui-ci peut passer. Deux patterns sont courants en production. Deep Agents permet à chaque sous-agent de déclarer les chemins de fichiers qu’il peut lire ou écrire, puis le middleware bloque tout ce qui sort de cette déclaration. Anthropic Managed Agents fait passer chaque tool call par un proxy Model Context Protocol (MCP) ; le proxy applique donc les permissions à la place du code de l’agent. Lorsqu’un appel sensible nécessite une approbation humaine, le interrupt() de LangGraph et le hook d’approbation de Deep Agents mettent le graphe en pause jusqu’à la validation d’une personne.

Secret broker

Le modèle ne devrait pas voir les secrets de longue durée, et la sandbox ne devrait généralement pas les voir non plus. Le pattern Managed Agents est celui à reproduire :

« Pour Git, nous utilisons le token d’accès de chaque dépôt pour cloner le dépôt lors de l’initialisation de la sandbox et l’injectons dans le remote git local. Git push et pull fonctionnent depuis la sandbox sans que l’agent ne manipule jamais lui-même le token. Pour les outils personnalisés, nous prenons en charge MCP et stockons les tokens OAuth dans un coffre sécurisé. Claude appelle les outils MCP via un proxy dédié ; ce proxy reçoit un token associé à la session. … Le harness n’a jamais connaissance des credentials. »

Dans la stack de référence market-analyst-agent — un petit agent LangGraph qui récupère des données de marché et rédige un rapport d’analyste, construit au fil de cette série — le sidecar MCP détient les clés API du fournisseur de données et n’expose au worker LangGraph que la surface des outils. Dans le fichier compose local, les deux conteneurs lisent le même .env, ce qui constitue un raccourci de développement et non le pattern recommandé. En production, l’environnement du sidecar provient d’un secret store — Docker secrets ou HashiCorp Vault — que le worker ne peut pas lire. Le worker appelle ensuite l’outil sans jamais détenir le credential sous-jacent.

Vérifier le positionnement

Une vérification pratique consiste à lister chaque composant et la primitive qu’il implémente. Postgres peut couvrir la session et le checkpoint. Le conteneur worker est le harness. Un service tel que Daytona, Modal ou E2B fournit la sandbox, tandis que Tempo ou LangSmith stocke la trace.

Examinez ensuite les pannes couplées. Si deux primitives résident dans le même processus, un seul crash les emporte toutes les deux. Si elles partagent un credential, une fuite franchit les deux frontières. Exemples courants : un worker qui possède également la durabilité des traces, ou un token de sidecar qui permet aussi d’accéder à la base de données des checkpoints.


Modes de panne d’un runtime d’AI agent en production

Le runtime gère les retries, restaure le travail précédent, isole les workspaces et applique les budgets. À mesure que les exécutions s’étendent sur plusieurs workers et fenêtres de contexte, les pannes se déplacent vers l’état, les effets de bord dupliqués, la dérive des sandboxes et les dépassements de budget.

Les pannes se répartissent en quatre groupes :

  • Pannes de qualité de sortie : l’agent annonce que le travail est terminé alors qu’il ne l’est pas, oublie ce qu’il a fait après une réinitialisation de la fenêtre de contexte, ou se fie à sa propre auto-évaluation et livre une sortie défectueuse.
  • Pannes de contrôle des coûts : l’agent se retrouve bloqué dans une boucle de retry, ou consomme un budget de tokens ou de tool calls sans rien produire d’utile.
  • Pannes d’état et de crash : les workspaces dérivent parce qu’une exécution modifie des fichiers appartenant à une autre, les tool calls sont exécutés plusieurs fois parce que les retries les rejouent, ou le travail est perdu lorsqu’un worker meurt entre deux événements.
  • Pannes de fenêtre de contexte : le modèle résume puis s’arrête prématurément parce qu’il croit manquer de place, alors que la fenêtre dispose encore d’une marge suffisante.

Le tableau associe chaque panne à une mitigation, à la base de la recommandation et au hook du runtime qui l’applique. Le comportement peut varier selon le modèle : considérez donc les observations des fournisseurs comme des hypothèses à retester, et non comme des règles permanentes.

Modes de panne et mitigationsModes de panne et mitigations

Mode de panneMitigationNote sur les éléments disponiblesHook du runtime
Achèvement prématuré : l’agent annonce trop tôt que le travail est terminéSéparer générateur et évaluateur : un évaluateur en fresh context — une seconde model session sans historique de l’exécution — lit les fichiers, et non le chat, puis vote « terminé » ou « non terminé ». Échouer par défaut lors de chaque contrôle d’acceptation.Le cwc-long-running-agents de démarrage rapide d’Anthropic inclut un sous-agent évaluateur ; validez le pattern sur votre suite de tâches.Sous-agent sans outils Write/Edit et avec sa propre fenêtre de contexte
Amnésie des fonctionnalités entre fenêtres de contexteL’agent initializer écrit PROGRESS.md, feature-list.json et init.sh. L’agent de code les lit à chaque cold boot.Exigence de conception du harness ; mesurez le taux de réussite des tâches après cold boot avant et après l’ajout de ces artefacts.Hook de boot avant le premier appel au modèle de chaque session
Travail dupliqué après une réinitialisation de sessionJournal d’événements en ajout seul et fichier de handoff structuré. Chaque nouvelle session commence par pwd → read PROGRESS.md → review tests.Exigence de conception d’un journal durable et de checkpoints ; testez en rejouant le même handoff de session.Checkpoint PostgresSaver de LangGraph plus artefact PROGRESS.md
Anxiété liée au contexte : le modèle résume et s’arrête prématurémentLimiter la session active et reconstruire l’état depuis un handoff lorsque le modèle n’utilise plus efficacement le contexte restant. Le workaround de Cognition pour Sonnet 4.5 activait une fenêtre plus grande, mais limitait son utilisation effective à 200k.Les observations du fournisseur diffèrent entre Sonnet 4.5 et les générations suivantes. Retestez avant de transférer le workaround à un autre modèle ou harness.Le harness limite la longueur de la session, démarre la suivante et reprend depuis le checkpoint
Optimisme de l’auto-évaluation : le modèle considère son travail comme réussiÉvaluateur en fresh context et ancrage Playwright/MCP dans le DOM réel, et non dans des captures d’écran. La conception du harness frontend d’Anthropic pénalise les valeurs par défaut « de style AI ».Pattern frontend-harness d’Anthropic ; validez-le avec des tests d’acceptation au niveau de la tâche sur l’application rendue.L’évaluateur s’exécute dans une session de sandbox séparée, sans outils d’écriture
Boucles bloquées et tempêtes de retriesLimite d’itérations par tour, exponential backoff, circuit breaker sur le taux d’erreur des outils. Budget strict de tool calls.Exigence de contrôle du runtime ; injectez des erreurs répétées d’outils et vérifiez la limite, le backoff et le circuit breaker.Décorateur sur le nœud d’exécution des outils ; RetryPolicy sur les Temporal Activities (voir Temporal OpenAI Agents SDK contrib)
Dérive du workspace : l’agent modifie des fichiers sans rapportCommits Git comme checkpoints, middleware de permissions des fichiers, montage d’un workspace par session. Le middleware Deep Agents permet de déclarer les chemins en lecture/écriture.Exigence d’isolation ; exécutez des sessions concurrentes sur des fixtures et inspectez les modifications de fichiers entre exécutions.Middleware de permissions des fichiers LangGraph ou fork par tâche via Daytona/Runloop
Coût incontrôlé des tokens ou des outilsBudget de tokens par exécution, budget par outil, kill switch relié à un compteur Prometheus.Recommandation de contrôle des coûts ; l’analyse d’Addy Osmani sur les agents longue durée illustre le risque, mais la dépense réelle dépend des prix du modèle et des outils.Attributs de spans pour l’attribution des coûts plus règle Alertmanager
Tool calls non idempotentsClé d’idempotence par tool call. Dans les workflows durables, les retries peuvent déclencher plusieurs fois le même tool call ; une clé de déduplication bloque les doublons.Propriété des retries en at-least-once ; vérifiez-la en forçant le retry d’une Activity après la réussite de l’effet de bord.Temporal Activity avec start_to_close_timeout et clé d’idempotence
Travail perdu après un crash du processus ou de la sandboxJournal de session durable en dehors du processus ; checkpoint après chaque super-step. wake(sessionId) → getSession(id) → resume.Exigence de récupération ; arrêtez un worker entre deux événements et comparez l’état repris avec le journal durable.PostgresSaver à chaque super-step, ou encapsulation dans un Temporal Workflow

Deux idées sous-tendent la plupart de ces lignes. Anthropic, à propos de l’obsolescence des harnesses dans Harness design for long-running application development :

« Chaque composant d’un harness encode une hypothèse sur ce que le modèle ne peut pas faire seul, et ces hypothèses méritent d’être testées sous contrainte, à la fois parce qu’elles peuvent être incorrectes et parce qu’elles peuvent rapidement devenir obsolètes à mesure que les modèles progressent. »

Vercel, sur le problème connexe du trop grand nombre d’outils qui encodent trop d’hypothèses, dans We removed 80% of our agent’s tools :

« Nous en avons supprimé la majeure partie et réduit l’agent à un seul outil : exécuter des commandes bash arbitraires. Nous appelons cela un agent de système de fichiers. »

La citation décrit le cœur bash ; l’agent livré par Vercel conservait deux outils, ExecuteCommand et ExecuteSQL, contre quinze auparavant. La partie 3 couvre l’intégralité de l’avant/après. Leur résultat rapporté sur cinq requêtes représentatives : le taux de réussite est passé de 4/5 à 5/5, et le pire cas de 724 s / 100 étapes / 145 463 tokens (échec) à 141 s / 19 étapes / 67 483 tokens (réussite). C’est cette ligne du pire cas qui est spectaculaire ; sur les cinq requêtes, l’économie moyenne de tokens était de 37 %. La leçon n’est pas « supprimez vos outils ». Elle est que chaque primitive de votre runtime, y compris la surface des outils, a une durée de vie limitée. Retestez l’hypothèse lorsque le modèle change.

Cognition a observé la même cible mouvante concernant la longueur des sessions avec Sonnet 4.5. Dans Rebuilding Devin for Claude Sonnet 4.5, l’équipe décrit un modèle qui écrit proactivement SUMMARY.md / CHANGELOG.md lorsqu’il détecte l’épuisement du contexte, mais sous-estime le nombre de tokens restants. Leur correctif consistait à activer le contexte de 1M tokens et à limiter l’utilisation à 200k afin que le modèle conserve l’impression d’avoir de la marge. Il s’agissait d’un flag beta au moment de la rédaction.

En août 2026, la documentation actuelle d’Anthropic sur les fenêtres de contexte indique toujours 200k pour Sonnet 4.5. La fenêtre de 1M est fournie par défaut, sans en-tête beta, sur Opus 4.6 et les versions ultérieures, ainsi que sur Sonnet 4.6 et les versions ultérieures. C’est la limite qui mérite d’être surveillée. Elle n’existe que parce que Sonnet 4.5 évalue mal le contexte restant ; le jour où un modèle ne fera plus cette erreur, la limite cessera d’être un correctif et deviendra un plafond artificiel. Les générations de modèles ont changé plusieurs fois depuis la publication de Cognition ; revérifiez les chiffres dans la liste actuelle des modèles avant de reprendre ces choix.

L’équipe harness d’OpenAI en donne la version courte : « Les humains orientent. Les agents exécutent. » Lorsqu’un problème survient, la question utile est de savoir quelle capacité manque et comment rendre cette capacité à la fois lisible et applicable par l’agent.


Le cycle de vie d’une exécution saine

Une exécution bien conçue est ennuyeuse. Elle consiste en une chaîne de petites étapes récupérables, et chaque étape écrit son résultat dans un stockage durable avant le démarrage de la suivante.

C’est l’écriture de chaque résultat avant le démarrage de l’étape suivante qui limite les dégâts d’un crash. Une panne ne fait perdre que l’étape en cours ; le worker suivant reprend depuis la dernière étape terminée au lieu de redémarrer toute la requête.

Cycle de vie d’une exécution d’agent déployéeCycle de vie d’une exécution d’agent déployée

  1. Démarrer depuis une session nouvelle ou reprise. Lors d’une reprise, monter le workspace dans son dernier état connu, lire les fichiers de progression laissés par la tentative précédente (PROGRESS.md, feature-list.json) et charger le dernier checkpoint depuis la base de données. C’est à ce moment que le harness fournit à l’agent tout ce que le worker précédent avait en mémoire avant de mourir.
  2. Planifier avant de déclencher le moindre tool call. Écrire ce que signifie « terminé », combien l’exécution peut dépenser, quels outils l’agent peut appeler et quelles conditions doivent arrêter rapidement l’exécution. Ces valeurs de plan deviennent des contrôles du runtime ; sans elles, l’exécution n’a aucun mécanisme pour se limiter.
  3. Exécuter un tool call à la fois. Le contrôle de permissions du harness décide de l’autoriser ou non, puis le dispatch, capture le résultat et écrit un événement dans le journal de session. Une étape, un événement. Un crash entre deux événements est récupérable, car le journal — et non la mémoire du worker — constitue la source de vérité.
  4. Créer un checkpoint aux frontières des super-steps, ou après chaque événement dans un harness plus simple. Persister l’état du graphe, le diff du workspace et les références vers les artefacts produits. C’est ce checkpoint que lit l’étape 1 lors de la reprise suivante. Si le checkpoint est absent ou obsolète, la récupération se dégrade en rejeu de tout le journal de session depuis le début, ce qui est beaucoup plus lent.
  5. Évaluer les artefacts lorsque l’agent pense avoir terminé : tests, évaluateur en fresh context, validation de schéma, contrôles dans le navigateur. Si le contrôle réussit, l’exécution se termine avec succès. S’il échoue, l’exécution reprend depuis le dernier checkpoint propre, avec le message d’échec ajouté au contexte, puis réessaie.

Aucune étape de cette liste ne nécessite que l’agent se souvienne de quoi que ce soit entre deux exécutions. L’état réside dans la session et le checkpoint ; l’agent le relit à chaque reprise.

Tout outil ayant des effets de bord nécessite une clé d’idempotence dérivée de l’ID de session et de l’ID du tool call, stockée avant l’exécution de l’effet de bord. send_email(session_id, tool_call_id, message_hash). create_pr(session_id, tool_call_id, branch_name). charge_customer(session_id, tool_call_id, invoice_id). L’exécution en at-least-once est le comportement par défaut des queues et des moteurs de workflow ; le doublon se produira donc. Si un tool call peut causer un dommage réel lorsqu’il est répété et que vous ne pouvez pas le dédupliquer au moyen d’une clé, l’outil n’est pas prêt pour les agents.

L’évaluation doit inclure des éléments de preuve extérieurs au contexte producteur. Un évaluateur en fresh context réduit le biais lié au partage du contexte, tandis que les tests, les linters, les contrôles dans le navigateur et la validation de schéma fournissent des preuves déterministes. Le contrôle peut retourner pass, fail ou needs_human. Pour les agents de code, le reviewer peut être une autre model session avec des outils en lecture seule. Pour les agents de données et de rapports, combinez une validation déterministe avec un modèle reviewer lorsqu’un jugement reste nécessaire.


Onze patterns de déploiement d’AI agents et les critères de choix

Une fois les cinq primitives nommées, la question devient celle de la forme de déploiement qui les exécute. Par « forme », j’entends une organisation de ces primitives : où réside le harness, où l’état est persisté et quel type de sandbox exécute le travail. Une forme est une décision de câblage, pas un choix de fournisseur. Le graphique ci-dessous indique les plages de durée d’exécution pour lesquelles chaque forme est adaptée. Le texte qui suit explique les critères de choix.

Si vous ne lisez qu’une seule des onze formes, choisissez la forme 2 : queue + worker + base de données de checkpoints. C’est le choix par défaut que je recommande à la plupart des équipes, celui utilisé par le dépôt de référence et le squelette dont dérivent la plupart des autres formes : queue → état durable via worker, avec remplacement de la source de sandbox, du propriétaire du harness ou du moteur d’état. Lire d’abord la forme 2 permet de parcourir les autres plus rapidement.

Formes de déploiement et durées d’exécution idéalesFormes de déploiement et durées d’exécution idéales

Le graphique compare les formes selon la durée d’exécution. La matrice ci-dessous les compare selon la responsabilité : chaque cellule encadrée nomme le composant qui fournit la primitive correspondante.

Emplacement de chaque primitive selon la forme de déploiementEmplacement de chaque primitive selon la forme de déploiement

1. SDK dans un serveur d’application (synchrone, limité à la requête)

La forme originale. L’agent SDK s’exécute dans un handler de requête. Adaptée aux tâches de moins de 30 secondes, aux démos et aux outils internes. Mauvaise pour tout ce dont un client HTTP pourrait se déconnecter. Le timeout HTTP de Cloud Run est limité à 60 minutes, et toute panne du web tier tue l’exécution. Le SDK est le harness, le processus web joue également le rôle de sandbox, et l’état réside généralement dans la mémoire du processus sauf si vous le déportez explicitement. N’utilisez pas cette forme pour un travail de plusieurs heures.

2. Queue + worker + base de données de checkpoints

Le choix par défaut que je recommande à la plupart des équipes, et la forme de production utilisée dans market-analyst-agent : un worker Python avec un checkpointer PostgreSQL, Redis Streams (ou RabbitMQ) pour la queue entrante et un sidecar MCP pour les outils. Adaptée aux exécutions de 10 minutes à plusieurs heures avec des étapes idempotentes. Le runner local peut contourner la queue pour le développement synchrone, mais celle-ci fait partie de la forme de production dès que vous avez besoin de soumissions asynchrones et de backpressure.

L’application accepte une requête, crée une ligne de session, place un job dans la queue et renvoie un ID d’exécution. Le worker récupère le job, exécute le harness, écrit les checkpoints, diffuse le statut et stocke les artefacts au fil de l’eau. Postgres persiste, les workers sont remplaçables et la profondeur de la queue fournit la backpressure. Le calcul Spot/Preemptible fonctionne tant que le checkpointer termine l’écriture sur disque avant de signaler le succès.

Dans cette forme, le worker est le harness. Son conteneur et le workspace par thread fournissent une frontière d’exécution, mais le code non fiable nécessite toujours une sandbox renforcée ou une VM. Postgres possède l’état de session et de checkpoint. Les traces passent par OpenTelemetry vers la stack d’observabilité que vous exploitez.

3. Moteur de workflow durable (style Temporal)

Le code d’orchestration de l’agent s’exécute dans un Temporal Workflow ; les appels au modèle et les tool calls s’exécutent comme des Activities. L’état du workflow réside dans un journal d’historique d’événements sauvegardé par Cassandra, MySQL ou Postgres, et peut donc être rejoué proprement entre les déploiements. L’intégration Temporal × OpenAI Agents SDK, généralement disponible depuis mars 2026, fournit un OpenAIAgentsPlugin et un helper activity_as_tool ; l’article sur les agentic sandboxes décrit le fork d’un agent en cours vers un autre fournisseur de sandbox au milieu d’une conversation. Les workflows inactifs consomment zéro capacité de calcul. Les réserves sont réelles : les agents realtime ne sont pas pris en charge, le streaming est encore marqué comme expérimental, et LocalShellTool ainsi que ComputerTool sont désactivés car ils ne correspondent pas à un modèle distribué.

Utilisez cette forme lorsque l’exécution comporte de véritables points d’attente : approbations humaines, callbacks externes, longues périodes de sommeil, retries soumis à des règles métier ou fenêtres de déploiement. Une approbation humaine devient un sommeil durable ne consommant aucune capacité de calcul, et non une boucle de polling.

Le code du Workflow est le harness. La sandbox réside généralement en dehors de Temporal et est appelée depuis les Activities. L’état de session et de checkpoint se fond dans le journal d’historique d’événements de Temporal, tandis que la visibilité des traces provient de l’interface Temporal et des spans OpenTelemetry de chaque Activity.

4. Fournisseur de sandbox par session

Une forme plus récente. Chaque exécution d’agent reçoit sa propre microVM ou son propre conteneur via un fournisseur de sandbox-as-a-service. Le harness réside quelque part de durable ; la sandbox est l’environnement d’exécution jetable.

FournisseurIsolationSession maximaleConcurrencePersistanceCold start
E2BMicroVM Firecracker1 h Hobby / 24 h Pro20 / 100 (jusqu’à 1 100 avec add-on)Pause/reprise, pause ~4 s/GiB, reprise ~1 s (beta publique)~150 ms
Vercel SandboxMicroVM Firecracker45 min Hobby / 24 h Pro/Ent10 / 10 000Sandboxes ou snapshots persistants ; expiration 30 jours après la dernière utilisationnon publié
DaytonaDocker (Kata en option)auto-stop/archivage configurableselon le tierStop → Archive → Delete ; fork pris en charge~90 ms (27 ms selon certaines configurations)
Modal SandboxesgVisor5 min par défaut, 24 h maximumélevéeVolumes persistants ; snapshot mémoire en preview« environ une seconde » selon la documentation Modal
Runloop DevboxesmicroVM (hyperviseur personnalisé)suspend/resume ; snapshot+branch« plus de 30 000 instances simultanées » selon la fiche AWS MarketplaceSnapshot + branch depuis l’état disque< 1 s

Les cold starts indiqués ici correspondent au provisioning de bout en bout, et non au boot brut : les ~150 ms d’E2B s’ajoutent aux ~125 ms du boot Firecracker cités dans la partie 4 pour l’hyperviseur lui-même. Le tableau combine la comparaison E2B vs Daytona, la documentation des sandboxes Daytona et son changelog fork/snapshot, les guides Modal sur les sandboxes et le cold start, la fiche Runloop AWS Marketplace et la tarification Vercel Sandbox.

Daytona enregistre un lien parent-enfant pour chaque fork indépendant, ce qui préserve la lignée des sandboxes dérivées. Le harness Codex d’OpenAI utilise la variante per-worktree : « Codex travaille sur une version entièrement isolée de l’application, y compris ses logs et ses métriques, qui sont supprimés lorsque la tâche est terminée. »

Choisissez cette forme lorsque l’agent exécute du code non fiable, automatise un navigateur, lance des tests ou installe des packages. Le compromis est un coût et un couplage au fournisseur plus élevés que pour des workers partagés.

Le fournisseur ne possède que la sandbox. Le harness, la session, le checkpoint et la trace restent de votre côté, généralement câblés selon la forme queue + worker de la section 2.

5. Anthropic Managed Agents (harness hébergé)

Anthropic a lancé Managed Agents en beta publique le 8 avril 2026, derrière l’en-tête beta managed-agents-2026-04-01. Le service fournit une session hébergée, un harness, une sandbox et un proxy MCP adossé à un vault. wake(sessionId) peut initialiser le harness sur un nouveau worker sans perdre l’état durable de la session.

Anthropic facture Managed Agents au tarif standard des tokens, auquel s’ajoutent $0.08 par heure-session. La facturation est faite à la milliseconde et ne s’applique que lorsque le statut de la session est « running » ; le temps d’inactivité est gratuit. Une boucle de retries incontrôlée ajoute donc un coût horaire de session au coût des tokens.

Lisez les réserves. La remise de la Batch API ne s’applique pas (« Les sessions sont stateful et interactives. Il n’existe pas de mode batch. »). Managed Agents n’est pas disponible via AWS Bedrock ou Google Vertex AI. Dans la beta, les tunnels MCP et le « dreaming » des agents nécessitent un accès supplémentaire en research preview ; la coordination multi-agent et l’auto-évaluation notée par rubric font partie de la documentation de la beta. Le lock-in est élevé : vous échangez la liberté sur le harness contre le fait de ne pas gérer vous-même la boucle.

Anthropic héberge les cinq primitives : session, harness, sandbox, checkpoint et trace. Vous déléguez le runtime et récupérez les sorties.

6. LangChain Deep Agents Deploy (harness ouvert géré)

deepagents deploy encapsule un deepagents.toml dans un LangSmith Deployment avec exécution durable, mémoire, multi-tenancy, human-in-the-loop, observabilité, exécution de code en sandbox et exécutions planifiées. Les modes de déploiement cloud, hybride et self-hosted sont pris en charge. Les fournisseurs de sandbox (LangSmith Sandboxes, Daytona, Modal, Runloop ou un fournisseur personnalisé) peuvent être changés via une seule valeur de configuration. L’état réside dans un système de fichiers virtuel avec des backends enfichables ; la mémoire est limitée à l’utilisateur, à l’assistant ou aux deux. Le lock-in est inférieur à celui de Managed Agents : le harness est sous licence MIT, les instructions utilisent le standard ouvert AGENTS.md, et les agents sont exposés via MCP, le protocole A2A (Agent2Agent) et Agent Protocol. Voir l’article de LangChain sur le runtime-behind-production-deep-agents.

Par défaut, les cinq primitives sont hébergées, mais chacune peut être remplacée par configuration. La sandbox est derrière une seule valeur de configuration. La session et le checkpoint résident dans un système de fichiers virtuel avec des backends enfichables. La trace est envoyée à LangSmith.

7. Service ou job Google Cloud Run

Cloud Run propose deux modes d’exécution distincts, et le mode adapté dépend de la manière dont l’agent est invoqué. Les services sont liés à HTTP et passent à zéro entre les requêtes ; le harness s’exécute comme un handler de requête qui retourne lorsque l’exécution est terminée. Les jobs s’exécutent jusqu’à leur terme sans point d’entrée HTTP ; le harness fonctionne comme un worker ponctuel qui se termine lorsque la tâche est achevée. Les deux peuvent héberger le harness, mais aucun ne conserve l’état entre les exécutions. Les sessions et les checkpoints doivent résider dans Postgres, Spanner ou un store externe similaire.

Les limites sont très différentes selon le mode. Timeout des requêtes Cloud Run service : 300 s par défaut, 3 600 s (60 min) maximum. Les WebSockets ont le même timeout. Cloud Run jobs : 10 min par tâche par défaut, 168 h (7 jours) maximum ; pour les tâches utilisant des GPUs, maximum 1 heure. Les services passent à zéro sauf si vous activez le CPU toujours disponible ; les jobs n’utilisent pas HTTP et ne s’autoscalent pas.

Utilisez un service pour les exécutions synchrones allant jusqu’à 60 minutes. Utilisez un job pour un travail ponctuel ou asynchrone plus long. Les Cloud Run Jobs peuvent maintenir une tâche pendant plusieurs jours, mais ils ne fournissent pas de replay durable entre les déploiements, les changements de version ou le remplacement d’un worker. Au-delà de 7 jours, n’utilisez pas Cloud Run.

Cloud Run héberge le harness. L’état de session et de checkpoint réside dans Postgres, Spanner ou un autre store externe, et les traces peuvent passer par Cloud Logging et OpenTelemetry. Le conteneur du service constitue un environnement d’exécution ; ajoutez une sandbox distincte si l’agent exécute du code non fiable.

8. AWS Lambda (pourquoi c’est le mauvais outil)

Le timeout maximal d’une fonction Lambda est de 900 s (15 minutes), sans exception. Si API Gateway est placé devant la fonction, la limite d’intégration dépend du type d’API. Les HTTP APIs autorisent 30 secondes ; les intégrations REST ont par défaut 29 secondes, tandis que les API REST régionales et privées peuvent configurer un timeout plus long. Aucun de ces chemins ne transforme Lambda en worker de plusieurs heures. Un harness longue durée nécessite toujours un état externe et des réinvocations, ce qui recrée la forme queue + worker. Utilisez Lambda pour des tool calls bornés, comme récupérer des fichiers ou envoyer des uploads S3, invoqués par un orchestrateur longue durée. N’y placez pas l’orchestrateur.

Au mieux, Lambda exécute un tool call dans sa limite de 15 minutes. Le harness, la session, le checkpoint, la sandbox et la trace doivent résider ailleurs.

9. Tâche AWS ECS / Fargate par exécution

Fargate ne documente aucune limite stricte sur la durée d’une tâche, contrairement à Lambda. Les quotas de throttling Fargate autorisent un burst de lancement de 100 tâches et un réapprovisionnement de 20 par seconde, avec des budgets distincts pour l’on-demand et le Spot. Les quotas de service ECS limitent à 1 000 tâches par service les services utilisant la découverte AWS Cloud Map, et à 5 000 instances de conteneurs les clusters adossés à EC2.

Fargate impose le mode awsvpc ; chaque tâche reçoit donc une interface réseau et une IP privée. Cette forme convient à l’accès à des données internes au VPC. Fargate Spot ajoute un risque d’interruption, et la durabilité reste à votre charge car la plateforme ne fournit pas de replay comparable à Temporal.

Fargate héberge le harness et attribue une tâche à chaque exécution. Cela sépare les workspaces et les credentials des tâches, mais ne constitue pas à lui seul une sandbox complète pour du code hostile. La session, le checkpoint et la trace sont envoyés vers des services externes tels que RDS ou DynamoDB, ainsi que CloudWatch/X-Ray.

10. Job Kubernetes ou namespace par session

Adapté si vous exploitez déjà Kubernetes et souhaitez une sandbox par session avec des contrôles à l’échelle du cluster. Mauvais choix si vous avez besoin d’un démarrage en moins d’une seconde, car le téléchargement de l’image du conteneur et l’initialisation du pod sont trop longs lors d’un cold start. Le pattern consiste à créer un Job par exécution d’agent, avec activeDeadlineSeconds, un PersistentVolumeClaim pour le workspace et un sidecar pour le serveur MCP. La récupération après crash doit être construite par vos soins. Adopter Kubernetes uniquement pour héberger des agents entraîne une forte surcharge de configuration et d’exploitation. Cela n’est intéressant que si vous exécutez déjà K8s pour d’autres raisons.

Kubernetes héberge le harness et l’environnement d’exécution de chaque exécution, généralement sous la forme d’un Job et parfois d’un namespace dédié. Une isolation forte dépend toujours de la runtime class, des network policies, de la sécurité des pods et de la frontière sous-jacente entre conteneur et VM. La session et le checkpoint résident dans une base de données externe ou sur un PersistentVolumeClaim.

11. Docker Compose local (développement uniquement)

La référence pour la section suivante. L’intérêt de cette forme est de reproduire la topologie de production un pour un — mêmes primitives, même forme de réseau — tout en fonctionnant sur une seule machine. Ce qu’elle ne reproduit pas, c’est l’isolation : un montage de workspace partagé, un seul Postgres, aucune sandbox renforcée et aucune séparation des domaines de panne entre le worker et son état. Ne mettez rien en production sous cette forme.

Compose reproduit la forme n° 2 sur un seul hôte. Postgres contient l’état de session et de checkpoint, et le conteneur worker est le harness. Le montage de workspace partagé est pratique en développement, mais n’isole pas les exécutions non fiables. La stack OpenTelemetry optionnelle enregistre les traces.


Stack de référence : Docker Compose

La topologie de référence, utilisée dans slavadubrov/market-analyst-agent, se compose d’un worker LangGraph, d’un checkpointer Postgres, de Qdrant pour la recherche, d’un sidecar MCP, d’une queue Redis pour des exécutions asynchrones proches de la production et d’une stack d’observabilité optionnelle Prometheus / Grafana / Loki / Tempo / OTel. Dans le compose local, Redis est optionnel uniquement parce que le runner synchrone peut appeler directement le worker. docker compose up démarre localement la topologie principale ; le sidecar MCP et la stack d’observabilité sont des profils optionnels (--profile mcp, --profile observability).

Topologie Docker Compose de référenceTopologie Docker Compose de référence

Le seul élément qui mérite d’être présenté inline est le câblage LangGraph canonique. Il s’agit d’un extrait illustratif, et non d’un exemple exécutable tel quel depuis le dépôt. Son exécution nécessite langgraph, langgraph-checkpoint-postgres et psycopg[binary,pool], une base PostgreSQL accessible avec les permissions nécessaires pour créer les tables du checkpointer, POSTGRES_PASSWORD, ainsi qu’un StateGraph préalablement construit dans builder ; voir la configuration du checkpointer Postgres de LangGraph.

import os
from urllib.parse import quote

from langgraph.checkpoint.postgres import PostgresSaver

password = quote(os.environ["POSTGRES_PASSWORD"], safe="")
DB_URI = f"postgresql://agent:{password}@postgres:5432/agent"
# `builder` is your StateGraph, already built
session_id = "session-123"
with PostgresSaver.from_conn_string(DB_URI) as checkpointer:
    checkpointer.setup()  # creates tables on first run
    graph = builder.compile(checkpointer=checkpointer)
    result = graph.invoke(
        {"messages": [{"role": "user", "content": "Continue the task"}]},
        {"configurable": {"thread_id": session_id}},
    )

Une observabilité qui survit à l’exécution

Les handlers de requêtes courts sont faciles à déboguer : lorsqu’un problème survient, on lit la réponse et le log en direct. Les agents longue durée n’offrent pas ce luxe. Lorsqu’une exécution de six heures échoue, l’événement intéressant s’est produit cinq heures auparavant, la sortie du terminal a disparu et le worker qui l’a produite a été remplacé. Personne ne va reconstituer l’exécution de mémoire. Le débogage doit donc s’appuyer sur des artefacts durables écrits pendant que l’exécution était encore active.

Les stacks de production couvrent généralement quatre types d’artefacts, répartis en deux groupes. Deux se consultent après la fin de l’exécution, pour les postmortems et le replay : un journal d’événements interrogeable de chaque étape et des traces OpenTelemetry indiquant où sont passés le temps et les tokens. Deux autres se consultent pendant l’exécution. Le premier est un flux en direct de ce que l’agent produit dans le workspace. Le second est une stack d’observabilité par worktree que l’agent peut interroger lui-même pendant son travail.

Journal d’événements structuré (à lire après l’exécution)

Chaque appel au modèle, tool call, résultat, erreur et approbation est écrit dans un stockage durable, indexé par ID de session et timestamp. Une fois l’exécution terminée, vous l’interrogez comme une table de base de données classique. Addy Osmani fixe clairement le niveau attendu dans Long-running Agents : « Si vous ne pouvez pas reconstituer depuis un stockage durable ce que l’agent a fait au cours des dernières 24 heures, vous avez un long script shell qui appelle par hasard un LLM, et non un agent longue durée. »

Traces OpenTelemetry GenAI (à lire après l’exécution)

Les mêmes données détaillées étape par étape sont émises sous forme de spans utilisant les attributs standard des gen_ai.* semantic conventions : nom du modèle, fournisseur, nombre de tokens d’entrée et de sortie, ID de conversation et nom du workflow. Ces conventions sont encore au niveau de stabilité Development.

En 2026, elles ont quitté le dépôt principal des conventions sémantiques OpenTelemetry pour rejoindre leur propre dépôt de conventions sémantiques GenAI. Les noms d’attributs peuvent être utilisés pour instrumenter le code, mais épinglez la révision que vous avez validée plutôt qu’un numéro de version du dépôt principal. Les champs spécifiques aux fournisseurs résident dans les sous-namespaces (anthropic.*, openai.*) indexés par gen_ai.provider.name. L’intérêt du standard est sa portabilité : sur des destinations compatibles OTLP qui prennent en charge ces conventions, changer de backend peut ne pas nécessiter de réinstrumenter le code, même si des adapters de backend ou une configuration propre à la destination peuvent rester nécessaires.

Chronologie des tool calls et diffs du workspace (à lire pendant l’exécution)

Le moyen le plus rapide de savoir ce que fait actuellement un agent est de suivre ce qu’il produit dans le workspace, et non de rechercher dans un journal de session. Le quick-start Harness Primitives for Long-Running Claude Agents d’Anthropic fournit une boucle de surveillance à deux panneaux : watch -n 5 'git log --oneline -8' affiche les derniers commits effectués par l’agent, et watch -n 5 'find screenshots -name "*.png" | tail -5' affiche les dernières captures d’écran prises. Deux panneaux de terminal actualisés toutes les cinq secondes suffisent pour déterminer si l’exécution progresse réellement ou tourne en boucle.

Stack éphémère par worktree (lue par l’agent lui-même pendant l’exécution)

Selon l’article d’OpenAI sur le harness : « Les logs, métriques et traces sont exposés à Codex via une stack locale d’observabilité, éphémère pour chaque worktree. » Chaque worktree d’agent reçoit ses propres Loki, Prometheus et Tempo de courte durée, limités à cette seule exécution. L’agent les interroge pendant son travail. C’est ce qui permet à un prompt tel que « aucun span de ces quatre parcours utilisateur ne dépasse deux secondes » de devenir une contrainte que l’agent peut vérifier directement, plutôt qu’une propriété qu’il doit deviner.

(L’évaluateur en fresh context du tableau des modes de panne lit ces artefacts pour décider si le travail est « terminé ». Il relève de l’évaluation, et non de l’observabilité ; voir § cycle de vie d’une exécution saine. Il dépend de toutes les surfaces ci-dessus.)

Une stack d’observabilité self-hosted minimale

Pour quelque chose comme market-analyst-agent :

  1. OpenTelemetry Collector avec le GenAI Normalizer Processor (contrib, alpha) pour les attributs GenAI pris en charge. Utilisez les processors génériques Attributes ou Transform pour filtrer ou réécrire les champs gen_ai.*.
  2. Tempo (ou Jaeger) pour les traces, indexées par gen_ai.conversation.id / thread_id.
  3. Loki pour les entrées du journal d’événements structurés.
  4. Prometheus pour gen_ai.client.token.usage, gen_ai.client.operation.duration et gen_ai.client.operation.time_to_first_chunk — les métriques gen_ai.server.* proviennent du serveur de modèles ; vous ne les obtenez donc que si vous hébergez les weights (voir les conventions de métriques GenAI).
  5. Grafana pour les dashboards indexés par gen_ai.agent.name et gen_ai.request.model.

Alternatives hébergées (choisissez-en une, pas trois) :

  • LangSmith : intégration LangGraph native ; également la cible de déploiement de Deep Agents Deploy.
  • Braintrust : meilleur choix si la priorité est donnée aux suites de régression centrées sur l’évaluation.
  • Arize Phoenix : OSS, natif OTLP (le protocole filaire OpenTelemetry), associé à l’instrumentation OpenInference.
  • Dashboard de tracing d’OpenAI : automatique lorsque vous utilisez l’OpenAI Agents SDK ou son intégration Temporal.
  • Tracing Claude d’Anthropic : pour les sessions exécutées dans Managed Agents.

Instrumenter le nœud LangGraph

Cet extrait est illustratif et ignoré par le runner d’exemples du dépôt. Il suppose que le nœud LangGraph dispose déjà d’un span OpenTelemetry actif, du thread_id courant et d’un objet de réponse du fournisseur usage contenant input_tokens et output_tokens ; la configuration du tracer, l’export et le mapping de l’usage propre au fournisseur sortent du périmètre de l’extrait.

# In the LangGraph node, around the model call:
span.set_attribute("gen_ai.operation.name", "chat")
span.set_attribute("gen_ai.provider.name", "anthropic")
span.set_attribute("gen_ai.request.model", "<your-model-id>")
span.set_attribute("gen_ai.response.model", "<your-model-id>")
span.set_attribute("gen_ai.conversation.id", thread_id)
span.set_attribute("gen_ai.agent.name", "market-analyst")
span.set_attribute("gen_ai.workflow.name", "research_then_write")
span.set_attribute("gen_ai.usage.input_tokens", usage.input_tokens)
span.set_attribute("gen_ai.usage.output_tokens", usage.output_tokens)

Les noms d’attributs sont repris tels quels du registre des conventions sémantiques GenAI d’OpenTelemetry.

Trois requêtes à afficher sur un dashboard

# Loki: token usage per agent over 1h
sum by (gen_ai_agent_name) (
    rate({service_name="market-analyst-agent"} | json | unwrap gen_ai_usage_output_tokens [1h])
)
# PromQL: p95 model latency per model
histogram_quantile(0.95,
    sum by (le, gen_ai_request_model) (
        rate(gen_ai_client_operation_duration_bucket[5m])
    )
)
# TraceQL: long-running tool calls
{ span.gen_ai.operation.name = "execute_tool" && duration > 30s }

Pattern du bundle de débogage

Lorsqu’une exécution échoue, le worker doit déposer /workspaces/${THREAD_ID}/_debug/ contenant les artefacts que vous demanderiez lors d’un postmortem :

  • session.jsonl : dump complet du journal d’événements du PostgresSaver (checkpointer.list({"configurable": {"thread_id": ...}})).
  • last_state.json : StateSnapshot.values depuis le dernier super-step réussi.
  • trace.json : spans exportés via OTLP pour l’exécution.
  • tool_calls.csv : (ts, tool, input_hash, latency_ms, status, error).
  • workspace.tar.zst : répertoire du workspace et git diff par rapport au commit initializer.
  • screenshots/*.png : ce que l’agent a vu.
  • PROGRESS.md, feature-list.json et tout autre fichier de progression rédigé par l’agent.
  • env.txt : tags d’image, version du modèle, SHA du commit du harness.

Ce bundle fournit à un humain ou à un agent reviewer suffisamment d’éléments pour reconstituer la panne. « L’agent est resté bloqué » est vague. Un rapport illustratif est concret : la session s_123 a dépensé 71 % de ses tokens à répéter trois commandes après l’échec de npm install.


Choisir la bonne forme : guide de décision

La plupart des comparaisons précédentes se résument à quelques décisions.

Commencer par la durée d’exécution

Utilisez la durée d’exécution comme premier filtre :

  • Moins de 30 secondes, idempotent : SDK limité au cycle de vie de la requête dans un serveur d’application.
  • De 30 s à 60 min : queue + worker + base de données de checkpoints.
  • De 60 min à 24 h : même queue + worker, ou Cloud Run Job pour un travail ponctuel. Utilisez un moteur de workflow durable si vous avez également besoin de versioning et de replay.
  • Plus de 24 h, avec survie aux déploiements : moteur de workflow durable (style Temporal). Les Cloud Run Jobs peuvent maintenir un travail long jusqu’à leur limite de tâche, mais ne fournissent pas de sémantique de replay.
  • Boucles d’entraînement de reinforcement learning sur plusieurs jours : K8s Job + volume + Temporal.

Après ce filtre grossier, examinez les effets de bord, la récupération, le replay, l’isolation, l’emplacement des données et l’équipe qui exploitera le système.

Adéquation de la plateforme selon le cas d’usage

Adéquation de la plateforme selon le cas d’usageAdéquation de la plateforme selon le cas d’usage

La matrice est dense, et aucune cellule verte ne suffit à déterminer l’architecture ; ce sont généralement les cellules jaunes, dans lesquelles une plateforme ne prend en charge une capacité qu’avec une réserve, qui tranchent. Une couverture étendue des workloads est utile, mais elle ne montre ni la résidence des données, ni les sémantiques de replay, ni la dépendance au fournisseur, ni la maturité opérationnelle, ni le coût du déplacement ultérieur de l’état.

Deep Agents Deploy est la seule colonne de la matrice sans cellule rouge ou jaune : les exécutions synchrones courtes, les traitements batch de plusieurs heures, le fork de sandboxes, les workloads GPU et le lock-in minimal sont tous au vert. C’est donc un candidat lorsqu’une seule plateforme doit couvrir tous vos workloads. Cette largeur fonctionnelle s’accompagne toutefois d’un historique de production plus court qu’une stack queue + worker + Postgres. Considérez les cellules vertes comme des déclarations de capacité à valider, puis comparez les contraintes opérationnelles que la matrice ne peut pas représenter.

Anthropic Managed Agents convient entièrement à votre workload ou pas du tout. Le produit présente deux contraintes strictes : il est uniquement hébergé et uniquement compatible avec Claude. Si votre workload satisfait ces deux conditions — Claude est déjà le modèle souhaité et vous préférez ne pas exploiter vous-même un harness — Managed Agents est un très bon choix. Un agent de code interne exécuté par rafales de deux à six heures correspond particulièrement bien à cette forme, qui retire une grande partie du travail de plateforme à votre équipe. Si l’une des deux contraintes échoue parce que vous avez besoin d’un modèle non-Claude ou d’une conformité self-hosted, Managed Agents ne convient pas. Aucune configuration ne changera cela.

La tarification doit être modélisée avant de vous engager, et non après. La ligne horaire de session est 0.08/hourontopofstandardtokencosts.Ifasinglesessionrancontinuously,thatisabout0.08/hour on top of standard token costs. If a single session ran continuously, that is about 58/mois par session. Avec 100 sessions exécutées en continu, cela représente environ 5,800/monthbeforetokens.Multiply5,800/month _before tokens_. Multiply 0.08 par vos heures-session concurrentes prévues ; ajoutez ce montant à votre facture de tokens et comparez-le au coût d’une stack queue + worker sur votre propre infrastructure. Quitter Managed Agents plus tard constitue un exercice de replatforming, et non un simple changement de configuration.

Harness hébergé ou harness géré par vos soins

La distinction porte ici sur l’opérateur du harness, et non sur l’auteur de son code. Hébergé signifie que le fournisseur exécute la boucle du harness dans son infrastructure et que vous appelez une API. Géré par vos soins signifie que vous exécutez la boucle dans votre propre infrastructure, même si le code du harness provient d’un fournisseur.

LangChain apparaît des deux côtés de cette frontière, ce qui prête à confusion. L’entreprise fournit LangGraph, une bibliothèque sous licence MIT que vous hébergez vous-même (géré par vos soins), et Deep Agents Deploy, un produit géré qui exécute un harness Deep Agents sur LangSmith Deployment dans son mode cloud par défaut (hébergé). Même entreprise, deux modèles opérationnels différents. Ce que vous choisissez, c’est l’opérateur de la boucle, et non le logo figurant sur la bibliothèque. (Deep Agents Deploy propose également un mode self-hosted pour les équipes qui veulent l’ergonomie du harness sans le composant cloud ; ce mode relève de la catégorie gérée par vos soins.)

Choisissez un harness hébergé lorsque son support des modèles, sa frontière de données, son comportement de récupération et ses points d’extension correspondent déjà à vos besoins. Choisissez un harness géré par vos soins lorsque vous prévoyez que ces contraintes évolueront. La migration entre les deux modifie l’état, l’observabilité et les frontières d’exécution ; testez donc le chemin de sortie avant que des données de production n’en dépendent.

Sandbox hébergée ou environnement d’exécution géré par vos soins

Choisissez une sandbox hébergée lorsque l’isolation, les sémantiques de pause/reprise ou de fork du fournisseur correspondent au threat model et au budget de démarrage. Docker ou Fargate peuvent convenir à des workloads internes de confiance nécessitant un accès au VPC ou une stricte résidence des données, mais un conteneur standard ne constitue pas une frontière suffisante pour du code hostile. La partie 4 détaille les options d’isolation dans ce cas.

Stores d’état : Git, base de données et object storage côte à côte

Les agents longue durée utilisent généralement trois stores d’état simultanément, car chacun gère un artefact différent.

Git stocke l’état du workspace : le code, les documents et les fichiers de progression modifiés par l’agent. Chaque commit fournit au harness un point de récupération stable et à la session suivante un historique compact.

La base de données de checkpoints stocke l’état du graphe : ce qui a été décidé, les nœuds exécutés, les résultats retournés et ce qui doit être exécuté ensuite. L’artifact store contient les grandes sorties finales telles que les PDF, les fichiers Parquet et les captures d’écran. Ces artefacts n’ont pas leur place dans Git ou dans la base de données des checkpoints.

Quand utiliser git comme état

Utilisez git lorsque le workload est de nature code — modifications multi-fichiers, refactorings, génération d’application — ou suffisamment documentaire pour que l’historique des fichiers soit important. Le pattern est simple : créer une branche d’exécution, faire un commit initializer, puis committer aux frontières significatives : après la configuration, après chaque fonctionnalité, après la réussite des tests et après le nettoyage final. Stockez le dernier SHA du commit du workspace à côté de la ligne de checkpoint. Lors d’une reprise, le worker suivant extrait la branche, lit git log --oneline -8, inspecte git status et le dernier diff, puis lit PROGRESS.md ou le fichier de handoff écrit par la session précédente.

Git devient ainsi une surface de récupération pour l’artefact en cours d’édition, et non un remplacement de la base de données de checkpoints. Git peut répondre à deux questions : qu’est-ce qui a changé et quelle version a passé les tests ? Il ne peut pas indiquer au harness quel nœud du graphe exécuter ensuite, quel tool call attend une approbation ou quel retry a déjà utilisé sa clé d’idempotence. Le harness d’Anthropic utilise des commits initializer et des commits par fonctionnalité comme source de vérité pour la récupération du workspace ; le modèle lit git log --oneline -8 pour restaurer l’état. Ignorez Git lorsque le produit est une réponse conversationnelle unique. Le coût de cette structure ne serait pas rentabilisé.

Quand utiliser le checkpointing en base de données

Utilisez un checkpointing de type PostgresSaver lorsque l’agent possède une structure de graphe composée de plusieurs nœuds dont l’état intermédiaire importe (planner → researcher → writer → verifier). Le dépôt de référence l’utilise précisément pour cette raison. Ne placez pas des artefacts de workspace de plusieurs téraoctets dans le checkpoint ; utilisez l’object storage.

Quand utiliser un artifact store (S3 / GCS)

Utilisez l’object storage lorsque :

  • la sortie est trop volumineuse pour être transportée par la base de données de checkpoints ;
  • les consommateurs en aval ont besoin d’un artefact adressable par URL sans passer par l’agent ; ou
  • le livrable et l’état d’exécution ont des durées de rétention différentes.

Vous pouvez, par exemple, supprimer le journal de session après 30 jours tout en conservant le rapport final pendant plusieurs années. Structurez le stockage selon (thread_id, checkpoint_id, artifact_name) afin que l’exécution productrice reste reconstituable.

Quand ajouter des gates d’approbation humaine

Ajoutez des gates lorsque le tool call est destructif et irréversible — écritures en base, mouvements d’argent, envoi de communications externes —, lorsqu’il sort du blast radius de l’agent — déploiements en production, publications destinées aux clients — ou lorsque les régulateurs imposent une revue. Le interrupt() de LangGraph et le middleware d’approbation de Deep Agents prennent tous deux ces gates en charge nativement. La partie 4 expliquait pourquoi ces gates relèvent des permissions et non du prompt.


Checklist pratique de mise en production

Avant de mettre en production un agent longue durée, répondez à ces questions en termes d’infrastructure concrets.

  1. Quel store possède les événements de session et les checkpoints ?
  2. Que se passe-t-il si le worker meurt au milieu d’un tool call ?
  3. Une exécution peut-elle corrompre le workspace d’une autre ?
  4. Quelles actions nécessitent une approbation ?
  5. Le modèle ou la sandbox peuvent-ils lire les credentials bruts ?
  6. Quels tool calls peuvent être retentés sans risque ?
  7. Où le plafond de coût par exécution est-il appliqué ?
  8. Quel évaluateur en fresh context décide que le travail est « terminé » ?
  9. Où les sorties finales résident-elles après la disparition de la sandbox ?
  10. Pourrons-nous expliquer demain une exécution échouée sans la relancer ?

Si la réponse à l’une de ces questions est « le prompt demande à l’agent de faire attention », le système n’est pas encore déployé. Ce n’est toujours qu’une démo.

La prochaine couche est la boucle du harness

Ce runtime peut maintenir une exécution active et récupérable, mais la durabilité ne prouve pas que le travail est correct. La partie 6, Harness Engineering for AI Agents, ouvre la primitive harness du tableau ci-dessus : comment une trace permet de distinguer plusieurs types de panne, où résident les règles de retry et d’arrêt, ce qu’un handoff doit préserver et comment un contrôle d’acceptation externe décide qu’une exécution est terminée. C’est également le dernier article de la série.

Références

Articles d’ingénierie

LangGraph et Deep Agents

OpenAI Agents SDK

Temporal

Plateforme Anthropic

Fournisseurs de sandbox

Timeouts et quotas des plateformes cloud

Observabilité


Le code du Market Analyst Agent — worker LangGraph, checkpointer Postgres, mémoire Qdrant, sidecar MCP et topologie Docker Compose décrite ci-dessus — est disponible sur GitHub.