Accueil / Articles

De Zero-Shot à l’autocohérence : une échelle pratique des techniques de prompting.

L’ingénierie des prompts en tant qu’échelle : mode zéro-shot, mode few-shot, décomposition, boucles de critique et prompts de raisonnement, avec un exemple de bot de soutien et les cas où il convient d’utiliser du code simple.

Éditeur : REACTAPP.TOP16 min de lecture3623 mots

Sources: Prompt Engineering for LLMs: Zero-Shot, Few-Shot, Reasoning, Decomposition & ReAct

Lorsqu’une application a déterminé ce que le modèle peut voir, quels documents doivent être récupérés, ce qui doit être condensé et ce qui doit être exclu, un autre problème apparaît : la formulation de la demande réelle. Aucune méthode de prompting ne s’avère universellement efficace. Une bonne pratique consiste à commencer par l’instruction la plus simple qui puisse fonctionner, et à ajouter des exemples ou une structure étape par étape uniquement lorsque la tâche en nécessite.

Le scénario présenté ci-dessous concerne un assistant de support client.

Commencer sans aucun exemple

Un prompt de type « zero-shot » décrit la tâche sans montrer à quoi ressemble un bon résultat. Pour l’assistant de support, il pourrait s’agir d’une demande en une seule ligne demandant de résumer une plainte, avec cette dernière collée en dessous :

Summarize the following customer complaint in one sentence.
<complaint>
The package arrived three days late and the box was damaged.
</complaint>

Le modèle reçoit une tâche et rien d’autre. C’est cette simplicité qui justifie de l’essayer en premier. Tout ce qui est ajouté à une instruction a un coût : les exemples consomment du contexte, des instructions supplémentaires augmentent la complexité, et chaque élément ajouté crée une nouvelle possibilité pour que deux règles entrent en conflit. Si une instruction directe produit déjà un résultat fiable, des structures complexes ne servent qu’à soigner une maladie qui n’existe pas.

À quoi répond une bonne instruction

Une description de tâche bien formulée définit quatre éléments : l’action à entreprendre, les sources d’information à utiliser, les limites à respecter, et la forme que doit avoir la réponse. Une version plus complète de l’instruction de plainte ressemble à ceci :

Task:
Summarize the customer complaint.

Source:
<complaint>
The package arrived three days late and the box was damaged.
</complaint>

Constraints:
- Use only the information in the complaint.
- Do not infer the cause of the damage.
- Use one sentence.

Output:
Return only the summary.

C’est plus détaillé qu’une simple demande de « Résumer ceci », mais chaque ligne supplémentaire élimine une supposition. Le modèle n’a plus besoin de se demander s’il doit spéculer sur les causes, combien de temps continuer, ou si des commentaires sont les bienvenus. Les directives publiées par les fournisseurs de grands modèles indiquent la même direction : préciser quelle est la tâche, quel doit être le résultat, quels sont les contraintes et quel contexte est important, au lieu d’espérer que le modèle l’infère. En bref, toute exigence importante pour l’application doit être écrite.

Des objectifs concrets valent mieux que des objectifs vagues

« Être utile » ne donne presque aucun objectif précis au modèle. « Nommez le problème décrit par le client et résumez-le en une phrase » lui fournit un objectif clair. Comparez deux instructions destinées à l’outil de support : l’une demande simplement d’aider le client, tandis que l’autre exige de citer le problème d’authentification décrit par le client, ainsi que trois étapes au maximum de dépannage basées sur la documentation fournie.

Cela est important car un modèle peut poursuivre une demande dans de nombreuses directions plausibles. Un objectif vague lui laisse la possibilité de choisir une interprétation différente de celle visée par le développeur, tandis qu’un objectif précis réduit cette marge d’interprétation.

Les limites doivent faire partie de la tâche

Il faut préciser que l’assistant ne doit jamais inventer une solution absente de la documentation. Il s’agit d’une règle de produit, donc l’instruction doit l’énoncer clairement : utiliser uniquement la documentation fournie, et si celle-ci ne couvre pas la question, indiquer que les informations disponibles ne sont pas suffisantes. Comparez cela à « Soyez précis », qui décrit un résultat souhaité mais ne donne aucune instruction pour gérer l’incertitude.

Cette logique s’applique de manière générale. Il ne suffit pas de décrire le résultat idéal ; il faut également indiquer ce que le modèle doit faire lorsque ce résultat ne peut pas être obtenu de manière fiable. Cela devient encore plus important par la suite, pour les appels d’outils et les sorties structurées.

Où le zero-shot suffit

Une instruction simple suffit généralement lorsque la tâche est facile, que le comportement se prête bien à des mots, que le modèle connaît déjà le type de tâche, que les règles de sortie sont modestes et que l’entrée ne présente pas de cas particuliers. Demander la version d’un produit dans un message, uniquement le numéro de version, en est un exemple. Traduire une phrase en français en est un autre. Ajouter cinq démonstrations ne rapporte que peu de bénéfices dans ces cas.

Ainsi, la première règle de l’optimisation des prompts est étrangement conservatrice : commencer par une approche sans exemple concret, et n’ajouter des mécanismes supplémentaires qu’après que l’évaluation ait montré un besoin.

Manières dont l’approche sans exemple échoue

Plusieurs types d’échec se reproduisent fréquemment.

Ambiguïté. L’expression « Améliorez ceci » soulève la question : plus court, plus convaincant, plus précis, plus formel ? Le modèle doit deviner. Comparez cela à une demande de réécriture d’une réponse de support afin qu’elle soit concise, professionnelle et claire pour un client non technique, tout en conservant toutes les affirmations factuelles. Dans ce cas, les contraintes sont bien plus strictes.

Manque de contexte. Un modèle ne peut pas s’appuyer sur des faits qui ne lui ont jamais été fournis et qu’il ne peut pas obtenir. Demandez-lui pourquoi l’authentification d’un client a échoué sans lui fournir de message d’erreur ou de détails du système ; aucune reformulation ne pourra créer les éléments manquants. Ici, la solution réside dans un meilleur contexte, et non dans des instructions plus précises. C’est un point évident, mais aussi une véritable limite de l’ingénierie des prompts.

Exigences contradictoires. Une demande exigeant une explication complète en exactement dix mots impose deux choses qui ne peuvent être accomplies correctement en même temps. Une bonne conception des instructions évite de tels conflits au lieu de compter sur le modèle pour les résoudre un par un.

Présupposés non exprimés. Un développeur qui écrit « Résumer la plainte » peut vouloir dire « énumérer uniquement les faits indiqués par le client ». Le modèle pourrait alors fournir un résumé fluide contenant des inférences raisonnables. Si cette différence est importante, l’instruction doit le préciser. Les présupposés importants pour le système doivent devenir des exigences explicites et lisibles par la machine.

Ajout d’exemples

Lorsqu’une instruction simple s’avère insuffisante, l’outil suivant est l’incitation à l’aide de quelques exemples : on insère dans le contexte des exemples concrets de la tâche à effectuer. Un classificateur qui trie les messages en catégories de facturation, techniques et de compte pourrait afficher quelques messages étiquetés avant le message réel :

Task:
Classify the customer message as BILLING, TECHNICAL, or ACCOUNT.

Example 1:
"My invoice contains an unexpected charge."
→ BILLING

Example 2:
"The application crashes when I upload a file."
→ TECHNICAL

Example 3:
"I cannot reset my password."
→ ACCOUNT

Now classify:
"I was charged twice for my subscription."

À partir de ces démonstrations, le modèle en déduit la correspondance. On appelle cela l’apprentissage in-context, car le modèle modifie son comportement pour la demande actuelle en s’appuyant sur les exemples présents dans son champ de vision, sans pour autant modifier ses paramètres sous-jacents. En essence, ces exemples indiquent : « C’est à quoi ressemble cette tâche en pratique », et ils peuvent transmettre des détails difficiles à exprimer par des mots écrits.

Les démonstrations enseignent la tâche, pas seulement son format

De nombreux développeurs considèrent les exemples de type few-shot comme un outil d’aide à la mise en forme. Ils servent en réalité à bien plus. Prenons par exemple la paire « L’application est lente » accompagnée de l’étiquette TECHNICAL : cela montre le format de sortie, mais il montre également comment cette application interprète la catégorie TECHNICAL. Les exemples influencent la compréhension que le modèle a de la tâche elle-même.

C’est pourquoi les mauvais exemples sont risqués. Des étiquettes incohérentes, des biais accidentels ou des cas limites contraires aux politiques peuvent tous être reproduits par le modèle.

Sélection des exemples à inclure

Avec 10 000 tickets historiques disponibles, il est impratique de les intégrer tous dans une requête, il faut donc en choisir un sous-ensemble. Le choix aléatoire est une approche naïve. Une meilleure méthode consiste à sélectionner délibérément des cas représentatifs :

Example 1: straightforward billing issue
Example 2: straightforward technical issue
Example 3: ambiguous issue
Example 4: boundary case
Example 5: short, poorly written request

Ce qui constitue une bonne sélection dépend de la tâche. Pour la classification, il est nécessaire de représenter les classes principales et leurs limites. Une tâche de formatage requiert des exemples montrant la structure requise. Une tâche axée sur le raisonnement bénéficie d’exemples qui illustrent comment décomposer le problème ou le vérifier. Dans tous les cas, un exemple trouve sa place grâce aux informations qu’il contient, et non simplement parce qu’il est disponible.

Combien ?

Plus n’est pas automatiquement mieux. Si un exemple soigneusement choisi rend le comportement évident, trente autres pourraient ajouter des milliers de tokens sans aucun avantage et introduire des schémas contradictoires. L’usage de peu d’exemples présente donc la même tension liée au budget de contexte que tout le reste, et le nombre idéal doit être déterminé par des essais.

Ici, l’ingénierie des prompts commence à ressembler à un travail expérimental. La question n’est plus de savoir si un prompt sonne mieux, mais plutôt si cette version performe mieux sur des cas de test représentatifs. Ce changement devient essentiel dès l’introduction de l’évaluation.

Variance dans les exemples

Si chaque démonstration correspond à une demande courte, claire et bien rédigée, le modèle pourrait apprendre un schéma restreint que les utilisateurs réels ne suivent pas. Les messages réels ont plutôt ce aspect :

"can't login"
"I've been locked out since yesterday"
"Password reset isn't sending me anything"
"login broken after changing phone"

Tous ces exemples décrivent des problèmes apparentés en utilisant des termes très différents. Un bon ensemble d’exemples de type few-shot reflète la variété attendue par l’application. Cela ne signifie pas ajouter des exemples au hasard, mais plutôt couvrir délibérément des différences significatives.

Montrer ce qu’il faut éviter

Pour certaines tâches, il est utile de combiner une bonne réponse avec une mauvaise, afin que le modèle puisse identifier la frontière. Dans le cas d’un message indiquant qu’un colis est arrivé en retard, on peut présenter à la fois un résumé acceptable et un résumé erroné :

Input:
"The customer says the package arrived late."
Good output:
"The customer reports that the package arrived late."
Bad output:
"The courier lost the package."
Reason:
The customer did not state that the courier lost it.

L’exemple négatif montre une limite : il ne faut pas en déduire des faits que l’entrée ne prouve pas. Cependant, les exemples négatifs exigent prudence. Un exemple marqué comme incorrect peut par erreur enseigner précisément le comportement qu’il était censé empêcher, surtout lorsque la différence est subtile. L’application doit vérifier si les démonstrations négatives améliorent les résultats et ne pas simplement supposer qu’elles le feront.

Exemples pour la structure

Lorsqu’il est difficile de décrire le format d’une sortie, un exemple s’avère très utile. Supposons que l’assistant doive répondre avec trois lignes étiquetées correspondant au problème, aux preuves et à l’action à entreprendre :

Issue: ...
Evidence: ...
Action: ...

Une démonstration en direct rend ce layout concrètement visible immédiatement :

Input:
"The login token expired after 30 days."
Output:
Issue: Expired authentication token
Evidence: Token expiration is reported after 30 days
Action: Regenerate the authentication token

Cela corrige à la fois le modèle de contenu et sa présentation. Cependant, les exemples ne sont pas toujours la solution idéale. Si un logiciel a besoin de JSON lisible par machine avec une validité garantie, une fonction de sortie contrainte par un schéma peut s’avérer plus fiable que de montrer au modèle un échantillon.

Assurer la cohérence des exemples

Les prompts à faible quantité d’exemples réagissent mal aux contradictions. Prenons deux démonstrations avec la même entrée, « Impossible de se connecter », étiquetée ACCOUNT dans l’une et TECHNICAL dans l’autre :

Example 1:
"Can't log in" → ACCOUNT
Example 2:
"Can't log in" → TECHNICAL

Le modèle ne dispose d’aucun moyen systématique pour déterminer quel mappage est prévu. Des incohérences plus subtiles sont également préjudiciables. Si certains exemples utilisent l’étiquette « BILLING » tandis que d’autres utilisent l’expression « Billing issue », l’espace de sortie devient flou. Les étiquettes, le formatage, la terminologie, le niveau de détail ainsi que la gestion des cas limites doivent être cohérents dans tous les exemples. Les démonstrations font partie de la spécification et méritent la même attention.

Apprentissage à l’intérieur de la fenêtre

L’apprentissage in-context est l’idée générale derrière l’incitation à l’aide de quelques exemples : les exemples se trouvent dans le contexte actuel, ce qui modifie le comportement pour cette interaction. Cela ne signifie pas que le modèle les ait absorbés de manière permanente. Si l’application envoie un exemple étiqueté puis un message de l’utilisateur indiquant qu’il ne peut pas accéder à son compte :

Example:
"Password reset email never arrived." → ACCOUNT
User:
"I can't access my account."

Le modèle peut utiliser la démonstration pour cette demande. Ses paramètres ne sont pas mis à jour et l’exemple n’est pas ajouté à sa connaissance permanente. Cela reflète la distinction entre contexte et mémoire évoquée précédemment. Les méthodes qui modifient effectivement les paramètres, comme le réglage fin à l’aide de données d’entraînement supplémentaires, constituent un mécanisme distinct, et leur comparaison avec l’incitation par des exemples intervient beaucoup plus tard. Pour l’instant, l’incitation par quelques exemples doit être considérée comme une conditionnement temporaire de la tâche fourni par le contexte.

Choix entre les deux approches

Un processus de décision efficace commence par définir en quoi la sortie est incorrecte. Une tâche ambiguë nécessite des formulations plus claires. Le manque d’informations exige un meilleur contexte. Lorsque le modèle néglige une convention subtile, des exemples peuvent être utiles. Si la tâche requiert des calculs mathématiques précis ou un accès à une base de données, davantage de texte dans l’incitation peut être complètement inadapté.

Ce dernier cas nous amène sur un terrain plus difficile. Certaines tâches sont trop complexes pour être gérées de manière fiable avec une seule instruction et une seule réponse. Il faut les diviser en opérations plus petites, les vérifier ou les relier à des calculs externes. Au-delà d’un certain point, le défi n’est plus de trouver la phrase parfaite, mais de concevoir une petite procédure que le modèle doit suivre.

Considérons un ticket dans lequel un client se voit bloqué immédiatement après un changement de mot de passe, et où l’assistant doit examiner l’historique, identifier la cause probable et rédiger une réponse. Cela semble être une seule tâche. En réalité, cela cache plusieurs tâches : déterminer ce qui s’est passé, trouver les preuves pertinentes, séparer les faits des suppositions, raisonner sur les causes possibles, décider de ce qui peut être recommandé en toute sécurité, vérifier cette recommandation et rédiger la réponse finale. Comprendre cela constitue la porte d’entrée vers la décomposition.

Décomposer une tâche en plusieurs

La décomposition remplace une tâche complexe par plusieurs tâches plus petites ayant des limites claires. Au lieu de demander tout en une seule fois, l’application peut organiser la demande en étapes :

Task:
Analyze this customer support case.

Step 1:
Extract the relevant facts.

Step 2:
Identify the customer's actual problem.

Step 3:
List plausible causes supported by the evidence.

Step 4:
Select the safest supported resolution.

Step 5:
Draft the customer-facing response.

Le modèle n’a pas besoin littéralement du mot « Étape ». Ce qui compte, c’est qu’un objectif vague se transforme en une séquence d’opérations gérables. Cela est particulièrement utile lorsque les différentes tâches ont des natures distinctes : l’extraction de faits relève d’une tâche d’information, le choix d’un diagnostic est un acte de raisonnement, et l’écriture du message constitue une forme de communication. Les regrouper en une seule instruction non différenciée rend le résultat plus difficile à diriger et à évaluer.

Un système décomposé offre également davantage d’occasions de tester. Si la réponse finale est incorrecte, on peut déterminer si c’est l’extraction des faits, le diagnostic ou l’écriture de la réponse qui a échoué. La mentalité à adopter est celle d’une chaîne de traitement plutôt que celle d’une simple question.

Planifier d’abord, puis agir

Une technique apparentée demande au modèle d’établir un plan avant d’effectuer une tâche complexe. Cela est utile lorsque le modèle doit déterminer quelles opérations sont nécessaires avant de pouvoir répondre. L’assistant de soutien peut commencer par un objectif et un plan ordonné :

Goal:
Resolve the customer's login problem using only supported evidence.
Plan:
1. Read the latest customer message.
2. Check the relevant conversation history.
3. Identify authentication-related evidence.
4. Compare the evidence with the known troubleshooting guidance.
5. Produce a response that does not claim unsupported facts.

La planification sépare la décision sur la manière de résoudre un problème de sa résolution effective. Cette séparation devient encore plus importante lorsqu’on utilise des outils, car le modèle peut devoir déterminer s’il doit d’abord consulter une base de connaissances, examiner un enregistrement de compte ou effectuer un calcul. Les indications permettent d’établir la structure du travail avant même qu’il ne commence.

Cela a un coût : la décomposition augmente la longueur des instructions, et lorsque chaque étape nécessite une appel distinct, cela entraîne également davantage d’appels du modèle et plus de latence. Un processus en cinq étapes peut coûter bien plus cher qu’un seul appel. Cela en vaut la peine lorsque le contrôle et la fiabilité supplémentaires justifient ce coût, et non parce que davantage d’étapes sont intrinsèquement meilleures.

Generer, critiquer, réviser

Un autre mécanisme efficace permet au modèle de reconsidérer son propre brouillon. La première réponse n’est pas considérée comme définitive ; une seconde étape l’examine en fonction de critères précis. Pour le système de soutien, cela signifie rédiger la réponse puis la vérifier à l’aide d’une liste de problèmes identifiés :

First:
Draft the response.

Then:
Check the draft for:
- unsupported claims,
- missing evidence,
- incorrect troubleshooting steps,
- promises the support team cannot make,
- failure to answer the customer's actual question.

Finally:
Revise the response to correct any problems.

Cela fonctionne parce que la production et l’évaluation sont des tâches distinctes. Générer signifie créer quelque chose de plausible. Examiner une réponse existante permet au modèle de rechercher des violations d’une liste de contrôle. Préciser les critères est généralement plus efficace que de lui demander de réfléchir davantage.

Cette approche s’adapte à différentes profondeurs : brouillon, révision, réponse finale, ou, pour une tâche plus structurée, extraction, vérification de l’extraction, classification, vérification de la classification, génération. La deuxième forme est plus facile à déboguer, car chaque étape dispose d’un contrat bien défini.

Une limite est importante : un modèle invité à se critiquer n’en devient pas pour autant une source indépendante de vérité. Si la réponse initiale repose sur une hypothèse fausse, le critique peut la partager. La autocritique peut améliorer la cohérence sans garantir la justesse, et pour des décisions à haut risque, il est utile de la vérifier à l’aide d’éléments extérieurs au modèle : une base de données, une règle connue, un calcul, un document récupéré ou du code déterministe.

Indications qui révèlent la structure de raisonnement

Des recherches sur les indications de type « chain-of-thought » ont montré que présenter à un modèle des exemples avec des étapes de raisonnement intermédiaires peut améliorer les résultats sur certains problèmes à plusieurs étapes, avec des gains constatés dans des tests arithmétiques, de bon sens et symboliques. La leçon d’ingénierie est plus large que cette simple phrase : une tâche complexe peut bénéficier lorsque l’indication rend explicite sa structure intermédiaire.

Identify the relevant facts.
Determine which facts support each possible conclusion.
Eliminate conclusions that require unsupported assumptions.
Select the conclusion supported by the evidence.

Il s’agit d’une incitation axée sur le raisonnement : on structure la tâche de manière à ce que les décisions intermédiaires soient suffisamment claires pour guider le modèle vers le résultat souhaité. Cela n’oblige pas une application de production à montrer à l’utilisateur le raisonnement interne du modèle. Souvent, une interface plus efficace demande simplement le résultat de la vérification, plutôt qu’une longue explication. L’application peut exiger un enregistrement interne compact comme celui ci-dessous, puis générer séparément une réponse courte pour le client :

classification: password_reset_issue
evidence_supported: true
recommended_action: resend_reset_link
confidence: high

La structure du raisonnement et l’explication destinée au client sont des exigences distinctes. Les séparer permet également d’éviter une erreur fréquente, à savoir supposer que plus le raisonnement est visible, plus la réponse est fiable. Les étapes intermédiaires peuvent elles aussi contenir des erreurs. Des études sur les prompts de type « chain-of-thought » ont montré que des propriétés des démonstrations, telles que leur pertinence et leur ordre, ont une grande importance ; par conséquent, ajouter simplement de longues justifications ne constitue pas une solution universelle.

Plusieurs tentatives, puis un vote

La génération est probabiliste, de sorte qu’un même problème peut produire des réponses différentes selon les exécutions. La cohérence interne exploite ce principe en échantillonnant plusieurs chemins de raisonnement et en choisissant la réponse que la plupart d’entre eux soutiennent, plutôt que de se fier à un seul chemin échantillonné.

Supposons que le système de support ne soit pas sûr de savoir s’il s’agit d’un problème de réinitialisation de mot de passe ou d’un blocage de compte. Au lieu d’accepter une seule classification, il pourrait générer plusieurs analyses et comparer les classifications qui en résultent.

L’accord entre ces analyses n’équivaut pas pour autant à la vérité. Si le modèle interprète constamment mal la situation, de nombreuses générations indépendantes peuvent aboutir à la même réponse erronée. La cohérence est un signe de stabilité, mais pas une preuve de justesse. De plus, elle entraîne plus de calculs et augmente la latence, ce qui ne la rend attractive que pour des tâches suffisamment complexes pour que l’amélioration de la fiabilité justifie les coûts.

Où les instructions doivent céder la place au code

C’est ici que se situe la frontière entre des instructions de plus en plus complexes et une bonne conception de système. Imaginez qu’on demande le total d’une facture comprenant 17 articles à 1500 ₹ chacun. Un modèle peut probablement calculer cette somme, mais lorsque des chiffres financiers exacts sont importants, il n’y a aucune raison de le faire simuler des opérations arithmétiques à l’aide d’instructions de plus en plus longues. Une calculatrice ou un programme ordinaire effectue ces multiplications de manière déterministe.

La même logique s’applique à d’autres tâches :

  • Les données comptables doivent provenir d’une requête de base de données, et non de la mémoire du modèle.
  • Les faits actuels doivent être récupérés, et non rappelés à partir de l’entraînement.
  • Les opérations arithmétiques relèvent d’une calculatrice ou d’un programme.
  • Vérifier un schéma est le travail d’un analyseur et d’un validateur.
  • L’autorisation relève du code d’application et des règles de contrôle d’accès.
  • Les règles métier critiques doivent être codées de manière déterministe chaque fois que c’est possible.

Une règle utile est la suivante : utilisez des prompts pour guider le comportement des modèles de langage, et recourez à du logiciel déterministe lorsque la tâche exige réellement un calcul ou une application déterministes.

Les actions externes précisent encore ce point. ReAct, une approche de recherche bien connue, alterne raisonnement et actions afin que le modèle puisse consulter des sources ou des environnements externes plutôt que de se fier uniquement à ses connaissances internes, et il a montré que cette interaction peut atténuer des problèmes tels que les hallucinations et la propagation des erreurs dans certaines tâches.

C’est le lien vers ce qui vient ensuite. Le système de soutien a commencé en tant que prompt et ressemble maintenant à un petit programme. Lorsque la vérification nécessite une base de données, une base de connaissances, une API ou une autre capacité externe, le modèle ne fonctionne plus uniquement sur du texte, et la question se déplace vers l’ingénierie de contexte : il s’agit de décider non seulement quelles instructions écrire, mais aussi quelles informations le modèle doit recevoir.