Skip to content
Tutorials12 Min. Lesezeit

Solo Mode: Wie ein einzelner Annotator 10.000 Beispiele beschriften kann

Schritt-für-Schritt-Tutorial zu Potatos Solo Mode: eine Startmenge selbst beschriften, den Rest von einem LLM beschriften lassen und anhand der Genauigkeitsprüfungen entscheiden, wann das Ergebnis gut genug ist, um aufzuhören.

Potato Team

Sie haben 10.000 Produktbewertungen nach Stimmung (Positiv, Neutral, Negativ) zu beschriften. Wenn drei Annotatoren alle davon beschriften, dauert das Wochen und kostet Tausende von Dollar. Mit Solo Mode erreicht ein einzelner Domänenexperte vergleichbare Qualität, indem er nur 500-1.000 Instanzen beschriftet. Ein LLM übernimmt den Rest, und der Mensch prüft alles, bei dem sich das LLM unsicher ist.

Dieses Tutorial geht den gesamten Prozess durch.


Was Sie benötigen

  • Potato 2.3.0 oder neuer, mit den KI-Extras für die LLM-Anbieter: pip install potato-annotation[ai]
  • Einen OpenAI- oder Anthropic-API-Schlüssel (für die LLM-Komponente)
  • Ihren Datensatz im JSONL-Format
  • Einen sachkundigen Annotator (das können Sie selbst sein)

Schritt 1: Daten vorbereiten

Erstellen Sie data/reviews.jsonl mit einer Bewertung pro Zeile:

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"}

Stellen Sie sich für dieses Tutorial vor, dass diese Datei 10.000 Bewertungen enthält.


Schritt 2: Die Konfiguration erstellen

Erstellen Sie config.yaml:

yaml
annotation_task_name: "Product Review Sentiment (Solo Mode)"
task_dir: "."
 
data_files:
  - "data/reviews.jsonl"
 
item_properties:
  id_key: id
  text_key: text
 
# --- Solo Mode Configuration ---
solo_mode:
  enabled: true
 
  # The model that labels. A list, so you can give fallbacks.
  labeling_models:
    - endpoint_type: openai
      model: "gpt-4o"
      api_key: ${OPENAI_API_KEY}
      temperature: 0.1
      max_tokens: 1024
 
  embedding:
    model_name: "all-MiniLM-L6-v2"
 
  uncertainty:
    strategy: direct_confidence
 
  # When you are allowed to stop labeling
  thresholds:
    end_human_annotation_agreement: 0.93
    minimum_validation_sample: 50
    confidence_low: 0.5
    confidence_high: 0.85
    periodic_review_interval: 100
 
  # What decides which instance you see next
  instance_selection:
    low_confidence_weight: 0.30
    disagreement_weight: 0.25
    diversity_weight: 0.20
    llm_predicted_weight: 0.15
    random_weight: 0.10
 
  batches:
    llm_labeling_batch: 25
    max_parallel_labels: 200
 
  labeling_functions:
    enabled: true
    auto_extract: true
    max_functions: 15
    min_confidence: 0.92
    min_coverage: 3
 
  edge_case_rules:
    enabled: true
    auto_extract_on_labeling: true
 
  confusion_analysis:
    enabled: true
    min_instances_for_pattern: 3
    max_patterns: 20
 
  prompt_optimization:
    enabled: true
    target_accuracy: 0.93
 
  refinement_loop:
    enabled: true
    trigger_interval: 50
    min_improvement: 0.02
    max_cycles: 3
 
  state_dir: "solo_state_reviews"
 
# --- Annotation Schema ---
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/"
export_annotation_format:
  - jsonl
  - parquet

Schritt 3: Den Server starten

bash
potato start config.yaml -p 8000

Öffnen Sie http://localhost:8000 und melden Sie sich an. Das Solo-Mode-Dashboard erscheint. Es zeigt das Projekt in der Einrichtung, bereit dafür, dass Sie den von ihm synthetisierten Prompt prüfen.


Schritt 4: Parallele Annotation, Ihre ersten 50

Potato hat mithilfe von embedding-basiertem Clustering 50 unterschiedliche Bewertungen ausgewählt. Sie sind nicht zufällig, sondern so gewählt, dass sie Ihre Datenverteilung möglichst breit abdecken.

Beschriften Sie jede einzelne. Diese Phase ist die wichtigste, denn die Qualität Ihrer Seed-Labels setzt die Obergrenze dessen, was das LLM lernen kann. Nehmen Sie sich Zeit und bleiben Sie konsistent.

Zeitschätzung: 15-25 Minuten bei 20-30 Sekunden pro Instanz.

Sobald genug davon beschriftet sind, beginnt das LLM ohne Aufforderung, parallel zu Ihnen zu beschriften.


Schritt 5: Das LLM holt auf

Diese Phase läuft von selbst. Potato sendet dem LLM einen Batch von 200 Instanzen mit Ihren 50 Seed-Labels als Few-Shot-Beispiele und vergleicht die Vorhersagen dann mit 10 zurückgehaltenen Seed-Labels, um die Basisgenauigkeit zu schätzen.

Im Dashboard erscheint ein Fortschrittsindikator. Das dauert je nach LLM-Anbieter meist 1-2 Minuten.

Typisches Ergebnis: Das LLM landet bei der ersten Kalibrierung bei 75-85 % Genauigkeit. Das ist zu erwarten. Es hat Ihren Annotationsstil noch nicht gelernt.


Schritt 6: Konfusionsanalyse

Potato zeigt eine Konfusionsmatrix, aus der hervorgeht, wo das LLM von Ihren Labels abweicht. Eine typische Ausgabe:

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%)

Das zeigt die Hauptschwäche des LLM in diesem Fall: Es stuft neutrale Bewertungen immer wieder zu positiv hoch. Das kommt häufig vor, weil LLMs zum Positiven neigen.

Ihre Aktion: Sehen Sie die Konfusionspaare durch. Klicken Sie auf jedes Paar, um die konkreten Instanzen zu sehen, bei denen das LLM falsch lag. So verstehen Sie am schnellsten, wie es scheitert.


Schritt 7: Zurück zur Prompt-Prüfung

Auf Grundlage der Konfusionsanalyse entwirft Potato verfeinerte Leitfäden für das LLM und zeigt sie nebeneinander an: auf der einen Seite den aktuellen Prompt, auf der anderen die konkreten Änderungen, die es aus den Fehlermustern ableitet.

Potato könnte zum Beispiel vorschlagen, Folgendes hinzuzufügen:

"Bewertungen, die ein Produkt ohne starke Emotion als 'in Ordnung', 'okay' oder 'ordentlich' beschreiben, sollten als Neutral beschriftet werden, auch wenn sie einen erneuten Kauf erwähnen."

Gehen Sie jede vorgeschlagene Änderung durch und genehmigen, ändern oder verwerfen Sie sie. Sie können auch eigene Klarstellungen ergänzen.

Zeitschätzung: 5-10 Minuten.


Schritt 8: Labeling-Funktionen

Potato erzeugt aus Mustern in Ihren Seed-Labels programmatische Labeling-Funktionen. Das sind schnelle, deterministische Regeln, die einfache Fälle abdecken:

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)

Die Labeling-Funktionen decken 18 % Ihres Datensatzes mit einer Präzision von über 92 % ab. Diese Instanzen werden automatisch beschriftet, sodass LLM und Mensch sich um die schwierigeren Fälle kümmern können.

Ihre Aktion: Sehen Sie die erzeugten Funktionen durch und deaktivieren Sie alle, die unzuverlässig wirken. Dieser Schritt ist optional, da Potato ohnehin nur Funktionen oberhalb Ihrer konfigurierten Präzisionsschwelle behält.


Schritt 9: Aktive Annotation (125-375 Instanzen)

Hier erledigen Sie den Großteil Ihrer Beschriftung. Potato wählt Instanzen anhand der gewichteten Pools aus, die oben in instance_selection festgelegt sind:

  • low_confidence_weight (0.30): Bewertungen, bei denen die Konfidenz des LLM am niedrigsten ist
  • disagreement_weight (0.25): Bewertungen, bei denen LLM und Labeling-Funktionen nicht übereinstimmen
  • diversity_weight (0.20): Bewertungen, die so gewählt sind, dass sie sich über den Embedding-Raum verteilen, statt sich zu häufen
  • llm_predicted_weight (0.15): Vom LLM beschriftete Bewertungen, die zum Vergleich mit einem Menschen zurückgeholt werden
  • random_weight (0.10): Zufällige Bewertungen zur Kalibrierung

Zwei weitere Gewichte gibt es. Sie bleiben hier auf ihrem Standardwert null und tragen daher nichts bei: edge_case_rule_weight für Instanzen, die zu einer entdeckten Grenzfallregel passen, und cartography_weight für Instanzen, deren Konfidenz zwischen den Runden schwankt. Potato prüft, ob die Gewichte 1.0 ergeben, und protokolliert eine Warnung, wenn nicht. Es verwendet die Werte aber so, wie sie geschrieben sind, also sorgen Sie selbst dafür, dass die Summe stimmt.

Sie beschriften diese in Batches von 25. Nach jedem Batch aktualisiert Potato die Genauigkeitsschätzung des LLM und entscheidet, ob es weitergeht.

Typischer Verlauf:

  • Batch 1-3 (75 Instanzen): Die Genauigkeit steigt von 82 % auf 87 %
  • Batch 4-6 (150 Instanzen): Die Genauigkeit erreicht 90 %
  • Batch 7-10 (250 Instanzen): Die Genauigkeit stagniert bei 91-92 %

Erreicht die Übereinstimmung Ihren Wert für end_human_annotation_agreement, geht Solo Mode zum autonomen Beschriften über. Andernfalls durchläuft es weiter Prüfung und Verfeinerung.

Zeitschätzung: 45-90 Minuten insgesamt, je nachdem, wie viele Batches nötig sind.


Schritt 10: Die Verfeinerungsschleife

Liegt die Genauigkeit nach der aktiven Beschriftung noch unter der Schwelle, führt Potato eine weitere Runde der Verfeinerungsschleife aus:

  1. Das LLM beschriftet den gesamten Datensatz mit aktualisierten Leitfäden und mehr Few-Shot-Beispielen neu
  2. Potato berechnet die Genauigkeit gegenüber allen menschlichen Labels neu
  3. Es ermittelt die neuen Konfusionsmuster
  4. Es verfeinert die Leitfäden erneut

Diese Phase läuft weitgehend ohne Ihr Zutun. Sie müssen nur die Änderungen an den Leitfäden genehmigen.

Typisches Ergebnis: Die Genauigkeit verbessert sich pro Verfeinerungsrunde um 2-4 %.


Schritt 11: Auflösung von Unstimmigkeiten

Potato legt Ihnen die umstrittensten Instanzen vor: Fälle, in denen LLM, Labeling-Funktionen und Nearest-Neighbor-Analyse jeweils unterschiedliche Antworten liefern. Zu jeder Instanz sehen Sie:

  • Den Text der Bewertung
  • Die Vorhersage des LLM und ihre Konfidenz
  • Die Stimmen der Labeling-Funktionen
  • Die 3 nächstgelegenen beschrifteten Beispiele mit ihren Labels
  • Die Chain-of-Thought-Begründung des LLM

Das sind die schwierigen Fälle, und Ihre Labels haben hier mehr Gewicht als an jeder anderen Stelle im Prozess.

Zeitschätzung: 20-30 Minuten für 100-150 Instanzen.


Schritt 12: Synthese von Grenzfällen

Potato erzeugt synthetische Bewertungen, die auf die verbleibenden Konfusionsmuster zielen. Hat das LLM zum Beispiel noch Probleme mit „neutralen Bewertungen, die einen erneuten Kauf erwähnen“, erzeugt es Beispiele wie:

"Für den Preis ist das Produkt okay. Vielleicht kaufe ich noch eines, wenn es im Angebot ist."

Sie beschriften diese synthetischen Beispiele, und Potato fügt sie dem Few-Shot-Kontext des LLM hinzu.

Zeitschätzung: 10-15 Minuten für 30 Beispiele.


Schritt 13: Periodische Prüfung

Inzwischen hat das LLM den größten Teil des Datensatzes beschriftet. Potato ordnet alle seine Labels nach Konfidenz und schickt Ihnen die mit der niedrigsten Konfidenz in Batches von 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

Sobald sich die Genauigkeit über drei Batches in Folge nicht mehr bewegt, behandelt Solo Mode die verbleibenden Labels mit hoher Konfidenz als vertrauenswürdig. Beachten Sie, dass es hier um Stabilität geht und nicht um Perfektion. Der Lauf oben stoppt nach 92 %, 96 % und 100 %, weil sich der Wert eingependelt hat, nicht weil der letzte Batch fehlerfrei war.

Zeitschätzung: 15-20 Minuten.


Schritt 14: Prompt-Optimierung

Diese Phase läuft von selbst. Potato probiert 8 Prompt-Varianten aus und behält diejenige mit dem höchsten F1-Score auf Ihren gesammelten menschlichen Labels:

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

Den besten Prompt verwendet es dann für einen abschließenden Durchgang zur Neubeschriftung.


Schritt 15: Abschließende Validierung

Potato wählt 100 zufällige vom LLM beschriftete Instanzen zur Prüfung aus. Sie beschriften diese, und Potato vergleicht Ihre Labels mit denen des LLM.

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

Erreicht das LLM Ihre Schwelle, ist das Projekt abgeschlossen. Andernfalls fällt es für eine weitere Runde auf die aktive Annotation zurück. Dieser Rückweg ist der einzige Übergang, der aus der abschließenden Validierung erlaubt ist.

Zeitschätzung: 10-15 Minuten.


Zusammenfassung der Ergebnisse

Am Ende zeigt das Dashboard, woher die Labels stammen. Solo Mode hat keine Kommandozeilenschnittstelle (es läuft im Server und wird über eigene Seiten gesteuert), daher lesen Sie diese Angaben in der laufenden Instanz ab und nicht in einem Terminal:

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%

Der Mensch hat 612 von 10.000 Instanzen beschriftet, etwa 6 %. Das LLM und die Labeling-Funktionen haben den Rest mit einer Genauigkeit von über 94 % übernommen.


Ergebnisse exportieren

Solo Mode schreibt in denselben Speicher wie jedes andere Projekt, daher kommen die Labels über den gewöhnlichen Exporter heraus:

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

Jede Zeile enthält das Label und seine Quelle:

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}

Für den Parquet-Export:

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

annotations.parquet enthält eine Zeile pro Instanz und Annotator, wobei jedes Annotationsschema in eine eigene Spalte aufgelöst wird. Sie wählen das Schema also über seinen Namen aus und nicht über eine generische Spalte value.


Qualitätssicherung: Hybride Verifikation

Für Datensätze in Publikationsqualität lassen Sie einen zweiten Annotator eine Stichprobe prüfen. Die Quelldokumentation zu Solo Mode beschreibt die Verifikationsoptionen ausführlicher.

Solo Mode hat keinen eigenen Verifikationsblock, das hier ist also ein gewöhnlicher zweiter Durchgang: Exportieren Sie die Labels, geben Sie sie als normales Projekt erneut in Potato, wobei ein Prüfer eine Stichprobe von 10 % bearbeitet, und berechnen Sie die Übereinstimmung zwischen Prüfer und Solo-Mode-Labels so, wie Sie es für zwei beliebige Annotatoren tun würden. (icl_labeling hat zwar einen Block verification, der gehört aber zum In-Context-Labeling und nicht zu Solo Mode.)


Fehlerbehebung

LLM-Genauigkeit stagniert unter der Schwelle

  • Seed-Anzahl erhöhen: Versuchen Sie 75-100 Seed-Instanzen statt 50
  • LLM wechseln: Versuchen Sie claude-sonnet-4-20250514 statt GPT-4o (oder umgekehrt)
  • Schwelle senken: Wenn 93 % nicht erreichbar sind, überlegen Sie, ob 90 % für Ihren Anwendungsfall genügen
  • Daten prüfen: Manche Datensätze sind von Natur aus mehrdeutig. Wenn die Übereinstimmung zwischen Menschen nur bei 90 % läge, erwarten Sie nicht, dass das LLM besser abschneidet

Die aktive Annotation braucht zu viele Batches

  • Batch-Größe erhöhen: Ändern Sie batch_size von 25 auf 50
  • Pool-Gewichte anpassen: Wenn die meisten eskalierten Instanzen aus dem Pool mit niedriger Konfidenz stammen, senken Sie low_confidence_weight und erhöhen Sie disagreement_weight oder diversity_weight

Labeling-Funktionen haben geringe Abdeckung

  • Das ist normal bei Aufgaben ohne starke lexikalische Signale (z. B. Sarkasmuserkennung, implizite Stimmung)
  • Labeling-Funktionen funktionieren am besten bei expliziten, schlüsselwortbasierten Mustern
  • Solo Mode funktioniert auch ohne Labeling-Funktionen, dann deckt das LLM diese Instanzen ab

Weiterführende Lektüre