# The 10 Anti-Patterns

Les dix anti-patterns critiques qui apparaissent comme mauvaises réponses à l’examen Architect — à quoi ressemble chacun dans un énoncé, pourquoi il échoue, l’alternative correcte avec un extrait, et comment il est formulé en distracteur.

import { Accordions, AccordionItem } from '@prosefly/astro-components';

Anthropic publie dix anti-patterns qui reviennent comme **mauvaises réponses** aux examens Architect et Developer. Si vous savez les repérer dans une option, vous pouvez éliminer cette option instantanément. Pour chacun : à quoi il ressemble dans un énoncé de question, pourquoi il échoue, l’alternative correcte avec un extrait, et la formulation que les examinateurs emploient pour le faire *paraître* juste.

Les distracteurs sont conçus pour être tentants — ils paraissent généralement « raisonnables », « plus simples » ou « plus flexibles ». La table ci-dessous est votre référence rapide ; les sections développent chacun.

| # | Anti-pattern | Alternative correcte |
| --- | --- | --- |
| 1 | Analyser le langage naturel pour la terminaison de boucle | Vérifier `stop_reason` |
| 2 | Plafonds d’itérations arbitraires comme arrêt principal | `stop_reason` principal ; plafond comme filet de sécurité |
| 3 | Application par prompt de règles critiques | Hooks déterministes (code de sortie 2) |
| 4 | Confiance auto-déclarée pour l’escalade | Demande explicite ou lacune de capacité |
| 5 | Escalade fondée sur le sentiment | Sentiment ≠ complexité |
| 6 | Messages d’erreur génériques masquant le contexte | Erreurs structurées (catégorie, réessayable) |
| 7 | Supprimer silencieusement les erreurs comme un succès | Faire remonter les défaillances explicitement |
| 8 | Trop d’outils par agent | 4 à 5 ciblés ; tool search + `defer_loading` |
| 9 | Auto-revue dans la même session | Évaluateur indépendant (session/modèle vierge) |
| 10 | Métriques agrégées masquant l’échec par type | Métriques par segment, barrer sur le pire |

---

## Anti-pattern 1 · Parsing natural language for loop termination

*(Analyser le langage naturel pour la terminaison de boucle.)*

**Dans un énoncé :** « La boucle d’agent s’arrête quand la réponse de Claude contient la phrase “task complete”. » / « Nous détectons l’achèvement en scannant le texte de sortie pour “done”. »

**Pourquoi ça échoue :** La prose du modèle n’est pas un signal de contrôle. Elle varie selon la formulation, peut être erronée, et peut être manipulée par une injection de prompt dans les résultats d’outils. Les boucles qui se calent sur le texte s’arrêtent trop tôt, ne s’arrêtent jamais, ou s’arrêtent quand elles sont détournées.

**Alternative correcte :** Piloter la boucle depuis le `stop_reason` de l’API.

```python
if resp.stop_reason == "tool_use":
    ...  # run tools, continue
elif resp.stop_reason == "end_turn":
    break  # done
elif resp.stop_reason == "max_tokens":
    raise OutputTruncated()  # not completion
```

**Formulation du distracteur :** « Pour la flexibilité, terminez quand le modèle dit qu’il a fini » — paraît adapté au langage naturel et adaptatif.

---

## Anti-pattern 2 · Arbitrary iteration caps as the primary stop

*(Plafonds d’itérations arbitraires comme arrêt principal.)*

**Dans un énoncé :** « La boucle exécute 10 itérations fixes puis s’arrête. » / « Nous limitons l’agent à 5 appels d’outils pour le borner. »

**Pourquoi ça échoue :** Un plafond seul ne dit rien sur l’achèvement ou non de la tâche. Si la boucle ne se termine qu’en atteignant le plafond, les résultats sont silencieusement incomplets ; si le plafond est trop élevé, le coût s’emballe.

**Alternative correcte :** `stop_reason` est l’arrêt principal ; le plafond est un **filet de sécurité** contre les boucles emballées.

```python
iterations = 0
while resp.stop_reason == "tool_use" and iterations < MAX_ITERS:  # cap = safety net
    ...
    iterations += 1
```

**Formulation du distracteur :** « Pour empêcher les boucles infinies, plafonnez les itérations et traitez l’atteinte du plafond comme un achèvement » — confond un filet de sécurité avec un signal d’achèvement.

---

## Anti-pattern 3 · Prompt-based enforcement of critical rules

*(Application par prompt de règles critiques.)*

**Dans un énoncé :** « Nous avons ajouté “ne jamais exécuter de commandes destructrices” au system prompt. » / « CLAUDE.md dit à Claude de toujours exécuter les tests avant de valider. »

**Pourquoi ça échoue :** Les instructions de prompt sont probabilistes et vulnérables à l’injection. Une règle métier ou de sécurité critique qui doit *toujours* tenir ne peut pas reposer sur un respect au mieux.

**Alternative correcte :** Imposer avec un **hook** déterministe (le code de sortie 2 bloque) ou une garde programmatique.

```bash
# PreToolUse hook: block the action deterministically
if echo "$cmd" | grep -q 'rm -rf'; then echo "blocked" >&2; exit 2; fi
```

**Formulation du distracteur :** « Renforcez l’instruction et utilisez une règle appuyée, tout en majuscules, dans le prompt » — sous-entend qu’une formulation peut rendre déterministe un contrôle probabiliste.

---

## Anti-pattern 4 · Self-reported confidence for escalation

*(Confiance auto-déclarée pour l’escalade.)*

**Dans un énoncé :** « L’agent escalade quand sa confiance auto-déclarée tombe sous 70 %. »

**Pourquoi ça échoue :** Les modèles de langage sont mal calibrés ; leur confiance déclarée ne suit pas de façon fiable la justesse. L’aiguillage dessus produit à la fois de fausses escalades et des escalades manquées.

**Alternative correcte :** Escalader sur **demande explicite de l’utilisateur** (immédiatement) ou sur une **lacune de capacité objective** (après avoir tenté la résolution).

```python
if turn.user_explicitly_requested_human: escalate()          # now
elif turn.needs_capability_agent_lacks and turn.attempts_exhausted: escalate()
```

**Formulation du distracteur :** « Utilisez le score de confiance du modèle pour décider quand un humain est nécessaire » — paraît piloté par les données et rigoureux.

---

## Anti-pattern 5 · Sentiment-based escalation

*(Escalade fondée sur le sentiment.)*

**Dans un énoncé :** « Quand l’analyse de sentiment signale le client comme frustré, escalader vers un humain. »

**Pourquoi ça échoue :** **Le sentiment n’est pas la complexité.** Un client frustré peut avoir une demande triviale et résoluble ; un client calme peut avoir un problème réellement difficile. L’aiguillage par sentiment envoie des cas résolubles à des humains et peut manquer les cas complexes.

**Alternative correcte :** Gérez l’émotion par une bonne réponse ; escaladez sur demande explicite ou lacune de capacité. Utilisez le sentiment pour *ajuster le ton*, non pour *aiguiller*.

**Formulation du distracteur :** « Améliorez l’expérience client en escaladant immédiatement les clients en colère » — fait appel à l’empathie.

---

## Anti-pattern 6 · Generic error messages hiding context

*(Messages d’erreur génériques masquant le contexte.)*

**Dans un énoncé :** « En cas d’échec l’outil renvoie “An error occurred”. » / « Les erreurs sont attrapées et un message générique est affiché. »

**Pourquoi ça échoue :** L’agent (et les opérateurs) perdent le détail diagnostique nécessaire pour décider s’il faut réessayer, escalader ou corriger l’entrée. Le rétablissement devient de la devinette.

**Alternative correcte :** Renvoyer des **erreurs structurées** avec catégorie, indicateur réessayable, message et tout résultat partiel.

```json
{ "status": "error", "category": "rate_limit", "retryable": true,
  "retry_after": 12, "partial": [] }
```

**Formulation du distracteur :** « Pour une expérience utilisateur propre, masquez les détails techniques derrière un message générique amical » — paraît être une bonne UX.

---

## Anti-pattern 7 · Silently suppressing errors as success

*(Supprimer silencieusement les erreurs comme un succès.)*

**Dans un énoncé :** « En cas d’échec l’outil renvoie une liste vide. » / « Les exceptions sont avalées et l’agent continue. »

**Pourquoi ça échoue :** Une défaillance déguisée en « aucun résultat » ou en succès propage des **données erronées** en aval. L’agent ne peut pas distinguer un vrai résultat vide d’un appel cassé.

**Alternative correcte :** Faites remonter les défaillances explicitement ; distinguez `{status:"ok", items:[]}` de `{status:"error", …}`.

```python
try:
    return {"status": "ok", "items": query()}
except BackendError as e:
    return {"status": "error", "category": "backend", "retryable": True, "message": str(e)}
```

**Formulation du distracteur :** « Pour garder l’agent robuste, attrapez les erreurs et renvoyez des résultats vides pour que le flux ne casse jamais » — paraît résilient.

---

## Anti-pattern 8 · Too many tools per agent

*(Trop d’outils par agent.)*

**Dans un énoncé :** « L’agent est configuré avec 18 outils couvrant chaque opération. »

**Pourquoi ça échoue :** Chaque schéma d’outil consomme du contexte, et passé une poignée la précision de sélection du modèle chute — il choisit le mauvais outil ou hallucine les arguments.

**Alternative correcte :** Donnez à chaque agent **4 à 5 outils ciblés** ; répartissez les responsabilités entre sous-agents ; pour les grands catalogues activez le **tool search tool** et `defer_loading: true`.

```python
tools = [
    {"type": "tool_search_tool_20250101", "name": "tool_search"},
    {"name": "search_kb", "defer_loading": True, "input_schema": {...}},  # loads on demand
]
```

**Formulation du distracteur :** « Donnez à l’agent tous les outils disponibles pour qu’il ne manque jamais d’une capacité » — paraît exhaustif et flexible.

---

## Anti-pattern 9 · Same-session self-review

*(Auto-revue dans la même session.)*

**Dans un énoncé :** « Nous demandons au modèle, dans la même conversation, de vérifier si sa réponse est correcte. »

**Pourquoi ça échoue :** Le tour de revue partage le contexte de raisonnement qui a produit l’erreur, donc il hérite du même biais et tend à confirmer la réponse d’origine.

**Alternative correcte :** Utilisez un évaluateur **indépendant** — une session vierge, idéalement un **modèle différent** — notant contre un barème explicite (evaluator-optimizer, LLM-as-judge).

```python
judge = client.messages.create(model="claude-sonnet-5",  # different model/session
    messages=[{"role": "user", "content": f"<rubric>{rubric}</rubric><answer>{ans}</answer> Score it."}])
```

**Formulation du distracteur :** « Faites l’auto-critique par le modèle dans le même chat pour attraper ses propres erreurs » — paraît efficace.

---

## Anti-pattern 10 · Aggregate metrics masking per-type failure

*(Métriques agrégées masquant l’échec par type.)*

**Dans un énoncé :** « La précision d’extraction est de 94 % globalement, donc le pipeline est prêt. » (alors qu’un type de document est à 60 %)

**Pourquoi ça échoue :** Un unique chiffre agrégé masque une catégorie qui échoue lourdement. Le segment le moins performant est exactement là où réside le risque métier.

**Alternative correcte :** Reportez des métriques **par segment / par type de document** et barrez sur le **pire** type, non sur la moyenne.

```text
overall: 94%   ← misleading
invoices: 99%  contracts: 60%  receipts: 96%   ← the real picture; gate on contracts
```

**Formulation du distracteur :** « La précision agrégée dépasse notre barre de 90 %, donc livrez-le » — paraît piloté par les métriques et objectif.

---

## Familles de distracteurs : comment les examinateurs déguisent chaque anti-pattern

Les dix anti-patterns se regroupent en familles qui partagent une surface « ça sonne bien ». Reconnaître la famille vous permet d’éliminer deux ou trois options d’un coup.

| Famille | Anti-patterns | Attrait de surface | Le signe révélateur |
| --- | --- | --- | --- |
| **Flux-de-contrôle-au-feeling** | #1 analyse de la prose, #2 plafond d’itérations | « flexible », « empêche les boucles infinies » | La justesse doit venir de `stop_reason` |
| **Application-par-espoir** | #3 application par prompt | « ajoutez juste une instruction claire » | Les règles critiques ont besoin d’un hook déterministe |
| **Faire-confiance-aux-ressentis-du-modèle** | #4 confiance, #5 sentiment | « piloté par les données », « empathique » | Escaladez sur demande explicite ou lacune de capacité |
| **Masquer-la-défaillance** | #6 erreurs génériques, #7 succès silencieux | « UX propre », « robuste » | Faites remonter des erreurs structurées ; distinguez vide d’échec |
| **Plus-c’est-mieux** | #8 trop d’outils | « exhaustif », « ne manque jamais d’une capacité » | 4 à 5 outils ciblés ; search + defer au-delà d’~10 |
| **Corriger-sa-propre-copie** | #9 revue en même session | « auto-vérification efficace » | Évaluateur indépendant, session/modèle vierge |
| **Un-seul-chiffre-pour-tout-régir** | #10 métriques agrégées | « objectif », « atteint la barre » | Découpez par segment ; barrez sur le pire |

:::tip[Énoncés à deux anti-patterns]
Les items plus difficiles placent deux anti-patterns en options séparées (par ex. un distracteur escalade sur le sentiment (#5) et un autre sur la confiance (#4)). En éliminer un ne suffit pas — reconnaissez la *famille* et rejetez les deux, puis choisissez la réponse demande-explicite/lacune-de-capacité.
:::

## Élimination de distracteurs travaillée

**Énoncé :** « Un agent de support doit passer la main à un humain. Le client est en colère mais sa demande (statut de commande) est entièrement résoluble, et le modèle signale 62 % de confiance. Laquelle est correcte ? »

```text
A. Escalate due to negative sentiment.            → #5 sentiment    ✗ eliminate
B. Escalate because confidence < 70%.             → #4 self-report  ✗ eliminate
C. Resolve the request; neither sentiment nor     → explicit-request/capability rule  ✓
   confidence is a valid trigger, and it is within capability.
D. Cap the chat at 3 turns then escalate.         → arbitrary cap, not an escalation rule  ✗
```

Deux distracteurs (A, B) appartiennent à la famille faire-confiance-aux-ressentis-du-modèle ; D est un plafond flux-de-contrôle-au-feeling mal appliqué à l’escalade. C applique la vraie règle.

---

## Comment utiliser cette liste à l’examen

<Accordions>
  <AccordionItem title="Q1 · Une option dit : « Plafonner l’agent à 10 itérations et traiter l’atteinte du plafond comme l’achèvement de la tâche. » Quel anti-pattern est-ce ? (Sélectionnez une réponse)">
    A. Anti-pattern 1.
    B. Anti-pattern 2 — le plafond d’itérations comme signal principal/d’achèvement.
    C. Anti-pattern 8.
    D. Anti-pattern 10.

    **Réponse : B.** Traiter le plafond comme un achèvement est l’anti-pattern 2. Le plafond n’est qu’un filet de sécurité ; l’achèvement vient de `stop_reason`.
  </AccordionItem>

  <AccordionItem title="Q2 · Une option dit : « Escalader dès que le classifieur de sentiment signale de la frustration. » Quelles deux familles de distracteurs sont apparentées ici, et de laquelle s’agit-il exactement ? (Sélectionnez une réponse)">
    A. C’est l’anti-pattern 5 (sentiment) ; son cousin est l’anti-pattern 4 (confiance auto-déclarée).
    B. C’est l’anti-pattern 4 ; son cousin est l’anti-pattern 6.
    C. C’est l’anti-pattern 9.
    D. C’est l’anti-pattern 7.

    **Réponse : A.** L’escalade fondée sur le sentiment est le #5 ; le piège d’escalade apparenté est le #4 (confiance auto-déclarée). L’escalade correcte est la demande explicite ou la lacune de capacité.
  </AccordionItem>

  <AccordionItem title="Q3 · Une option dit : « En cas de toute erreur backend, renvoyer un résultat vide pour que le pipeline continue de tourner. » Quel anti-pattern, et quel est le correctif ? (Sélectionnez une réponse)">
    A. Anti-pattern 6 ; ajouter un message générique.
    B. Anti-pattern 7 ; renvoyer une erreur structurée distinguant succès-vide d’échec pour que le code en aval et l’agent puissent réagir.
    C. Anti-pattern 3 ; utiliser un hook.
    D. Anti-pattern 10 ; ajouter des métriques par type.

    **Réponse : B.** Renvoyer vide en cas d’échec est une suppression silencieuse (#7). Le correctif est des erreurs structurées qui ne déguisent jamais une défaillance en « aucun résultat ».
  </AccordionItem>

  <AccordionItem title="Q4 · Un énoncé propose : « Donner à l’agent tous les 18 outils disponibles pour qu’il ne manque jamais d’une capacité. » Quel anti-pattern, et quelle est l’alternative correcte ? (Sélectionnez une réponse)">
    A. #10 ; reporter des métriques par segment.
    B. #8 (trop d’outils par agent) ; donner 4 à 5 outils ciblés, répartir les responsabilités vers des sous-agents, ou activer le tool search avec `defer_loading` au-delà d’~10.
    C. #1 ; vérifier `stop_reason`.
    D. #3 ; utiliser un hook.

    **Réponse : B.** « Tous les outils pour être complet » est le #8 — cela gonfle le contexte et dégrade la sélection. Le correctif est moins d’outils ciblés, une scission en sous-agents, ou tool search + defer_loading. Les autres options nomment des anti-patterns sans rapport.
  </AccordionItem>

  <AccordionItem title="Q5 · Une option dit : « Faire noter par le modèle, dans le même chat, si sa réponse respecte le barème. » Quel anti-pattern, et le correctif ? (Sélectionnez une réponse)">
    A. #9 (auto-revue dans la même session) ; exécuter un évaluateur indépendant (session vierge, idéalement un modèle différent) contre le barème.
    B. #4 ; utiliser l’escalade sur demande explicite.
    C. #2 ; ajouter un plafond d’itérations.
    D. #6 ; renvoyer une erreur structurée.

    **Réponse : A.** L’auto-notation en session hérite du biais du générateur (#9) ; l’indépendance le supprime. Les autres anti-patterns sont sans rapport avec le biais d’évaluation.
  </AccordionItem>

  <AccordionItem title="Q6 · Un énoncé unique propose deux distracteurs d’escalade — un sur le sentiment, un sur la confiance auto-déclarée — plus une demande résoluble. Quelles DEUX options devez-vous éliminer, et pourquoi ? (Sélectionnez deux réponses)">
    A. Escalader sur le sentiment négatif.
    B. Résoudre la demande, puisqu’elle est dans le périmètre de capacité et qu’aucun déclencheur ne s’applique.
    C. Escalader sur une confiance sous un seuil.
    D. Escalader sur demande explicite d’un humain.
    E. Escalader parce que la réponse est longue.

    **Réponse : A et C.** Le sentiment (#5) et la confiance auto-déclarée (#4) sont tous deux des déclencheurs invalides et appartiennent à la même famille de distracteurs — éliminez les deux. Résoudre (B) est correct ici ; la demande explicite (D) serait valide mais n’est pas présente ; la longueur (E) est sans rapport.
  </AccordionItem>

  <AccordionItem title="Q7 · Une option dit : « La précision agrégée est de 94 % et dépasse notre barre de 90 %, donc livrez-le. » Qu’est-ce qui est faux, et qu’est-ce qui devrait barrer la mise en production ? (Sélectionnez une réponse)">
    A. Rien ; 94 % dépasse la barre.
    B. #10 — l’agrégat peut masquer un segment (par ex. les contrats à 60 %) ; reportez la précision par type de document et barrez sur le type le moins performant.
    C. #7 — renvoyer vide en cas d’échec.
    D. #2 — ajouter un plafond d’itérations.

    **Réponse : B.** Un unique chiffre agrégé masque un segment défaillant (#10) ; barrez sur le pire type, non sur la moyenne. C et D nomment des anti-patterns sans rapport, et livrer sur l’agrégat (A) est le piège lui-même.
  </AccordionItem>
</Accordions>
