Skip to content
Tutorials12 min read

Solo Mode: Come un Solo Annotatore Può Etichettare 10.000 Esempi

Tutorial passo per passo sull'utilizzo di Solo Mode di Potato per etichettare in modo efficiente grandi dataset con la collaborazione umano-LLM, riducendo il costo dell'annotazione fino al 90%.

Potato Team·
Esta página aún no está disponible en su idioma. Se muestra la versión en inglés.

Solo Mode: Come un Solo Annotatore Può Etichettare 10.000 Esempi

Hai 10.000 recensioni di prodotti da etichettare per il sentiment (Positivo, Neutro, Negativo). Assumere tre annotatori per etichettare tutto richiederebbe settimane e costerebbe migliaia di euro. Con Solo Mode, un singolo esperto del dominio può ottenere una qualità comparabile etichettando solo 500-1.000 istanze mentre un LLM gestisce il resto -- con il revisore umano che controlla ogni decisione di cui l'LLM non è sicuro.

Questo tutorial illustra l'intero processo dall'inizio alla fine.


Cosa Ti Servirà

  • Potato 2.3.0+ con i pacchetti aggiuntivi Solo Mode: pip install potato-annotation[solo]
  • Una API key di OpenAI o Anthropic (per il componente LLM)
  • Il tuo dataset in formato JSONL
  • Un annotatore esperto (potresti essere tu)

Passo 1: Prepara i Tuoi Dati

Crea data/reviews.jsonl con una recensione per riga:

json
{"id": "rev_001", "text": "Absolutely love this product! Best purchase I've made all year.", "source": "amazon"}
{"id": "rev_002", "text": "It works fine. Nothing special but gets the job done.", "source": "amazon"}
{"id": "rev_003", "text": "Broke after two weeks. Complete waste of money.", "source": "amazon"}
{"id": "rev_004", "text": "The quality is decent for the price point. I might buy again.", "source": "amazon"}
{"id": "rev_005", "text": "Arrived damaged and customer service was unhelpful.", "source": "amazon"}

Per questo tutorial, immagina che questo file contenga 10.000 recensioni.


Passo 2: Crea la Configurazione

Crea config.yaml:

yaml
task_name: "Product Review Sentiment (Solo Mode)"
task_dir: "."
 
data_files:
  - "data/reviews.jsonl"
 
item_properties:
  id_key: id
  text_key: text
 
# --- Configurazione Solo Mode ---
solo_mode:
  enabled: true
 
  llm:
    endpoint_type: openai
    model: "gpt-4o"
    api_key: ${OPENAI_API_KEY}
    temperature: 0.1
    max_tokens: 64
 
  # Obiettivi di qualità
  seed_count: 50
  accuracy_threshold: 0.93
  confidence_threshold: 0.85
 
  # Impostazioni specifiche per fase
  phases:
    seed:
      count: 50
      selection: diversity
      embedding_model: "all-MiniLM-L6-v2"
 
    calibration:
      batch_size: 200
      holdout_fraction: 0.2
 
    labeling_functions:
      enabled: true
      max_functions: 15
      min_precision: 0.92
      min_coverage: 0.01
 
    active_labeling:
      batch_size: 25
      strategy: hybrid
      max_batches: 15
 
    refinement_loop:
      max_iterations: 3
      improvement_threshold: 0.02
 
    disagreement_exploration:
      max_instances: 150
      show_llm_reasoning: true
      show_nearest_neighbors: 3
 
    edge_case_synthesis:
      enabled: true
      count: 30
 
    confidence_escalation:
      escalation_budget: 150
      batch_size: 25
      stop_when_stable: true
 
    prompt_optimization:
      enabled: true
      candidates: 8
      metric: f1_macro
 
    final_validation:
      sample_size: 100
      min_accuracy: 0.93
 
  # Prioritizzazione delle istanze
  prioritization:
    pools:
      - name: uncertain
        weight: 0.30
      - name: disagreement
        weight: 0.25
      - name: boundary
        weight: 0.20
      - name: novel
        weight: 0.10
      - name: error_pattern
        weight: 0.10
      - name: random
        weight: 0.05
 
# --- Schema di Annotazione ---
annotation_schemes:
  - annotation_type: radio
    name: sentiment
    description: "What is the overall sentiment of this review?"
    labels:
      - "Positive"
      - "Neutral"
      - "Negative"
    label_requirement:
      required: true
    sequential_key_binding: true
 
output_annotation_dir: "output/"
output_annotation_format: "jsonl"
 
parquet_export:
  enabled: true
  output_dir: "output/parquet/"

Passo 3: Avvia il Server

bash
potato start config.yaml -p 8000

Apri http://localhost:8000 ed effettua il login. Apparirà la dashboard di Solo Mode, che ti mostra di essere nella Fase 1: Annotazione Seed.


Passo 4: Fase 1 -- Annotazione Seed (50 Istanze)

Potato ha selezionato 50 recensioni diverse usando il clustering basato su embedding. Non sono casuali; sono scelte per massimizzare la copertura della distribuzione dei tuoi dati.

Etichettane ciascuna. Questa è la fase più importante -- la qualità delle tue etichette seed determina quanto bene l'LLM imparerà. Prenditi il tuo tempo e sii coerente.

Stima del tempo: 15-25 minuti a 20-30 secondi per istanza.

Quando finisci la 50ª istanza, Potato avanza automaticamente alla Fase 2.


Passo 5: Fase 2 -- Calibrazione Iniziale dell'LLM

Questa fase viene eseguita automaticamente. Potato invia all'LLM un batch di 200 istanze con le tue 50 etichette seed come esempi few-shot. Poi confronta le previsioni dell'LLM con 10 etichette seed tenute da parte per stimare l'accuratezza di base.

Vedrai un indicatore di progresso nella dashboard. Questo richiede tipicamente 1-2 minuti a seconda del provider LLM.

Risultato tipico: L'LLM raggiunge un'accuratezza del 75-85% nella prima calibrazione. Questo è previsto -- l'LLM non ha ancora imparato il tuo stile di annotazione specifico.


Passo 6: Fase 3 -- Analisi della Confusione

Potato mostra una matrice di confusione che indica dove l'LLM non è d'accordo con le tue etichette. Un output tipico:

text
Confusion Analysis (Round 1)
============================
Overall Accuracy: 0.82 (target: 0.93)

Top Confusion Pairs:
  Neutral -> Positive:  14 instances (7.0%)
  Negative -> Neutral:   9 instances (4.5%)
  Positive -> Neutral:   4 instances (2.0%)

Questo ti dice il punto debole principale dell'LLM: tende ad aggiornare le recensioni neutre a positive. Questo è comune -- gli LLM sono spesso parziali verso il sentiment positivo.

La tua azione: Esamina le coppie di confusione. Clicca su ciascuna coppia per vedere le istanze specifiche in cui l'LLM ha sbagliato. Questo ti aiuta a capire le modalità di fallimento dell'LLM.


Passo 7: Fase 4 -- Raffinamento delle Linee Guida

Sulla base dell'analisi della confusione, Potato genera linee guida raffinate per l'LLM. Vedi una vista affiancata:

  • Linee guida attuali: Il prompt iniziale usato per l'LLM
  • Modifiche suggerite: Cambiamenti specifici che l'LLM propone sulla base degli schemi di errore

Ad esempio, Potato potrebbe suggerire di aggiungere:

"Reviews that describe a product as 'fine', 'okay', or 'decent' without strong emotion should be labeled Neutral, even if they mention buying again."

Esamina ciascuna modifica suggerita. Approva, modifica o rifiuta ciascuna. Puoi anche aggiungere le tue chiarificazioni.

Stima del tempo: 5-10 minuti.


Passo 8: Fase 5 -- Generazione di Funzioni di Etichettatura

Potato genera funzioni di etichettatura programmatiche dagli schemi nelle tue etichette seed. Si tratta di regole veloci e deterministiche che gestiscono i casi facili:

text
Generated Labeling Functions:
  LF1: Strong positive words (love, amazing, best, excellent)
       Precision: 0.97, Coverage: 0.06
  LF2: Strong negative words (terrible, awful, worst, waste)
       Precision: 0.95, Coverage: 0.04
  LF3: Exclamation + positive adjective
       Precision: 0.94, Coverage: 0.03
  LF4: Return/refund mention + negative context
       Precision: 0.92, Coverage: 0.02
  ...
  Total coverage: 0.18 (1,800 of 10,000 instances)

Le funzioni di etichettatura coprono il 18% del dataset con una precisione superiore al 92%. Queste istanze vengono etichettate automaticamente, liberando l'LLM e lo sforzo umano per i casi più difficili.

La tua azione: Esamina le funzioni generate. Disabilita quelle che sembrano inaffidabili. Questo è facoltativo -- Potato mantiene solo le funzioni al di sopra della soglia di precisione configurata.


Passo 9: Fase 6 -- Etichettatura Attiva (125-375 Istanze)

Questa è la fase principale di etichettatura umana. Potato seleziona le istanze usando il sistema di prioritizzazione a sei pool:

  • Uncertain (30%): Recensioni in cui la confidenza dell'LLM è inferiore all'85%
  • Disagreement (25%): Recensioni in cui l'LLM e le funzioni di etichettatura danno etichette diverse
  • Boundary (20%): Recensioni vicine al confine decisionale nello spazio degli embedding
  • Novel (10%): Recensioni diverse da tutto quello che hai etichettato finora
  • Error pattern (10%): Recensioni che corrispondono a schemi di confusione noti (ad es. tono tiepido-positivo)
  • Random (5%): Recensioni casuali per la calibrazione

Le etichetti in batch da 25. Dopo ogni batch, Potato aggiorna la stima dell'accuratezza dell'LLM e decide se continuare.

Traiettoria tipica:

  • Batch 1-3 (75 istanze): L'accuratezza sale dall'82% all'87%
  • Batch 4-6 (150 istanze): L'accuratezza raggiunge il 90%
  • Batch 7-10 (250 istanze): L'accuratezza si stabilizza al 91-92%

Se l'accuratezza raggiunge il 93% (la tua soglia), Solo Mode salta direttamente alla Fase 10. Altrimenti continua alla Fase 7.

Stima del tempo: 45-90 minuti totali, a seconda di quanti batch sono necessari.


Passo 10: Fase 7 -- Loop di Raffinamento Automatizzato

Se l'accuratezza è ancora al di sotto della soglia dopo l'etichettatura attiva, Potato esegue un altro ciclo del loop di raffinamento:

  1. L'LLM ri-etichetta l'intero dataset con linee guida aggiornate e più esempi few-shot
  2. L'accuratezza viene ricalcolata rispetto a tutte le etichette umane
  3. Vengono identificati nuovi schemi di confusione
  4. Le linee guida vengono raffinate di nuovo

Questa fase è principalmente automatica. Devi solo approvare le modifiche alle linee guida.

Risultato tipico: L'accuratezza migliora del 2-4% per ogni ciclo di raffinamento.


Passo 11: Fase 8 -- Esplorazione dei Disaccordi

Potato presenta le istanze più controverse: casi in cui l'LLM, le funzioni di etichettatura e l'analisi dei vicini più prossimi danno risposte diverse. Per ogni istanza, vedi:

  • Il testo della recensione
  • La previsione e la confidenza dell'LLM
  • I voti delle funzioni di etichettatura
  • 3 esempi etichettati più vicini con le loro etichette
  • Il ragionamento chain-of-thought dell'LLM

Questi sono casi genuinamente difficili. Le tue etichette qui hanno il valore marginale più alto di qualsiasi annotazione nell'intero processo.

Stima del tempo: 20-30 minuti per 100-150 istanze.


Passo 12: Fase 9 -- Sintesi dei Casi Limite

Potato genera recensioni sintetiche che mirano agli schemi di confusione rimanenti. Ad esempio, se l'LLM fatica ancora con le "recensioni neutre che menzionano l'acquisto futuro", genera esempi come:

"It's an okay product for the price. I might get another one if there's a sale."

Etichetti questi esempi sintetici, che vengono aggiunti al contesto few-shot dell'LLM.

Stima del tempo: 10-15 minuti per 30 esempi.


Passo 13: Fase 10 -- Escalation Cascata della Confidenza

L'LLM ha ora etichettato la maggior parte del dataset. Potato classifica tutte le istanze etichettate dall'LLM per confidenza e ti invia quelle con la confidenza più bassa in batch da 25.

text
Confidence Escalation Progress:
  Batch 1: 25 instances, 23/25 correct (92%)
  Batch 2: 25 instances, 24/25 correct (96%)
  Batch 3: 25 instances, 25/25 correct (100%)
  -> Stopping: last 3 batches stable

Una volta che vedi tre batch consecutivi in cui l'LLM ha fatto tutto correttamente, Solo Mode conclude che le etichette rimanenti con alta confidenza sono affidabili.

Stima del tempo: 15-20 minuti.


Passo 14: Fase 11 -- Ottimizzazione del Prompt

Questa fase viene eseguita automaticamente. Potato prova 8 varianti del prompt e seleziona quella con il punteggio F1 più alto sulle tue etichette umane accumulate:

text
Prompt Optimization Results:
  Variant 1 (direct, 5 examples):     F1=0.91
  Variant 2 (CoT, 5 examples):        F1=0.93
  Variant 3 (direct, 10 examples):    F1=0.92
  Variant 4 (CoT, 10 examples):       F1=0.94  <-- selected
  Variant 5 (direct, 15 examples):    F1=0.92
  Variant 6 (CoT, 15 examples):       F1=0.93
  Variant 7 (self-consistency, 5x):   F1=0.94
  Variant 8 (self-consistency, 10x):  F1=0.94

Il miglior prompt viene usato per un passaggio finale di ri-etichettatura.


Passo 15: Fase 12 -- Validazione Finale

Potato seleziona 100 istanze etichettate dall'LLM a caso per la tua revisione. Le etichetti, e Potato confronta con le etichette dell'LLM.

text
Final Validation:
  Reviewed: 100 instances
  LLM correct: 94/100 (94%)
  Threshold: 93%
  -> PASSED

Se l'accuratezza dell'LLM soddisfa la tua soglia, il dataset è completo. Altrimenti, Solo Mode torna alla Fase 6 per un altro ciclo di etichettatura attiva.

Stima del tempo: 10-15 minuti.


Riepilogo dei Risultati

Dopo aver percorso tutte le 12 fasi, controlla le statistiche finali:

bash
python -m potato.solo status --config config.yaml
text
Solo Mode Complete
==================
Dataset: 10,000 instances
Total human labels: 612
  Seed: 50
  Active labeling: 275
  Disagreement exploration: 137
  Edge case synthesis: 30
  Confidence escalation: 75
  Final validation: 45

LLM labels: 8,200 (accuracy: 94.1%)
LF labels: 1,800 (precision: 95.3%)
Unlabeled: 0

Final label distribution:
  Positive: 4,823 (48.2%)
  Neutral:  3,011 (30.1%)
  Negative: 2,166 (21.7%)

Total human time: ~3.5 hours
Estimated multi-annotator cost (3x): ~$4,500
Solo Mode cost: ~$450 (API fees) + ~$175 (annotator time)
Savings: ~88%

L'annotatore umano ha etichettato 612 su 10.000 istanze (6,1%). L'LLM e le funzioni di etichettatura hanno gestito il resto con un'accuratezza del 94%+.


Esportazione dei Risultati

Esporta il dataset finale etichettato:

bash
python -m potato.solo export --config config.yaml --output final_labels.jsonl

Ogni riga include l'etichetta e la sua fonte:

json
{"id": "rev_001", "sentiment": "Positive", "source": "human", "confidence": 1.0}
{"id": "rev_002", "sentiment": "Neutral", "source": "llm", "confidence": 0.91}
{"id": "rev_003", "sentiment": "Negative", "source": "labeling_function", "confidence": 0.97}

Per l'esportazione Parquet:

python
import pandas as pd
df = pd.read_parquet("output/parquet/annotations.parquet")
print(df["value"].value_counts())

Garanzia della Qualità: Verifica Ibrida

Per dataset di qualità da pubblicazione, aggiungi un secondo annotatore per revisionare un campione:

yaml
solo_mode:
  verification:
    enabled: true
    sample_fraction: 0.10
    annotator: "reviewer_1"

Questo assegna 1.000 istanze casuali a un secondo annotatore. Puoi quindi calcolare l'accordo inter-annotatore tra le etichette di Solo Mode e le etichette del revisore.


Risoluzione dei Problemi

L'accuratezza dell'LLM si stabilizza al di sotto della soglia

  • Aumenta il numero di seed: Prova con 75-100 istanze seed invece di 50
  • Cambia LLM: Prova claude-sonnet-4-20250514 invece di GPT-4o (o viceversa)
  • Abbassa la soglia: Se il 93% non è raggiungibile, considera se il 90% è accettabile per il tuo caso d'uso
  • Controlla i tuoi dati: Alcuni dataset sono intrinsecamente ambigui. Se l'accordo umano-umano sarebbe solo del 90%, non aspettarti che l'LLM faccia meglio

La Fase 6 richiede troppi batch

  • Aumenta la dimensione del batch: Cambia batch_size da 25 a 50
  • Regola i pesi dei pool: Se la maggior parte delle istanze escalate proviene dal pool "uncertain", riduci il suo peso e aumenta "disagreement" e "error_pattern"

Le funzioni di etichettatura hanno una bassa copertura

  • Questo è normale per task senza forti segnali lessicali (ad es. rilevamento del sarcasmo, sentiment implicito)
  • Le funzioni di etichettatura funzionano meglio per schemi espliciti e guidati da parole chiave
  • Solo Mode funziona ancora senza funzioni di etichettatura -- l'LLM compensa

Ulteriori Letture