Données structurées : extraire, classer, normaliser
Objectifs de ce chapitre
- Extraire des informations précises depuis du texte libre avec un schéma strict
- Classer en lot avec une taxonomie fermée et des définitions par catégorie
- Normaliser les valeurs et router les cas douteux vers une revue humaine
Le gisement caché dans le texte libre
Après le salon professionnel de Lyon, Sofia rapporte un butin encombrant : 80 emails de prospects, des notes de conversations prises au vol, et le fichier des 200 avis clients du trimestre qui dort depuis le chapitre 4. Toute cette matière contient des données précieuses — qui demande une démo, quel restaurant, quelle taille d'équipe, quel niveau d'urgence — mais enfermées dans du texte libre, illisible pour un tableur. Les ressaisir à la main ? Deux jours. Les faire extraire par un prompt bien conçu ? Une heure, vérification comprise.
C'est le métier de ce chapitre : transformer du texte libre en données structurées fiables. Le chapitre 4 a posé la brique de base — le JSON strict avec schéma. On va maintenant l'industrialiser : extraction multi-champs, classification avec taxonomie fermée, normalisation des valeurs, traitement en lot, et surtout le routage des cas douteux — car la différence entre un gadget de démo et un outil de production se joue entièrement sur les cas qui ne rentrent pas dans les cases.
L’extraction : un schéma, des règles par champ
L'extraction consiste à repérer dans un texte des informations précises et à les ranger dans des champs définis. La qualité dépend de trois éléments que tu connais déjà séparément : un schéma exact (chapitre 4), une règle de non-invention (chapitre 6), et — la nouveauté — des règles par champ : pour chaque champ, ce qu'on extrait, sous quelle forme, et quoi mettre quand l'information est absente.
Tu extrais des données de contact depuis des emails de prospects, pour l'équipe commerciale d'un éditeur de logiciel de planning pour restaurants.
Pour chaque email entre délimiteurs, renvoie UNIQUEMENT un objet JSON :
{
"nom": "prénom et nom, ou null si absent",
"etablissement": "nom du restaurant ou groupe, ou null",
"taille_equipe": "nombre entier d'employés, ou null si non mentionné",
"demande": "demo" | "tarifs" | "question" | "autre",
"urgence": "haute" | "normale",
"citation_cle": "la phrase de l'email qui justifie le champ demande"
}
Règles :
- N'invente JAMAIS une valeur : information absente = null.
- taille_equipe : uniquement si un nombre est écrit ; « une grosse équipe » = null.
- urgence = haute uniquement si un délai explicite est mentionné.
- citation_cle : copie exacte du texte, sans reformulation.
--- EMAIL ---
{{email}}
--- FIN ---Le champ citation_cle est l'astuce la plus rentable de ce prompt : en exigeant la phrase exacte qui justifie la classification, tu rends chaque ligne auditable en deux secondes — la citation colle ou ne colle pas — et tu réduis l'invention, car le modèle doit ancrer sa réponse dans le texte. C'est le même principe que le raisonnement vérifiable du chapitre 3, transposé aux données. Quant aux règles par champ, elles tranchent d'avance les ambiguïtés que tu découvrirais sinon en production : que faire de « une grosse équipe », qu'est-ce qui mérite « haute » urgence.
La classification : une taxonomie fermée et définie
Classer, c'est ranger chaque élément dans une catégorie d'une liste fermée. L'erreur classique est de donner les noms des catégories sans les définir : « classe ces avis en : service, produit, prix, autre ». Le modèle a alors sa propre idée de la frontière entre « service » et « produit » — et elle change d'un avis à l'autre. Une taxonomie professionnelle définit chaque catégorie, donne un exemple, et précise les règles de départage.
Classe chaque avis client dans UNE catégorie de cette liste fermée :
- "fonctionnalite" : l'avis porte sur ce que le logiciel fait ou ne fait pas. Ex. : « impossible d'exporter le planning en PDF ».
- "ergonomie" : l'avis porte sur la facilité d'utilisation. Ex. : « j'ai mis 3 jours à trouver où changer un horaire ».
- "support" : l'avis porte sur l'aide reçue de l'équipe. Ex. : « réponse en 10 minutes, problème réglé ».
- "prix" : l'avis porte sur le coût ou le rapport qualité-prix.
- "autre" : rien de ce qui précède ne s'applique clairement.
Règles de départage :
- Si l'avis touche plusieurs catégories, choisis celle de la phrase la plus développée et note les autres dans "categories_secondaires".
- En cas de doute réel, utilise "autre" avec "confiance": "basse" — ne force jamais une catégorie.
Format par avis : { "id": N, "categorie": "...", "categories_secondaires": [...], "confiance": "haute|basse", "citation_cle": "..." }Trois mécanismes à retenir. Les définitions avec exemples stabilisent les frontières — c'est du few-shot (chapitre 2) appliqué aux catégories. La règle de départage traite le cas multi-thèmes, inévitable sur des avis réels. Et le champ confiance donne au modèle une sortie honorable quand il hésite : sans elle, il force une catégorie avec aplomb, et tes statistiques mentent en silence. Un « autre, confiance basse » est une donnée honnête ; un « prix » deviné est une donnée toxique.
Normaliser : la donnée propre du premier coup
Extraire ne suffit pas : il faut que les valeurs soient comparables. Si une extraction renvoie « 15 », « quinze employés » et « ~15 pers. », ton tableur croule sous les variantes et chaque tri devient faux. La normalisation se prescrit dans le prompt, champ par champ : dates au format AAAA-MM-JJ, montants en nombre sans symbole, téléphones en chiffres collés, noms d'établissement en casse d'origine mais sans guillemets. Chaque format précisé d'avance est une heure de nettoyage économisée ensuite.
Un piège spécifique mérite l'avertissement : les conversions silencieuses. Demande « le nombre d'employés » et le modèle pourrait convertir « une dizaine » en 10 — une invention déguisée en normalisation. La règle « uniquement si un nombre est écrit » du prompt d'extraction existe pour ça. Le principe général : la normalisation change la forme d'une valeur présente, jamais elle ne crée une valeur absente. La frontière entre les deux doit être écrite noir sur blanc dans tes règles par champ.
Avant/après : la passe de normalisation en pratique
La normalisation peut s'intégrer aux règles par champ dès l'extraction — c'est l'idéal — mais elle fonctionne aussi en passe séparée, très utile quand tu hérites de données déjà extraites mais sales : un export de formulaire, un vieux tableur rempli à la main, le fichier de contacts du salon saisi par trois personnes différentes. Le prompt de normalisation est alors une étape de chaîne (chapitre 7) à part entière :
Tu normalises des fiches prospects saisies manuellement, sans modifier le fond.
Pour chaque ligne entre délimiteurs, renvoie la version normalisée :
- date_contact : format AAAA-MM-JJ. « mardi dernier » ou date ambiguë = null.
- telephone : chiffres uniquement, sans espaces ni points. Numéro incomplet = null.
- etablissement : casse d'origine, sans guillemets ni « Restaurant » redondant en préfixe.
- taille_equipe : nombre entier uniquement si un nombre figure dans la fiche, sinon null.
- ville : nom complet, première lettre en majuscule, sans code postal.
Règles absolues :
- Tu changes la FORME des valeurs présentes, tu ne crées JAMAIS une valeur absente.
- Ajoute un champ "alertes" listant tout ce qui t'a semblé ambigu dans la ligne.
- Conserve l'identifiant de ligne tel quel.
--- LIGNES ---
{{lignes ID ; date ; téléphone ; établissement ; taille ; ville}}
--- FIN ---Le champ alertes joue ici le rôle que jouait confiance en classification : une sortie honorable pour le doute. « 06.12.34 » est-il un téléphone tronqué ? « La Brasserie » et « Brasserie » sont-ils le même établissement ? Le modèle signale au lieu de trancher en silence, et Sofia arbitre les alertes en bloc à la fin — quelques minutes, contre des heures à relire chaque ligne. Une donnée normalisée sans piste d'audit est une donnée qu'on finit par re-vérifier entièrement le jour du premier doute.
Traiter en lot sans perdre le fil
Reste la question d'échelle : 200 avis ne se traitent pas en un seul prompt géant. Au-delà d'un certain volume, la qualité se dégrade en milieu de liste — l'attention du modèle est meilleure aux extrémités, comme vu au chapitre 4 — et une seule sortie malformée peut ruiner le lot entier. La pratique robuste : des paquets de 10 à 20 éléments, chacun portant un identifiant explicite, et une vérification par paquet avant de passer au suivant.
Les identifiants sont le détail qui sauve : numérote tes entrées (« AVIS-001 », « AVIS-002 ») et exige l'identifiant dans chaque objet de sortie. Tu peux alors vérifier mécaniquement qu'aucune entrée n'a été sautée ni dupliquée — le modèle saute parfois un élément en plein milieu d'un lot sans le signaler. Compte les entrées, compte les sorties, compare les identifiants : trois vérifications de dix secondes qui attrapent les pertes silencieuses.
flowchart LR
T["Texte brut : avis, emails, notes"] --> L["Lots de 10 a 20 avec identifiants"]
L --> X["Extraction et classification selon schéma"]
X --> C{"Confiance haute et JSON valide ?"}
C -->|"Oui"| D["Tableur ou tableau de bord"]
C -->|"Non"| H["File de revue humaine"]
H -->|"Cas tranchés"| DLe filet de sécurité : router le douteux, vérifier par sondage
Le diagramme ci-dessus contient la décision d'architecture la plus importante du chapitre : les cas à confiance basse ne vont pas dans le tableur, ils vont dans une file de revue humaine. Sur les 200 avis de Sofia, 14 sont sortis en confiance basse ; elle les a tranchés à la main en dix minutes. Les 186 autres étaient fiables — elle l'a vérifié par sondage : 15 avis tirés au hasard, citation comparée au texte source, zéro erreur. Sondage propre, lot accepté. C'est le même esprit que le jeu d'essai qu'on systématisera au chapitre 9.
Si le sondage révèle des erreurs, ne corrige pas les lignes une à une : cherche le motif. Trois erreurs sur des avis ironiques ? Ajoute une règle ou un exemple few-shot d'ironie dans le prompt et relance le lot. Corriger la sortie répare une fois ; corriger le prompt répare toutes les fois suivantes — c'est la leçon des templates du chapitre 5, appliquée aux données. Et garde la version corrigée du prompt dans ta bibliothèque, avec ses cas de test.
Au final, le pipeline de Sofia tient en une phrase : des lots identifiés, un schéma avec règles par champ, des citations pour auditer, un champ confiance pour router, un sondage pour valider. Cinq mécanismes simples — et le fichier de 200 avis qui dormait depuis deux mois est devenu, en une matinée, un tableau de bord que la direction consulte chaque semaine.
Contexte
Au retour du salon de Lyon, l'équipe commerciale attend la liste qualifiée des prospects : qui veut une démo, quelle taille d'établissement, quelle urgence. Sofia a 80 emails en vrac. Elle veut construire le pipeline d'extraction complet — schéma, règles par champ, lots identifiés, routage des cas douteux — et livrer un tableau fiable avant vendredi, avec la preuve par sondage que les données sont justes.
Consignes
- Choisis un gisement de texte libre de ton quotidien (emails, avis, notes, tickets) et liste les 5-6 champs qui auraient de la valeur dans un tableur.
- Écris le schéma JSON avec une règle par champ : forme attendue, normalisation, et valeur en cas d'absence (null, jamais d'invention).
- Ajoute un champ citation_cle et un champ confiance avec sa règle d'usage : en cas de doute, confiance basse plutôt que catégorie forcée.
- Numérote 15-20 entrées réelles, traite-les en un lot, puis vérifie mécaniquement : autant de sorties que d'entrées, identifiants tous présents, JSON valide.
- Fais un sondage sur 5 lignes : compare chaque citation au texte source. S'il y a des erreurs, cherche le motif et corrige le prompt, pas les lignes.
- Traite à la main la file des confiances basses, puis livre le tableau final — et range le prompt validé dans ta bibliothèque avec ses cas de test.
En résumé
- L’extraction fiable = schéma exact + règles par champ (forme, normalisation, valeur si absent) + interdiction d’inventer.
- Le champ citation_cle ancre chaque donnée dans le texte source : auditable en deux secondes, invention réduite.
- Une taxonomie professionnelle définit chaque catégorie avec un exemple et des règles de départage — pas juste des noms.
- Le champ confiance donne une sortie honorable au doute : « autre, confiance basse » vaut mieux qu’une catégorie forcée qui fausse les stats.
- La normalisation change la forme d’une valeur présente, jamais elle ne crée une valeur absente.
- Traite par lots de 10-20 avec identifiants, et vérifie mécaniquement : compte des sorties, identifiants, validité du JSON.
- Route les cas douteux vers une revue humaine et valide les lots par sondage ; si erreurs, corrige le prompt (le motif), pas les lignes.
Quiz — vérifie ta compréhension
1. À quoi sert le champ citation_cle dans un prompt d’extraction ?
2. Pourquoi définir chaque catégorie d’une taxonomie avec un exemple ?
3. Que faire d’un élément que le modèle hésite à classer ?
4. Quelle est la limite de la normalisation ?
5. Pourquoi traiter 200 avis en lots de 10-20 plutôt qu’en un prompt géant ?
6. Le sondage révèle 3 erreurs sur des avis ironiques. Que fais-tu ?