Traduction automatique
Cet article a été traduit automatiquement depuis la version originale en anglais.
Le guide définitif du NER en 2026 : encodeurs, LLM et architecture de production à 3 niveaux
Il y a deux ans, choisir une approche NER revenait à arbitrer entre vitesse (modèles encodeurs) et précision (LLM). Ce compromis a disparu. Un modèle GLiNER de 300M de paramètres atteint la précision zero-shot d’un UniNER 13B tout en étant 100x plus rapide. Une variante bi-encodeur plus récente passe à l’échelle jusqu’à des millions de types d’entités avec un avantage de débit de 130x par rapport au cross-encodeur d’origine. Le pattern de production qui a émergé : utiliser les LLM pour annoter les données, fine-tuner des encodeurs compacts, déployer avec ONNX ou Rust.
J’ai construit le repo compagnon et benchmarké chaque approche majeure. Les encodeurs ont gagné le marché du NER en production. Les LLM restent essentiels, mais comme générateurs de données d’entraînement plutôt que comme moteurs d’inférence. Ce guide couvre les papiers, benchmarks et patterns de déploiement derrière ce basculement.
Repo compagnon : ner-field-guide — démos exécutables pour GLiNER, export ONNX, pipeline LLM-as-teacher et extraction structurée avec Instructor.
TL;DR : vous n’avez plus besoin de construire des modèles NER from scratch. Pour l’extraction zero-shot, GLiNER sur CPU via ONNX surpasse même les LLM les plus récents pour un coût quasi nul. Pour les tâches spécifiques à un domaine, le pipeline LLM-as-teacher (annotations LLM → revue → fine-tuning) produit des encodeurs qui atteignent 90-93%+ de F1. Pour les cas qui demandent du raisonnement, utilisez Instructor ou Outlines avec une API LLM — mais prévoyez \$2+/1K documents. L’architecture à 3 niveaux combine les trois.
Pourquoi le NER compte encore plus aujourd’hui : agents, RAG et Document Intelligence
Le NER signifie toujours la même chose : repérer des spans nommés dans un texte et les classifier. Ce qui a changé, c’est l’endroit où il intervient. Avant, c’était la dernière étape d’un pipeline NLP, un utilitaire discret sur lequel personne n’écrivait de billet de blog. Aujourd’hui, c’est un bloc de base dans les systèmes RAG, les boucles d’agents et les plateformes de traitement documentaire. C’est pourquoi la vague de recherche NER 2024-2026 compte au-delà des benchmarks académiques.
RAG : améliorer la recherche via l’extraction d’entités
Le RAG standard — découper le texte en chunks, embedder, récupérer par similarité, espérer que ça marche — s’effondre quand les utilisateurs posent des questions sur des entités spécifiques. Si quelqu’un demande « qu’a dit Anthropic à propos de la sécurité des modèles au T4 2024 ? », le système doit reconnaître « Anthropic » et « T4 2024 » comme des filtres, pas seulement s’appuyer sur la similarité d’embeddings.
Pendant l’indexation, vous extrayez les entités de chaque chunk et les stockez comme métadonnées : {"organizations": ["Anthropic"], "dates": ["Q4 2024"], ...}. Cela permet de filtrer par entité avant de lancer la recherche vectorielle. Le knowledge graph RAG (GraphRAG, LlamaIndex property graphs) va plus loin : NER + extraction de relations construisent un graphe capable de répondre à des questions multi-hop que des embeddings plats ne peuvent pas traiter.
Au moment de la requête, les entités extraites de la question de l’utilisateur pilotent le routage. Une question mentionnant le nom d’une entreprise va vers un index finance ; une autre mentionnant des noms de médicaments va vers une base de connaissances clinique. GLiNER fonctionne bien ici parce que les entités de requête sont imprévisibles — vous ne pouvez pas réentraîner pour chaque nouveau type d’entité que les utilisateurs pourraient demander.
Agents IA : transformer du texte en faits structurés
Les agents reçoivent du texte non structuré — pages web, réponses d’API, messages utilisateurs — et doivent agir dessus. Le NER convertit ce texte en faits structurés que l’agent peut raisonner, stocker ou transmettre à des outils.
Il y a deux endroits où cela compte le plus.
Le premier est le routage d’outils. Quand un utilisateur dit « planifie une réunion avec Sarah Chen d’Accenture jeudi à 14h », l’agent doit extraire PERSON: Sarah Chen, ORGANIZATION: Accenture et DATETIME: Thursday 2pm avant d’appeler l’API calendrier. Un modèle NER à base d’encodeur fait cela en moins de 10 ms. Un LLM ajoute 1 à 2 secondes par appel, et cet overhead se cumule sur les workflows multi-étapes jusqu’à ce que votre agent « instantané » donne l’impression d’avoir fait des études de philosophie.
Le second est le suivi des entités au fil des conversations. Les systèmes de mémoire d’agent doivent savoir que « Sarah » au tour 3 et « Mme Chen » au tour 12 désignent la même personne. Le NER identifie les spans ; l’entity linking les résout vers le même ID.
Dans les deux cas, la contrainte est la latence. Un appel NER de 200 ms dans une chaîne d’agent de 10 étapes ajoute 2 secondes de délai perçu. C’est pourquoi les modèles encodeurs, et non l’extraction basée sur LLM, sont le bon choix pour le travail sur les entités dans les boucles d’agents.
Document Intelligence : des images aux données structurées
L’OCR transforme les images en texte. Le NER transforme le texte en champs structurés. Ensemble, ils alimentent la numérisation documentaire à grande échelle.
Le pipeline standard : exécuter l’OCR (Tesseract, Azure Document Intelligence, AWS Textract) pour obtenir le texte et les bounding boxes, puis exécuter le NER pour extraire des champs structurés — invoice_number, vendor_name, line_items, total, due_date — à partir de ce qui n’était qu’un JPEG d’une facture papier. La même approche fonctionne pour les contrats, les dossiers médicaux et les déclarations réglementaires.
Les plateformes modernes combinent trois étapes : compréhension de mise en page (est-ce un en-tête ou une cellule de tableau ?), extraction d’entités (quel est le type de ce texte ?), et extraction de relations (quelles valeurs vont ensemble ?). GLiNER 2 gère les trois en un seul forward pass ; un seul appel modèle peut renvoyer {vendor: "Acme Corp", amount: "\$4,200", due_date: "2026-04-15"} à partir d’une facture.
C’est ici que le coût compte. Un cabinet comptable de taille moyenne traite des dizaines de milliers de factures par mois. Faire passer chacune par un LLM, même un modèle économique comme GPT-5.4 Nano, coûte des centaines de dollars par jour. Un GLiNER fine-tuné sur CPU coûte quelques centimes. Votre CFO verra la différence. La voie à suivre : annoter 500 factures d’exemple avec un LLM, fine-tuner GLiNER sur les résultats, déployer sur CPU à \$0.10/heure.
Détection de PII et garde-fous pour LLM
Les réglementations sur la vie privée (GDPR, HIPAA, CCPA) imposent d’identifier les données personnelles avant qu’elles n’atteignent les systèmes aval. Pour les déploiements LLM, cela signifie scanner les entrées avant qu’elles n’atteignent le modèle et les sorties avant qu’elles n’arrivent à l’utilisateur.
Le NER gère cela directement. Les modèles de désidentification détectent les spans PERSON, SSN, PHONE, EMAIL, ADDRESS puis soit les redigent, soit les remplacent par des équivalents fictifs. Les modèles cliniques de John Snow Labs atteignent 96% de F1 sur la détection de PHI (contre Azure 91%, AWS 83%, GPT-4o 79%) tout en traitant plus de 100K notes cliniques par jour.
Pour les garde-fous LLM, le NER fonctionne comme une couche de pré-screening : scanner l’entrée utilisateur pour détecter les PII avant l’envoi vers une API externe, puis bloquer ou anonymiser. C’est plus rapide et plus simple que de demander au LLM de s’auto-modérer. GLiNER est particulièrement utile ici parce que les catégories de PII varient selon les juridictions. Vous pouvez ajouter de nouveaux types d’entités comme « information génétique » sous une nouvelle réglementation sans réentraînement.
GLiNER réécrit l’économie du NER avec un modèle de 300M de paramètres
GLiNER (NAACL 2024, Zaratiana et al.) a rendu le NER à base d’encodeurs compétitif face aux LLM pour une fraction du coût. Au lieu de traiter le NER comme un problème de sequence labeling ou de génération de texte, GLiNER le traite comme un problème d’appariement : scorer chaque span candidat dans le texte (chaque séquence contiguë de mots comme « Bill Gates » ou « Microsoft ») contre chaque label de type d’entité, puis conserver les paires à score élevé.
Le modèle prend les labels de types d’entités et le texte d’entrée comme une séquence unique : [ENT] person [ENT] organization [ENT] date [SEP] Bill Gates founded Microsoft.... Un transformer bidirectionnel (DeBERTa-v3) encode le tout conjointement.
À partir de la sortie, le modèle construit deux ensembles de représentations : l’un pour les types d’entités (à partir des positions de token [ENT]) et l’autre pour les spans de texte (en combinant les vecteurs de tokens de début et de fin via un petit FFN). Un produit scalaire entre une représentation de span et une représentation de type d’entité donne un score.
Après application d’une sigmoïde, on obtient la probabilité que le span du token \(i\) au token \(j\) appartienne au type d’entité \(t\) : \(\\phi(i, j, t) = \\sigma(S_{ij}^T \\cdot q_t)\), où \(S_{ij}\) est le vecteur de span produit par le FFN et \(q_t\) est l’embedding du type d’entité issu du token [ENT] correspondant (Zaratiana et al., 2024, Eq. 1). Les spans sont limités à 12 tokens pour rester rapides.
En pratique, cela signifie que toute description en langage naturel peut servir de label au moment de l’inférence. Aucun réentraînement. Vous passez simplement les types d’entités souhaités (« person », « adverse drug reaction », « financial instrument »), et le modèle score les spans par rapport à eux. Trois tailles sont disponibles : GLiNER-S (50M params), GLiNER-M (90M), et GLiNER-L (300M). Les données d’entraînement proviennent du dataset Pile-NER : 44 889 passages avec 240K spans d’entités sur 13K types d’entités, tous annotés par ChatGPT. L’entraînement de GLiNER-L prend environ 4 heures sur un unique A100 (Zaratiana et al., 2024).
Résultats de benchmark
Résultats zero-shot issus de Zaratiana et al. (2024), Tables 1 et 2 :
| Model | Params | CrossNER F1 | Avg (20 datasets) |
|---|---|---|---|
| GLiNER-L | 300M | 60.9% | 47.8% |
| GoLLIE | 7B | 58.0% | -- |
| UniNER-13B | 13B | 55.6% | -- |
| GLiNER-M | 90M | 55.4% | -- |
| UniNER-7B | 7B | 53.7% | 45.7% |
| GLiNER-S | 50M | 52.7% | -- |
| ChatGPT (GPT-3.5) | -- | 47.5% | 36.5% |
GLiNER-M avec 90M de paramètres atteint presque UniNER-13B (55.4% vs 55.6% F1) tout en étant 140x plus petit. Même le minuscule GLiNER-S de 50M bat ChatGPT (GPT-3.5) de 5 points de F1. La variante multilingue — entraînée uniquement sur des données anglaises — bat ChatGPT dans 8 langues non anglaises sur 10 (Zaratiana et al., 2024). Remarque : les LLM plus récents (GPT-5.4, Claude 4.6) obtiennent probablement de meilleurs scores sur ces benchmarks, mais l’écart de coût n’a fait que se creuser — ces modèles restent de plusieurs ordres de grandeur plus chers qu’un encodeur 90M sur CPU.
L’écosystème est vaste : 280+ modèles compatibles GLiNER sur HuggingFace, ~350 000 téléchargements PyPI par mois, ~2 800 étoiles GitHub. Les variantes couvrent le texte biomédical, la détection de PII, l’actualité et le support multilingue.
Depuis quickstart.py :
from gliner import GLiNER
model = GLiNER.from_pretrained("urchade/gliner_medium-v2.1")
text = "Bill Gates founded Microsoft on April 4, 1975."
labels = ["person", "organization", "date"]
entities = model.predict_entities(text, labels, threshold=0.5)
for entity in entities:
print(f" {entity['text']} => {entity['label']} ({entity['score']:.3f})")
# Bill Gates => person (0.987)
# Microsoft => organization (0.991)
# April 4, 1975 => date (0.974)
Comment GLiNER se compare à spaCy
Aucun guide NER ne serait complet sans spaCy — ~21M téléchargements par mois, le cafard des bibliothèques NLP (affectueux — ça survit à tout). Mais il résout un problème différent de celui de GLiNER.
Les pipelines spaCy (en_core_web_sm, en_core_web_trf) font du closed-vocabulary NER : un ensemble fixe de types d’entités (PERSON, ORG, GPE, DATE, etc.) défini au moment de l’entraînement. Vous voulez un nouveau type d’entité ? Il faut collecter des données annotées et réentraîner. Le pipeline en_core_web_trf adossé à un transformer atteint 89.8% de F1 sur OntoNotes 5.0, mais uniquement pour ses 18 types prédéfinis.
GLiNER fait du open-vocabulary NER : n’importe quel label fonctionne à l’inférence, sans réentraînement. Cela en fait le meilleur choix quand les types d’entités sont inconnus à l’avance, changent souvent, ou sont spécifiques à un domaine (« adverse drug reaction », « financial instrument », « threat indicator »).
Ma recommandation : utilisez spaCy pour les types d’entités standard lorsque les pipelines préentraînés sont bien validés. Utilisez GLiNER quand vous avez besoin de types flexibles, zero-shot ou quand votre pipeline doit s’adapter sans réentraînement. Les deux fonctionnent bien ensemble — spaCy gère la tokenization et le sentence splitting, GLiNER gère l’extraction d’entités.
UniNER et NuNER : jusqu’où peut-on réduire la taille ?
UniNER (ICLR 2024, Zhou et al.) et NuNER (EMNLP 2024, Bogdanov et al.) distillent tous deux des annotations LLM dans des modèles NER plus petits — mais divergent sur la limite minimale de taille viable.
UniNER : la voie maximaliste
UniNER fine-tune LLaMA-7B/13B sur 44 889 paires NER (240K entités, 13K types) générées par ChatGPT. Pour chaque type d’entité, le modèle répond à la question « What describes [type] in the text? » et produit des listes JSON. Une astuce d’entraînement clé : le frequency-based negative sampling fait passer la F1 de 31.5% à 53.4% (Zhou et al., 2024).
UniNER-7B atteint 41.7% de F1 zero-shot sur 43 datasets — battant les 34.9% de ChatGPT de 7 points. La variante 13B monte à 43.4%, soit seulement 1.7 point de plus pour presque deux fois le compute (Zhou et al., 2024).
Le problème en production : en tant que modèle autoregressif 7B, UniNER a besoin de N forward passes pour N types d’entités, exige 14GB+ de VRAM (donc votre budget GPU est déjà parti avant midi), et impose une licence restrictive CC BY-NC 4.0.
NuNER : la voie minimaliste
NuNER part de RoBERTa-base (125M paramètres) et utilise un entraînement contrastif avec 4,38 millions d’annotations GPT-3.5 sur 200K concepts — coût total d’annotation inférieur à \$500. Après entraînement, l’encodeur de concepts est jeté ; l’encodeur de texte s’insère dans n’importe quel pipeline NER standard en remplacement de RoBERTa (Bogdanov et al., 2024).
Résultat : NuNER bat RoBERTa standard de 6 à 15 points de F1 sur toutes les tailles few-shot. Avec seulement une douzaine d’exemples par type d’entité, NuNER atteint UniNER-7B tout en étant 56x plus petit (Bogdanov et al., 2024).
Les deux papiers montrent la même chose : distiller des annotations LLM dans des modèles plus petits produit un NER meilleur que le teacher. Et vous n’avez pas besoin de 7B de paramètres — 125M suffisent quand des données de fine-tuning sont disponibles, avec une licence MIT et une inférence compatible CPU.
GLiNER 2 : un modèle, quatre tâches
L’écosystème GLiNER d’origine avait un problème croissant : des modèles séparés pour le NER (GLiNER), l’extraction de relations (GLiREL), la classification (GLiClass) et la RE au niveau document (GLiDRE) — chacun avec son propre déploiement, son propre conteneur Docker et sa propre ligne dans votre tableur « services pour lesquels on prie qu’ils ne cassent pas ». GLiNER 2 (EMNLP 2025, Zaratiana et al.) fusionne les quatre dans un seul modèle de 205M de paramètres avec une interface pilotée par schéma.
L’architecture conserve la conception cross-encoder mais étend le contexte à 2 048 tokens (4x l’original) et ajoute des schémas déclaratifs pour définir les tâches d’extraction. L’entraînement utilise 135 698 documents réels annotés avec GPT-4o plus 118 636 exemples synthétiques (Zaratiana et al., 2025).
En zero-shot sur CrossNER, GLiNER 2 obtient 0.590 de F1 — proche des 0.599 de GPT-4o tels que benchmarkés dans le papier (mi-2025). Les modèles plus récents comme GPT-5.4 obtiennent probablement mieux, mais à une fraction de la vitesse et du coût de GLiNER 2. En classification, il atteint 0.72 en moyenne sur 7 benchmarks, devant DeBERTa-v3-large (0.69). Sur CPU, GLiNER 2 exécute la classification en 130-208 ms quel que soit le nombre de labels. DeBERTa scale linéairement : 1 714 ms pour 5 labels, 16 897 ms pour 50 (Zaratiana et al., 2025).
from gliner2 import GLiNER2
extractor = GLiNER2.from_pretrained("fastino/gliner2-base-v1")
# Multi-task composition in ONE forward pass
schema = (extractor.create_schema()
.entities({"person": "Names of people", "company": "Organization names"})
.classification("sentiment", ["positive", "negative", "neutral"])
.relations(["works_for", "founded", "located_in"])
.structure("product_info")
.field("name", dtype="str")
.field("price", dtype="str"))
results = extractor.extract(text, schema)
Un seul déploiement de modèle en remplace quatre. Infrastructure plus simple, précision compétitive.
Le bi-encodeur : passer à l’échelle du NER à un million de labels
Le GLiNER d’origine encode labels et texte ensemble — ce qui crée un bottleneck. Plus il y a de types d’entités, plus la séquence d’entrée s’allonge, et les performances chutent rapidement au-delà d’environ 30 types. Le bi-encodeur GLiNER (février 2026, Stepanov et al. ; arXiv 2602.18487) corrige cela en séparant l’encodage du texte et celui des labels dans deux transformers distincts.
L’encodeur de texte utilise ModernBERT (famille Ettin), l’encodeur de labels utilise des sentence transformers (BGE ou MiniLM). Les spans et les labels sont scorés via produit scalaire. L’astuce : les embeddings de types d’entités peuvent être pré-calculés une fois puis mis en cache. À l’inférence, seul le texte doit être encodé — la lookup de labels est instantanée.
Quatre tailles de modèles sont disponibles, toutes benchmarkées sur CrossNER (Stepanov et al., 2026, Table 1) :
| Model | Parameters | CrossNER F1 | Throughput (H100) | With Pre-computed Labels |
|---|---|---|---|---|
| bi-edge-v2.0 | 60M | 54.0% | 13.64 ex/s | 24.62 ex/s |
| bi-small-v2.0 | 108M | 57.2% | 7.99 ex/s | 15.22 ex/s |
| bi-base-v2.0 | 194M | 60.3% | 5.91 ex/s | 9.51 ex/s |
| bi-large-v2.0 | 530M | 61.5% | 2.68 ex/s | 3.60 ex/s |
À 1 024 types d’entités, le bi-encodeur (edge, pré-calculé) ne perd que 5.2% de débit par rapport à un label unique. Le cross-encodeur perd 98.7% (10.7 → 0.14 ex/s). Cela représente un avantage de débit de 130x à grande échelle. Avec 100 types d’entités sur un seul H100, le bi-encodeur traite 1,96 million de prédictions par jour contre 368K pour le cross-encodeur (Stepanov et al., 2026).
La précision tient aussi. Bi-encoder-large atteint 61.5% de F1 sur CrossNER, légèrement devant les 60.9% du cross-encodeur. Les auteurs recommandent bi-base-v2.0 (194M) comme sweet spot, atteignant 98% de la précision du grand modèle pour 2.6x la vitesse (Stepanov et al., 2026).
from gliner import GLiNER
model = GLiNER.from_pretrained("knowledgator/gliner-bi-base-v2.0")
# Pre-compute embeddings for massive label sets — encode once, use forever
entity_types = ["person", "organization", "date"] # Can be thousands or millions
entity_embeddings = model.encode_labels(entity_types, batch_size=8)
# Inference only encodes text — labels are a cached lookup
outputs = model.batch_predict_with_embeds(texts, entity_embeddings, entity_types)
Les applications incluent le NER biomédical contre l’ontologie UMLS (4M+ concepts), les taxonomies d’entreprise qui évoluent sans réentraînement du modèle, et l’entity linking via le framework compagnon GLiNKER.
Les LLM comme teachers : le pipeline à \\(70 qui bat le modèle à \\\)8/heure
Le pattern LLM-as-teacher est devenu un pipeline de production standard. Trois études montrent ce que cela coûte et ce que cela rapporte.
Le cas d’étude CFM
Capital Fund Management extrayait les noms d’entreprise à partir d’environ 900K titres d’actualités financières. GLiNER zero-shot obtenait 87.0% de F1. Ils ont utilisé Llama 3.1-70b (le meilleur modèle open au moment des faits) pour annoter l’ensemble du dataset en environ 8 heures pour ~\$70, puis ont fait relire 2 714 échantillons par des humains via Argilla en 8 heures supplémentaires.
Le fine-tuning de GLiNER sur ces données a poussé la performance à 93.4% de F1 — au-dessus même des 92.7% de F1 du teacher Llama 70b. Le modèle fine-tuné tourne à \\(0.10/heure sur CPU** contre \\\)8/heure pour le teacher — 80x moins cher** avec une meilleure précision (CFM Case Study). Aujourd’hui, on obtiendrait des annotations teacher encore meilleures avec Llama 4 Maverick ou GPT-5.4 Mini pour un coût comparable ou inférieur.
L’étude Refuel AI
Refuel AI a benchmarké l’annotation par LLM sur 8 datasets NLP, dont CoNLL-2003. GPT-4 (mars 2023) a atteint 88.4% d’accord avec la vérité terrain — au-dessus des 86.2% des annotateurs humains qualifiés. Les LLM étaient 20x plus rapides et 7x moins chers. Leur approche d’ensembling — modèles bon marché pour les exemples faciles, GPT-4 pour les exemples difficiles — a atteint 95%+ d’accord tout en maintenant les coûts bas (Refuel AI Technical Report). Avec GPT-5.4 et Claude 4.6 désormais disponibles, la qualité teacher n’a fait que progresser.
NER clinique chez Tonic.ai
Tonic.ai a montré que le pattern fonctionne aussi pour le NER clinique. Les annotations LLM seules ont permis d’entraîner un modèle RoBERTa LoRA à 0.70 de F1 sur le NCBI Disease Corpus (contre 0.81 avec des labels humains complets). Sur l’extraction d’identifiants de santé, il a atteint 0.947 de F1 — au-dessus du seuil de production de 0.914 — sans aucune donnée annotée manuellement.
Le pipeline standard
La recette de production s’est stabilisée en six étapes :
- Écrire des guidelines d’annotation en langage naturel
- Créer un petit jeu de validation annoté par des humains (50-200 documents)
- Utiliser un LLM (GPT-5.4 Mini, Llama 4 Maverick ou Qwen3.5) pour annoter en masse les données d’entraînement
- Revoir un sous-ensemble via Argilla ou Label Studio
- Fine-tuner un encodeur compact (GLiNER, SpanMarker, RoBERTa)
- Déployer avec un coût d’inférence 16-80x plus faible
Le coût du NER n’est plus « annoter toutes ses données d’entraînement en embauchant une armée d’étudiants ». C’est « construire un bon jeu de validation, écrire des guidelines claires, et laisser le LLM faire le reste ».
Là où GLiNER échoue et où les LLM restent essentiels
Le benchmark Sease (octobre 2025) a testé GLiNER face à GPT-4.1-mini sur 30 tâches de query parsing. GPT-4.1-mini a obtenu 100% de réponses entièrement correctes. GLiNER a obtenu 53% (16 sur 30). Mais GLiNER a répondu en 0.08 seconde contre 1.21 seconde pour le LLM — 15x plus rapide.
GLiNER échoue selon trois patterns précis :
- Entités implicites : extraire « event » à partir de « Elton John performed at Madison Square Garden » — rien dans le texte ne dit littéralement « event », mais le LLM infère « concert »
- Sensibilité au phrasé des labels : « 2022 » obtient un score de 0.388 contre « date » mais 0.958 contre « year » — de petites variations de label provoquent de grands écarts de score
- Value mapping : GLiNER renvoie le texte de surface exact (« family houses ») au lieu de la valeur canonique (« Single family house ») — les LLM font cela naturellement
Entités imbriquées et chevauchantes
GLiNER gère aussi mal les entités imbriquées. Dans « New York University », un humain peut annoter à la fois « New York » (LOCATION) et « New York University » (ORGANIZATION). GLiNER ne garde que le span au score le plus élevé. C’est important en biomédical (« acute myeloid leukemia » contient à la fois une maladie et un modificateur) et en juridique (hiérarchies organisationnelles imbriquées). Des modèles spécialisés gèrent l’imbrication, mais la conception flat-span de GLiNER ne le permet pas.
En pratique : GLiNER gère l’extraction d’entités explicites — le cœur du NER en production. Les LLM prennent le relais quand l’extraction exige inférence, raisonnement ou mapping vers des ontologies prédéfinies. Utilisez les deux.
Évaluer le NER : métriques, pièges et construction des jeux de test
J’ai vu des équipes mettre en production des modèles à 95% de F1 sur leur jeu de test et échouer en production — parce que le jeu de test ne reflétait pas la distribution réelle des documents. Votre jeu de test n’est pas vos données de production. Je sais, cela semble évident. Je l’ai quand même vu mal tourner.
Les métriques de base
- F1 au niveau entité : la métrique standard. Une prédiction n’est correcte que si les bornes du span et le type correspondent exactement à la vérité terrain. C’est ce que rapportent la plupart des papiers.
- F1 au niveau token : score chaque token indépendamment. Gonfle les résultats parce qu’obtenir la majeure partie d’une longue entité rapporte un crédit partiel. Préférez la F1 au niveau entité.
- Précision vs rappel : leurs coûts sont souvent asymétriques. Pour la désidentification, le rappel compte davantage — manquer un nom est pire que sur-rediger. Pour l’extraction vers une base de données, la précision compte davantage — les fausses entrées corrompent les analyses aval.
Pièges classiques d’évaluation
- Inflation par correspondance partielle : « Bill » extrait alors que le gold label est « Bill Gates » — certains scripts comptent cela comme une correspondance partielle. Utilisez une correspondance exacte du span sauf raison explicite de faire autrement.
- Confusion de type : « Microsoft » correctement identifié comme span mais étiqueté PERSON au lieu de ORG doit valoir zéro. Vérifiez que votre code d’évaluation le gère bien.
- Fuite du jeu de test : si les entités du test se recouvrent avec celles de l’entraînement, les scores sont gonflés. Les benchmarks zero-shot (CrossNER, Few-NERD) existent pour tester la généralisation.
Construire un jeu de test métier
Pour l’évaluation en production, je recommande :
- Échantillonner à partir des données de production, pas d’exemples curés. Incluez les documents sales que votre modèle verra réellement.
- 200 à 500 documents annotés donnent des estimations F1 stables. En dessous de 100, les intervalles de confiance sont trop larges.
- Deux annotateurs minimum, avec accord inter-annotateur (kappa de Cohen > 0.8). Si les humains ne sont pas d’accord, votre modèle ne fera pas mieux.
- Stratifier par difficulté — cas faciles (texte propre, types standard) et cas difficiles (entités ambiguës, jargon, texte bruité).
NER en production dans quatre industries
Voici les déploiements NER les plus matures que j’ai trouvés, avec des chiffres précis.
Santé
La santé dispose de l’outillage NER le plus mature. John Snow Labs propose plus de 2 500 modèles préentraînés, dont 1 200+ pour la santé, couvrant plus de 400 types d’entités cliniques mappés vers ICD-10, SNOMED CT, LOINC et RxNorm. Leurs modèles de désidentification atteignent 96% de F1 (contre Azure 91%, AWS 83%, GPT-4o 79%), avec Providence St. Joseph Health traitant 100K-500K notes cliniques par jour.
Le projet open-source OpenMed project propose plus de 380 modèles NER biomédicaux avec 29.7M de téléchargements HuggingFace, établissant un nouvel état de l’art sur 10 des 12 benchmarks biomédicaux publics.
NER financier
Cas d’usage principal : l’extraction depuis les déclarations SEC. Finance NLP de John Snow Labs extrait plus de 11 types d’entités à partir des formulaires 10-K/10-Q (adresses, tickers, exercices fiscaux, bourses). Les variantes FinBERT-MRC atteignent 0.87-0.93 de F1 sur les tâches d’entités financières. Le défi clé : les longs documents et les entités imbriquées dans les instruments financiers complexes.
E-commerce
Du NER à très grande échelle. Le système EAMT de Walmart (KDD 2023) s’entraîne sur 965 millions de requêtes avec ~60 labels d’entités, générant un gain de 0.51% de GMV en tests A/B — soit des millions de revenus incrémentaux. Le framework TripleLearn de Home Depot (AAAI 2021) a fait passer la F1 NER de 69.5 à 93.3 par entraînement itératif.
Cybersécurité
Le système iACE (CCS 2016) a traité 71 000 articles provenant de 45 blogs sécurité, extrayant 900K IOC items à 98% de précision et 93% de rappel. Des systèmes modernes comme CyNER combinent DeBERTa (F1 >91%) avec des heuristiques IOC basées regex. Le dataset unifié CyberNER (2025) harmonise quatre jeux de données en 21 types d’entités alignés STIX 2.1, avec RoBERTa à 0.736 de F1.
Optimisation du déploiement : de Python à l’inférence sub-milliseconde
J’ai testé trois façons d’accélérer GLiNER pour la production dans le repo compagnon.
Export ONNX
GLiNER dispose d’une conversion native vers ONNX, et des modèles déjà convertis existent sur HuggingFace (onnx-community/gliner_small-v2.1). ONNX Runtime fournit un gain de vitesse de 1.5 à 3x sur CPU par rapport à PyTorch, avec quatre niveaux d’optimisation allant du basic au mixed-precision.
Depuis onnx_export.py :
# Export with quantization
# python convert_to_onnx.py --model_path model/ --save_path onnx/ --quantize True
# Load ONNX model — same API, faster inference
from gliner import GLiNER
model = GLiNER.from_pretrained("path/to/model", load_onnx_model=True)
# Same predict_entities call, 1.5-3x faster on CPU
entities = model.predict_entities(text, labels, threshold=0.5)
Quantization INT8
La quantization dynamique réduit les modèles de 2.4x (438MB → 181MB) avec moins de 0.6% de perte de F1. La vitesse s’améliore de 1.8x sur CPU. Sur des CPU Intel VNNI avec ONNX Runtime, l’INT8 atteint jusqu’à 6x d’accélération par rapport à PyTorch FP32.
from onnxruntime.quantization import quantize_dynamic, QuantType
# One-line quantization — 2.4x smaller, <1% F1 loss
quantize_dynamic("gliner.onnx", "gliner_int8.onnx", weight_type=QuantType.QInt8)
gline-rs : réimplémentation Rust
gline-rs (Apache 2.0) élimine l’overhead Python. Sur CPU : 6.67 seq/s contre 1.61 pour Python — soit un gain de 4.1x. Sur une RTX 4080 : 248.75 seq/s (benchmarks gline-rs). Il supporte les modèles span et token, GPU/NPU via ONNX Runtime, et est publié comme crate sur crates.io.
use gliner::{GLiNER, TokenMode, Parameters, RuntimeParameters, TextInput};
let model = GLiNER::<TokenMode>::new(
Parameters::default(), RuntimeParameters::default(),
"tokenizer.json", "model.onnx")?;
let input = TextInput::from_str(
&["My name is James Bond."], &["person", "vehicle"])?;
let output = model.inference(input)?;
// => "James Bond" : "person" (99.7%)
Le package fast-gliner fournit des bindings Python via PyO3 — la vitesse de Rust avec l’ergonomie de Python.
Résumé de la pile d’optimisation
| Optimization | Speedup vs PyTorch | Model Size | F1 Impact | Best For |
|---|---|---|---|---|
| ONNX Runtime | 1.5-3x | Same | None | Quick win, any hardware |
| INT8 Quantization | 3-6x | 2.4x smaller | <0.6% loss | CPU deployment, memory-constrained |
| gline-rs (Rust) | 4.1x (CPU) | ONNX format | None | High-throughput, latency-critical |
| gline-rs + INT8 | 4-8x | 2.4x smaller | <1% loss | Production at scale |
Extraction structurée : Instructor vs Outlines
Quand vous avez besoin de plus de flexibilité que ce que proposent les modèles encodeurs — entités implicites, raisonnement, mapping d’ontologie — deux bibliothèques gèrent l’extraction structurée à partir de LLM.
Instructor (~12 600 étoiles GitHub, ~8.8M téléchargements/mois en mars 2026) de Jason Liu patch les SDK LLM pour accepter des modèles de réponse Pydantic, avec retry automatique en cas d’échec de validation. Il supporte plus de 15 providers et a inspiré la fonctionnalité native de structured output d’OpenAI.
Depuis structured_extraction.py :
import instructor
from pydantic import BaseModel
from typing import List, Literal
from openai import OpenAI
class Entity(BaseModel):
name: str
label: Literal["PERSON", "ORGANIZATION", "LOCATION"]
class ExtractEntities(BaseModel):
entities: List[Entity]
client = instructor.from_openai(OpenAI())
result = client.chat.completions.create(
model="gpt-5.4-mini", temperature=0.0,
response_model=ExtractEntities,
messages=[{"role": "user", "content": "BioNTech SE acquired InstaDeep in the U.K."}])
# entities=[Entity(name='BioNTech SE', label='ORGANIZATION'), ...]
Outlines (~13 600 étoiles GitHub) de dottxt adopte une approche différente : génération de tokens contrainte via machines à états finis. Au lieu de générer une sortie puis de retry en cas d’échec de validation, Outlines empêche tout simplement la génération de tokens invalides — 100% de conformité au schéma, zéro retry. Les benchmarks AWS montrent 98% d’adhérence au schéma contre 76% pour la validation post-génération, avec une génération 5x plus rapide par rapport à une génération non contrainte avec retries de post-validation.
import outlines
model = outlines.models.transformers("microsoft/Phi-3-mini-128k-instruct")
generator = outlines.generate.json(model, ExtractEntities)
result = generator("Extract entities from: BioNTech SE acquired InstaDeep in the U.K.")
Le choix dépend de l’endroit où vous exécutez vos modèles. Instructor est le meilleur choix pour les API LLM cloud — prototypage rapide, support multi-provider, patterns Pydantic familiers. Outlines gagne pour les modèles locaux quand vous avez besoin de garanties de format sans dépendances externes. Les deux fonctionnent bien pour l’extraction de type NER, mais aucun n’atteint le débit des encodeurs : Instructor ajoute 200 ms à 2 s de latence API par appel, et Outlines dépend de la vitesse du modèle local. Pour le NER à haut débit, les encodeurs restent 10 à 100x plus rapides.
L’architecture de production à 3 niveaux
Voici comment j’assemblerais tout cela pour du NER en production.
Niveau 1 — Modèles encodeurs pour les types d’entités connus. GLiNER (cross-encoder pour <30 types, bi-encodeur pour 30+), fine-tuné via le pipeline LLM-as-teacher. Déployez avec ONNX + INT8 ou gline-rs. Gère >90% du volume avec une latence sub-50 ms et un coût quasi nul. Le bi-encodeur passe à l’échelle jusqu’à des millions de types d’entités avec des embeddings pré-calculés.
Niveau 2 — GLiNER 2 pour l’extraction multi-tâches. Lorsqu’une requête doit faire en une fois NER + classification + extraction de relations + données structurées, le modèle 205M paramètres de GLiNER 2 remplace quatre déploiements. Il tourne sur CPU en 130-208 ms quel que soit le nombre de labels — idéal pour les pipelines documentaires nécessitant plusieurs tâches d’extraction en un seul passage.
Niveau 3 — LLM pour l’extraction à fort besoin de raisonnement. Quand les entités sont implicites, demandent une inférence contextuelle, ou exigent un mapping d’ontologie, routez vers un LLM (GPT-5.4 Mini, Claude Sonnet 4.6, Llama 4 Maverick) via Instructor (cloud) ou Outlines (local). Cela gère les ~10% de requêtes que les encodeurs ratent. Les mêmes LLM génèrent aussi les données d’entraînement du niveau 1.
Combien cela coûte-t-il ? Un GLiNER fine-tuné atteint 93.4% de F1 à \\(0.10/heure sur CPU**, en égalant les **92.7% de F1** de son teacher Llama-70b à **\\\)8/heure — 80x moins cher.
Compromis et limites
Rien ici n’est gratuit. En ML, il y a toujours un piège — la seule question est de savoir quand vous le découvrez.
Les erreurs du LLM-as-teacher se propagent. Si le LLM se trompe systématiquement sur un type d’entité précis (par exemple en confondant des noms de filiales avec des maisons mères), l’encodeur fine-tuné hérite de ce biais. Le correctif est une revue humaine ciblée — concentrez l’effort sur les types d’entités où la confiance du LLM est faible ou incohérente, pas sur un échantillonnage aléatoire.
Les pertes dues à la quantization ne sont pas uniformes. La perte moyenne de F1 d’environ 0.6% en INT8 peut être plus forte sur les types d’entités rares avec des patterns de frontières subtils (composés chimiques, abréviations multi-mots). Benchmarkez toujours les modèles quantifiés sur vos types d’entités spécifiques, pas seulement sur la F1 agrégée.
Quand l’architecture à 3 niveaux est excessive. Domaine unique, types d’entités bien définis, 500+ exemples annotés ? Un RoBERTa ou un pipeline spaCy fine-tuné est plus simple et suffisant. Le pattern à 3 niveaux devient rentable avec (a) plusieurs domaines, (b) des types d’entités évolutifs, ou (c) un mélange de tâches d’extraction faciles et difficiles. Si vous extrayez simplement des noms et des dates de factures, le niveau 1 seul suffit.
Plafond de qualité du bi-encodeur. Le bi-encodeur échange l’attention conjointe contre du débit. Quand la sémantique des labels interagit avec le contexte textuel (« date » vs « year » vs « period » pour le même span), le cross-encodeur garde l’avantage. Utilisez le cross-encodeur pour les tâches critiques avec peu de labels ; le bi-encodeur pour la largeur.
Points clés à retenir
- Les encodeurs ont gagné. GLiNER et les variantes bi-encodeur battent les LLM sur les benchmarks NER standard à un coût 80-130x inférieur. Même avec GPT-5.4 Nano et Llama 4 qui font baisser les prix, exécuter un LLM sur chaque requête NER n’est plus justifié.
- Les LLM sont essentiels — comme teachers. Ils annotent des données d’entraînement pour \$70 alors qu’une annotation humaine coûterait des milliers, et l’encodeur fine-tuné finit généralement par battre le LLM qui l’a entraîné.
- Le bi-encodeur débloque l’échelle du million de labels. Les embeddings pré-calculés résolvent le problème de complexité quadratique, avec seulement 5.2% de perte de débit à 1 024 labels.
- GLiNER 2 consolide l’extraction multi-tâches. Un modèle 205M unique pour NER + classification + RE + extraction structurée.
- Évaluez sur vos données. Utilisez la F1 au niveau entité, construisez les jeux de test à partir de documents de production, et benchmarkez les modèles quantifiés sur vos types d’entités spécifiques.
- Utilisez le pattern hybride. Niveaux 1/2 pour l’extraction rapide, niveau 3 pour le raisonnement. Les mêmes LLM qui traitent les 10% les plus difficiles génèrent les données d’entraînement des 90%.
Références
Papiers
- GLiNER: Generalist Model for Named Entity Recognition using Bidirectional Transformer - Zaratiana et al., NAACL 2024. L’architecture fondatrice d’appariement span-entité.
- GLiNER 2: Open Problems for Automatic Information Extraction - Zaratiana et al., EMNLP 2025 System Demonstrations. Unifie NER, classification, RE et extraction structurée.
- GLiNER Bi-Encoder: Scalable Named Entity Recognition with Bi-Encoder Architecture - Stepanov et al., février 2026. Encodage découplé pour l’échelle du million de labels.
- UniNER: Universal NER using Large Language Models - Zhou et al., ICLR 2024. NER universel basé LLM via distillation depuis ChatGPT.
- NuNER: Entity Recognition Encoder Pre-training via LLM-Annotated Data - Bogdanov et al., EMNLP 2024. Montre que 125M de paramètres suffisent avec des données d’entraînement générées par LLM.
Papiers industriels
- EAMT: Entity-Aware Multi-Task Learning for Query Understanding - Walmart, KDD 2023. 965M requêtes, gain de 0.51% de GMV.
- TripleLearn: End-to-End NER for E-Commerce Search - Home Depot, AAAI 2021. F1 de 69.5 à 93.3.
- iACE: Automatic Collection of Cyber Threat Intelligence - CCS 2016. 71K articles, 900K IOCs.
- CyberNER: A Harmonized STIX Corpus for Cybersecurity NER - 21 types d’entités alignés STIX 2.1.
- FinBERT-MRC: Financial NER via Machine Reading Comprehension - 0.87-0.93 de F1 sur les tâches d’entités financières.
Cas d’étude
- CFM Case Study: Fine-tuning GLiNER for Financial NER - Pipeline d’annotation LLM à \$70 de Capital Fund Management atteignant 93.4% de F1.
- Refuel AI: LLM Labeling Technical Report - GPT-4 atteignant 88.4% d’accord d’annotation, au-dessus des annotateurs humains.
- Sease: GLiNER as an Alternative to LLMs for Query Parsing - Là où GLiNER échoue et où les LLM restent nécessaires.
- John Snow Labs: Medical Text De-Identification Benchmark - Comparatif de détection PHI à 96% de F1 entre providers.
- OpenMed: Year in Review 2025 - 380+ modèles NER biomédicaux, 29.7M téléchargements HuggingFace.
Outils et frameworks
- ner-field-guide demo repo - Démos compagnons pour cet article : quickstart GLiNER, export ONNX, LLM-as-teacher et extraction structurée.
- gline-rs: Rust reimplementation of GLiNER - Accélération CPU 4.1x par rapport à Python, sous licence Apache 2.0.
- Instructor - Extraction LLM structurée via modèles Pydantic, ~8.8M téléchargements mensuels.
- Outlines - Génération de tokens contrainte via FSM, garantissant la conformité au schéma.
- AWS: Structured Output with Outlines - Benchmark à 98% d’adhérence au schéma.