Skip to content
Annonces9 min de lecture

Potato 2.3 : annotation agentique, Solo Mode et Best-Worst Scaling

Potato 2.3.0 ajoute le Solo Mode pour l'étiquetage conjoint humain-LLM, l'annotation de traces d'agents, le Best-Worst Scaling, la connexion SSO et OAuth, l'export Parquet et 15 projets de démonstration.

Potato Team

Note : cet article décrit Potato 2.3 tel qu'il était à sa sortie en mars 2026. Plusieurs des clés de configuration ci-dessous ont été renommées ou remplacées dans les versions suivantes, et la syntaxe actuelle se trouve dans la documentation. Ne copiez pas ces blocs dans un projet qui utilise une version actuelle de Potato.

Potato 2.3.0 ajoute le Solo Mode, un flux d'étiquetage humain-LLM qui se déroule en dix phases documentées, ainsi que l'annotation de traces d'agents avec onze convertisseurs de traces enregistrés, le Best-Worst Scaling avec trois méthodes de calcul des scores, la connexion SSO et OAuth pour Google, GitHub et les fournisseurs OIDC génériques, l'export Parquet et 15 projets de démonstration. Les notes de version recensent 50 commits ou plus depuis la 2.2.0 et des correctifs pour 12 vulnérabilités de sécurité réparties dans 8 modules.

Cette version fait suite à un changement dans ce que l'on annote. Des chercheurs qui étiquetaient le sentiment et les entités nommées il y a deux ans décortiquent aujourd'hui des traces d'agents en plusieurs étapes, comparent des sorties de modèles en masse et constituent des jeux de données pour des tâches qui n'existaient pas quand l'ensemble de schémas de Potato a été conçu. Le Solo Mode et le travail sur les traces d'agents visent tous deux ce changement.

Mise à niveau

bash
pip install --upgrade potato-annotation==2.3.0

L'export Parquet nécessite PyArrow 12.0.0 ou une version plus récente, qui s'installe séparément :

bash
pip install "pyarrow>=12.0.0"

Annotation de traces d'agents

Une exécution d'agent est une suite d'appels d'outils, d'étapes de raisonnement et de sorties intermédiaires, et la réduire à du texte brut détruit la structure qu'un évaluateur a besoin de voir. Potato 2.3 affiche plutôt les traces via le système d'affichage, si bien que la trace se présente comme une conversation dont les tours individuels portent des notes.

L'affichage se déclare dans instance_display, avec les schémas de notation par tour imbriqués sous le champ qui contient la conversation :

yaml
instance_display:
  layout:
    direction: vertical
    gap: 16px
  fields:
    - key: task_description
      type: text
      label: "Task"
    - key: conversation
      type: dialogue
      label: "Agent Trace"
      span_target: true
      display_options:
        show_turn_numbers: true
        alternating_shading: true

Deux types d'affichage prennent en charge le travail sur les agents dans la 2.3. L'affichage dialogue présente une trace sous forme de tours et permet l'annotation de segments sur ces tours, et interactive_chat couvre les conversations auxquelles l'annotateur participe au lieu de les relire. C'est le réglage span_target: true qui permet aux annotateurs de surligner un passage à l'intérieur d'un tour, et c'est ainsi que les hallucinations et les affirmations non étayées sont marquées à l'endroit où elles apparaissent.

Les traces issues d'autres frameworks passent par le convertisseur, qui enregistre onze formats dans cette version : openai, anthropic, swebench, otel, mcp, multi_agent, langchain, langfuse, react, webarena et atif.

bash
python -m potato.trace_converter -i traces.json -f react -o data/traces.jsonl

Solo Mode

L'étiquetage à plusieurs annotateurs exige de recruter, former et coordonner des personnes, et dans beaucoup de projets de recherche c'est cette logistique qui fait goulot d'étranglement, plus que l'interface d'annotation. Le Solo Mode associe plutôt un expert du domaine à un LLM. L'humain étiquette, le LLM propose, chaque correction est réinjectée dans le prompt, et l'humain cède une part croissante de la file à mesure que les deux convergent.

Le flux se déroule en dix phases documentées : configuration, revue du prompt, synthèse de cas limites, étiquetage des cas limites, validation du prompt, annotation en parallèle, résolution des désaccords, revue périodique, étiquetage autonome et validation finale. Tous les projets ne passent pas par toutes les phases.

yaml
solo_mode:
  enabled: true
 
  labeling_models:
    - endpoint_type: "ollama"
      model: "qwen3:4b"
      endpoint_url: "http://localhost:11434"
      max_tokens: 256
      temperature: 0.1
 
  revision_models:
    - endpoint_type: "ollama"
      model: "qwen3:4b"
      endpoint_url: "http://localhost:11434"
 
  uncertainty:
    strategy: "direct_confidence"
 
  thresholds:
    end_human_annotation_agreement: 0.90
    minimum_validation_sample: 20
    confidence_low: 0.5
    periodic_review_interval: 50
 
  instance_selection:
    low_confidence_weight: 0.4
    diversity_weight: 0.3
    random_weight: 0.2
    disagreement_weight: 0.1
 
  state_dir: "solo_state"

Les quatre poids de instance_selection déterminent quels éléments méritent l'attention d'un humain. Donner un poids de 0.4 à la faible confiance et de 0.3 à la diversité consacre l'essentiel du temps de l'humain aux instances sur lesquelles le modèle hésite, tout en couvrant assez le reste de la distribution pour repérer une erreur systématique. Le 0.2 de l'échantillonnage aléatoire est ce qui donne un sens à l'estimation d'accord de end_human_annotation_agreement, car un taux d'accord calculé uniquement sur les instances difficiles n'est pas celui que l'on obtient sur le corpus.

Le Solo Mode est livré avec 85 tests d'intégration et de bout en bout, un guide pour les développeurs et deux projets d'exemple dans examples/advanced/solo-mode/ et examples/advanced/simple-solo-mode/. Commencez par le plus simple, qui fonctionne avec un modèle Ollama local et ne demande aucune clé d'API. La première chose que vous évaluez est alors l'adéquation du flux à votre tâche, et non la question de savoir si le modèle vaut son coût.

Best-Worst Scaling

Le Best-Worst Scaling présente à l'annotateur un tuple d'éléments, généralement quatre, et lui demande seulement le meilleur et le pire selon un critère. Ces deux choix impliquent un ensemble de comparaisons par paires, et les scores calculés sur de nombreux tuples qui se recouvrent se placent sur une échelle réelle, à partir de jugements plus rapides à formuler qu'une note.

yaml
annotation_schemes:
  - annotation_type: bws
    name: sentiment_bws
    description: "Sentiment Intensity"
    best_description: "Which sentence expresses the MOST positive sentiment?"
    worst_description: "Which sentence expresses the LEAST positive sentiment?"
    tuple_size: 4
    sequential_key_binding: true

Trois méthodes de calcul des scores s'appliquent aux tuples collectés. counting est la référence transparente, avec (best_count - worst_count) / appearances ; elle ne demande aucune dépendance supplémentaire et est déterministe. bradley_terry ajuste un modèle de comparaison par paires et produit des paramètres de force sur une échelle logarithmique. plackett_luce ajuste un modèle de classement complet. Les deux méthodes fondées sur un modèle nécessitent pip install choix.

bash
python -m potato.bws_scoring --config config.yaml --method bradley_terry

Les scores sont écrits dans bws_scores.tsv dans le répertoire de sortie, avec pour chaque élément son score, son rang, ses nombres de choix comme meilleur et comme pire, et ses apparitions. Le tableau de bord d'administration comporte un onglet BWS Scoring qui lance le même calcul depuis un bouton et affiche les résultats dans un tableau.

SSO et OAuth

Un déploiement auquel les annotateurs accèdent par Internet a besoin de vrais comptes, et la 2.3 ajoute OAuth 2.0 et OpenID Connect pour qu'ils puissent utiliser l'identité qu'ils ont déjà. Google, GitHub et tout fournisseur OIDC générique sont pris en charge, et l'accès peut être restreint par domaine de messagerie ou par organisation GitHub.

yaml
authentication:
  method: "oauth"
  providers:
    google:
      client_id: ${GOOGLE_CLIENT_ID}
      client_secret: ${GOOGLE_CLIENT_SECRET}
  user_identity_field: "email"
 
secret_key: ${POTATO_SECRET_KEY}

Ajoutez ce bloc à votre configuration. Il s'accompagne de deux exigences. OAuth nécessite un déploiement en HTTPS, localhost étant exempté pour le développement, ainsi qu'une secret_key stable, car une clé de signature qui change à chaque redémarrage invalide les sessions que la connexion a déjà ouvertes. Enregistrez l'URI de redirection auprès de votre fournisseur sous la forme https://your-domain.com/auth/callback/google, en remplaçant le nom du fournisseur.

Export Parquet

Les données d'annotation aboutissent de plus en plus dans des outils d'analyse qui attendent un format en colonnes, et la 2.3 ajoute donc Parquet au registre d'export. Un export produit jusqu'à trois tables : annotations.parquet avec une ligne par instance et par annotateur, spans.parquet avec une ligne par annotation de segment, et items.parquet avec les données source.

bash
python -m potato.export -c config.yaml -f parquet -o ./export/

Les options se passent en ligne de commande au lieu d'être configurées dans le projet, et le codec de compression est l'un de snappy (par défaut), gzip, zstd, lz4 ou none :

bash
python -m potato.export -c config.yaml -f parquet -o ./export/ \
    --option compression=gzip --option include_items=false

Les tables se joignent sur la clé d'instance, même si le nom de la colonne diffère de l'une à l'autre : annotations.parquet et spans.parquet portent instance_id, tandis que items.parquet porte item_id. C'est ce qui rend l'export utilisable depuis DuckDB sans rien charger au préalable dans pandas :

python
import duckdb
duckdb.sql("""
  SELECT i.item_id, a.user_id, a.*
  FROM './export/annotations.parquet' a
  JOIN './export/items.parquet' i ON a.instance_id = i.item_id
""")

annotations.parquet contient une ligne par instance et par annotateur, chaque schéma d'annotation étant aplati dans sa propre colonne ; il n'y a donc pas de colonne générique value à sélectionner. Un schéma qui stocke plusieurs réponses à la fois se déploie en sous-colonnes pointées nommées <scheme>.<part>.

Correctifs de sécurité

La version corrige 12 vulnérabilités de sécurité réparties dans 8 modules, ainsi que des problèmes de XSS, de robustesse et d'intégrité des données dans 25 fichiers, et une suppression en cascade des segments qui parcourait les clés du dictionnaire au lieu de ses valeurs et laissait des enregistrements de liens derrière elle. Un audit des dépendances a mis à jour les dépendances Python et JavaScript.

Deux des autres correctifs auraient pu modifier des données que vous avez déjà collectées. Un plantage lié au booléen has_free_response (issue #111) et une boucle de navigation sur toutes les phases déterminaient si les annotations étaient enregistrées comme prévu, et la gestion des guillemets dans le multirate dynamique affectait la façon dont ces valeurs étaient écrites. Si vous avez mené une étude sous la 2.2 avec des options de réponse libre ou des schémas multirate, vérifiez la sortie avant de la considérer comme définitive.

Projets de démonstration

La version livre 15 projets de démonstration dans demo/, numérotés dans l'ordre où ils s'appuient les uns sur les autres, de 01-sentiment-admin à 15-agentic-chat. Ils couvrent les segments, les mises en page de modération personnalisées, la classification d'images, l'émotion dans l'audio, la vidéo, les éléments multimodaux, l'adjudication, les curseurs, les boîtes englobantes, les arbres de dépendances, l'annotation ELAN par niveaux et le chat agentique. Chaque répertoire de démonstration contient un config.yaml et son data/, et l'ensemble partage un script qui génère les médias dont les démonstrations fondées sur des médias ont besoin.

bash
# From the repository root: generates the demo data, then starts all 15 servers
bash demo/launch.sh

Pour le journal des modifications complet, y compris chacun des correctifs cités plus haut, consultez les notes de version v2.3.0 dans le dépôt. Signalez les problèmes sur GitHub ou ouvrez un fil dans GitHub Discussions.

Liens