L'IA fait exactement ce que tu lui demandes — c'est le problème

J'ai demandé à Claude d'ajouter une pagination sur une liste de produits. Réponse en 30 secondes : propre, fonctionnelle, avec gestion d'erreurs et tout. Et totalement déconnectée du reste de l'app. Mauvais composant de pagination (on en avait déjà un), style inventé de toutes pièces, filtres existants cassés. Techniquement correct. Inutilisable en l'état.

Le problème n'était pas dans l'IA — c'était dans ma demande. J'avais écrit : "Ajoute une pagination sur cette liste." C'est exactement ce qu'elle a fait. Ni plus, ni moins.

Les modèles actuels (Claude 4.x, GPT-4o) ont abandonné le comportement "deviner l'intention". Ils prennent le prompt au pied de la lettre. C'est un progrès sur le fond, mais ça change radicalement comment il faut prompter pour du code. Un bon prompt de code, c'est pas une question d'astuces : c'est donner à l'IA le même contexte que tu donnerais à un dev junior qui débarque sur le projet.

J'ai testé et scoré des dizaines de formulations sur les quatre tâches les plus courantes. Voici ce qui marche vraiment.

La structure qui s'applique à toutes les tâches

Avant d'entrer dans les cas spécifiques, il y a quatre éléments présents dans tous les bons prompts de code :

  1. Stack/contexte — langage, version, framework, fichier concerné
  2. Tâche précise — ce que tu veux, exprimé comme une instruction et non une question
  3. Contraintes — ce qu'il ne faut PAS toucher, les limites de scope
  4. Format attendu — diff, code complet, explication seule, CVSS score…

Une règle simple d'Anthropic résume tout : montre ton prompt à un collègue sans contexte. S'il serait perdu, l'IA le sera aussi.

Pour les gros prompts (plusieurs fichiers, instructions complexes), les balises XML aident à séparer les sections. Les tests montrent une amélioration de 30 à 39% sur la qualité des réponses quand le prompt est structuré avec des balises claires :


<contexte>PHP 8.1, Laravel 10, app multi-tenant</contexte>
<tache>Ajouter la pagination sur ProductList</tache>
<contraintes>Ne pas toucher getFilteredProducts()</contraintes>
<code>[coller les fichiers]</code>

Deuxième règle : code d'abord, question à la fin. Mettre le contexte et les fichiers en haut, et l'instruction en bas du prompt, améliore la précision de ~30% sur les gros contextes selon les mesures d'Anthropic. L'IA lit tout avant d'agir.

Bug fix — décrire le symptôme, pas la théorie

L'erreur classique : coller le code en demandant "ça ne marche pas". L'IA ne sait pas si ça plante, si ça retourne une mauvaise valeur, ou si c'est juste trop lent. Elle va inventer un problème plausible et le "corriger".

❌ Prompt vague — score : 3/10


Ce code ne marche pas, aide-moi.

function getUserById($id) {
    $result = $db->query("SELECT * FROM users WHERE id = $id");
    return $result->fetch();
}

Résultat type : l'IA corrige l'injection SQL (certes, problème réel), ignore l'erreur réelle, et réécrit la fonction avec PDO prépared statements. Correct sur le fond, mais pas ce que tu cherchais.

✅ Prompt précis — score : 9/10


Stack: PHP 8.1 + PDO, Laravel 10.

Comportement actuel :
  Call to a member function fetch() on bool
  → uniquement quand l'ID n'existe pas dans la table

Comportement attendu :
  Retourner null si l'utilisateur n'existe pas (pas d'exception)

J'ai déjà essayé :
  isset($result) avant fetch() — même erreur

Code :
function getUserById($id) {
    $result = $db->query("SELECT * FROM users WHERE id = $id");
    return $result->fetch();
}

La ligne "j'ai déjà essayé" est critique. Sans elle, l'IA va te re-suggérer exactement ce que tu as tenté. Avec elle, elle cherche ailleurs — et trouve que PDO::query() retourne false quand la requête échoue, donc il faut $result !== false ? $result->fetch() : null.

Template bug fix :


Stack: [langage + version + framework]
Comportement actuel: [symptôme exact — message d'erreur, valeur retournée, comportement observé]
Comportement attendu: [ce que le code devrait faire]
J'ai déjà essayé: [tentatives précédentes et pourquoi elles n'ont pas fonctionné]
Code: [le code minimal qui reproduit le bug]

Nouvelle feature — les critères d'acceptance et le hors scope

"Ajoute un système de commentaires." L'IA va choisir une stack (base de données, probablement), une UI (modals, inline, page dédiée ?), une validation (côté client, serveur ?). Chacun de ces choix peut être incompatible avec ton projet.

❌ Sans contexte d'intégration — score : 3/10


Ajoute un système de commentaires à ce blog.

Résultat probable : solution avec MySQL, formulaire jQuery, et un design qui ne ressemble à rien dans le projet existant.

✅ Avec contexte, critères et hors scope — score : 9/10


Stack: PHP 8 + Bootstrap 3, pas de base de données (stockage fichiers JSON).

Tâche: Ajouter les commentaires sur les articles de blog.

Critères d'acceptance:
- Formulaire: nom + message (pas d'email, pas de compte)
- Validation côté serveur uniquement (pas de JS)
- Stockage: un fichier JSON par article dans /blog/comments/{slug}.json
- Notification email à l'auteur à chaque nouveau commentaire (PHPMailer déjà installé)

Hors scope:
- Pas de modération pour l'instant
- Pas de réponses imbriquées
- Pas de modification CSS existante

Fichiers concernés: [blog_footer.php, template.php]

Ce qui change la donne ici : le hors scope. Dire à l'IA ce qu'elle ne doit pas implémenter est aussi important que ce qu'elle doit faire. Sans ça, elle va soit sur-engineer (modération, auth, nested comments), soit inventer des contraintes qui n'existent pas.

Template nouvelle feature :


Stack: [contexte technique]
Contexte d'intégration: [avec quoi ça doit s'intégrer — composants existants, patterns du projet]
Tâche: [description précise de la feature]
Critères d'acceptance: [liste des comportements attendus]
Hors scope: [ce qu'on ne veut PAS implémenter maintenant]
Code concerné: [fichiers à modifier ou créer]

Refactoring — définir le problème, pas la solution

"Refactorise ce code" est le pire prompt possible pour du refactoring. L'IA va choisir ses propres critères de qualité, probablement changer des signatures de méthodes, ajouter des abstractions non demandées, et casser l'API publique existante.

❌ Sans objectif ni contraintes — score : 2/10


Refactorise ce code pour le rendre plus propre.

[450 lignes de OrderService]

Résultat type : extraction de 8 méthodes privées, renommages, ajout d'interfaces, une classe abstraite "pour la flexibilité future". Ça compile, les tests cassent.

✅ Problème concret + objectif + contraintes — score : 9/10


Problème concret:
  OrderService::processOrder() (450 lignes) est appelée depuis 8 endroits
  avec des combinaisons de paramètres différentes.
  Impossible de savoir quels cas sont couverts par les tests existants.

Objectif:
  Extraire les règles de calcul de prix dans des Value Objects immutables.
  Une classe = une règle (ex: DiscountRule, TaxRule, ShippingRule).

Contraintes absolues:
  - Comportement observable inchangé — les tests existants doivent passer sans modification
  - Ne pas modifier les signatures des méthodes publiques
  - Ne pas changer les types de retour

Scope limité: uniquement le calcul de prix, pas la persistance ni la validation.

Code: [OrderService.php]

Le point clé : "comportement observable inchangé — les tests existants doivent passer sans modification." Sans cette contrainte, l'IA va optimiser selon ses critères à elle. Avec elle, elle est forcée de rester dans les rails.

Template refactoring :


Problème concret: [pourquoi ce code est problématique — pas "c'est sale", mais le vrai impact]
Objectif: [ce qu'on veut obtenir après le refactoring]
Contraintes absolues:
  - [ce qui ne doit pas changer : signatures, tests, comportement observable]
Scope: [ce qui est IN et ce qui est OUT]
Code: [le code à refactorer]

Code review — choisir son angle

Sans angle, l'IA fait une revue de style générique. Elle va pointer l'absence de docstrings, suggérer des noms de variables plus explicites, et rater la faille d'injection SQL béante dans la méthode du bas. La revue de code IA ne vaut quelque chose que si tu lui dis sur quoi concentrer l'attention.

❌ Revue générique — score : 4/10


Revue ce code en tant que senior dev et donne-moi des suggestions d'amélioration.

Résultat : 80% de suggestions de style, nommage, commentaires. 20% de vrais problèmes — noyés dans le bruit.

✅ Angle ciblé + décisions intentionnelles — score : 9/10


Contexte:
  Endpoint public POST /api/documents/upload
  Données entrantes non filtrées, accès système de fichiers, auth JWT vérifiée en amont.

Focus de la revue: sécurité uniquement
  - Injection (commandes, SQL, path)
  - Path traversal
  - Upload de fichiers malveillants (exécution côté serveur)
  - IDOR

Décisions intentionnelles — ne pas signaler:
  - Le cast (int) sur l'ID est délibéré
  - La gestion d'erreurs minimaliste est volontaire (app interne, logs centralisés)
  - Le nom de la variable $tmp est intentionnel (convention équipe)

Format de sortie:
  Pour chaque problème : gravité (critique/haute/moyenne) + description + fix avec code.

Code: [upload-handler.php]

La section "décisions intentionnelles" réduit le bruit de moitié. L'IA ne va pas signaler ce que tu sais déjà — elle se concentre sur ce que tu as demandé.

Template code review :


Contexte: [type d'endpoint, qui l'appelle, données en entrée, auth en place]
Focus: [sécurité / performance / logique métier / architecture — un seul angle à la fois]
Décisions intentionnelles (ne pas signaler): [ce qui est délibéré dans le code]
Format de sortie: [gravité + description + fix avec code / liste simple / …]
Code: [le code à review]

Deux techniques transversales qui changent tout

1. Deux passes valent mieux qu'une

Pour les tâches complexes (gros refactos, reviews approfondies), séparer la critique de l'implémentation donne de meilleurs résultats que tout demander en une fois :

Passe 1 : "Qu'est-ce qui ne va pas dans ce code ? Liste les problèmes sans les corriger."
Passe 2 : "Maintenant, corrige les problèmes 1, 2 et 4 que tu as identifiés. Ignore le 3."

La séparation force l'IA à analyser avant d'agir. Les résultats de la deuxième passe sont significativement plus précis.

2. "Suggère" vs "Modifie" — ça compte

Avec Claude 4.x, la distinction est devenue littérale :

  • Can you suggest some changes? → l'IA liste des suggestions, ne touche rien
  • Change this function to improve its performance. → l'IA modifie

Si tu veux que l'IA agisse : utilise des verbes d'action. "Modifie", "Corrige", "Extrais", "Renomme". Pas "Tu pourrais peut-être regarder si...".

Aller plus loin : des skills qui s'auto-déclenchent

Les templates ci-dessus restent manuels — c'est toi qui choisis de les appliquer. L'étape suivante : créer des skills (commandes slash personnalisées) qui chargent automatiquement le bon template quand le contexte correspond.

Dans Claude Code, un skill est un fichier markdown avec deux choses : une description (les conditions de déclenchement) et le contenu (ce que Claude doit faire). À chaque message, Claude lit la liste des skills disponibles et invoque ceux qui s'appliquent — sans que tu aies besoin de taper la commande.

Identifier ses patterns depuis le git log

Avant de créer des skills génériques, audite ce que tu fais vraiment. Ton git log ne ment pas :


git log --oneline -50 | cut -d' ' -f2- | sort | uniq -c | sort -rn | head -20

Sur un projet réel, ce type d'analyse révèle immédiatement les tâches récurrentes. Par exemple, sur ce portfolio :


8  fix(veille): ...       → système de veille Node.js — bugs fréquents, architecture spécifique
5  feat(blog): ...        → création d'articles toujours dans le même ordre (FR → EN → context → OG → deploy)
3  fix(blog): ...         → corrections post-publication (typos, slugs, syntaxe PHP)
2  refactor(veille): ...  → refactorisations du même sous-système

Ces patterns indiquent exactement quels skills créer. Pas des skills génériques "bug fix" — des skills adaptés à ton projet : la séquence exacte pour un article, les fichiers à lire en premier pour débugger la veille, les contraintes spécifiques du refacto.

Structure d'un skill auto-déclenchable

Un skill Claude Code est un fichier markdown dans ~/.claude/plugins/<nom>/skills/. La clé : une description précise des conditions de déclenchement.


---
name: blog-article
description: >
  Utiliser quand l'utilisateur demande à créer, écrire ou publier un article de blog.
  Déclencher aussi sur : "nouvel article", "écris un article sur X", "publie sur LinkedIn".
---

Ordre d'exécution pour un article (FR + EN) :
1. Créer blog/posts/<slug>.php (version FR)
2. Créer blog/posts/<slug>.en.php (version EN)
3. Mettre à jour blog/posts.json (entrée FR + EN en première position)
4. npm run og <slug>
5. php -l blog/posts/<slug>.php && php -l blog/posts/<slug>.en.php
6. Commiter + pusher
7. node scripts/publish-article.js <slug>

Ce skill s'auto-déclenche dès qu'on parle d'article. La description n'est pas une documentation — c'est un pattern de détection. Plus elle est précise, moins il y a de faux positifs.

Le vrai avantage : le contexte projet embarqué

Un skill générique "bug fix" demandera les mêmes questions à chaque fois. Un skill projet lira d'abord les bons fichiers :


---
name: veille-debug
description: >
  Utiliser pour tout bug dans le système de veille automatisée (Node.js).
  Déclencher sur : erreurs veille, jobs qui ne tournent pas, articles non générés.
---

Avant de diagnostiquer, lire dans cet ordre :
1. scripts/veille/registry.json (jobs configurés)
2. logs/veille-daemon.log (dernière exécution)
3. scripts/veille/runner.js (architecture générale)

Points de défaillance connus :
- Timeout Claude API → augmenter dans job config
- Slug regex → tester avec scripts/veille/test-slug.js
- Corrupt updates.json → supprimer, le système se recrée

C'est ça la différence entre un template générique et un skill projet : le skill sait où regarder en premier sur ton codebase. Il encode l'expérience accumulée sur le projet, pas une procédure abstraite.

Récapitulatif : les 4 templates

Tâche Éléments indispensables Erreur la plus commune
Bug fix Symptôme exact + attendu + "j'ai déjà essayé" Oublier les tentatives précédentes
Nouvelle feature Contexte d'intégration + critères + hors scope Ne pas définir le hors scope
Refactoring Problème concret + objectif + contraintes comportementales Pas de contrainte "tests doivent passer"
Code review Angle ciblé + décisions intentionnelles + format Revue générique sans focus

Conclusion

La vraie utilité de ces templates n'est pas dans l'IA — c'est dans toi. Écrire "comportement actuel vs comportement attendu" te force à caractériser précisément le bug. Écrire le hors scope d'une feature te force à décider ce qui n'est pas prioritaire. Écrire les contraintes d'un refactoring te force à définir ce qui ne doit pas bouger.

Plusieurs fois, en rédigeant un prompt structuré, j'ai réalisé que la tâche était mal définie depuis le départ. L'IA n'avait pas besoin de tourner — le prompt avait déjà fait le travail.

L'IA ne résout pas le problème à ta place. Elle résout le problème que tu lui as décrit. Autant que cette description soit exacte.

📄 CLAUDE.md associé

Commentaires (0)