Skip to content
Tutorials12 min read

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

Tutorial passo a passo sobre o uso do Modo Solo do Potato para rotular grandes conjuntos de dados de forma eficiente com colaboração humano-LLM, reduzindo o custo de anotação em até 90%.

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