Aller au contenu
English

Classer des demandes bancaires avec un LLM

  • Étude de cas 3
  • 120 min
  • Facultative · 1 étude de cas requise pour le certificat

Ce que vous saurez faire

Découvrez si une requête peut remplacer un modèle entraîné. Vous acheminez de vrais messages de soutien bancaire vers 77 intentions avec un TermeModèle hébergéUn modèle qui fonctionne sur les ordinateurs d’un fournisseur. Votre code lui envoie des requêtes par Internet, et vous payez chaque appel.En savoir plus Modèle hébergé ou autohébergéLes LLM : comment ils fonctionnent et comment en choisir un, une requête et un schéma strict. Vous n’utilisez aucun exemple d’entraînement. Vous le comparez ensuite honnêtement aux modèles d’acheminement entraînés sur 9 003 messages étiquetés. Vous comparez l’exactitude, les erreurs, le coût, la vitesse et les données qui quittent la banque.

Étude de casPièce de portfolio

Licence
CC BY 4.0
Durée
Environ 2 h
S’exécute dans
Colab, Kaggle ou VS Code
Compétences utilisées
  • Versions des requêtes
  • Sortie structurée avec une grande énumération
  • Validation dans le code
  • Comparaison équitable
  • Intervalles de confiance
  • Coût par 1 000 requêtes
  • Recours à une personne
  • Minimisation des données

Les carnets sont en anglais. Colab et Kaggle ouvrent votre propre copie. Pour utiliser VS Code, téléchargez le carnet depuis GitHub. Vous êtes bloqué ? Consultez le carnet de solution.

Cette étude de cas est une analyse. Elle prend donc la forme d’un carnet (notebook) Jupyter, pas d’un dossier de projet. Le code de l’application est court : un fichier de requête, un schéma et une vérification, comme aux modules 2 et 3. Le vrai travail consiste à mesurer environ 6 000 réponses enregistrées et à prendre une décision à partir des résultats. Le carnet rejoue les vraies réponses. Vous n’avez donc besoin ni de compte ni de clé, et l’exécution prend moins d’une minute. Un appel réel à un modèle local ou avec votre propre clé est facultatif, dans la dernière cellule.

Avant de commencerCe qu’il faut savoir et avoir sous la mainEnviron 120 minutes

Ce que vous devez savoir

Cette étude de cas utilise surtout les modules 2 et 3 :

L’étude de cas Faire le réglage fin d’un petit transformeur du cours d’apprentissage profond a entraîné les modèles d’acheminement comparés ici. La connaître est utile, mais pas nécessaire : cette page reprend ses mesures.

Ce qu’il vous faut sur votre ordinateur

Rien : le carnet fonctionne dans Colab ou Kaggle. Pour l’exécuter dans VS Code, utilisez un environnement virtuel avec pandas, scikit-learn et pydantic (version 2). Nous l’avons testé dans Jupyter sur macOS, en repartant de zéro, avec Python 3.12, pydantic 2.14.0 et scikit-learn 1.9.1. Nous ne l’avons pas exécuté dans Colab ou Kaggle.

Les modèles et les API changent vite. Les réponses, les prix et les durées de cette page représentent un instant précis. C’est la méthode qui dure.

Nadia dirige l’équipe de soutien d’une banque en ligne. Les clients écrivent de courts messages dans le clavardage de l’application : « Ma carte n’est toujours pas arrivée », « Pourquoi mon ajout de fonds a-t-il échoué? ». Chaque message doit être associé à l’une des 77 intentions. Chaque intention a son propre processus de réponse. Dans le cours d’apprentissage profond, Kofi, l’ingénieur en apprentissage automatique de la banque, a entraîné un modèle d’acheminement pour cela. Son modèle DistilBERT au TermeRéglage finUn entraînement de plus d’un modèle préentraîné sur vos propres exemples étiquetés, pour qu’il fasse bien une tâche. Ses poids changent un peu.En savoir plus Entraînement et inférenceL'apprentissage profond et les transformeurs expliqués a choisi la bonne intention pour 91,8 % des messages de test. Il a appris à partir de 9 003 messages que des personnes avaient étiquetés à la main.

Leila, une développeuse de l’équipe de l’application, a une autre idée. « Pourquoi entraîner un modèle? Un modèle de langage hébergé peut lire les 77 intentions et en choisir une. Pas d’étiquettes, pas d’entraînement, en service demain. » Nadia pose les questions qui permettront de décider :

  • Est-il aussi exact que le modèle d’acheminement de Kofi, sur les mêmes messages?
  • Combien coûte chaque message, et quelle est sa vitesse?
  • Les messages contiennent des problèmes de carte, des montants et parfois des noms. Peuvent-ils quitter la banque?
  • Que se passe-t-il quand le modèle hésite?

Vous allez construire le classificateur de Leila avec les habitudes de ce cours. Il comprend des fichiers de requête versionnés, le texte du client entre des balises et une vérification dans le code. Une énumération des 77 intentions fait partie de la TermeSortie structuréeUne requête qui envoie au fournisseur le schéma de la réponse, pour que le modèle ne puisse écrire qu’une réponse de cette forme. Elle contrôle la forme, pas la vérité : l’application vérifie toujours chaque réponse.En savoir plus Définir un schémaCréer des applications fiables avec les API de LLM stricte. Vous comparez deux versions de requête sur 1 000 messages de validation fixes, puis ouvrez le fichier de test une seule fois. Ensuite, vous comparez les modèles d’acheminement entraînés sur les mêmes messages de test. Vous mesurez l’exactitude avec un TermeIntervalle de confianceUne plage autour d’une valeur mesurée, obtenue par une méthode qui contient la vraie valeur 95 fois sur 100. Si l’intervalle d’une différence ne contient pas zéro, la différence n’est probablement pas due au hasard.En savoir plus Estimer l'incertitudeMathématiques et statistiques essentielles pour l'IA, les erreurs, le coût et la latence par 1 000 messages. Vous mesurez aussi l’effet des règles qui envoient les messages incertains à une personne.

Le jeu de données est BANKING77, publié par l’entreprise PolyAI en 2020. Il contient 13 083 courts messages destinés au soutien bancaire en ligne, chacun associé à l’une des 77 intentions. L’article ne dit pas qui les a écrits. Traitez-les comme des messages réalistes, pas comme ceux des clients d’une seule banque.

Pourquoi ce jeu de données? L’étude de cas du cours d’apprentissage profond l’a utilisé. Vous pouvez donc évaluer le modèle de langage sur exactement les messages qui ont servi à évaluer les modèles d’acheminement entraînés. La fiche du jeu de données, dans le dossier du carnet, présente les autres candidats, comme CLINC150. Elle explique pourquoi ils n’ont pas été retenus.

La répartition vient aussi du cours d’apprentissage profond. Les données de validation comprennent 1 000 messages du fichier d’entraînement officiel et servent à comparer les requêtes. Le fichier de test officiel, avec 3 080 messages, soit 40 par intention, reste fermé jusqu’à la fin. Le carnet reconstruit le modèle d’acheminement TF-IDF du cours avec les 9 003 autres messages. Il obtient exactement les mêmes résultats : 88,0 % en validation et 89,0 % au test.

Trois intentions montrent la difficulté :

train, valid = train_test_split(raw_train, test_size=1000, stratify=[r["category"] for r in raw_train], random_state=0)
test = raw_test
print(len(train), "train |", len(valid), "valid |", len(test), "test |", len({r["category"] for r in raw_train}), "intents")
for intent in ("card_arrival", "card_delivery_estimate", "get_physical_card"):
print(f"{intent:24}", [r["text"] for r in train if r["category"] == intent][:2])

La sortie :

9003 train | 1000 valid | 3080 test | 77 intents
card_arrival ['Is my card lost? I am still waiting for it to be delivered.', "It's been a week since you issued me a card and I still didn't get it. Should I keep waiting?"]
card_delivery_estimate ['How long does it take for my physical card to be delivered.', 'how long does delivery take?']
get_physical_card ["I didn't get a PIN yet. What gives?", "I haven't received my pin"]

Ce que cela nous dit. card_arrival (arrivée de la carte) concerne une carte en retard. card_delivery_estimate (estimation de livraison de la carte) concerne les délais de livraison avant tout retard. Certains messages peuvent prêter à discussion. Et get_physical_card (obtenir une carte physique) concerne surtout le NIP d’une nouvelle carte, pas l’obtention d’une carte. Le nom ne dit pas ce que la banque entend par là. Un modèle entraîné l’apprend à partir des exemples. Un modèle qui ne voit que le nom ne le peut pas.

  • L’unité : un message, tel que le client l’envoie. La cible : l’intention, parmi les 77.
  • La mesure : l’exactitude, la proportion de messages acheminés vers la bonne intention, avec un intervalle à 95 %. Chaque mauvaise intention coûte à peu près autant : un message de plus d’un client mécontent. Toujours choisir l’intention la plus fréquente donne une réponse correcte pour 1,9 % des messages de validation et 1,3 % des messages de test.
  • Autres mesures : le coût et la latence par 1 000 messages, l’effort de mise en place et les données qui quittent la banque.

La nouvelle idée : un modèle d’acheminement sans exemples d’entraînement

Section intitulée « La nouvelle idée : un modèle d’acheminement sans exemples d’entraînement »

Lors d’une journée chargée, Nadia fait venir un agent temporaire qui a travaillé au soutien d’autres banques. Elle lui donne la liste des 77 intentions. Il achemine bien les messages clairs, car il sait comment les clients écrivent. Mais il ne connaît pas les habitudes de cette banque. Il ne peut pas savoir qu’« obtenir une carte physique » concerne le NIP. Il ignore aussi où finit le retard d’une carte et où commence une question de livraison. Une note d’une ligne à côté de chaque intention l’aiderait beaucoup.

Le modèle voit ce que voit l’agent temporaire. La requête v1 ne présente que les 77 noms. Avec elle, chat-small a correctement acheminé 0 des 11 messages get_physical_card des données de validation. « Où puis-je trouver le NIP de ma carte? » a été associé à change_pin (changer le NIP). C’est une interprétation raisonnable du nom, mais elle est incorrecte pour cette banque.

Classer avec seulement une description des classes, sans exemples étiquetés dans la requête, s’appelle la classification sans exemple (zero-shot classification). « Shot » désigne un exemple montré au modèle : ici, zéro exemple. Avec quelques exemples dans la requête, c’est la classification avec quelques exemples (few-shot). Le modèle apporte ce qu’il a appris au préentraînement; la requête apporte les définitions de la banque. La liste des intentions et leur sens constituent donc la spécification. Rédigez-la avec le soin d’une politique, comme celle de TermeGraceLa responsable du service d’assistance de Larkfield. Elle écrit la politique de support et décide ce qu’est une bonne réponse à un client. pour TermeLarkfieldUne boutique en ligne d’articles pour la maison. Ce n’est pas une vraie entreprise. Tous les cours Nextia utilisent son service d’assistance et ses données comme exemple.En savoir plus L'IA dans les produits de tous les joursBases d'une carrière en IA : rôles, compétences et feuilles de route dans Préciser la tâche.

La requête v2 reprend v1 et ajoute une ligne par intention. L’équipe du cours l’a rédigée à partir des noms et de quelques messages d’entraînement pour chaque intention. Aucun message de validation ou de test n’a été utilisé. Voici deux des 77 lignes :

- card_arrival: An ordered card has not arrived yet, and the customer asks where it is.
- get_physical_card: Getting the PIN for a new physical card: where to find it or how to set it.

Les trois mêmes messages de validation, traités par chat-small (gpt-6-luna sur Azure) avec chaque requête :

Message Intention réelle v1 (noms seulement) v2 (noms + une ligne)
Où puis-je trouver le NIP de ma carte? get_physical_card change_pin ✗ get_physical_card ✓
Comment suivre la carte que vous m’avez envoyée? card_arrival card_delivery_estimate ✗ card_arrival ✓
J’ai commandé ma carte il y a quelques semaines et je ne l’ai toujours pas reçue. Quand arrivera-t-elle? card_delivery_estimate card_delivery_estimate ✓ card_arrival ✗

La ligne corrige la question du NIP. Elle déplace aussi la frontière entre les deux intentions liées aux cartes, dans les deux sens. Une définition aide, mais elle ne peut pas trancher une étiquette qui prête à discussion.

Deux façons de construire le modèle d'acheminement. En haut : le modèle entraîné du cours d'apprentissage profond. L'entraînement utilise 9 003 messages étiquetés, chacun avec son intention, et prend quelques minutes sur un processeur. Il produit un fichier de modèle sur les serveurs de la banque. Un nouveau message entre dans ce modèle, qui donne l'intention et une probabilité. En bas : le modèle d'acheminement par requête de cette étude de cas. Une personne rédige les 77 noms d'intention et une ligne pour chacun. Ils deviennent une requête et un schéma avec une énumération de 77 intentions. Un nouveau message les accompagne vers un modèle hébergé et quitte ainsi la banque. Le code vérifie ensuite la réponse selon le schéma, pour obtenir l'intention et la confiance déclarée par le modèle.
Le modèle d'acheminement entraîné apprend les intentions de la banque à partir d'exemples étiquetés et fonctionne sur ses serveurs. Le modèle d'acheminement par requête lit les définitions de la banque à chaque requête et fonctionne chez le fournisseur. Chaque message quitte donc la banque.
Description textuelle du diagramme

Deux rangées, chacune allant d’un nouveau message à une intention.

  1. Modèle d’acheminement entraîné (cours d’apprentissage profond) : l’entraînement utilise 9 003 messages étiquetés, chacun avec son intention. Il prend quelques minutes sur un processeur. Le résultat est un fichier de modèle sur les serveurs de la banque. Un nouveau message entre dans le modèle, qui donne l’intention et une probabilité.
  2. Modèle d’acheminement par requête (cette étude de cas) : une personne rédige les 77 noms d’intention et une ligne pour chacun. Ils deviennent la requête et le schéma avec une énumération de 77 intentions. Un nouveau message les accompagne vers un modèle hébergé : le message quitte la banque. Le code vérifie chaque réponse selon le schéma avant d’utiliser l’intention et la confiance déclarée par le modèle.

Quand l’utiliser, et ce que cela coûte. La classification sans exemple convient quand vous n’avez pas encore de données étiquetées ou quand les classes changent souvent. Ses coûts : des jetons (tokens) pour chaque message et un fournisseur qui voit chaque message. Un autre coût se cache derrière « pas de données d’entraînement » : il faut quand même des messages étiquetés pour savoir si cela fonctionne. Cette étude de cas en a utilisé 4 080.

Le classificateur reprend les éléments du projet du cours, avec un contrat différent. Le schéma est un modèle Pydantic avec deux champs obligatoires. Il est construit à partir de la même liste d’intentions que la requête. Les deux ne peuvent donc jamais diverger :

INTENTS = [line.split("\t")[0] for line in Path("prompts/intents.tsv").read_text().splitlines()]
IntentAnswer = create_model(
"IntentAnswer",
__config__=ConfigDict(extra="forbid"), # no other field allowed
intent=(Literal[tuple(INTENTS)], ...), # an enum of the 77 intents, required
confidence=(Literal["low", "medium", "high"], ...),
)
def response_format():
return {"type": "json_schema",
"json_schema": {"name": "banking_intent", "strict": True, "schema": IntentAnswer.model_json_schema()}}

create_model construit le même type de classe que TicketAnalysis dans Définir un schéma, mais à partir d’une liste. Personne ne devrait taper 77 noms deux fois. build_request() place le fichier de requête dans le message système et le texte du client entre des balises <message>. La requête v2 de Larkfield faisait de même.

Chaque réponse enregistrée passe ensuite par la barrière 1, la vérification Pydantic de Traiter les résultats incomplets :

valid1000_chat-small_v1 1000 answers {'valid': 1000}
valid1000_chat-small_v2 1000 answers {'valid': 1000}
valid300_chat-small_v1_text 300 answers {'valid': 300}
test_chat-small_v2 3080 answers {'valid': 3080}
test770_chat-strong_v2 770 answers {'valid': 770}

Ce que cela nous dit. Avec la sortie structurée stricte, les 5 850 réponses étaient du JSON complet contenant l’une des 77 intentions. Aucune n’a été coupée ou refusée.

Une énumération de 77 valeurs est grande. Leila a donc vérifié la limite du fournisseur par un vrai essai. Une énumération de 1 000 valeurs a été acceptée. Avec 1 001 valeurs, chat-small a refusé la requête avant l’exécution du modèle :

HTTP 400: Invalid schema for response_format 'many': Expected at most 1000 enum values in total within a single schema when using structured outputs, but received 1001. Consider reducing the number of enums, or use 'strict: false' to opt out of structured outputs.

L’énumération coûte aussi des jetons, car le schéma accompagne chaque requête. Pour 77 intentions, il ajoute environ 460 jetons d’entrée par message. La TermeMédianeLa valeur du milieu quand on trie les valeurs. La moitié est plus basse, l’autre plus haute. Un seul appel très lent la change peu : c’est un bon temps « habituel ».En savoir plus Mesurer la performance en pratiqueLes LLM : comment ils fonctionnent et comment en choisir un de v1 est de 1 069 jetons d’entrée avec le schéma, et de 612 sans lui.

Modèle d’acheminement Validation (1 000) Méthode de construction
Toujours l’intention la plus fréquente 1,9 % Comptage
TF-IDF + régression logistique 88,0 % Entraînement sur 9 003 messages étiquetés, environ 1 seconde
DistilBERT au réglage fin 91,6 % Entraînement sur 9 003 messages étiquetés, environ 8 minutes sur un processeur

Les deux modèles d’acheminement entraînés viennent du cours d’apprentissage profond. Le carnet reconstruit TF-IDF et reprend les résultats de DistilBERT.

chat-small a répondu aux 1 000 messages de validation avec chaque requête. Le modèle, les messages et le code d’évaluation restent identiques, comme dans Comparer des requêtes.

1 000 messages de validation. chat-small est gpt-6-luna sur Azure. TF-IDF est le modèle d'acheminement du cours d'apprentissage profond, entraîné sur 9 003 messages étiquetés. En bas : la différence appariée v2 − v1 sur les mêmes messages.
Description textuelle du graphique

Panneau du haut, trois rangées : TF-IDF entraîné sur 9 003 messages étiquetés, 88,0 % (intervalle à 95 % de 85,8 à 89,9). Termechat-smallLe nom que le code de Larkfield donne à un petit modèle hébergé peu coûteux : gpt-6-luna sur Azure. Le code utilise ce nom, donc le modèle peut changer sans modifier le code.En savoir plus Ce qu'est une API de LLMCréer des applications fiables avec les API de LLM avec la requête v1, noms seulement, 80,3 % (77,7 à 82,7). chat-small avec la requête v2, noms et une ligne chacun, 84,2 % (81,8 à 86,3). Panneau du bas : la différence appariée v2 moins v1 est de +3,9 points de pourcentage. Son intervalle à 95 % va de +2,3 à +5,5 et exclut clairement zéro.

Le carnet compte les messages pour lesquels une seule version donne la bonne réponse :

only v1 right 14 | only v2 right 53 | v2 - v1 = +3.9% (95% interval +2.3% to +5.5%)
v1: median 1069 input tokens per message
v2: median 1956 input tokens per message

Ce que cela nous dit. Les deux requêtes ont donné la même intention à 909 des 1 000 messages. Parmi les autres, v2 a corrigé 53 réponses et rendu 14 réponses incorrectes. L’intervalle apparié, de +2,3 à +5,5 points, exclut clairement zéro. Ce gain n’est donc pas le bruit d’échantillonnage que les 69 billets de soutien de Larkfield ne pouvaient pas exclure. Les corrections montrent l’effet des définitions. get_physical_card est passé de 0 sur 11 à 10 sur 11. « Comment savoir d’où vient l’argent? » est passé de receiving_money (recevoir de l’argent) à verify_source_of_funds (vérifier la provenance des fonds). Les 14 pertes concernent surtout les frontières déplacées par les lignes, comme celle entre carte en retard et délai de livraison.

Le prix : v2 envoie 1 956 jetons d’entrée par message au lieu de 1 069. Cela représente environ 0,23 $ US au lieu de 0,15 $ US par 1 000 messages avec chat-small. Pour 3,9 points, c’est peu cher. Leila choisit v2. Elle ouvre le fichier de test une seule fois, pour v2 uniquement.

Même v2 reste à 3,8 points derrière TF-IDF en validation. C’est le premier résultat honnête : 77 définitions d’une ligne ne contiennent pas encore ce que contiennent 9 003 messages étiquetés.

chat-small a répondu aux 3 080 messages de test avec v2. chat-strong coûte environ 18 fois plus par message. Il a donc répondu à un échantillon fixe de 770 messages de test, soit 10 par intention. Cet échantillon a été tiré avant de voir les réponses. Pour une comparaison équitable, le carnet (notebook) Jupyter évalue aussi chat-small et TF-IDF sur ces 770 messages.

En haut : les 3 080 messages de test. En bas : l'échantillon fixe de 770 messages de test auxquels chat-strong a répondu. chat-small est gpt-6-luna et chat-strong est gpt-6.1-sol, tous deux sur Azure, avec la requête v2. Les résultats de DistilBERT proviennent du cours sur l'apprentissage profond.
Description textuelle du graphique

Graphique du haut, les 3 080 messages de test : TF-IDF avec régression logistique, 89,0 % (intervalle à 95 % de 87,8 à 90,0). DistilBERT avec réglage fin, 91,8 % (90,7 à 92,7). chat-small avec la requête v2, 87,5 % (86,3 à 88,6). Graphique du bas, les 770 messages de l’échantillon : TF-IDF, 90,4 % (88,1 à 92,3). chat-small, 87,0 % (84,5 à 89,2). Termechat-strongLe nom que le code de Larkfield donne à un modèle hébergé plus grand : gpt-6.1-sol sur Azure. Il est souvent plus exact que chat-small et coûte environ 14 à 18 fois plus par appel.En savoir plus Les éléments d'une requêteCréer des applications fiables avec les API de LLM avec la requête v2, 89,1 % (86,7 à 91,1). Dans les deux graphiques, les routeurs guidés par requête égalent TF-IDF ou restent en dessous. DistilBERT obtient le meilleur résultat.

Routeur Messages de test Réponses correctes Exactitude (intervalle à 95 %)
TF-IDF + régression logistique 3 080 2 740 89,0 % (87,8–90,0)
DistilBERT avec réglage fin 3 080 2 826 91,8 % (90,7–92,7)
chat-small, requête v2 3 080 2 695 87,5 % (86,3–88,6)
chat-strong, requête v2 770 (échantillon) 686 89,1 % (86,7–91,1)
chat-small, les mêmes 770 770 670 87,0 % (84,5–89,2)

Ce que cela nous apprend. Sans exemple d’entraînement et avec une ligne par intention, chat-small achemine correctement 87,5 % des messages de test. Ce résultat approche celui du comptage de mots entraîné sur 9 003 étiquettes, sans l’égaler. Sur les mêmes messages, TF-IDF devance le modèle de 1,5 point, avec un intervalle apparié de +0,1 à +2,8. DistilBERT avec réglage fin devance les deux, avec 4,3 points de plus que chat-small. Tous les routeurs ont fait un peu mieux sur les données de test que sur les données de validation. Le cours sur l’apprentissage profond avait fait le même constat.

chat-strong dépasse chat-small sur les mêmes 770 messages : 22 messages que lui seul a réussis, contre 6 pour l’autre. Le gain est de 2,1 points (+0,7 à +3,4). Mais il ne dépasse pas TF-IDF sur ces messages (90,4 %) : on ne peut pas distinguer la différence de zéro. Le plus grand modèle apporte donc environ 2 points, pour environ 18 fois le prix par message.

Le bilan honnête : une requête a atteint environ le niveau d’un routeur entraîné par comptage de mots, sans aucun exemple d’entraînement. Elle n’a pas atteint le modèle avec réglage fin.

Le carnet compte les erreurs de chat-small sur les données de test par paire d’intentions, dans les deux sens :

Intention A Intention B Erreurs
beneficiary_not_allowed failed_transfer 18
declined_card_payment declined_transfer 12
card_payment_not_recognised direct_debit_payment_not_recognised 11
receiving_money topping_up_by_card 10
exchange_via_app fiat_currency_support 9
top_up_by_bank_transfer_charge transfer_fee_charged 9
card_arrival card_delivery_estimate 8

Plusieurs paires posaient aussi problème aux routeurs du cours sur l’apprentissage profond. Mais l’intention la moins bien reconnue révèle autre chose. beneficiary_not_allowed (bénéficiaire non autorisé) est correcte pour seulement 11 de ses 40 messages de test. Le modèle en a acheminé 18 vers failed_transfer (virement échoué). Lisez-les :

"I couldn't do a transfer to an account" → failed_transfer
"I want to buy cryptocurrency, but your app doesn't let me. Why?" → exchange_via_app

TF-IDF achemine les deux vers beneficiary_not_allowed, car les étiquettes d’entraînement indiquent cette intention. Dans ce jeu de données, une cryptomonnaie que l’application refuse d’acheter correspond à « bénéficiaire non autorisé ». Parmi les 140 messages d’entraînement de cette intention, 11 mentionnent les cryptomonnaies. Et 22 des 120 messages d’entraînement de declined_transfer (virement refusé) parlent d’un achat ou d’une carte. Le jeu de données étiquette « Quand j’essaie d’acheter quelque chose avec ma carte, le paiement est toujours refusé » comme declined_transfer. Le modèle répond declined_card_payment (paiement par carte refusé), et la plupart des gens seraient d’accord avec lui.

Voilà la vraie différence entre les deux routeurs. Un routeur entraîné apprend les conventions de la banque à partir de ses exemples, même les conventions étranges. Un routeur guidé par requête connaît seulement ce que disent les définitions. La correction se trouve dans les définitions, par exemple une ligne v3 qui mentionne les achats de cryptomonnaies. Comparez ensuite v3 à v2 sur les données de validation.

Les deux routeurs échouent-ils sur les mêmes messages?

TF-IDF correct TF-IDF incorrect
chat-small correct 2 487 208
chat-small incorrect 253 132

Seulement 132 messages ont posé problème aux deux : les deux routeurs font des erreurs différentes. Ce sera utile plus loin.

Le coût par 1 000 messages utilise la formule du cours et les prix Azure que nous avons notés. Vérifiez la page des prix actuels. Par million de jetons (tokens) d’entrée et de sortie, chat-small coûte 0,10 $ US et 0,50 $ US. chat-strong coûte 2 $ US et 10 $ US. Le calcul ignore le rabais sur les entrées en cache. C’est donc une limite supérieure : 98,7 % des jetons d’entrée étaient en cache.

chat-small US$0.229 per 1,000 | latency median 1.28 s, p95 2.30 s
chat-strong US$4.239 per 1,000 | latency median 1.78 s, p95 2.96 s

La majeure partie du coût vient de l’entrée : 1 956 jetons de requête (prompt) et de schéma pour un message d’environ 10 mots. Voici la comparaison complète dont Nadia a besoin :

TF-IDF + régression logistique DistilBERT avec réglage fin chat-small, requête v2 chat-strong, requête v2
Exactitude sur les données de test 89,0 % 91,8 % 87,5 % 89,1 % (770 messages)
Coût par 1 000 messages le serveur de la banque le serveur de la banque 0,23 $ US 4,24 $ US
Temps par message 0,2 ms sur un processeur 7 ms sur un processeur 1,3 s (médiane) 1,8 s (médiane)
Messages étiquetés pour le créer 9 003 9 003 aucun (77 définitions d’une ligne) aucun
Messages étiquetés pour le tester oui oui oui oui
Une nouvelle intention étiqueter des exemples, réentraîner (secondes) étiqueter des exemples, réentraîner (minutes) modifier la requête, tester à nouveau modifier la requête, tester à nouveau
Destination du message reste dans la banque reste dans la banque chez le fournisseur chez le fournisseur

Les temps des routeurs entraînés ont été mesurés sur un processeur dans le cours sur l’apprentissage profond. Les temps des modèles de langage ont été mesurés de Toronto à East US 2 et incluent le réseau.

Ce que cela nous apprend. Le coût reste faible dans les deux cas : 100 000 messages par mois coûtent environ 23 $ US avec chat-small. Les plus grandes différences sont ailleurs. Le modèle de langage est environ 170 fois plus lent que DistilBERT. Un délai de 1,3 seconde reste toutefois acceptable pour une conversation. Il n’a besoin d’aucune étiquette pour commencer. Et chaque message quitte la banque.

Nadia veut confier les messages incertains à une personne. Le modèle écrit sa propre confidence (confiance), qui n’est pas une probabilité mesurée (Valider le sens). Sur les données de test, ses réponses « high » (élevée) étaient correctes dans 93,3 % des cas. Les réponses « medium » (moyenne) l’étaient dans 68,0 % des cas, et les réponses « low » (faible), dans 48,9 %. Il classe donc les réponses, de façon approximative.

Un deuxième signal ne coûte rien : TF-IDF fonctionne déjà sur le serveur de la banque. Quand les deux routeurs ne sont pas d’accord, au moins un se trompe. Voici quatre règles, sur les mêmes 3 080 messages de test :

chat-small, requête v2, les 3 080 messages de test. En haut : la proportion de messages confiés à une personne. En bas : l'exactitude des messages acheminés automatiquement, avec des intervalles à 95 %.
Description textuelle du graphique

Quatre règles. Aucun recours : 0 % confiés à une personne, 87,5 % de réponses correctes parmi le reste (86,3 à 88,6). Confiance non élevée : 19,6 % confiés à une personne, 93,3 % de réponses correctes parmi le reste (92,3 à 94,3). Désaccord avec TF-IDF : 17,2 % confiés à une personne, 97,5 % de réponses correctes parmi le reste (96,9 à 98,1). L’une ou l’autre règle : 28,6 % confiés à une personne, 98,4 % de réponses correctes parmi le reste (97,7 à 98,8).

Ce que cela nous apprend. La confiance du modèle confie 603 messages à une personne et laisse encore passer 165 erreurs. Le désaccord avec TF-IDF en confie moins, soit 530, et laisse passer seulement 63 erreurs. Les messages acheminés sont corrects dans 97,5 % des cas. Les erreurs différentes des deux routeurs valent plus que l’opinion du modèle sur lui-même. Choisissez la règle selon le coût du temps d’une personne et celui d’une mauvaise réponse. À titre de comparaison, la probabilité de DistilBERT, avec un seuil de 0,5, confiait 2,8 % des messages de validation à une personne. Il répondait correctement à 93,1 % du reste.

Ces messages sont inventés pour cette étude de cas; aucun client ne les a écrits. Ce sont les nouveaux messages du cours sur l’apprentissage profond, ce qui permet de comparer les réponses. Chaque message a été envoyé trois fois à chaque TermeDéploiementUn modèle qu’un compte configure chez un fournisseur, avec son propre nom et ses propres limites. Larkfield a deux déploiements sur Azure, le nuage de Microsoft : chat-small et chat-strong.En savoir plus Gérer les limites du fournisseurCréer des applications fiables avec les API de LLM avec la requête v2, car ces déploiements échantillonnent leurs réponses :

Message chat-small (3 essais) chat-strong (3 essais) DistilBERT avec réglage fin (cours sur l’apprentissage profond)
J’ai ajouté de l’argent à mon compte ce matin, mais l’argent n’est toujours pas là. pending_top_up ×3 pending_top_up ×3 top_up_reverted 0.55, pending_top_up 0.23
Ma nouvelle carte n’est toujours pas arrivée et je l’ai commandée il y a deux semaines. card_arrival ×3 card_arrival ×3 card_arrival 0.99
On m’a facturé deux fois le même café. transaction_charged_twice ×3 transaction_charged_twice ×3 transaction_charged_twice 0.99
Le virement a réussi, mais l’ajout d’argent a échoué. top_up_failed ×3 top_up_failed ×3 top_up_failed 0.95
L’ajout d’argent a réussi, mais le virement a échoué. failed_transfer ×3 failed_transfer ×3 top_up_failed 0.91
Puis-je récupérer mon argent pour un achat en ligne? Le vendeur ne l’a jamais envoyé. request_refund ×3 request_refund ×3 request_refund 0.88

Ce que cela nous apprend. Les deux déploiements interprètent correctement la paire utilisant les mêmes mots, chaque fois : la partie qui échoue est le virement. Le modèle avec réglage fin a acheminé les deux messages vers top_up_failed (ajout d’argent échoué). TF-IDF ne peut pas les distinguer. Un grand modèle comprend mieux l’ordre des mots qu’un petit modèle. La confiance variait entre les essais (high ou medium); l’intention ne changeait pas.

Erreur courante

Une énumération qui dépasse la limite

Symptôme : l’équipe produit veut chacune des 77 intentions pour chaque produit de carte, soit 13 produits au total. Leila construit l’énumération à partir des combinaisons. La première requête échoue avant l’exécution du modèle, avec la vraie erreur HTTP 400 ci-dessus : « Au plus 1000 valeurs d’énumération attendues au total dans un seul schéma… mais 1001 reçues. »

Cause : la sortie structurée stricte construit une grammaire à partir du schéma, et le fournisseur limite sa taille. 77 × 13 donne 1 001 valeurs. La limite s’applique par schéma; deux grandes énumérations dans un même schéma la partagent donc.

Correction : limitez l’énumération aux besoins d’une seule décision. Demandez l’intention (77 valeurs), puis laissez le code trouver le produit dans le compte du client. Vérifiez les limites de schéma du fournisseur pendant la conception. Ne passez jamais à strict: false pour faire taire l’erreur : la validation dans le code serait alors votre seule protection.

Et la question inverse : l’énumération corrige-t-elle un problème observable? Leila a aussi envoyé v1 sans le schéma pour 300 messages de validation. Les 300 réponses correspondaient à l’un des 77 noms. Parmi elles, 247 étaient correctes, contre 246 avec le schéma. Le schéma apporte une garantie, pas un meilleur résultat, pour environ 0,05 $ US par 1 000 messages.

Leila et Kofi écrivent ensemble à Nadia :

  • Gardez le routeur avec réglage fin pour la conversation. Sur les mêmes 3 080 messages de test, il répond correctement dans 91,8 % des cas. chat-small atteint 87,5 % avec la meilleure requête. Il fonctionne sur le serveur de la banque, en millisecondes, et aucun message ne quitte la banque.
  • Utilisez le routeur guidé par requête là où il n’y a pas encore d’étiquettes. Pour les intentions du nouveau produit, une requête avec des définitions claires fonctionne dès le premier jour. Conservez comme étiquettes les messages corrigés par des personnes. Entraînez un routeur quand chaque intention possède quelques exemples.
  • Rédigez les définitions d’intentions comme une politique. Une ligne par intention a apporté 3,9 points. Notez aussi les conventions de la banque; cela aide également les nouveaux agents.
  • Combinez les deux pour le recours. Quand le routeur entraîné et le modèle de langage sont en désaccord, confiez le message à une personne. Cela représente environ 17 messages sur 100, et 97,5 % du reste sont corrects.
  • Pas chat-strong. Il a gagné environ 2 points sur chat-small pour environ 18 fois le prix, sans dépasser le comptage de mots.

Et voici à quoi ne pas l’utiliser : les décisions concernant un client. Par exemple, détecter la fraude, bloquer une carte ou fermer un compte. Le routeur choisit un parcours de réponse; une personne ou un processus distinct et testé prend les décisions.

  • Le modèle a peut-être vu ces données. BANKING77 est public depuis 2020, et les données d’entraînement des modèles hébergés ne sont pas publiées. Leurs résultats pourraient être un peu meilleurs ici que sur les messages de la banque. Testez-les sur ces messages avant le lancement.
  • Un enregistrement par message. Ces déploiements échantillonnent leurs réponses (Les éléments d’une requête). Un deuxième essai changerait donc le classement de quelques messages.
  • chat-strong sur un échantillon. Les 770 messages donnent un intervalle d’environ 4 points de large. C’est suffisant pour voir qu’il ne dépasse pas TF-IDF, mais pas pour le classer précisément.
  • Deux versions de requête. Une v3 avec quelques exemples par intention (few-shot) pourrait réduire une partie de l’écart, avec plus de jetons par message. Comparez-la sur les mêmes données de validation, comme ici.
  • Latence depuis Toronto, avec 4 requêtes en parallèle. Plusieurs requêtes ont reçu une vraie erreur HTTP 429 et ont attendu (Gérer les limites du fournisseur). La latence sur cette page correspond seulement au temps de l’appel réussi.
  • Ensuite : envoyez au LLM seulement les messages pour lesquels TF-IDF est incertain. Essayez un modèle ouvert autohébergé, pour qu’aucun message ne quitte la banque.

Ce que contiennent les messages. Les messages de conversation d’une banque contiennent des données personnelles et financières : noms, numéros de carte et de compte, montants. Ils contiennent parfois aussi des problèmes de santé ou d’argent. Les lois sur la protection des renseignements personnels et les règles bancaires les protègent. Les envoyer à un modèle hébergé constitue un transfert à une autre entreprise. La banque doit prendre cette décision délibérément.

Ce qui peut être envoyé à un modèle hébergé. Avant le premier vrai message, la personne responsable de la protection des données vérifie les conditions du fournisseur. Elle utilise les questions de Licences et conditions d’utilisation des données du cours sur les modèles de langage. Dans quelle région les données sont-elles traitées? Combien de temps les requêtes sont-elles conservées, et qui peut les lire? Le fournisseur les utilise-t-il pour l’entraînement? Existe-t-il une entente signée sur le traitement des données? Si une réponse reste floue, utilisez le routeur entraîné ou un modèle autohébergé : aucun message ne quitte alors la banque.

Envoyez seulement ce dont la tâche a besoin. L’intention n’a jamais besoin d’un numéro de carte. Leila l’a testé avec un message inventé :

Hello, this is Sarah Okafor (sarah.okafor@example.com, 07700 900123). My card 4929 1234 5678 9012 was used last night for a cash withdrawal of £200 that I never made. My account is 31926819, sort code 60-16-13.

Avant que le message quitte la banque, une fonction redact() remplace ce que les motifs peuvent repérer. La fonction redact() du projet, dans La frontière de l’application, fonctionne de la même façon :

Hello, this is Sarah Okafor ([EMAIL], [PHONE]). My card [CARD NUMBER] was used last night for a cash withdrawal of £200 that I never made. My account is [NUMBER], sort code [SORT CODE].

Les deux versions ont obtenu cash_withdrawal_not_recognised (retrait d’espèces non reconnu) aux trois essais sur les deux déploiements. Le masquage n’a pas réduit l’exactitude ici. Mais le nom est toujours là. Les motifs trouvent les numéros et les adresses courriel, pas les noms ni le récit d’une maladie. Le masquage réduit ce qui quitte la banque; il ne rend pas un message anonyme.

Journaux (logs). Consignez l’intention, le modèle, les jetons, la latence et l’identifiant de requête. Ne consignez jamais le texte du message. Le journal d’utilisation de Mesurer l’utilisation et le coût fait de même.

Des personnes dans le processus. Confiez les messages incertains à une personne, et permettez à chaque client de joindre une personne. Certaines intentions coûtent plus cher lorsqu’elles sont mal classées. Un message compromised_card (carte compromise) dans la mauvaise file peut coûter de l’argent au client. Mesurez séparément les erreurs de ces intentions.

Les données. Toute copie de BANKING77 (CC BY 4.0) doit mentionner PolyAI comme source.

Cette étude de cas montre à un employeur que vous savez choisir entre une requête et un modèle entraîné, preuves à l’appui. Personnalisez-la avec un changement, par exemple une requête v3 avec les conventions de la banque ou un modèle ouvert local. Ensuite, rendez-la publique et facile à lire en cinq minutes.

Quoi mettre dans le dépôt :

  • README.md, la page que les gens lisent en premier (modèle ci-dessous).
  • Le carnet (notebook) Jupyter, exécuté du début à la fin, avec ses sorties.
  • prompts/ avec chaque version mesurée, sans jamais la modifier après la mesure.
  • MODEL_CARD.md. Usage prévu : acheminer les messages de clavardage vers un parcours de réponse, avec une personne pour les messages incertains. Usage exclu : prendre des décisions concernant les clients. Puis les modèles et les dates, l’évaluation, les limites et les règles sur les données.
  • La source et la licence des données, avec le texte d’attribution de l’encadré ci-dessus. N’incluez jamais une clé d’API dans un commit (enregistrement dans le dépôt); lisez-la depuis une TermeVariable d’environnementUne valeur nommée que le système donne à un programme au démarrage, par exemple une clé d’API. La valeur reste hors du code et hors de Git.En savoir plus Configuration et secretsPython pour l'ingénierie de l'IA en pratique.

Un modèle de README :

# Can a prompt replace a trained intent router?
## Problem
Route short bank-support messages to one of 77 intents. A trained router needs
9,003 labelled messages; a prompted router needs none.
## Data and licence
BANKING77 (PolyAI, 2020), CC BY 4.0, github.com/PolyAI-LDN/task-specific-datasets
(commit 57ec275). The deep learning course's split: 1,000 validation messages,
the official 3,080 test messages used once.
## Approach
A hosted LLM with a prompt (77 intent names, then one line per intent) and strict
structured output (an enum of the 77 intents), validated in code. Two prompt
versions compared on the same 1,000 validation messages; the better one tested once.
## Results (test, 95% intervals)
Fine-tuned DistilBERT 91.8% (90.7-92.7) | TF-IDF 89.0% (87.8-90.0)
chat-small, prompt v2 87.5% (86.3-88.6) | chat-strong, 770 messages 89.1%
Prompt v2 vs v1 (validation): +3.9 points (+2.3 to +5.5).
Cost per 1,000: US$0.23 (chat-small), US$4.24 (chat-strong). Median 1.3 s.
## Limits
One recording per message; the hosted model may have seen this public dataset;
every message leaves the bank; the model's confidence is not a probability.

Comment le décrire en entrevue, en deux phrases : « J’ai acheminé des messages de soutien bancaire vers 77 intentions avec un LLM, un schéma d’énumération strict et aucune donnée d’entraînement, puis fait une comparaison équitable avec des modèles d’acheminement entraînés sur les mêmes 3 080 messages de test. La requête a atteint 87,5 %, près du comptage de mots, mais 4 points derrière un modèle avec réglage fin; je l’ai donc recommandée pour les intentions sans étiquettes, avec un transfert à une personne quand les deux modèles d’acheminement sont en désaccord. »

Pour aller plus loin :

  • Rédigez une requête v3 avec les conventions de « Où les erreurs se produisent », puis comparez-la à v2 sur les données de validation.
  • Traitez les mêmes 1 000 messages de validation avec un modèle local dans TermeOllamaUn programme gratuit qui télécharge des modèles ouverts et les fait fonctionner sur votre ordinateur. Votre code l’appelle à une adresse locale, comme une API hébergée.En savoir plus Modèle hébergé ou autohébergéLes LLM : comment ils fonctionnent et comment en choisir un, puis comparez l’exactitude et le temps.
  • Envoyez 100 messages de validation trois fois, puis comptez combien changent d’intention entre les essais.

Vérifiez votre compréhension

La requête v2 dépassait v1 de 3,9 points sur 1 000 messages de validation. Dans Comparer des requêtes, une différence de trois billets sur 69 n'était pas jugée fiable. Pourquoi cette différence est-elle fiable?

Afficher la réponse

Pour deux raisons. Le jeu de données est beaucoup plus grand : 1 000 messages plutôt que 69. Et la comparaison est appariée : les deux requêtes ont répondu aux mêmes messages. Seuls les 67 messages où exactement une version avait raison apportent de l’information. Parmi eux, 53 favorisent v2 et 14 favorisent v1. L’intervalle apparié à 95 % de la différence, de +2,3 à +5,5 points, n’inclut pas zéro. Sur 69 billets, le même type d’intervalle aurait été large et aurait inclus zéro. Le contenu va aussi dans ce sens. Les corrections correspondent aux nouvelles lignes ajoutées, comme les messages sur le NIP de get_physical_card : 0 sur 11 avant, 10 sur 11 après.

Vérifiez votre compréhension

Tomás dit : « Le LLM n'a pas besoin de données d'entraînement, alors on peut complètement éviter l'étiquetage. » Que dit cette étude de cas?

Afficher la réponse

Il n’a pas besoin d’étiquettes pour construire le modèle d’acheminement. Mais il faut encore des messages étiquetés pour savoir s’il fonctionne, choisir entre les requêtes et définir une règle de repli. Cette étude de cas utilisait 1 000 messages de validation étiquetés et 3 080 messages de test étiquetés. Sans eux, personne ne saurait que la requête atteint 87,5 %. Personne ne saurait qu’une ligne par intention aide, ou que les messages sur les cryptomonnaies contredisent la convention bancaire. Les étiquettes permettent aussi d’entraîner plus tard un modèle d’acheminement, qui était plus exact ici.

Vérifiez votre compréhension

Nadia demande : « Quel modèle d'acheminement utiliser pour un nouveau produit lancé la semaine prochaine, avec 12 nouvelles intentions et aucun message étiqueté? » Répondez avec les chiffres de l'étude de cas et dites ce que vous surveilleriez.

Afficher la réponse

Commencez par le modèle d’acheminement guidé par requête pour les nouvelles intentions : un modèle entraîné ne peut pas apprendre des intentions sans exemples. Écrivez une ligne claire par intention, car cela a apporté 3,9 points ici. Attendez-vous à une exactitude proche de 90 %, mais inférieure, plutôt qu’aux 92 % du modèle avec réglage fin. Prévoyez environ 0,23 $ US par 1 000 messages avec chat-small. Vérifiez les conditions du fournisseur concernant les données avant d’envoyer un vrai message, et masquez les renseignements inutiles à la tâche. Transférez les messages incertains à une personne et conservez les messages corrigés comme étiquettes. Quand chaque intention a quelques exemples, réentraînez le modèle d’acheminement de la banque, puis comparez les deux sur des données de test fixes.

Récapitulatif

  • La classification sans exemple (zero-shot classification) utilise seulement les noms et les définitions des classes pour acheminer les messages. Les définitions sont la spécification. Une ligne par intention a fait passer chat-small de 80,3 % à 84,2 % sur 1 000 messages de validation (+3,9 points, +2,3 à +5,5).
  • Une sortie structurée stricte avec une énumération de 77 intentions a gardé chacune des 5 850 réponses valide. Le fournisseur limite chaque schéma à 1 000 valeurs d’énumération, et l’énumération ajoute environ 460 jetons (tokens) d’entrée par message. Validez quand même dans le code.
  • Sur les mêmes 3 080 messages de test : DistilBERT avec réglage fin 91,8 %, TF-IDF 89,0 %, chat-small 87,5 % sans aucun exemple d’entraînement. chat-strong a gagné environ 2 points sur un échantillon, pour environ 18 fois le prix.
  • Un modèle d’acheminement entraîné apprend les conventions bancaires à partir de ses exemples; une requête ne connaît que ses définitions. La plupart des erreurs viennent de là.
  • Le coût est faible (0,23 $ US par 1 000 messages avec chat-small); la latence est d’environ 1,3 seconde; chaque message quitte la banque. Le désaccord avec le modèle d’acheminement entraîné est un meilleur signal de repli que la confiance du modèle lui-même.
  • Les étiquettes restent nécessaires : pour tester, choisir et définir la règle de repli.

C’était la dernière étude de cas. Dans le travail final, vous créez votre propre assistant pour les billets de soutien, avec des sorties validées, des tests et des preuves semblables.

Leçon suivante : Travail final