Skip to content
Tutorials12 min read

Modo Solo: Como um Único Anotador Pode Rotular 10.000 Exemplos

Tutorial passo a passo do Modo Solo do Potato: rotule você mesmo um conjunto inicial, deixe um LLM rotular o resto e use as verificações de acurácia para decidir quando parar.

Potato Team

Você tem 10.000 avaliações de produtos para rotular quanto ao sentimento (Positivo, Neutro, Negativo). Contratar três anotadores para rotular todas elas leva semanas e custa milhares de dólares. O Modo Solo permite que um único especialista do domínio obtenha qualidade comparável rotulando apenas 500-1.000 instâncias; um LLM cuida do restante, e a pessoa revisa o que quer que o LLM não tenha certeza.

Este tutorial percorre todo o processo.


O que você vai precisar

  • Potato 2.3.0+ com os extras do Modo Solo: pip install potato-annotation[solo]
  • Uma chave de API da OpenAI ou da Anthropic (para o componente LLM)
  • Seu conjunto de dados em formato JSONL
  • Um anotador com conhecimento (que pode ser você)

Passo 1: Prepare seus dados

Crie data/reviews.jsonl com uma avaliação por linha:

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

Para este tutorial, imagine que este arquivo contém 10.000 avaliações.


Passo 2: Crie a configuração

Crie 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
 
  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/"
export_annotation_format: "jsonl"
 
parquet_export:
  enabled: true
  output_dir: "output/parquet/"

Passo 3: Inicie o servidor

bash
potato start config.yaml -p 8000

Abra http://localhost:8000 e faça login. O painel do Modo Solo aparece, mostrando que você está na Fase 1: Anotação de Sementes.


Passo 4: Fase 1 -- Anotação de Sementes (50 Instâncias)

O Potato escolheu 50 avaliações diversas usando clusterização baseada em embeddings. Elas não são aleatórias; foram selecionadas para cobrir a distribuição dos seus dados da forma mais ampla possível.

Rotule cada uma delas. Esta é a fase que mais importa, pois a qualidade dos seus rótulos de semente define o teto do que o LLM consegue aprender. Reserve seu tempo e mantenha a consistência.

Estimativa de tempo: 15-25 minutos, a 20-30 segundos por instância.

Quando você terminar a 50ª instância, o Potato avança sozinho para a Fase 2.


Passo 5: Fase 2 -- Calibração Inicial do LLM

Esta fase roda sozinha. O Potato envia ao LLM um lote de 200 instâncias com seus 50 rótulos de semente como exemplos few-shot, depois compara as previsões com 10 rótulos de semente reservados para estimar a acurácia de base.

Um indicador de progresso aparece no painel. Isso normalmente leva de 1 a 2 minutos, dependendo do provedor do LLM.

Resultado típico: O LLM fica em 75-85% de acurácia na primeira calibração. Isso é esperado. Ele ainda não aprendeu o seu estilo de anotação.


Passo 6: Fase 3 -- Análise de Confusão

O Potato exibe uma matriz de confusão mostrando onde o LLM discorda dos seus rótulos. Uma saída típica:

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

Isso aponta para a principal fraqueza do LLM aqui: ele continua promovendo avaliações neutras a positivas. Essa é comum, já que os LLMs tendem a pender para o positivo.

Sua ação: Examine os pares de confusão. Clique em cada par para ver as instâncias específicas que o LLM errou, que é a forma mais rápida de entender como ele falha.


Passo 7: Fase 4 -- Refinamento das Diretrizes

Com base na análise de confusão, o Potato redige diretrizes refinadas para o LLM e as mostra lado a lado: o prompt atual de um lado, e as edições específicas que ele propõe a partir dos padrões de erro do outro.

Por exemplo, o Potato pode sugerir adicionar:

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

Passe por cada edição sugerida e aprove, modifique ou rejeite. Você também pode escrever suas próprias clarificações.

Estimativa de tempo: 5-10 minutos.


Passo 8: Fase 5 -- Geração de Funções de Rotulagem

O Potato gera funções de rotulagem programáticas a partir de padrões nos seus rótulos de semente. São regras rápidas e determinísticas que tratam os casos fáceis:

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)

As funções de rotulagem cobrem 18% do seu conjunto de dados com 92%+ de precisão. Essas instâncias são rotuladas automaticamente, o que libera o LLM e a pessoa para os casos mais difíceis.

Sua ação: Examine as funções geradas e desative qualquer uma que pareça não confiável. Este passo é opcional, já que o Potato só mantém funções acima do limiar de precisão que você configurou.


Passo 9: Fase 6 -- Rotulagem Ativa (125-375 Instâncias)

É aqui que você faz a maior parte da sua rotulagem. O Potato escolhe instâncias usando o sistema de priorização de seis grupos:

  • Incerto (30%): Avaliações em que a confiança do LLM está abaixo de 85%
  • Discordância (25%): Avaliações em que o LLM e as funções de rotulagem dão rótulos diferentes
  • Fronteira (20%): Avaliações próximas da fronteira de decisão no espaço de embeddings
  • Novo (10%): Avaliações diferentes de tudo o que você já rotulou
  • Padrão de erro (10%): Avaliações que correspondem a padrões de confusão conhecidos (por exemplo, positivo morno)
  • Aleatório (5%): Avaliações aleatórias para calibração

Você rotula essas em lotes de 25. Após cada lote, o Potato atualiza a estimativa de acurácia do LLM e decide se continua.

Trajetória típica:

  • Lote 1-3 (75 instâncias): A acurácia sobe de 82% para 87%
  • Lote 4-6 (150 instâncias): A acurácia chega a 90%
  • Lote 7-10 (250 instâncias): A acurácia estabiliza em 91-92%

Se a acurácia atingir 93% (seu limiar), o Modo Solo pula direto para a Fase 10. Caso contrário, segue para a Fase 7.

Estimativa de tempo: 45-90 minutos no total, dependendo de quantos lotes forem necessários.


Passo 10: Fase 7 -- Laço de Refinamento Automatizado

Se a acurácia ainda estiver abaixo do limiar depois da rotulagem ativa, o Potato roda mais uma rodada do laço de refinamento:

  1. O LLM re-rotula o conjunto de dados completo com diretrizes atualizadas e mais exemplos few-shot
  2. O Potato recalcula a acurácia em relação a todos os rótulos humanos
  3. Ele encontra os novos padrões de confusão
  4. Ele refina as diretrizes de novo

Esta fase é quase toda automática. Você só precisa aprovar as mudanças nas diretrizes.

Resultado típico: A acurácia melhora de 2 a 4% por rodada de refinamento.


Passo 11: Fase 8 -- Exploração de Discordância

O Potato apresenta as instâncias mais contenciosas: casos em que o LLM, as funções de rotulagem e a análise de vizinhos mais próximos dão respostas diferentes. Para cada instância, você vê:

  • O texto da avaliação
  • A previsão e a confiança do LLM
  • Os votos das funções de rotulagem
  • Os 3 exemplos rotulados mais próximos com seus rótulos
  • O raciocínio em cadeia de pensamento do LLM

Esses são casos genuinamente difíceis, e seus rótulos aqui valem mais do que quaisquer outros em todo o processo.

Estimativa de tempo: 20-30 minutos para 100-150 instâncias.


Passo 12: Fase 9 -- Síntese de Casos Limítrofes

O Potato gera avaliações sintéticas que visam os padrões de confusão restantes. Por exemplo, se o LLM ainda tem dificuldade com "avaliações neutras que mencionam comprar de novo", ele gera exemplos como:

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

Você rotula esses exemplos sintéticos, e o Potato os adiciona ao contexto few-shot do LLM.

Estimativa de tempo: 10-15 minutos para 30 exemplos.


Passo 13: Fase 10 -- Escalonamento de Confiança em Cascata

A esta altura, o LLM já rotulou a maior parte do conjunto de dados. O Potato classifica todos os seus rótulos por confiança e lhe envia os de menor confiança em lotes de 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

Quando três lotes seguidos voltam com o LLM acertando tudo, o Modo Solo trata os rótulos de alta confiança restantes como confiáveis.

Estimativa de tempo: 15-20 minutos.


Passo 14: Fase 11 -- Otimização de Prompt

Esta fase roda sozinha. O Potato testa 8 variantes de prompt e mantém aquela com a maior pontuação F1 nos seus rótulos humanos acumulados:

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

Em seguida, ele usa o melhor prompt para uma passagem final de re-rotulagem.


Passo 15: Fase 12 -- Validação Final

O Potato extrai 100 instâncias aleatórias rotuladas pelo LLM para você revisar. Você as rotula, e o Potato compara seus rótulos com os do LLM.

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

Se o LLM superar o seu limiar, o conjunto de dados está pronto. Caso contrário, o Modo Solo volta para a Fase 6 para mais uma rodada de rotulagem ativa.

Estimativa de tempo: 10-15 minutos.


Resumo dos Resultados

Depois de todas as 12 fases, confira as estatísticas finais:

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%

A pessoa rotulou 612 de 10.000 instâncias, cerca de 6%. O LLM e as funções de rotulagem cuidaram do restante com 94%+ de acurácia.


Exportando os Resultados

Exporte o conjunto de dados final rotulado:

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

Cada linha inclui o rótulo e sua origem:

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}

Para exportação em Parquet:

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

Garantia de Qualidade: Verificação Híbrida

Para conjuntos de dados em qualidade de publicação, adicione um segundo anotador para revisar uma amostra. A documentação de origem do Modo Solo descreve as opções de verificação em mais detalhe.

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

Isso envia 1.000 instâncias aleatórias a um segundo anotador. Você pode então calcular a concordância entre anotadores entre os rótulos do Modo Solo e os rótulos do revisor.


Solução de Problemas

A acurácia do LLM estaciona abaixo do limiar

  • Aumente a contagem de sementes: Tente 75-100 instâncias de semente em vez de 50
  • Troque de LLM: Tente claude-sonnet-4-20250514 no lugar do GPT-4o (ou vice-versa)
  • Reduza o limiar: Se 93% não for alcançável, considere se 90% é aceitável para o seu caso de uso
  • Verifique seus dados: Alguns conjuntos de dados são inerentemente ambíguos. Se a concordância humano-humano seria de apenas 90%, não espere que o LLM faça melhor

A Fase 6 leva lotes demais

  • Aumente o tamanho do lote: Mude batch_size de 25 para 50
  • Ajuste os pesos dos grupos: Se a maioria das instâncias escaladas vem do grupo "incerto", reduza seu peso e aumente "discordância" e "padrão de erro"

As funções de rotulagem têm cobertura baixa

  • Isso é normal para tarefas sem sinais lexicais fortes (por exemplo, detecção de sarcasmo, sentimento implícito)
  • As funções de rotulagem funcionam melhor para padrões explícitos, baseados em palavras-chave
  • O Modo Solo ainda funciona sem funções de rotulagem -- o LLM compensa a diferença

Leitura Complementar