EN

D1 — Architecture et orchestration des agents (27 %)

Le domaine le plus lourd de l'examen : sept task statements, 27 % de la note. Une section par task statement, dans l'ordre du guide et sous le libellé du guide — pour qu'une question repérée le jour J renvoie ici sans traduction.

Table des matières
  1. 1.1 — Design and implement agentic loops for autonomous task execution
  2. 1.2 — Orchestrate multi-agent systems with coordinator-subagent patterns
  3. 1.3 — Configure subagent invocation, context passing, and spawning
  4. 1.4 — Implement multi-step workflows with enforcement and handoff patterns
  5. 1.5 — Apply Agent SDK hooks for tool call interception and data normalization
  6. 1.6 — Design task decomposition strategies for complex workflows
  7. 1.7 — Manage session state, resumption, and forking
Ce que ce cours possède, ce qu’il renvoie ailleurs

D0 est supposé acquis. Ce cours commence là où D0 s'arrête : D0 a nommé stop_reason et dit ce que vaut chaque valeur ; D1 transforme cette vérification en boucle, puis en système d'agents autour d'elle.

Le guide place les notions voisines ailleurs, et ce cours le respecte. tool_choice et les JSON Schemas sont testés en TS 2.3 et TS 4.3 ; les réponses d'erreur structurées en TS 2.2 et TS 5.3 ; les fichiers .claude/agents/ et la commande /agents relèvent de la configuration Claude Code, testée au domaine 3. Chacune reçoit ici une phrase et un renvoi, jamais un second développement.

1. 1.1 — Design and implement agentic loops for autonomous task execution

Un seul appel à la Messages API produit une réponse. Une vraie tâche — retrouver le client, consulter la commande, décider d'un remboursement — demande plusieurs actions, chacune choisie à la lumière de ce que la précédente a retourné. L'agentic loop est ce mécanisme : requête, réponse, exécution d'outil, nouvelle requête, jusqu'à ce que le modèle signale qu'il a terminé.

Le cycle, en cinq étapes :

  1. Vous envoyez une requête avec l'historique de conversation et le paramètre tools.
  2. Claude répond. La réponse peut porter du texte, un ou plusieurs blocs tool_use, ou les deux.
  3. Votre code exécute chaque outil demandé et collecte les résultats.
  4. Vous ajoutez à l'historique la réponse de l'assistant et les blocs tool_result.
  5. Vous renvoyez tout l'historique. On recommence jusqu'à ce que stop_reason soit terminal.

stop_reason est le champ de la réponse qui dit pourquoi la génération s'est arrêtée ; l'ensemble de ses valeurs est catalogué en D0. Deux seulement pilotent cette boucle :

stop_reason Ce que fait votre code
"tool_use" Exécuter les outils demandés, ajouter leurs résultats, itérer
"end_turn" Le modèle n'a plus rien à demander — sortir de la boucle
while True:
    response = client.messages.create(
        model="claude-sonnet-5",
        messages=messages,
        tools=tools,
    )
    # Toute la réponse repart : blocs de texte et blocs tool_use ensemble.
    messages.append({"role": "assistant", "content": response.content})

    if response.stop_reason != "tool_use":
        break                      # terminal — D0 catalogue les autres valeurs

    tool_results = execute_tools(response.content)
    messages.append({"role": "user", "content": tool_results})

Deux lignes portent tout le task statement. Le break s'appuie sur stop_reason, sur rien d'autre. Et le second append est ce qui fait de l'itération suivante une étape de raisonnement plutôt qu'une répétition : les résultats d'outils entrent dans l'historique de conversation, donc le prochain choix d'outil se fait à la lumière de ce que le dernier a retourné. Une boucle qui exécute les outils sans jamais ajouter leurs résultats repose éternellement la même question.

Plusieurs appels dans une même réponse

Une même réponse peut aussi porter plusieurs blocs tool_use, par exemple deux recherches que le modèle veut mener ensemble. Exécutez-les toutes, puis renvoyez chaque tool_result dans un seul message user, un bloc par appel. C'est le mécanisme par lequel un coordinateur lance plusieurs subagents à la fois, développé en 1.3.

La boucle est model-driven : Claude lit le contexte accumulé et décide quel outil vient ensuite. C'est ce qui sépare un agent d'un workflow. Un pre-configured decision tree — votre code fixant à l'avance la séquence read_schema → plan_changes → apply_migration — est de l'ingénierie légitime, mais il ne traitera jamais que les cas prévus par qui l'a écrit. Le guide teste votre capacité à distinguer les deux et à choisir selon la prévisibilité de la tâche.

Le guide nomme trois mauvaises façons de piloter la boucle, et ce sont les distracteurs de ce task statement :

Les plafonds sont des garde-fous, pas des conditions d'arrêt

Les plafonds ont leur place, tant qu'ils restent des plafonds. L'Agent SDK expose max_turns / maxTurns (allers-retours agentiques) et max_budget_usd / maxBudgetUsd (dépense) ; les deux sont sans limite par défaut, et poser un budget est un bon défaut de production sur un prompt ouvert. Ni l'un ni l'autre n'est une condition de terminaison, et le SDK marque une exécution qui en a atteint un comme un subtype d'erreur, pas comme un succès.

Dès qu'une question demande comment décider si la boucle continue ou s'arrête, la réponse est stop_reason, et précisément "tool_use" contre "end_turn". Toute alternative plausible dans la liste d'options — parsing de texte, plafond d'itérations, test de présence d'un bloc de texte — est l'un des trois anti-patterns ci-dessus, déguisé.

Teste-toi sur cette section

Q4 Who decides the next tool call

Scenario: A migration agent needs to run read_schema, then plan_changes, then apply_migration for each table. To keep the process predictable, the orchestrator pre-computes this exact call sequence before the first request and feeds each tool result into the next hardcoded step, never letting the model's own response decide what happens next. When a table turns out to need an extra validation step the sequence doesn't account for, the agent has no way to trigger it.

Question: What should change about how the loop is driven?

A) Keep the fixed sequence, but add a fourth hardcoded step for validation, since the gap that appeared today is now a known case.

B) Let the model choose the next action each turn from the latest tool_result, and stop when it stops requesting tools.

C) Run all three tools on every turn regardless of need, so the missing step is always covered and no table can slip through, accepting the wasted work as the price of completeness.

D) Keep the fixed sequence, but let the orchestrator retry a failed step before moving to the next one.


Answer: hand control back to the model, turn by turn

Why: a sequence fixed in advance by the orchestrator is a hardcoded decision tree — it can only be as flexible as whoever wrote it anticipated. An agentic loop is model-driven: the model reads each tool result and decides the next action itself, the loop continues for as long as it keeps requesting tools, and it ends when the model signals it is done. That is what lets it insert a step nobody hardcoded.

Why the others are wrong:

  • Fixes this one gap but leaves the orchestrator guessing every future case in advance — the same limitation returns with the next table that needs something different.
  • Running every tool regardless of need does not add judgment, it just hides the missing decision behind unconditional execution — and the completeness it buys is an illusion, since it still only covers steps that were written down.
  • A retry addresses a step failing, not a step nobody planned for.

Toutes les questions de la banque sur 1.1

2. 1.2 — Orchestrate multi-agent systems with coordinator-subagent patterns

Déléguer à un subagent est une décision qui vient avant toute architecture. Un subagent tourne dans sa propre fenêtre de contexte, fait son travail et ne renvoie qu'un résumé ; les lectures, recherches et appels d'outils intermédiaires sont jetés avec lui. Ce compromis tient en une question : le travail intermédiaire intéresse-t-il l'appelant ? Si seule la réponse compte, déléguez. S'il faut voir et réagir à chaque étape, gardez la main dans le thread principal.

La forme hub-and-spoke

Quand une tâche est vraiment trop large pour un seul agent — un rapport de recherche qui demande recherche web, analyse documentaire et synthèse — on obtient une architecture hub-and-spoke : un coordinateur (le hub) pilote plusieurs subagents spécialisés (les spokes), et tout le trafic passe par le hub.

              Coordinateur (hub)
             /        |         \
   subagent recherche  analyse    synthèse
        (web)        (documents)  (rapport)

   chaque résultat, chaque erreur, chaque retry
   passe hub ↔ spoke — jamais spoke ↔ spoke

Rien dans le SDK n'impose cette forme. C'est un choix de conception, et le guide en nomme les trois motifs : l'observabilité (un seul endroit voit toute l'exécution), la cohérence du traitement d'erreur (une politique, pas une par agent) et le contrôle du flux d'information (le hub décide de ce que chaque spoke apprend).

Ce dont le coordinateur a la charge

Le travail du coordinateur, tel que le guide l'énonce :

Responsabilité Ce que cela veut dire en pratique
Task decomposition Découper la demande en sous-tâches qui, ensemble, la couvrent
Délégation dynamique Choisir les subagents dont une requête donnée a réellement besoin, plutôt que de router chaque requête à travers tout le pipeline
Agrégation des résultats Collecter les sorties des spokes et assembler la réponse
Gestion d'erreur Décider de réessayer, d'adapter la requête, ou de continuer avec des résultats partiels

Deux savoir-faire sur lesquels portent les questions

Deux compétences méritent d'être énoncées à part, parce que ce sont elles que les questions de scénario mettent en jeu.

Partitionner le périmètre avant de déléguer. Donnez à chaque subagent de recherche un sous-thème distinct ou un type de source distinct. Des briefs qui se recouvrent produisent du travail dupliqué et, pire, des angles morts corrélés.

Raffiner par itération. Le coordinateur lit la sortie de synthèse, y cherche les manques, re-délègue aux subagents de recherche et d'analyse avec des requêtes ciblées, et relance la synthèse jusqu'à couverture suffisante. C'est une boucle de qualité posée au-dessus de la boucle d'exécution de 1.1, et c'est le remède que le guide nomme contre une couverture incomplète.

Les subagents démarrent d'un contexte isolé : ils n'héritent pas de l'historique de conversation du coordinateur et ne partagent aucune mémoire d'une invocation à l'autre. Tout ce dont un spoke a besoin voyage dans le prompt que le hub écrit pour lui, et la mécanique de ce passage est en TS 1.3, ci-dessous.

Une décomposition trop étroite

Le risque que le guide nomme explicitement est une décomposition trop étroite par le coordinateur, et il se voit dans le rapport plutôt que dans les journaux. Un coordinateur à qui l'on demande un panorama de l'IA générative dans les industries créatives assigne « l'IA dans l'art visuel », « l'IA dans la génération d'images », « l'IA en photographie ». Chaque subagent exécute correctement sa consigne. Le rapport ne couvre que l'art visuel ; la musique, la littérature et le cinéma sont simplement absents. Rien n'a échoué en aval. L'assignation était déjà incomplète.

Quand chaque subagent a fait ce qu'on lui demandait et que le rapport final rate encore des pans entiers du sujet, le défaut est la décomposition du coordinateur, pas un spoke. Les distracteurs incrimineront un composant réel — requêtes de recherche trop étroites, absence de détection de lacunes dans la synthèse, critères de pertinence trop stricts dans l'analyse — et ils séduisent parce qu'ils nomment quelque chose qui existe. L'énoncé vous a déjà dit que chaque agent avait correctement exécuté son assignation. Ce qui a été mal fait, c'est l'assignation.

Laisser un subagent passer sa sortie directement à un autre pour économiser un saut. Cela paraît efficace et cela casse les trois raisons d'être du hub : plus aucun endroit ne voit l'exécution entière, le traitement d'erreur cesse d'être uniforme, et personne ne contrôle ce que le second agent a réellement reçu.

Router chaque requête à travers tout le pipeline est l'erreur symétrique : le coordinateur est censé analyser la requête et n'invoquer que les subagents nécessaires.

Les erreurs passent aussi par le hub

Les erreurs voyagent de la même façon. Le pattern attendu est la récupération locale d'abord : le subagent traite lui-même les échecs transitoires et ne propage au coordinateur que ce qu'il ne peut pas résoudre, accompagné de ses résultats partiels et de ce qu'il a déjà tenté. Le coordinateur continue avec des résultats partiels et annote la sortie finale de ce qui est resté non couvert. La forme de ces réponses d'erreur — catégories, caractère réessayable, échec métier contre échec de permission — relève de la conception des erreurs structurées, développée en D2.2.

Teste-toi sur cette section

Q2 Forty pages about one of five areas

Scenario: A coordinator was asked for a pre-launch risk brief on a payments feature. The request names five areas to cover: regulatory exposure, fraud, support load, vendor dependencies, data residency. It mentions chargebacks once, as an example under fraud. Six workers ran over two rounds and each returned a well-formed section; the brief that came back is forty pages, all of them about chargebacks. The coordinator's plan is still in the log, and it opens by restating the job as chargeback exposure.

Question: Which change keeps this from recurring?

A) Gate the delivery step: hold the brief back until every area named in the request has a section of its own, and send the job round again whenever one of them is missing.

B) Split the work into five independent runs, one per area, and have the requester stitch the five briefs together afterwards.

C) Have the coordinator derive one assignment per area named in the request, before it delegates.

D) Raise the worker count so each round covers more ground.


Answer: derive the assignments from the areas the request names, ahead of any delegation

Why: the plan in the log names the defect — a five-part request became a one-part job before any worker started. Coverage that was never assigned cannot be recovered by anything downstream, so the fix has to sit ahead of the delegation.

Why the others are wrong:

  • The gate proves the brief incomplete only once six workers have been paid for, and it hands the job back to the same planning step that read five areas as one — so the next round can return just as narrow.
  • Guarantees the coverage by removing the coordinator from the job. Whatever sits across two areas is lost, and the requester now does the merging on every request.
  • Capacity was never the constraint. Six workers already produced forty pages; more of them widen nothing while every assignment points at the same area.

Toutes les questions de la banque sur 1.2

3. 1.3 — Configure subagent invocation, context passing, and spawning

Le mécanisme de lancement est un outil : un coordinateur lance un subagent en appelant l'outil Task, et son allowedTools doit inclure "Task" pour que ces invocations soient auto-approuvées. Omettez-le et l'appel retombe dans le flux de permission : en mode par défaut, sans callback canUseTool pour y répondre, il est refusé. Le coordinateur ne délègue pas, quoi que dise son prompt.

Les versions récentes du SDK ont renommé cet outil de Task en Agent, et le code actuel émet Agent dans les blocs tool_use. Le guide d'examen v1.0 dit encore Task, et pose l'inclusion de "Task" dans allowedTools comme l'exigence. À l'examen, Task est la réponse attendue. En vrai code, écrivez Agent et testez les deux noms quand vous détectez une invocation.

Ce qui franchit la frontière, et ce qui ne la franchit pas

Ce qu'un subagent reçoit, et ce qu'il ne reçoit pas, est le fait le plus testé de ce domaine :

Le subagent reçoit Le subagent ne reçoit pas
Son propre system prompt, issu de sa définition d'agent L'historique de conversation du parent et ses résultats d'outils
La chaîne de prompt de l'appel qui le lance Le system prompt du parent
Ses définitions d'outils — héritées, ou le sous-ensemble qu'on lui a donné Le moindre souvenir d'une invocation précédente de lui-même

La conséquence est décisive : le seul contenu qui passe du parent au subagent est la chaîne de prompt de l'appel qui le lance. Si les chemins de fichiers, les messages d'erreur, les résultats de recherche antérieurs ou les décisions déjà prises ne sont pas dans cette chaîne, le subagent ne les a pas.

Mauvais  Task: « Analyse le document. »
         → quel document ? aucun résultat antérieur, aucun format de sortie attendu.

Bon      Task: « Analyse le document ci-dessous et renvoie le tableau des clauses.
              DOCUMENT (source: vendor-contract-2026.pdf, pages 4-9) :
                <texte intégral>
              RÉSULTATS ANTÉRIEURS (du subagent de recherche) :
                - claim: 'net-45 payment terms'
                  source_url: https://…  retrieved: 2026-08-14
              FORMAT DE SORTIE : une ligne par clause — clause_type, text, page. »

Notez ce que la bonne version fait au-delà d'être longue. Elle emploie un format structuré qui sépare le contenu des métadonnées. URL source, nom du document, numéro de page et date de collecte vivent dans leurs propres champs, pas fondus dans la prose. C'est ce qui préserve l'attribution jusqu'au rapport final, et le guide le nomme parmi les compétences de ce task statement.

Rien n'est hérité : la chaîne du prompt est tout le canal. Un subagent qui renvoie une réponse maigre ou à côté a été mal briefé, pas sous-doté. Cela trie les options d'un seul geste : agrandir sa fenêtre de contexte, lui passer le transcript du parent, ou le laisser lire le travail d'un autre subagent traitent tous l'isolation comme un défaut à contourner, alors qu'elle est le mécanisme lui-même. Tout ce dont le subagent a besoin entre dans le prompt de lancement.

Parallélisme : une réponse, plusieurs appels

Le parallélisme vient d'une réponse, plusieurs appels. Un coordinateur qui émet trois appels Task dans une seule réponse obtient trois subagents qui tournent en même temps ; les mêmes trois appels répartis sur trois tours consécutifs s'exécutent l'un après l'autre. C'est le même mécanisme que les appels d'outils parallèles de 1.1 — plusieurs blocs tool_use dans un même message assistant — appliqué à l'outil Task.

agents = {
    "code-reviewer": AgentDefinition(
        description="Spécialiste de la revue de code. À utiliser pour la "
                    "qualité, la sécurité et la maintenabilité. Indique à "
                    "l'agent précisément quels fichiers relire.",
        prompt="Tu es un spécialiste de la revue de code…\n"
               "Rends : 1. Résumé  2. Problèmes critiques  3. Problèmes majeurs  "
               "4. Problèmes mineurs  5. Verdict  6. Obstacles rencontrés",
        tools=["Read", "Grep", "Glob"],
        model="sonnet",
    ),
}

Les quatre champs d'une définition de subagent

Quatre champs, quatre décisions :

Champ Obligatoire Ce qu'il décide
description oui Quand le coordinateur lance ce subagent — et ce qu'il écrit dans le prompt de délégation
prompt oui Le system prompt du subagent : son rôle, sa méthode, son format de sortie
tools non Les outils qu'il peut utiliser ; omis, il hérite de tout ce qui est disponible aux subagents
model non opus, sonnet, haiku, inherit, ou un identifiant de modèle complet

La description a ce double rôle, et il est facile de le manquer. Le nom et la description de chaque subagent disponible sont placés dans le system prompt de l'agent principal : ils décident donc quand la délégation a lieu ; l'agent principal se sert ensuite de la description comme guide pour rédiger le prompt d'entrée, si bien qu'elle façonne aussi ce qu'on dit au subagent de faire. Une description qui dit « vous devez indiquer à l'agent précisément quels fichiers relire » produit des prompts de délégation qui listent des fichiers. Une description vague produit des délégations vagues.

Deux autres leviers de conception. Le premier vient du cours Subagents ; le second est la quatrième compétence que le guide liste sous ce task statement :

Restreindre les outils d'un subagent

Les restrictions d'outils relèvent aussi d'ici, puisque le guide les liste parmi les connaissances de ce task statement. Un subagent de recherche en lecture seule reçoit Read, Grep, Glob ; un relecteur y ajoute Bash pour lancer git diff ; seul un agent dont le métier est de modifier du code reçoit Edit et Write. Un outil que vous laissez de côté n'est pas du tout dans la session du subagent : ni prompt de permission, ni erreur, l'agent travaille simplement sans. Pourquoi une grande surface d'outils dégrade la fiabilité de sélection, et comment répartir les outils entre agents, relève de la distribution des outils, développée en D2.3.

Trois gestes qui ressemblent à des correctifs et n'en sont pas :

Forker une session pour donner à deux subagents une base d'analyse commune relève de la gestion des sessions, développée en 1.7 ci-dessous. Définir des subagents comme fichiers markdown sous .claude/agents/, et la commande /agents qui les crée, relève de la configuration Claude Code, développée au domaine 3.

Teste-toi sur cette section

Q7 Delegating a contract review (Select the 2 correct answers.)

Scenario: A coordinator has a clause-extraction subagent read two vendor contracts while a pricing subagent prepares a quote, and both outputs must land in one report.

Question: Which two moves are correct?

A) Put the contract text, the clause types wanted, and the output schema into the delegation prompt itself.

B) Emit both delegations in one coordinator response so the subagents run at the same time.

C) Count on each subagent inheriting the coordinator's conversation history.

D) Let the clause subagent hand its output straight to the pricing subagent, saving a hop.

E) Give both subagents the coordinator's whole tool set so neither is ever blocked.


Answers: carry the needed context in the delegation prompt, and issue both delegations in one response

Why: a subagent starts from an isolated context, so whatever it needs — source text, target clause types, output shape — travels in the prompt. Parallelism comes from several delegations inside one coordinator response; spread over consecutive turns they just run one after another.

Why the others are wrong:

  • Nothing is inherited: an isolated context is the defining property of a subagent.
  • Every exchange goes through the hub, which keeps the run observable and error handling uniform.
  • A wider tool set degrades selection reliability; each spoke gets only the tools its role needs.

Toutes les questions de la banque sur 1.3

4. 1.4 — Implement multi-step workflows with enforcement and handoff patterns

Certains ordonnancements dans un workflow doivent tenir à chaque fois qu'il s'exécute : vérifier l'identité du client avant de traiter un remboursement ; contrôler les interactions médicamenteuses avant de délivrer. Vous pouvez l'écrire dans le system prompt, et une instruction de prompt est une demande que le modèle honore généralement. La formulation du guide est nette : quand une conformité déterministe est requise, les instructions de prompt seules ont un taux d'échec non nul. Sur des milliers d'interactions, ce reliquat, ce sont des remboursements versés au mauvais client.

Le gate de prérequis

Le programmatic enforcement referme cet écart en rendant la violation impossible par le code plutôt qu'improbable par la prose. Sa forme concrète est un prerequisite gate : un appel d'outil en aval est bloqué tant qu'une étape amont n'a pas retourné.

async def require_verified_customer(input_data, tool_use_id, context):
    if input_data["tool_name"] != "process_refund":
        return {}
    if not session_state.get("verified_customer_id"):
        return {"hookSpecificOutput": {
            "hookEventName": "PreToolUse",
            "permissionDecision": "deny",
            "permissionDecisionReason":
                "Appelez d'abord get_customer : process_refund exige un ID "
                "client vérifié pour cette session.",
        }}
    return {}

process_refund ne peut pas s'exécuter tant que get_customer n'a pas retourné un identifiant vérifié. Pas « a peu de chances de » — ne peut pas. La chaîne de raison compte autant que le blocage : le modèle la lit, donc il réessaie la bonne chose au lieu de réessayer à l'aveugle. L'API des hooks elle-même — événements, matchers, champs de décision — est en TS 1.5, ci-dessous.

La conformité déterministe est une propriété du code, pas de la formulation. Les mauvaises réponses sont ici le plus souvent de vraies améliorations : une consigne plus ferme, des exemples few-shot montrant le bon ordre, un audit qui rattrape les violations après coup. Les deux premières abaissent le taux d'échec et laissent un reste ; la troisième signale la brèche après l'action qu'elle devait empêcher. Quand le scénario nomme une conséquence financière, légale ou de sécurité, seul un mécanisme qui rend la violation impossible satisfait l'exigence.

La demande à plusieurs objets

Un second pattern de ce task statement est la demande multi-sujets. Un client écrit : « Je veux un remboursement sur la commande #1234 et l'adresse de livraison a changé sur la commande #5678. » Traiter cela séquentiellement et répondre en deux blocs déconnectés est l'échec. Le geste attendu : décomposer en items distincts, investiguer chacun en parallèle sur le contexte client partagé, puis synthétiser une résolution unifiée.

Le handoff structuré

Le troisième est le structured handoff. Quand l'agent escalade en cours de traitement, l'humain qui reprend n'a pas accès au transcript de la conversation. Le résumé doit donc se tenir seul :

{
  "customer_id": "CUST-12345",
  "order_id": "ORD-67890",
  "issue_summary": "Demande de remboursement pour article endommagé",
  "root_cause": "Article arrivé endommagé ; photos jointes",
  "actions_taken": [
    "Identité vérifiée via get_customer",
    "Commande confirmée via lookup_order",
    "Remplacement proposé — le client insiste pour un remboursement"
  ],
  "refund_amount": "$89.99",
  "recommended_action": "Approuver le remboursement intégral",
  "escalation_reason": "Le client a demandé à parler à un responsable"
}

Identité du client, cause racine, montant, action recommandée : les quatre que le guide nomme. Un handoff qui suppose que l'humain lira la conversation est un handoff raté.

Les distracteurs des questions d'enforcement sont les mesures qui font réellement baisser le taux d'échec sans jamais atteindre zéro :

Les trois premiers font baisser le taux ; la question demandait une garantie, et un audit trouve la violation une fois l'argent parti. Le quatrième traite les outils disponibles, pas l'ordre dans lequel ils sont appelés, ce qui est un autre problème.

La règle à emporter : conséquences financières, légales ou de sécurité → programmatic enforcement. Préférences, ton et mise en forme → instructions de prompt. Si l'énoncé contient le mot « garantie », ou décrit une action irréversible, aucune dose de prompt engineering n'est la réponse.

Quand escalader — les critères, le respect d'une préférence explicite du client, la détection d'un trou dans la politique — relève de la décision d'escalade, développée en D5.2.

Teste-toi sur cette section

Q1 A dose released before the interaction check

Scenario: A pharmacy agent fills prescription requests through MCP tools (check_interactions, dispense, page_pharmacist). Reviewers pulled last month's transcripts and found doses released to patients whose interaction check never ran: in those requests the agent took the allergy list pasted into the ticket at face value and went straight to dispense.

Question: Which change makes the skipped check impossible?

A) Have the agent write out the sequence it intends to follow before its first call, so a skipped step shows up in the transcript.

B) Cache interaction results per patient so the check costs almost nothing and the agent has no reason to route around it.

C) Refuse dispense in code until check_interactions has returned for that patient.

D) Add a hook that rejects malformed prescription identifiers before the outgoing call leaves the agent.


Answer: refuse the downstream call in code until the upstream check has returned

Why: an ordering that guards a patient-safety boundary needs a guarantee, not a tendency. A prerequisite evaluated in code cannot be argued out of by a convincing-looking allergy list sitting in the ticket.

Why the others are wrong:

  • A stated plan is still the model's own output, nothing holds it to what it wrote, and the transcript gets read after the dose is out.
  • Cost was never the obstacle — the agent skipped a step it believed it already had the answer to.
  • Enforces a property of the arguments, not the fact that anything ran first. A well-formed identifier says nothing about the check.

Toutes les questions de la banque sur 1.4

5. 1.5 — Apply Agent SDK hooks for tool call interception and data normalization

Un hook est une fonction de rappel à vous que le SDK exécute quand un événement de l'agent se déclenche. Elle tourne dans le process de votre application, pas dans la fenêtre de contexte de l'agent — elle ne coûte donc aucun token, et c'est du code ordinaire avec des garanties ordinaires.

Deux événements portent ce task statement :

Événement Se déclenche Peut-il encore changer l'issue ?
PreToolUse Un appel d'outil est demandé, avant qu'il ne s'exécute Oui — autoriser, refuser, ou réécrire l'entrée
PostToolUse L'outil a retourné, avant que le modèle ne lise le résultat L'appel a déjà eu lieu ; vous pouvez remplacer ce que le modèle lit

PreToolUse — rendre une action impossible

PreToolUse est le primitif d'application de règles. Son callback retourne un hookSpecificOutput portant permissionDecision ("allow", "deny", "ask", "defer"), un permissionDecisionReason que le modèle lit, et éventuellement updatedInput pour réécrire l'appel plutôt que le refuser.

async def cap_refunds(input_data, tool_use_id, context):
    if input_data["tool_name"] != "process_refund":
        return {}
    if input_data["tool_input"].get("amount", 0) > 500:
        return {"hookSpecificOutput": {
            "hookEventName": "PreToolUse",
            "permissionDecision": "deny",
            "permissionDecisionReason":
                "Un remboursement au-dessus de 500 $ exige un validateur "
                "humain. Appelez escalate_to_human avec le résumé du dossier.",
        }}
    return {}

Le blocage est la moitié du travail ; la raison redirige l'agent vers le workflow alternatif au lieu de le laisser deviner. Quand plusieurs hooks et règles de permission divergent, le SDK tranche par priorité — deny l'emporte sur defer, qui l'emporte sur ask, qui l'emporte sur allow — donc un seul deny suffit.

PostToolUse — changer ce que le modèle lit

PostToolUse est le primitif de normalisation. Son champ updatedToolOutput remplace la sortie de l'outil avant que Claude ne la voie ; additionalContext la complète sans la remplacer.

async def normalize_dates(input_data, tool_use_id, context):
    if input_data["tool_name"] not in ORDER_TOOLS:
        return {}
    raw = json.loads(input_data["tool_response"]["content"])
    return {"hookSpecificOutput": {
        "hookEventName": "PostToolUse",
        "updatedToolOutput": json.dumps({
            **raw,
            "shipped_at": to_iso8601(raw["shipped_at"]),   # 1743800400 → "2025-04-04"
            "status": STATUS_NAMES[raw["status"]],          # 2 → "shipped"
        }),
    }}

C'est le cas du guide, littéralement : plusieurs outils MCP renvoient des dates en timestamps Unix, d'autres en ISO 8601, des statuts en codes numériques. Les faire correspondre est une table fixe, pas un jugement — cela relève donc d'un code qui tourne sur chaque résultat, pas d'un prompt qui demande au modèle de composer avec trois formats.

Le choix entre un hook et une instruction de prompt est le même qu'en 1.4, un niveau plus bas :

Hook Instruction de prompt
Garantie Déterministe — c'est du code qui s'exécute Probabiliste — aucune garantie
À utiliser pour Règles métier, plafonds financiers et réglementaires Préférences, ton, mise en forme
Exemple Bloquer les remboursements au-dessus de 500 $ « Essaie de résoudre le problème avant d'escalader »

Recourir à PostToolUse pour empêcher quelque chose. Il se déclenche après l'exécution de l'outil, quand le remboursement est déjà versé et les lignes déjà supprimées. Bloquer, c'est PreToolUse.

L'erreur miroir est un blocage PreToolUse employé pour corriger un problème de lecture. Si un outil renvoie un champ surchargé que le modèle interprète mal, bloquer l'appel en aval supprime aussi les appels corrects ; le correctif est de réécrire le résultat au retour, pour que l'ambiguïté n'atteigne jamais le modèle.

Deux questions séparent proprement les deux hooks. Faut-il que quelque chose n'arrive pas ? → PreToolUse. Faut-il que le modèle lise autre chose que ce que l'outil a retourné ? → PostToolUse. Les distracteurs placeront le bon mécanisme au mauvais endroit de la boucle.

Les hooks de Claude Code au niveau configuration, déclarés dans les settings plutôt que dans du code SDK, sont développés au domaine 3.

Teste-toi sur cette section

Q6 Five hundred rows, and then a signature

Scenario: A retention agent trims expired records through purge_records. Policy lets it delete up to 500 rows in one call; a larger purge needs a data steward's sign-off. The rule is written in the system prompt, and last week a single call removed 40,000 rows from an audit table.

Question: What makes the ceiling hold?

A) Give the agent a request_signoff tool, with a description telling it when a purge has grown too large to run alone.

B) A hook that blocks the outgoing call when the row count passes the ceiling.

C) State the ceiling in the tool's own description, so the limit travels with the tool wherever it is used.

D) Have the agent announce the row count it is about to delete before it issues the call.


Answer: intercept the outgoing call and stop it above the ceiling

Why: a ceiling that must hold every time belongs in code that sees the actual argument. The hook runs before the tool does, so an oversized purge never reaches the database, and a deletion is not something an apology can undo.

Why the others are wrong:

  • Offers a way out that the agent still has to choose, and the incident was precisely a case where it did not.
  • Moves the rule closer to the call site without changing its nature: it stays text the model reads, not a condition anything evaluates.
  • An announcement is a claim about an intent, made by the same run that is about to ignore it.
Q8 One integer, three meanings

Scenario: A storefront agent checks availability through check_stock before it confirms an order through place_order. The available field carries three meanings in one integer: a positive number is units on hand, -1 marks an item the supplier ships on request, and 0 marks a SKU the warehouse does not track. The agent treats anything that is not positive as sold out, and it has spent a month declining orders that could have been filled.

Question: Where does the fix belong?

A) Ask the inventory team to retire the overloaded integer and publish an explicit status field, since one number carrying three meanings will mislead every consumer of that API and not only this agent.

B) A PreToolUse hook on place_order that blocks the confirmation whenever the availability figure behind it was not positive.

C) Log every non-positive figure and review the pattern each week.

D) A hook that rewrites the figure into an explicit state before the model reads the result.


Answer: map the integer onto an explicit state in a hook, before the model reads the result

Why: the three readings are a fixed table, so applying them is a transformation and not a judgment call. A PostToolUse hook runs it on every result on the way back, which is the last moment at which the ambiguous integer can be kept out of what the model reads.

Why the others are wrong:

  • The right thing to fix and the wrong thing to wait for: the field belongs to another team, every existing consumer has to move with it, and orders keep being declined until that lands.
  • Hardens the misreading rather than removing it. The confirmations it would block are precisely the ones that should go through, and the agent is still reading the same integer.
  • Counts the symptom every week and changes nothing about what the model reads. The mapping is already known, which is what makes measurement the wrong instrument.

Toutes les questions de la banque sur 1.5

6. 1.6 — Design task decomposition strategies for complex workflows

Toutes les tâches ne se découpent pas de la même façon, et se tromper de régime coûte soit de la rigidité, soit du chaos. Il y en a deux.

Pipeline séquentiel fixe — prompt chaining. Chaque étape est décidée à l'avance et s'exécute dans l'ordre. À utiliser quand la structure de la tâche est prévisible, que toutes les étapes sont connues et que vous voulez des résultats stables et comparables d'une exécution à l'autre.

Décomposition dynamique adaptative. Les sous-tâches émergent de ce que l'étape précédente a trouvé. À utiliser pour l'investigation ouverte, quand le périmètre est inconnu au départ.

Le critère est la prévisibilité, pas la taille. Une pull request de douze fichiers a un ensemble de cibles connu et énumérable : pipeline fixe. Un bug d'un seul fichier dont on ignore l'origine, non.

Les deux exemples du guide

L'exemple de prompt chaining du guide lui-même est la revue de code multi-aspects. Une passe unique sur un gros diff produit une sortie inégale : commentaires détaillés sur certains fichiers, superficiels sur d'autres, et contradictions entre eux. Découpez :

Passe 1 — par fichier, une analyse ciblée chacun
          → bugs locaux, problèmes de qualité, vulnérabilités
Passe 2 — une passe d'intégration inter-fichiers sur les résultats de la passe 1
          → types incohérents, dépendances circulaires, flux de données cassés

Découper ainsi est ce qui évite la dilution de l'attention sur une grosse revue.

L'exemple de décomposition adaptative du guide est « ajouter une couverture de tests complète à un codebase legacy ». Vous ne pouvez pas lister les sous-tâches d'avance, parce qu'elles sont précisément ce que vous allez découvrir :

1. Cartographier la structure         (Glob, Grep)
2. Découverte : 3 modules sans tests, 2 partiellement couverts
3. Prioriser par impact               → le module de paiements d'abord (risque élevé)
4. Surprise : une dépendance vers une API externe non mockée
5. Adapter le plan                    → construire le mock, puis écrire les tests

La formulation du guide est : cartographier la structure, identifier les zones à fort impact, produire un plan priorisé qui s'adapte à mesure que les dépendances apparaissent. L'étape 4 est tout l'enjeu : le plan a changé à cause de ce que l'étape 1 a trouvé.

Trois mauvais appariements, et ce sont exactement les distracteurs :

Et le quatrième, plus discret : la décomposition adaptative sur des cibles figées. Elle n'apporte rien dès lors que les cibles ne varient jamais, et elle rend les exécutions successives plus difficiles à comparer.

Lisez l'énoncé pour une seule chose : la liste des cibles est-elle connaissable avant le premier appel ? Oui → prompt chaining. Non → décomposition dynamique. Des formules comme « les mêmes six adaptateurs, chaque trimestre » pointent d'un côté ; « personne ne sait combien d'étages il comporte » pointe de l'autre.

Teste-toi sur cette section

Q3 Two backlog items, two decomposition strategies

Scenario: Each quarter you audit the same six connector adapters against the same three concerns: retry policy, secret handling, schema versioning. Separately, you must make an undocumented ingestion pipeline observable; nobody knows how many stages it has or which already emit metrics.

Question: Which strategy fits each item?

A) Prompt chaining for the audit, dynamic adaptive decomposition for the observability work.

B) Dynamic adaptive decomposition for the audit, prompt chaining for the observability work.

C) Prompt chaining for both, because a fixed pipeline is always more reproducible.

D) Dynamic adaptive decomposition for both, because letting the model replan is always safer.


Answer: prompt chaining for the audit, adaptive decomposition for the pipeline

Why: the criterion is whether the scope is known before you start. The audit repeats a fixed set of targets, so a chained sequence of focused passes gives even depth and comparable results. The observability work is open-ended: each stage you uncover changes what to look at next.

Why the others are wrong:

  • Inverts the criterion: the fixed sequence lands on the item whose steps nobody knows, the adaptive one on the item that never varies.
  • A fixed pipeline presupposes knowing the stages and their order, precisely the unknown here.
  • Adaptivity buys nothing once targets are frozen, and it makes successive audits harder to compare.

Toutes les questions de la banque sur 1.6

7. 1.7 — Manage session state, resumption, and forking

Une session est l'historique de conversation que le SDK accumule pendant le travail de l'agent — votre prompt, chaque appel d'outil, chaque résultat, chaque réponse — écrit sur disque automatiquement. Les longues investigations s'étalent sur plusieurs sessions de travail, et entre-temps les fichiers changent et les résultats d'outils enregistrés se périment.

Trois opérations, trois métiers différents :

Opération Ce qu'elle fait
--resume <session-name> Continue une conversation antérieure précise, par son nom
fork_session Crée une branche indépendante à partir de l'historique d'une session existante ; l'originale reste intacte et le fork obtient son propre id
Session neuve + résumé injecté Démarre à vide et reçoit, dans le prompt, un résumé structuré de ce qui tient encore
# Forker la base d'analyse pour explorer une seconde approche.
async for message in query(
    prompt="Plutôt que Redux, décris comment la Context API fonctionnerait ici",
    options=ClaudeAgentOptions(
        resume=session_id,      # un fork branche toujours une session existante
        fork_session=True,
        max_turns=5,
    ),
):
    if isinstance(message, ResultMessage):
        forked_id = message.session_id     # distinct de session_id

Deux faits sur le fork

Deux faits sur le fork sur lesquels les questions se jouent. Il se combine toujours à la reprise, puisqu'on forke une session existante, jamais à partir de rien. Et il branche l'historique de conversation, pas le système de fichiers : deux agents forkés qui modifient des fichiers dans le même répertoire modifient les mêmes fichiers.

Choisir entre les trois

Choisir entre les trois est la compétence que le guide teste :

Situation Choix
Le contexte antérieur est encore valide, fichiers inchangés --resume
Quelques fichiers précis ont changé, le reste tient encore --resume, en nommant les fichiers modifiés pour que l'agent les ré-analyse plutôt que de tout ré-explorer
Les résultats d'outils sont périmés — fichiers modifiés largement ou de façon incertaine Session neuve, amorcée par un résumé structuré
Comparer deux approches depuis une base d'analyse commune fork_session

La troisième ligne est le jugement du guide lui-même, et il est assez contre-intuitif pour être testé : démarrer une session neuve avec un résumé structuré est plus fiable que reprendre avec des résultats d'outils périmés. Une session reprise transporte des réponses enregistrées qui décrivent un système qui n'existe plus, et l'agent raisonne dessus comme si elles étaient à jour. Un résumé écrit emporte les conclusions qui ont survécu et laisse derrière les payloads morts.

Une session est un relevé de ce qui a été lu, pas l'état de ce qui est sur le disque. Chacun des trois choix se joue sur ce qui reste vrai de ce relevé. La reprise convient tant que le relevé est en grande partie valide, et c'est le fait de nommer les fichiers qui ont changé qui la rend ciblée plutôt que hasardeuse. Un fork branche l'historique de conversation et non le système de fichiers, et c'est pourquoi il compare deux approches et jamais deux versions d'un fichier. Une session neuve accompagnée d'un résumé écrit garde vos conclusions et laisse derrière elle les lectures périmées.

Trois gestes que les distracteurs proposent à la place des trois réponses ci-dessus :

Trois situations, trois réponses, et les distracteurs les permutent. Contexte majoritairement valide → --resume accompagné de la liste des fichiers modifiés. Résultats d'outils largement périmés → session neuve avec un résumé injecté. Deux approches à comparer → fork_session. Notez aussi que le guide écrit --resume <session-name> alors que le SDK documente resume prenant un session ID ; c'est le concept — reprendre une investigation nommée à travers plusieurs sessions de travail — qui est testé, pas la syntaxe.

Teste-toi sur cette section

Q5 The vendor retired the version you probed

Scenario: A session named fx-integration spent a long afternoon probing a currency vendor's sandbox: sample payloads, error shapes, throttling behavior. The vendor has since shipped v3 and retired v2, so every recorded response describes an endpoint that now answers 410. What that session concluded about the vendor's pagination model and its throttling window still holds.

Question: How do you take the integration work forward?

A) Start a new session and seed it with a summary of what still holds.

B) Resume the session and let the agent re-probe each endpoint as it needs one, so the recorded v2 responses get corrected along the way.

C) Start a new session and replay the entire v2 transcript into it, so nothing observed that afternoon is lost.

D) Start a new session with only the vendor's v3 changelog.


Answer: a new session seeded with what survived the version change

Why: resumption pays off while the stored tool results still describe the system you are talking to. Here they describe endpoints that answer 410, so replaying them makes the agent reason about a vendor that no longer exists. A summary carries the pagination model and the throttling window forward and leaves the dead payloads behind.

Why the others are wrong:

  • Re-probing corrects the record only where the agent happens to look; everything it does not revisit sits in context as though it were still true.
  • Carries the obsolete payloads into the new session, which is the one thing a fresh start was meant to avoid.
  • A changelog says what moved on the vendor's side, not what you learned. Pagination and throttling would have to be rediscovered.

Toutes les questions de la banque sur 1.7


CCA Révision — D1 — Architecture et orchestration des agents (27 %) · 2026

↑