Skip to content
Tutorials11 min read

Solo Mode: Wie ein Annotator 10.000 Beispiele beschriften kann

Schritt-für-Schritt-Tutorial zur effizienten Beschriftung großer Datensätze mit Potatos Solo Mode und menschlich-LLM-Kollaboration – Annotationskosten um bis zu 90 % reduzieren.

Potato Team·
このページはまだお使いの言語に翻訳されていません。英語版を表示しています。

Solo Mode: Wie ein Annotator 10.000 Beispiele beschriften kann

Sie haben 10.000 Produktbewertungen nach Stimmung (Positiv, Neutral, Negativ) zu beschriften. Drei Annotatoren für alles einzustellen würde Wochen dauern und Tausende von Euro kosten. Mit Solo Mode kann ein einzelner Domänenexperte vergleichbare Qualität erreichen, indem er nur 500–1.000 Instanzen beschriftet, während ein LLM den Rest übernimmt -- wobei der Mensch jede Entscheidung überprüft, bei der das LLM unsicher ist.

Dieses Tutorial führt Sie durch den gesamten Prozess von Anfang bis Ende.


Was Sie benötigen

  • Potato 2.3.0+ mit den Solo-Mode-Extras: pip install potato-annotation[solo]
  • Einen OpenAI- oder Anthropic-API-Schlüssel (für die LLM-Komponente)
  • Ihren Datensatz im JSONL-Format
  • Einen sachkundigen Annotator (das könnten Sie selbst sein)

Schritt 1: Ihre 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
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
 
  llm:
    endpoint_type: openai
    model: "gpt-4o"
    api_key: ${OPENAI_API_KEY}
    temperature: 0.1
    max_tokens: 64
 
  # Quality targets
  seed_count: 50
  accuracy_threshold: 0.93
  confidence_threshold: 0.85
 
  # Phase-specific settings
  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
 
  # Instance prioritization
  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
 
# --- 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/"
output_annotation_format: "jsonl"
 
parquet_export:
  enabled: true
  output_dir: "output/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 und zeigt an, dass Sie sich in Phase 1: Seed-Annotation befinden.


Schritt 4: Phase 1 -- Seed-Annotation (50 Instanzen)

Potato hat 50 diverse Bewertungen mittels embedding-basiertem Clustering ausgewählt. Diese sind nicht zufällig; sie wurden ausgewählt, um die Abdeckung Ihrer Datenverteilung zu maximieren.

Beschriften Sie jede einzelne. Dies ist die wichtigste Phase -- die Qualität Ihrer Seed-Labels bestimmt, wie gut das LLM lernen wird. Nehmen Sie sich Zeit und seien Sie konsistent.

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

Wenn Sie die 50. Instanz abschließen, wechselt Potato automatisch zu Phase 2.


Schritt 5: Phase 2 -- Initiale LLM-Kalibrierung

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

Im Dashboard sehen Sie einen Fortschrittsindikator. Dies dauert typischerweise 1–2 Minuten, abhängig vom LLM-Anbieter.

Typisches Ergebnis: Das LLM erreicht beim ersten Kalibrierungsschritt 75–85 % Genauigkeit. Dies ist zu erwarten -- das LLM hat Ihren spezifischen Annotationsstil noch nicht gelernt.


Schritt 6: Phase 3 -- Konfusionsanalyse

Potato zeigt eine Konfusionsmatrix, die zeigt, wo das LLM mit Ihren Labels nicht übereinstimmt. 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%)

Dies zeigt die Hauptschwäche des LLM: Es neigt dazu, neutrale Bewertungen zu positiv hochzustufen. Dies ist häufig -- LLMs haben oft eine Tendenz zu positiver Stimmung.

Ihre Aktion: Überprüfen Sie die Konfusionspaare. Klicken Sie auf jedes Paar, um die spezifischen Instanzen zu sehen, bei denen das LLM falsch lag. Das hilft Ihnen, die Fehlerarten des LLM zu verstehen.


Schritt 7: Phase 4 -- Leitfaden-Verfeinerung

Basierend auf der Konfusionsanalyse generiert Potato verfeinerte Leitfäden für das LLM. Sie sehen eine Nebeneinanderdarstellung:

  • Aktuelle Leitfäden: Der initiale Prompt für das LLM
  • Vorgeschlagene Änderungen: Spezifische Anpassungen, die das LLM basierend auf Fehlermustern vorschlägt

Zum Beispiel könnte Potato vorschlagen, hinzuzufügen:

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

Überprüfen Sie jeden vorgeschlagenen Edit. Genehmigen, ändern oder lehnen Sie jeden ab. Sie können auch eigene Klarstellungen hinzufügen.

Zeitschätzung: 5–10 Minuten.


Schritt 8: Phase 5 -- Labeling-Funktions-Generierung

Potato generiert programmatische Labeling-Funktionen aus Mustern in Ihren Seed-Labels. Dies sind schnelle, deterministische Regeln, die einfache Fälle behandeln:

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)

Labeling-Funktionen decken 18 % Ihres Datensatzes mit einer Präzision von 92 %+ ab. Diese Instanzen werden automatisch beschriftet, was LLM- und Menschenaufwand für schwierigere Fälle freisetzt.

Ihre Aktion: Überprüfen Sie die generierten Funktionen. Deaktivieren Sie alle, die unzuverlässig erscheinen. Dies ist optional -- Potato behält nur Funktionen, die über Ihrer konfigurierten Präzisionsschwelle liegen.


Schritt 9: Phase 6 -- Aktives Labeling (125–375 Instanzen)

Dies ist die Haupt-Beschriftungsphase für Menschen. Potato wählt Instanzen mit dem Sechs-Pool-Priorisierungssystem aus:

  • Uncertain (30 %): Bewertungen, bei denen die Konfidenz des LLM unter 85 % liegt
  • Disagreement (25 %): Bewertungen, bei denen LLM und Labeling-Funktionen unterschiedliche Labels vergeben
  • Boundary (20 %): Bewertungen nahe der Entscheidungsgrenze im Embedding-Raum
  • Novel (10 %): Bewertungen, die sich von allem bisher Beschrifteten unterscheiden
  • Error pattern (10 %): Bewertungen, die bekannten Konfusionsmustern entsprechen (z.B. lau-positiv)
  • Random (5 %): Zufällige Bewertungen zur Kalibrierung

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

Typischer Verlauf:

  • Batches 1–3 (75 Instanzen): Genauigkeit steigt von 82 % auf 87 %
  • Batches 4–6 (150 Instanzen): Genauigkeit erreicht 90 %
  • Batches 7–10 (250 Instanzen): Genauigkeit stabilisiert sich bei 91–92 %

Wenn die Genauigkeit 93 % (Ihre Schwelle) erreicht, springt Solo Mode direkt zu Phase 10. Andernfalls geht es mit Phase 7 weiter.

Zeitschätzung: 45–90 Minuten insgesamt, je nachdem, wie viele Batches benötigt werden.


Schritt 10: Phase 7 -- Automatisierte Verfeinerungsschleife

Wenn die Genauigkeit nach dem aktiven Labeling noch unter der Schwelle liegt, führt Potato eine weitere Runde der Verfeinerungsschleife durch:

  1. LLM beschriftet den gesamten Datensatz erneut mit aktualisierten Leitfäden und mehr Few-Shot-Beispielen
  2. Genauigkeit wird anhand aller menschlichen Labels neu berechnet
  3. Neue Konfusionsmuster werden identifiziert
  4. Leitfäden werden erneut verfeinert

Diese Phase ist größtenteils automatisch. Sie müssen nur Leitfadenänderungen genehmigen.

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


Schritt 11: Phase 8 -- Disagreement-Erkundung

Potato präsentiert die umstrittensten Instanzen: Fälle, bei denen LLM, Labeling-Funktionen und Nearest-Neighbor-Analyse alle unterschiedliche Antworten geben. Für jede Instanz sehen Sie:

  • Den Bewertungstext
  • LLM-Vorhersage und Konfidenz
  • Stimmen der Labeling-Funktionen
  • 3 nächste beschriftete Beispiele mit ihren Labels
  • Die Chain-of-Thought-Überlegung des LLM

Dies sind echte schwierige Fälle. Ihre Labels hier haben den höchsten Grenzwert aller Annotationen im gesamten Prozess.

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


Schritt 12: Phase 9 -- Edge-Case-Synthese

Potato generiert synthetische Bewertungen, die auf die verbleibenden Konfusionsmuster abzielen. Wenn das LLM zum Beispiel noch Schwierigkeiten mit „neutralen Bewertungen, die erneuten Kauf erwähnen" hat, generiert es Beispiele wie:

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

Sie beschriften diese synthetischen Beispiele, und sie werden dem Few-Shot-Kontext des LLM hinzugefügt.

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


Schritt 13: Phase 10 -- Kaskadierte Konfidenz-Eskalation

Das LLM hat nun den größten Teil des Datensatzes beschriftet. Potato ordnet alle LLM-beschrifteten Instanzen nach Konfidenz und schickt die mit der niedrigsten Konfidenz in Batches von 25 zu Ihnen.

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 Sie drei aufeinanderfolgende Batches sehen, bei denen das LLM alles richtig gemacht hat, schlussfolgert Solo Mode, dass die verbleibenden Hochkonfidenz-Labels vertrauenswürdig sind.

Zeitschätzung: 15–20 Minuten.


Schritt 14: Phase 11 -- Prompt-Optimierung

Diese Phase läuft automatisch. Potato testet 8 Prompt-Varianten und wählt diejenige mit dem höchsten F1-Score auf Ihren akkumulierten menschlichen Labels aus:

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

Der beste Prompt wird für einen abschließenden Neubeschriftungsdurchgang verwendet.


Schritt 15: Phase 12 -- Abschlussprüfung

Potato wählt 100 zufällige LLM-beschriftete Instanzen zur Überprüfung aus. Sie beschriften diese, und Potato vergleicht sie mit den Labels des LLM.

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

Wenn die Genauigkeit des LLM Ihre Schwelle erreicht, ist der Datensatz vollständig. Falls nicht, kehrt Solo Mode zu Phase 6 für eine weitere Runde aktiven Labelings zurück.

Zeitschätzung: 10–15 Minuten.


Ergebniszusammenfassung

Überprüfen Sie nach allen 12 Phasen die abschließenden Statistiken:

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%

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


Ergebnisse exportieren

Exportieren Sie den endgültig beschrifteten Datensatz:

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

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 Parquet-Export:

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

Qualitätssicherung: Hybride Verifikation

Für publikationsqualitative Datensätze fügen Sie einen zweiten Annotator hinzu, der eine Stichprobe überprüft:

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

Dies weist 1.000 zufällige Instanzen einem zweiten Annotator zu. Sie können dann die Übereinstimmung zwischen Annotatoren zwischen den Solo-Mode-Labels und den Labels des Prüfers berechnen.


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 ist, überlegen Sie, ob 90 % für Ihren Anwendungsfall akzeptabel ist
  • Ihre Daten prüfen: Einige Datensätze sind inhärent mehrdeutig. Wenn die menschliche Übereinstimmung nur 90 % betragen würde, erwarten Sie nicht, dass das LLM besser abschneidet

Phase 6 benötigt zu viele Batches

  • Batch-Größe erhöhen: batch_size von 25 auf 50 ändern
  • Pool-Gewichte anpassen: Wenn die meisten eskalierten Instanzen aus dem „uncertain"-Pool stammen, reduzieren Sie dessen Gewicht und erhöhen Sie „disagreement" und „error_pattern"

Labeling-Funktionen haben geringe Abdeckung

  • Dies ist normal bei Aufgaben ohne starke lexikalische Signale (z.B. Sarkasmus-Erkennung, implizite Stimmung)
  • Labeling-Funktionen funktionieren am besten für explizite, schlüsselwortgesteuerte Muster
  • Solo Mode funktioniert auch ohne Labeling-Funktionen -- das LLM übernimmt den Rest

Weiterführende Lektüre