Module 02 · Leçon 2

Donner des exemples : le few-shot

Classer des messages d'utilisateurs en quatre catégories – sans exemple, 18 bonnes réponses ; avec 4 exemples, 20. Comment choisir les exemples, combien en mettre, et quels effets secondaires ils entraînent.

  • Environ 30 minutes
  • Niveau : Débutant
  • Testé : 2026-09-14 deepseek-flash

Le code et les sorties des programmes sont reproduits tels qu’ils ont tourné : commentaires et sorties sont donc en chinois.

Certaines exigences sont difficiles à formuler en mots. Où passe la frontière entre « bug » et « question d'utilisation » ? Un utilisateur demande « le cookie disparaît après une redirection, est-ce que je m'y prends mal ? » : dans quelle catégorie le ranger ? Vous pourriez écrire une longue définition, mais donner directement quelques exemples va souvent plus vite.

Montrer au modèle quelques exemples « entrée → sortie » pour qu'il les imite s'appelle le few-shot (few-shot prompting, apprentissage par quelques exemples). Le faire travailler sans exemple s'appelle le zero-shot.

Expérience : classer des messages d'utilisateurs

Les mainteneurs de httpx reçoivent chaque jour toutes sortes de messages. Nous voulons que le modèle les classe automatiquement en quatre catégories : bug, suggestion de fonctionnalité, question d'utilisation, autre. J'ai préparé 20 messages, chacun étiqueté à la main avec la bonne catégorie, par exemple :

TESTS = [
    ("用 AsyncClient 并发 100 个请求,程序直接卡死,CPU 占满", "缺陷"),
    ("能不能加一个像 requests 那样的 Session 重试适配器?", "功能建议"),
    ("怎么给单个请求设置不同的超时时间?", "使用问题"),
    ("你们的文档网站打不开了", "其他"),
    # ……一共 20 条,每类 5 条,完整列表见 code/02-prompting/few_shot.py
]

Le prompt zero-shot n'explique que les règles de classement :

ZERO_SHOT = """把用户留言分成以下四类之一:缺陷、功能建议、使用问题、其他。
只输出类别名称。"""

Le prompt few-shot y ajoute 4 exemples, un par catégorie, et aucun de ces 4 messages ne figure dans le jeu de test :

FEW_SHOT = ZERO_SHOT + """

例子:
留言:调用 client.close() 之后再发请求没有报错,而是静默返回了旧的响应
类别:缺陷

留言:想要一个参数,能在请求失败时自动打印完整的请求和响应
类别:功能建议

留言:base_url 和 url 拼接的规则是什么?结尾的斜杠有没有影响
类别:使用问题

留言:这个项目和 aiohttp 比哪个更好
类别:其他"""

Chaque message est envoyé au modèle au format 留言:{text}\n类别: (message : … catégorie :), température à 0, réflexion désactivée, puis comparé à l'étiquette humaine :

def classify(system, text):
    response = client.chat.completions.create(
        model=MODEL,
        messages=[{"role": "system", "content": system}, {"role": "user", "content": f"留言:{text}\n类别:"}],
        temperature=0,
        extra_body={"thinking": {"type": "disabled"}},
    )
    return response.choices[0].message.content.strip()

Mon résultat :

零样本:答对 18/20,格式不对 0 条 []
    怎么给单个请求设置不同的超时时间?  标注=使用问题  模型=功能建议
    你们的文档网站打不开了  标注=其他  模型=缺陷
少样本:答对 20/20,格式不对 0 条 []

Où le zero-shot se trompe

Regardons les deux erreurs du zero-shot.

« Comment définir un délai d'expiration différent pour une seule requête ? » a été classé comme suggestion de fonctionnalité. Le modèle a sans doute compris « l'utilisateur veut une fonctionnalité pour définir le délai d'une seule requête ». Or httpx prend cela en charge depuis longtemps ; l'utilisateur ne sait simplement pas comment l'écrire.

« Votre site de documentation ne s'ouvre plus » a été classé comme bug. À la lettre, un site qui ne s'ouvre pas est bien un bug, mais notre « bug » désigne les problèmes de la bibliothèque httpx elle-même ; le site de documentation relève de « autre ».

Aucune de ces erreurs ne vient d'un modèle stupide : les critères de classement ont des zones floues, et mes règles ne les précisaient pas. Avec des exemples, le modèle a compris, à partir de « quelle est la règle de concaténation entre base_url et url », que « demander comment faire = question d'utilisation », et à partir de « ce projet ou aiohttp, lequel est le meilleur » que « sans rapport avec la bibliothèque elle-même = autre ». Les exemples ont précisé les règles à ma place.

Vous pourriez aussi, sans exemples, écrire des règles plus détaillées : « une question sur “comment faire” est une question d'utilisation, même si elle ressemble à une demande de fonctionnalité », « seuls les problèmes de comportement de la bibliothèque httpx elle-même sont des bugs ». Cela fonctionne aussi, et économise des tokens. En pratique, on combine souvent les deux : les règles pour l'essentiel, les exemples pour les détails.

Comment choisir les exemples

Couvrir chaque sortie possible. Un exemple pour chacune des quatre catégories. Si vous ne donnez que des exemples de « bug » et de « question d'utilisation », le modèle produira rarement les deux autres.

Choisir des exemples à la frontière. Les exemples les plus précieux ne sont pas les plus typiques, mais ceux qu'on classe le plus facilement de travers. « Après avoir appelé close(), une nouvelle requête ne provoque pas d'erreur » en est un bon : il ressemble à une question d'utilisation, mais révèle en réalité un problème de comportement de la bibliothèque.

Les séparer du jeu de test. Les exemples ne doivent pas figurer dans le jeu de test, sinon cela revient à donner les réponses au modèle, et la précision est artificiellement gonflée. Les 4 exemples de cette expérience ont été écrits à part.

Même format que les vraies entrées. Les exemples utilisent le format « message : … catégorie : … », et les vraies requêtes le même. Le modèle imite rigoureusement le format des exemples ; le format des exemples est donc le format de sortie que vous voulez. Dans cette expérience, ni le zero-shot ni le few-shot n'ont eu d'erreur de format, mais quand vous exigez une sortie plus complexe (du JSON par exemple), un exemple au bon format réduit fortement les problèmes de format.

Combien en mettre

En général, 3 à 5 suffisent. Plus il y a d'exemples, plus chaque requête est longue et plus elle coûte. Heureusement, les exemples sont fixes ; placés dans le message system, ils sont servis depuis le cache.

Si le résultat n'est toujours pas assez bon, demandez-vous d'abord si les exemples sont bien choisis, avant d'en ajouter. 10 exemples semblables valent moins que 3 exemples couvrant des cas limites différents.

Les effets secondaires des exemples

Les exemples sont très efficaces, et donc aussi très capables d'égarer le modèle.

Le modèle imite tout dans les exemples. Si toutes les réponses des exemples sont courtes, celles du modèle raccourcissent aussi ; si les exemples sont tous en chinois, face à un message anglais il répondra peut-être quand même avec le nom de catégorie chinois (ce qui, ici, est voulu). Il imite aussi des traits que vous ne vouliez pas lui faire imiter.

Le modèle peut recopier le contenu des exemples. Dans une tâche de génération (écrire des descriptions de produits, par exemple), si tous les exemples parlent de café, le modèle risque de glisser du vocabulaire du café dans une description de thé. Les exemples doivent donc être variés et différer par leur contenu.

L'ordre et les proportions comptent. Si 4 exemples sur 5 sont des « bugs », le modèle aura tendance à classer davantage en « bug ». Équilibrez autant que possible le nombre d'exemples par catégorie.

Problèmes courants

Mettre les exemples dans le message system, ou sous forme de conversation à plusieurs tours ? Les deux marchent. Ci-dessus, les exemples sont écrits dans le message system. L'autre méthode fait de chaque exemple une paire de messages user et assistant placée avant la vraie question, comme si le modèle avait déjà répondu ainsi plusieurs fois. Cette seconde méthode est particulièrement efficace pour faire imiter un format, mais la liste de messages s'allonge et devient plus difficile à maintenir. Je commence en général par le message system, et je change si le format pose problème.

Il y a beaucoup de catégories, par exemple 30 ; un exemple par catégorie, c'est trop long. Que faire ? Voyez d'abord si l'on peut classer en deux niveaux : grandes catégories, puis sous-catégories. Ou ne donnez des exemples que pour les catégories qui se confondent facilement. Plus avancé : utiliser les embeddings de la leçon 5 du module 01 pour trouver, dans une grande banque d'exemples, les quelques-uns les plus proches de l'entrée courante, et ne mettre qu'eux dans le prompt. C'est le few-shot dynamique, sur le même principe que le RAG du module 04.

Ce que cette expérience ne prouve pas

20 données de test, c'est trop peu. L'écart entre 18 et 20 pourrait devenir 19 contre 20, voire s'inverser, avec un autre lot de données. Cette expérience illustre concrètement que « le few-shot aide sur ce type de tâche » ; elle ne prouve pas que « le few-shot augmente la précision de 10 % ». Pour comparer de façon fiable deux prompts, il faut plus de données de test ; c'est l'objet de la leçon 5.

Exercices

  1. Réduisez les exemples du prompt few-shot à 2 (seulement « bug » et « question d'utilisation »), relancez, et voyez comment évolue la précision des catégories « autre » et « suggestion de fonctionnalité ».
  2. Mettez volontairement 4 exemples qui sont tous des « bugs », et voyez si le modèle classe davantage en « bug ».
  3. Écrivez vous-même 10 messages supplémentaires, de préférence ceux que même vous devez réfléchir pour bien classer, ajoutez-les au jeu de test et relancez. L'écart entre zero-shot et few-shot grandit-il ou diminue-t-il ?
  4. Sans exemples, ajoutez aux règles zero-shot deux précisions (« une question sur comment utiliser, même si elle ressemble à une demande de fonctionnalité, est une question d'utilisation », « ce qui concerne la documentation ou la communauté relève de autre ») et voyez si vous atteignez le même résultat qu'avec le few-shot.

Auto-test

1. Pourquoi les exemples d'un prompt few-shot ne doivent-ils pas figurer dans le jeu de test ?

Les exemples donnent au modèle la bonne réponse pour ces entrées. Si le jeu de test contient les mêmes entrées, le modèle n'a qu'à recopier pour répondre juste ; la précision mesurée est gonflée et ne reflète pas son comportement réel sur de nouvelles données.

2. Vous donnez 5 exemples au modèle, dont 4 sont des « bugs ». Quel problème cela peut-il poser ?

Le modèle aura tendance à classer davantage de messages en « bug », car la proportion des exemples suggère que « la plupart des messages sont des bugs ». Le nombre d'exemples par catégorie doit être aussi équilibré que possible, avec au moins un exemple pour chaque sortie.

3. Pour choisir les exemples, faut-il prendre les plus typiques ou ceux qu'on classe le plus facilement de travers ?

De préférence ceux qu'on classe le plus facilement de travers, à la frontière. Le modèle classe déjà bien les exemples typiques ; ce sont les exemples limites qui l'aident à comprendre les règles des zones floues.

Questions et discussion

Bloqué sur cette leçon ? Posez votre question ici. Et si vous pouvez répondre à quelqu'un, n'hésitez pas.

Une question rapporte 3 points, une réponse 6. Les messages paraissent après vérification.

Chargement de la discussion…