Skip to content

Contrats du moteur d'étiquetage

Les six types de contrats que le moteur d'étiquetage teste sur des étiquettes humaines, du risque sélectif et des intervalles PPI au test de l'annotateur alternatif, et la façon dont chacun échoue.

Un contrat est une affirmation sur les étiquettes finales que le moteur d'étiquetage teste sur les étiquettes humaines d'un échantillon aléatoire. Chaque contrat nomme un schéma d'annotation (schema) et a une confidence, 0,9 par défaut, qui est la probabilité que l'affirmation tienne. Une confidence de 0,9 laisse donc 10 % de chances qu'un contrat respecté soit faux.

Les six types formulent des affirmations différentes et conviennent à des études différentes :

TypeAffirmationPour
selective_riskAu plus error des étiquettes machine acceptées sont faussesJeux de données et jeux d'entraînement où chaque étiquette doit être utilisable
ppiUn intervalle pour la prévalence de chaque étiquette (ou un score moyen), valide quelle que soit la qualité de la machineRapporter des taux, comme « 12 % des messages sont toxiques [10,5 ; 13,6] »
no_worse_than_humanLa machine s'accorde avec les personnes au moins aussi bien qu'une personneRemplacer des annotateurs ou un juge LLM
budget_firstCe qu'un budget d'étiquettes humaines permet d'obtenirPlanifier avant de dépenser
distributionalLa distribution des étiquettes de la machine est proche de la façon dont les personnes se répartissentTâches subjectives où le désaccord est une donnée
threshold_legacyAucune, il accepte au-dessus d'une confiance fixeConfigurations traduites uniquement

Aucun de ces contrats n'affirme que les étiquettes sont exemptes d'erreurs. selective_risk borne le taux d'erreur parmi les étiquettes acceptées, et chaque contrat qui teste les machines les mesure par rapport aux personnes qui ont étiqueté l'échantillon.

Statut d'un contrat

Chaque contrat porte l'un de cinq statuts, affiché sur la page d'administration, par potato label status et dans le certificat :

StatutSignification
metLe test a réussi sur la cascade actuelle.
insufficientPas encore assez d'étiquettes humaines, avec une estimation du nombre qu'il en faut encore. Quand cette estimation dépasse ce qu'il reste à échantillonner dans le corpus, le statut indique que la cible n'est pas atteignable avec ce corpus.
infeasibleAssez d'étiquettes, mais aucune règle d'acceptation ne passe, par exemple parce que la confiance de la machine ne sépare pas les bonnes réponses des mauvaises.
violatedLes audits des étiquettes acceptées montrent un taux d'erreur supérieur à la cible (avec features.drift, activé par défaut).
staleUne source, un prompt ou le schéma a changé depuis le dernier test. Les étiquettes acceptées attendent en pending_recert.

Une étiquette machine n'est acceptée que si chaque contrat selective_risk et threshold_legacy de son schéma est respecté et l'accepte. Les contrats énoncent ce que les étiquettes doivent respecter, donc un contrat non respecté bloque l'acceptation au lieu d'être ignoré, et le statut, la page d'administration et le certificat nomment le contrat non respecté. Quand aucune règle ne peut s'appliquer et que plus rien n'est échantillonné (un contrat est infaisable, l'échantillon de calibration est terminé, ou rien n'a pu être projeté), les items encore sans étiquette vont à des personnes, dans la limite de budgets.human_labels.

Partitions dev et cert

Le moteur sépare les étiquettes qui choisissent une règle de celles qui la testent. Les demandes de calibration sont tirées au hasard avec une probabilité d'inclusion enregistrée, sont toujours présentées en aveugle, et chacune rejoint au hasard l'une de deux partitions :

  • dev (humans.dev_fraction, la moitié par défaut) ajuste les calibrateurs et choisit les seuils ;
  • cert teste la règle choisie, et rien d'autre ne la lit.

Examens successifs

Chaque nouveau test d'un contrat se fait à un niveau plus strict, si bien que tester de nouveau à mesure que les étiquettes arrivent ne gonfle pas la confiance. L'examen k reçoit (1 - confidence) * 6 / (pi^2 k^2) du budget d'erreur, ce qui fait la somme du budget entier sur tous les examens possibles, et le premier examen en reçoit 61 %.

  • Les examens se comptent par contrat, sur toutes les cascades sous lesquelles il a été testé, et un contrat renommé garde les examens de son ancien identifiant. Essayer des prompts ou des modèles jusqu'à ce que l'un passe coûte un examen à chaque fois. Revenir à une cascade antérieure compte aussi comme un nouvel examen, et son ancien résultat n'est pas rétabli.
  • Retester les mêmes données n'est pas un nouvel examen. Les mêmes étiquettes cert, les mêmes prédictions et la même règle choisie sur dev renvoient le résultat enregistré. Un test qui n'a pas pu s'exécuter, par exemple faute d'étiquettes cert dans une classe, ne dépense rien.
  • potato label certify teste en une fois les nouvelles étiquettes cert et les nouvelles prédictions, comme ses équivalents REST, MCP et SDK. Quand seules les étiquettes dev ont changé, il renvoie le résultat enregistré avec une note indiquant que dev choisit désormais une autre règle, et --retest teste cette règle à l'examen suivant.
  • Le planificateur certifie de lui-même à mesure que les étiquettes arrivent. Un contrat selective_risk respecté le reste pour sa cascade, et les audits le surveillent. Un contrat non respecté est retesté une fois que ses étiquettes ont augmenté d'un quart, et d'au moins 10. Les résultats ppi, distributional et no_worse_than_human sont des estimations plutôt que des tests réussis ou échoués, donc le planificateur les réestime aux mêmes étapes et une dernière fois quand l'échantillon de calibration est complet.
  • Une étiquette cert modifiée est une nouvelle donnée. Quand un annotateur change sa réponse, la modification ne coûte pas plus qu'une nouvelle étiquette. Ramenée à un état déjà testé, elle fait revenir le résultat de ce test. Si aucun des tests du résultat enregistré ne voit plus d'erreurs après la modification, le résultat et son examen restent valables. Sinon, le planificateur attend que les étiquettes aient augmenté d'un quart depuis la première modification, de sorte qu'une rafale de corrections donne un seul test, et les étiquettes acceptées le restent entre-temps, avec une note sur le contrat. Quand plus aucune étiquette n'arrive, il teste immédiatement, et une certification explicite teste à l'examen suivant.

Les étiquettes que des personnes ont données après avoir vu une réponse machine (demandes de vérification) et celles données en dehors des demandes du moteur ne certifient ni n'estiment jamais rien. Elles peuvent servir à entraîner un modèle distillé.

selective_risk

selective_risk borne la part des étiquettes machine acceptées qui sont fausses. La clé error est le taux d'erreur maximal toléré parmi les étiquettes acceptées, et elle est obligatoire :

yaml
- id: accuracy
  kind: selective_risk
  schema: sentiment
  error: 0.05          # required: largest tolerated error among accepted labels
  confidence: 0.9
  per_class: true      # test each predicted class separately
  tolerance: 0.5       # graded families only: loss at or below this counts as correct

La règle est un seuil de confiance pour chaque niveau de la cascade et, avec per_class, pour chaque classe prédite. Pour tous les niveaux sauf le dernier, le seuil est choisi sur dev et testé une fois sur cert. Le dernier niveau essaie des seuils en partant du choix de dev vers des seuils plus permissifs, les teste l'un après l'autre et s'arrête au premier qui échoue. Cette procédure est le Learn-then-Test à séquence fixe (Angelopoulos et al., 2025). Chaque test est un test binomial unilatéral de l'hypothèse selon laquelle l'erreur parmi les étiquettes acceptées dépasse error, le niveau étant réparti entre les niveaux de cascade et les classes. Un niveau qui échoue n'accepte rien, et ses items vont à des personnes.

Ce qui compte comme « juste » dépend de la famille du schéma. Le tableau donne la perte pour chaque famille, et une étiquette compte comme juste quand sa perte est inférieure ou égale à tolerance :

Famille de schémaPertetolerance par défaut
Choix unique parmi N (radio, select)0 si même étiquette0
Ordinal (likert)distance sur l'échelle / (points - 1)0
Continu (slider, number)distance / (max - min)0.05
Multi-étiquettes (multiselect)1 - recouvrement de Jaccard0
Régions d'image (image_annotation)1 - IoU moyen sur les formes appariées0.5
Segments audio/vidéo, temporal_grounding, tiered_annotation1 - IoU temporel moyen0.5
Objets 3D (spatial_annotation)1 - IoU 3D moyen0.5
Traces d'agents (process_reward, trajectory_eval, ...)part des étapes communes étiquetées différemment0

Les pertes des régions, segments, objets 3D et traces sont celles qu'utilise le rapport d'accord à /admin/iaa, si bien qu'une machine est évaluée face à une personne comme deux personnes le sont entre elles. Le texte libre et les schémas par paires n'ont pas encore de famille, et le certificat les signale comme non pris en charge.

Le test exige que chaque groupe d'items cert testé soit un échantillon uniforme. Un groupe dont les items ont été tirés avec des probabilités inégales n'est pas testé, et le résultat le nomme.

Sur le dernier niveau, un seuil n'est choisi sur dev que si l'erreur de dev vaut au plus la moitié de la cible et que suffisamment d'étiquettes cert sont attendues pour réussir un premier test. La projection du nombre d'étiquettes encore nécessaires ne compte que les seuils qui pourraient être choisis ainsi. Quand cert dispose déjà des étiquettes demandées par la projection et que le test échoue encore, la projection suivante utilise le taux d'erreur que montrent dev et cert ensemble, et non celui de dev seul. Quand l'erreur minimale sur dev est sous la cible mais au-dessus de sa moitié, rien n'est testé ni projeté. Le résultat le signale et indique l'erreur, car davantage d'étiquettes n'aident que si l'erreur s'avère plus faible.

metrics.accepted_by_tier est la couverture de la règle sur toute la population, items de calibration compris, et non un décompte des étiquettes machine livrées. La ligne « Machine labels accepted, by source » du certificat compte celles-ci.

La perte sur les traces ne compare que les étapes que les deux parties ont étiquetées, donc une personne qui a annoté certaines étapes est comparée sur ces étapes. Les étapes que personne n'a étiquetées ne sont pas vérifiées, et une personne qui n'étiquette que l'étape 0 et y est d'accord avec le juge compte comme d'accord avec l'étiquette de toute la trace. Là où chaque étape doit être vérifiée, demandez aux personnes d'étiqueter chaque étape.

ppi

ppi donne un intervalle pour la prévalence de chaque étiquette, ou pour un score moyen, corrigé des erreurs de la machine :

yaml
- id: prevalence
  kind: ppi
  schema: sentiment
  estimand: prevalence   # or mean, for numeric scores
  by: language           # optional: an interval per value of this item field
  confidence: 0.95
  max_width: 0.05        # optional: met once every interval is at most this wide

L'inférence assistée par prédiction (prediction-powered inference, Angelopoulos et al., 2023) corrige l'estimation de la machine par son erreur sur l'échantillon étiqueté par des personnes. L'intervalle est valide quelle que soit la qualité de la machine. Une bonne machine le rend plus étroit que ce que les personnes seules obtiendraient, et une mauvaise ne l'élargit pas. Avec des probabilités d'inclusion égales, le moteur utilise PPI++ avec un poids ajusté, et avec des probabilités inégales (échantillonnage stratifié ou guidé par l'incertitude), l'estimateur par différence de Horvitz-Thompson. L'étiquette machine qu'il utilise est celle que la cascade livrerait. Le champ by est copié depuis les items au moment de leur enregistrement. Sans max_width, le contrat est respecté dès qu'il a assez d'étiquettes pour rendre un résultat.

no_worse_than_human

no_worse_than_human demande si la machine s'accorde avec les personnes au moins aussi souvent qu'une personne :

yaml
- id: replaces-a-person
  kind: no_worse_than_human
  schema: verdict
  epsilon: 0.1

Le contrat exécute le test de l'annotateur alternatif (Calderon et al., 2025). En écartant tour à tour chaque personne, il teste si la machine s'accorde avec les personnes restantes au moins aussi souvent que la personne écartée, à epsilon près. La machine réussit quand elle l'emporte face à au moins la moitié des personnes, le taux de fausses découvertes étant contrôlé sur l'ensemble des personnes.

Le test exige des items étiquetés par plusieurs personnes. Définissez humans.overlap (la part de l'échantillon étiquetée plus d'une fois) et humans.overlap_k (le nombre de personnes par item, au moins 3), et il faut au moins 3 annotateurs avec 30 items chacun. Le contrat reste insufficient tant que ce n'est pas le cas. Utilisez ce contrat quand une cible d'exactitude fixe mesurerait surtout le bruit des annotateurs. Si deux personnes attentives s'accordent 85 % du temps, on ne peut montrer qu'aucun étiqueteur a « raison » à 95 %.

budget_first

budget_first projette ce qu'un budget d'étiquettes humaines permet d'obtenir avant de le dépenser :

yaml
- id: plan
  kind: budget_first
  schema: sentiment
  human_labels: 500      # or human_usd, priced at the crowd reward

La projection s'appuie sur les étiquettes dev recueillies jusque-là. Pour chaque cible d'erreur d'une grille, elle donne la part du corpus que les machines pourraient être certifiées à étiqueter avec ce budget, et la largeur qu'aurait chaque intervalle de prévalence. Le contrat est met dès qu'il y a assez d'étiquettes dev pour projeter. Il ne promet rien sur les étiquettes, ce que font selective_risk et ppi une fois les étiquettes recueillies.

distributional

distributional compare la distribution des étiquettes de la machine à la façon dont les personnes se répartissent, pour les tâches subjectives où les personnes sont en désaccord pour des raisons qui ont leur place dans les données :

yaml
- id: disagreement
  kind: distributional
  schema: offensiveness
  max_distance: 0.15     # optional
  groups_by: age_band    # optional: a prestudy question whose answer groups the annotators

Chaque item étiqueté par plusieurs personnes (humans.distribution_k, 5 par défaut) a une distribution d'étiquettes humaines. Le contrat rapporte la distance de Jensen-Shannon moyenne entre la distribution de la machine et celle des personnes, avec un intervalle bootstrap. Il rapporte aussi un plafond de bruit, la même distance entre deux moitiés aléatoires des personnes sur chaque item. Une machine plus proche des personnes que celles-ci ne le sont entre elles est aussi proche que les données le permettent.

La distribution de la machine est faite de ses probabilités là où la source les fournit (modèles de décision, k_sample, logprob), sinon de son étiquette sous forme de vecteur one-hot. Le contrat est respecté quand la borne supérieure de l'intervalle vaut au plus max_distance, ou, sans max_distance, dès qu'il y a 20 items étiquetés par 3 personnes ou plus. Quand la borne inférieure de l'intervalle dépasse max_distance, il est infeasible, car davantage d'items ne font que resserrer l'intervalle autour d'une distance trop grande.

Avec groups_by, les mêmes chiffres sont rapportés par groupe d'annotateurs. La distribution de chaque groupe sur un item ne se construit qu'à partir des personnes de ce groupe, d'après leurs réponses à la question de pré-étude nommée, et si personne n'a répondu à la question, le contrat le signale.

threshold_legacy

threshold_legacy accepte les étiquettes machine au-dessus d'une confiance fixe et n'exécute aucun test statistique :

yaml
- id: old-rule
  kind: threshold_legacy
  schema: sentiment
  threshold: 0.8

potato label migrate-config écrit ce contrat pour icl_labeling, à l'ancien confidence_threshold, afin qu'une configuration traduite se comporte comme avant, et vous pouvez aussi l'écrire à la main. Le certificat marque ces étiquettes comme non certifiées et indique leur erreur mesurée sur les étiquettes de calibration, et l'export leur donne le statut accepted_uncertified.

Résultats des études d'exemple

Les trois études d'exemple sous examples/labeling-engine/ ont été exécutées avec les sources LLM, juge et vision pointées vers Gemma 12B sur un serveur vLLM, au lieu des modèles Ollama qu'utilisent les configurations publiées. Le README de chaque exemple montre le bloc de source modifié, et avec les modèles Ollama par défaut les chiffres seront différents.

  • Sentiment sur du texte (481 avis, Gemma 12B avec une confiance logprob comme dernier niveau). selective_risk à 10 % avec une confiance de 0,9 a été respecté sur 165 étiquettes humaines, et 316 étiquettes machine ont été acceptées. Leur erreur mesurée par rapport aux vraies étiquettes était de 7,6 %, et les intervalles PPI couvraient la vraie prévalence des trois étiquettes.
  • Images (128 images COCO, YOLOv8n et Gemma 12B comme modèle de vision). Une étiquette de présence de personne a été certifiée à 10 %. Le contrat sur les boîtes est resté insufficient, car les boîtes de YOLOv8n étaient fausses sur 32 % des images dev à un IoU de 0,5.
  • Traces d'agents (288 traces, Gemma 12B comme juge). Le juge avait raison sur 80 % des traces, mais sa confiance valait 1,0 partout, donc selective_risk était infaisable. Le test de l'annotateur alternatif était insuffisant, la machine obtenant 0,82 contre 0,93 pour les personnes. PPI a estimé le succès des tâches à 0,66 [0,57 ; 0,76], alors que la vraie valeur était 0,60 et que le juge seul annonçait 0,76, soit 16 points de trop.

Pour aller plus loin

Pour les détails d'implémentation, consultez la documentation source.

Références

  1. Angelopoulos, A. N., Bates, S., Candès, E. J., et al. (2025). Learn then test: Calibrating predictive algorithms to achieve risk control. The Annals of Applied Statistics. https://doi.org/10.1214/24-AOAS1998
  2. Angelopoulos, A. N., Bates, S., Fannjiang, C., et al. (2023). Prediction-powered inference. Science, 382(6671). https://doi.org/10.1126/science.adi6000
  3. Angelopoulos, A. N., Duchi, J. C., and Zrnic, T. (2023). PPI++: Efficient prediction-powered inference. arXiv. https://arxiv.org/abs/2311.01453
  4. Calderon, N., Reichart, R., and Dror, R. (2025). The alternative annotator test for LLM-as-a-judge: How to statistically justify replacing human annotators with LLMs. Proceedings of ACL 2025. https://aclanthology.org/2025.acl-long.782/