Skip to content

Modo Solo

Execute sozinho no Potato um pipeline completo de anotação, com um especialista e um LLM avançando por uma máquina de estados de fases que cobre a escrita do prompt, a anotação paralela, a resolução de discordâncias e a validação final.

Novo na v2.3.0

Projetos de anotação tradicionais exigem múltiplos anotadores, cálculo de concordância entre anotadores, rodadas de arbitragem e uma sobrecarga considerável de coordenação. Para muitas equipes de pesquisa, esse é o gargalo principal. Não é a interface de anotação, e sim a logística de contratar, treinar e gerenciar uma equipe.

O Modo Solo substitui o paradigma de múltiplos anotadores por um único especialista humano colaborando com um LLM. O humano fornece rótulos de alta qualidade em um subconjunto pequeno e selecionado de forma estratégica. O LLM aprende com esses rótulos, propõe rótulos para o restante, e o humano revisa apenas os casos em que o LLM está incerto ou provavelmente errado. Uma máquina de estados de fases orquestra esse processo. Ela avança conforme os limiares que você define e volta ao prompt sempre que o problema se revela ser o próprio prompt.

Em benchmarks internos, o Modo Solo alcançou mais de 95% de concordância com pipelines completos de múltiplos anotadores, exigindo apenas 10 a 15% do total de rótulos humanos.

O fluxo de trabalho

O Modo Solo é uma máquina de estados. SoloPhaseController registra em qual fase um projeto está e para quais fases ele pode seguir, então o percurso não é uma linha reta. Várias fases podem voltar atrás quando o prompt ainda precisa de ajustes.

Configuração inicial

Descrição da tarefa e dados. A única fase para a qual ela pode seguir é a revisão do prompt.

Revisão do prompt

O Potato sintetiza um prompt a partir da descrição da tarefa e você o edita. Várias fases posteriores voltam para cá quando o problema se revela ser o prompt, o que faz desta fase o eixo de todo o fluxo de trabalho, e não uma etapa única.

Daqui o projeto passa pelo ciclo de casos extremos ou vai direto para a anotação paralela.

Síntese de casos extremos, depois rotulagem de casos extremos

O LLM gera exemplos de fronteira e você os rotula. A rotulagem pode voltar à revisão do prompt se os exemplos mostrarem que o prompt está errado.

Validação do prompt

Seus rótulos nos casos extremos são comparados com o que o prompt produz. A partir daí o projeto segue para a anotação paralela ou volta à revisão do prompt.

Anotação paralela

Você e o LLM anotam os mesmos dados ao mesmo tempo. É esta fase que produz o valor de concordância do qual todo o resto depende.

Resolução de discordâncias

Onde você e o LLM divergem, você decide. O projeto volta à anotação paralela, ou à revisão do prompt quando as discordâncias apontam para o prompt e não para itens individuais.

Anotação ativa

A fase principal de anotação, com as instâncias escolhidas pelos pools ponderados em instance_selection. Daqui o Potato pode seguir para a revisão periódica, para a revisão de regras ou para a rotulagem autônoma.

Revisão periódica

Rótulos do LLM com baixa confiança, apresentados a cada thresholds.periodic_review_interval itens. O projeto volta à anotação ativa, segue para a revisão de regras ou recua para a revisão do prompt.

Revisão de regras

As regras de casos extremos que o Potato extraiu da sua rotulagem, apresentadas para aprovação. O projeto volta à anotação ativa ou à revisão do prompt.

Rotulagem autônoma

O LLM rotula o que resta. A única saída desta fase é a validação final.

Validação final

Você confere uma amostra dos rótulos atribuídos apenas pelo LLM. Superar thresholds.end_human_annotation_agreement conclui o projeto. Se não superar, o projeto volta à anotação ativa.

Concluído

Estado terminal.


Configuração

Início rápido

Uma configuração mínima do Modo Solo:

yaml
annotation_task_name: "Sentiment Classification"
task_dir: "."
 
data_files:
  - "data/reviews.jsonl"
 
item_properties:
  id_key: id
  text_key: text
 
solo_mode:
  enabled: true
 
  # The models that label. A list: the first is used, the rest are fallbacks.
  labeling_models:
    - endpoint_type: openai
      model: "gpt-4o"
      api_key: ${OPENAI_API_KEY}
      temperature: 0.1
      max_tokens: 1024
 
  # When the project may stop asking the human
  thresholds:
    end_human_annotation_agreement: 0.92
    minimum_validation_sample: 50
    confidence_low: 0.5
 
  state_dir: "solo_state_sentiment"
 
annotation_schemes:
  - annotation_type: radio
    name: sentiment
    description: "What is the sentiment of this text?"
    labels:
      - Positive
      - Neutral
      - Negative
 
output_annotation_dir: "output/"
export_annotation_format: "jsonl"

Referência completa de configuração

yaml
solo_mode:
  enabled: true
 
  # Models that label, and models that revise. Both are lists; revision_models
  # defaults to labeling_models when omitted.
  labeling_models:
    - endpoint_type: openai       # openai, anthropic, ollama, vllm, ...
      model: "gpt-4o"
      api_key: ${OPENAI_API_KEY}
      temperature: 0.1
      max_tokens: 1024
  revision_models:
    - endpoint_type: anthropic
      model: "claude-sonnet-4-20250514"
      api_key: ${ANTHROPIC_API_KEY}
      max_tokens: 1024
 
  # Sentence embeddings, used for diversity and neighbour lookups
  embedding:
    model_name: "all-MiniLM-L6-v2"
 
  # How the LLM's uncertainty is measured
  uncertainty:
    strategy: direct_confidence
    sampling_diversity:
      num_samples: 5
      temperature: 1.0
 
  # When the human can stop, and what counts as agreement per scheme type
  thresholds:
    end_human_annotation_agreement: 0.90
    minimum_validation_sample: 50
    confidence_low: 0.5
    confidence_high: 0.8
    periodic_review_interval: 100
    likert_tolerance: 1
    multiselect_jaccard_threshold: 0.5
    textbox_embedding_threshold: 0.7
    span_overlap_threshold: 0.5
 
  # Weights for the pools that choose what the human sees next
  instance_selection:
    low_confidence_weight: 0.3
    disagreement_weight: 0.1
    diversity_weight: 0.2
    llm_predicted_weight: 0.3
    random_weight: 0.1
    cartography_weight: 0.0
    edge_case_rule_weight: 0.0
 
  batches:
    llm_labeling_batch: 50
    max_parallel_labels: 200
 
  labeling_functions:
    enabled: true
    auto_extract: true
    max_functions: 50
    min_confidence: 0.85
    min_coverage: 3               # instances, not a fraction
    vote_threshold: 0.5
 
  edge_case_rules:
    enabled: true
    auto_extract_on_labeling: true
    confidence_threshold: 0.75
    min_rules_for_clustering: 10
    target_cluster_size: 15
    reannotation_enabled: true
    reannotation_confidence_threshold: 0.60
    max_reannotations_per_instance: 2
 
  confusion_analysis:
    enabled: true
    min_instances_for_pattern: 3
    max_patterns: 20
    auto_suggest_guidelines: false
 
  prompt_optimization:
    enabled: true
    find_smallest_model: true
    target_accuracy: 0.85
    optimization_interval_seconds: 300
    accuracy_weight: 0.7
    length_weight: 0.2
 
  # Send cheap cases to a small model and hard ones to a larger one
  confidence_routing:
    enabled: false
    tiers:
      - name: cheap
        confidence_threshold: 0.8
        model:
          endpoint_type: ollama
          model: "llama3.2"
 
  refinement_loop:
    enabled: true
    trigger_interval: 50
    min_improvement: 0.02
    max_cycles: 5
    patience: 2
 
  state_dir: "solo_state_sentiment"

Principais recursos

Análise de confusão

Após cada rodada de rotulagem, o Potato constrói uma matriz de confusão entre os rótulos humanos e os do LLM. O painel de administração exibe:

  • Precisão, revocação e F1 por classe a partir da perspectiva do LLM
  • Pares de confusão mais comuns (por exemplo, "neutral classificado erroneamente como positive: 23 instâncias")
  • Instâncias de exemplo para cada par de confusão
  • Gráficos de tendência que mostram a melhoria ao longo das rodadas de refinamento

O Modo Solo não tem interface de linha de comando. Ele roda dentro do servidor e é conduzido pelas suas próprias páginas na instância em execução, então a análise é lida no painel e não em uma CLI. O que ele relata tem esta aparência:

text
Confusion Analysis (Round 2)
============================
Overall Accuracy: 0.87 (target: 0.92)

Top Confusion Pairs:
  neutral -> positive:  23 instances (15.3%)
  negative -> neutral:  11 instances (7.3%)
  positive -> neutral:   5 instances (3.3%)

Per-Class Performance:
  Positive:  P=0.91  R=0.94  F1=0.92
  Neutral:   P=0.78  R=0.71  F1=0.74
  Negative:  P=0.93  R=0.88  F1=0.90

Ciclo de refinamento automatizado

O ciclo de refinamento alterna entre a rotulagem pelo LLM, a análise de confusão e a atualização das diretrizes. Em cada iteração:

  1. O LLM rotula todo o conjunto de dados com as diretrizes atuais
  2. O Potato compara o resultado com todos os rótulos humanos disponíveis
  3. Se a acurácia estiver abaixo do limiar, a análise de confusão é executada
  4. O LLM propõe edições nas diretrizes com base nos padrões de erro
  5. O humano revisa e aprova as edições
  6. O ciclo se repete (até max_cycles)
yaml
solo_mode:
  revision_models:
    - endpoint_type: anthropic
      model: "claude-sonnet-4-20250514"
      api_key: ${ANTHROPIC_API_KEY}
 
  refinement_loop:
    enabled: true
    trigger_interval: 50           # run a cycle every 50 new human labels
    min_improvement: 0.02          # stop if a cycle gains less than 2%
    max_cycles: 5
    patience: 2                    # cycles below min_improvement before stopping

Funções de rotulagem (inspiradas no ALCHEmist)

O Potato gera funções de rotulagem leves a partir de padrões observados nas anotações humanas. Elas não são chamadas ao LLM. São regras rápidas e determinísticas.

Exemplos de funções de rotulagem geradas:

python
# Auto-generated labeling function 1
# Precision: 0.96, Coverage: 0.08
def lf_strong_positive_words(text):
    positive = {"excellent", "amazing", "fantastic", "outstanding", "perfect"}
    if any(w in text.lower() for w in positive):
        if not any(neg in text.lower() for neg in {"not", "never", "no"}):
            return "Positive"
    return None  # abstain
 
# Auto-generated labeling function 2
# Precision: 0.93, Coverage: 0.05
def lf_explicit_negative(text):
    negative = {"terrible", "awful", "horrible", "worst", "disgusting"}
    if any(w in text.lower() for w in negative):
        return "Negative"
    return None

Configure o comportamento das funções de rotulagem:

yaml
solo_mode:
  labeling_functions:
    enabled: true
    auto_extract: true
    max_functions: 50
    min_confidence: 0.85
    min_coverage: 3          # minimum instances a function must cover
    vote_threshold: 0.5      # agreement needed when functions disagree

Explorador de discordâncias

O explorador de discordâncias apresenta instâncias em que sinais diferentes entram em conflito. Para cada instância, o anotador vê:

  • O rótulo previsto pelo LLM e a confiança
  • Os votos das funções de rotulagem (se houver)
  • Os vizinhos rotulados mais próximos no espaço de embeddings
  • O texto ou conteúdo bruto

Esta é a atividade de anotação de maior valor, porque cada rótulo resolve uma ambiguidade real.

yaml
solo_mode:
  # Disagreement is a phase, not a configurable block. What you control is how
  # heavily disagreement weighs when Potato picks the next instance.
  instance_selection:
    disagreement_weight: 0.3
    low_confidence_weight: 0.3
    diversity_weight: 0.2
    llm_predicted_weight: 0.1
    random_weight: 0.1

Escalonamento em cascata por confiança

Depois que o LLM rotula a maior parte do conjunto de dados, o Potato ordena todas as instâncias rotuladas pelo LLM por confiança e encaminha ao humano as de menor confiança. Isso continua em lotes até que a qualidade se estabilize.

yaml
solo_mode:
  thresholds:
    confidence_low: 0.5           # below this, the human sees it
    confidence_high: 0.8          # above this, the LLM's label stands
    periodic_review_interval: 100 # surface low-confidence labels this often
 
  batches:
    llm_labeling_batch: 50
    max_parallel_labels: 200

Priorização de instâncias por múltiplos sinais

Em todas as fases que envolvem rotulagem humana, o Potato usa um sistema de pools ponderados para selecionar as instâncias mais informativas. Sete pools alimentam uma fila de prioridade unificada:

yaml
solo_mode:
  instance_selection:
    low_confidence_weight: 0.3
    diversity_weight: 0.2
    llm_predicted_weight: 0.3
    disagreement_weight: 0.1
    random_weight: 0.1
    cartography_weight: 0.0
    edge_case_rule_weight: 0.0
  • low_confidence: a confiança do LLM fica abaixo de thresholds.confidence_low
  • diversity: distante, no espaço de embeddings, do que você já rotulou
  • llm_predicted: o LLM tem um rótulo que ainda não foi conferido
  • disagreement: os sinais disponíveis para a instância não concordam
  • random: uma pequena amostra aleatória, para manter a estimativa honesta e detectar pontos cegos
  • cartography: sinal de dinâmica de treinamento, desativado por padrão
  • edge_case_rule: corresponde a uma regra extraída da sua rotulagem anterior, desativado por padrão

Síntese de casos extremos

O Potato usa o LLM para gerar exemplos sintéticos voltados a fraquezas conhecidas:

yaml
solo_mode:
  edge_case_rules:
    enabled: true
    auto_extract_on_labeling: true   # derive rules as you label
    confidence_threshold: 0.75
    min_rules_for_clustering: 10
    target_cluster_size: 15
    reannotation_enabled: true       # revisit items a new rule contradicts
    reannotation_confidence_threshold: 0.60
    max_reannotations_per_instance: 2

O LLM gera exemplos ambíguos entre os pares de rótulos especificados. O humano os rotula, e esses rótulos são adicionados ao contexto few-shot das rodadas seguintes de rotulagem pelo LLM.

Otimização de prompts (inspirada no DSPy)

O Potato executa uma otimização automatizada de prompts para encontrar o melhor formato de instrução para o LLM, e procura o menor modelo que ainda mantém a acurácia-alvo:

yaml
solo_mode:
  prompt_optimization:
    enabled: true
    find_smallest_model: true          # prefer the cheapest model that holds up
    target_accuracy: 0.85
    optimization_interval_seconds: 300
    accuracy_weight: 0.7               # how the candidates are scored
    length_weight: 0.2

Acompanhamento do progresso

O painel de administração mostra o progresso do Modo Solo em tempo real:

  • Fase atual e progresso dentro de cada fase
  • Rótulos humanos concluídos vs. orçamento total
  • Acurácia do LLM ao longo do tempo (por rodada)
  • Cobertura e precisão das funções de rotulagem
  • Histograma da distribuição de confiança
  • Tempo estimado até a conclusão

Não existe um módulo potato.solo nem uma CLI do Modo Solo. Todo o fluxo de trabalho fica atrás das rotas do próprio servidor, então o progresso é lido no painel. Ele informa:

text
Solo Mode Status
================
Current Phase: 6 (Active Labeling) - Batch 3/10
Human Labels: 142 / ~300 estimated total
LLM Accuracy: 0.89 (target: 0.92)
LF Coverage: 0.23 (labeling functions cover 23% of data)
Dataset Size: 10,000 instances
  - Human labeled: 142
  - LF labeled: 2,300
  - LLM labeled: 7,558
  - Unlabeled: 0

Quando usar o Modo Solo vs. múltiplos anotadores tradicional

Use o Modo Solo quando:

  • Você tem um especialista de domínio que pode fornecer rótulos de alta qualidade
  • O orçamento ou a logística impedem a contratação de múltiplos anotadores
  • A tarefa tem categorias claras e bem definidas
  • Você precisa rotular um conjunto de dados grande (mais de 1.000 instâncias)
  • A velocidade importa mais do que medir a concordância entre anotadores

Use múltiplos anotadores tradicional quando:

  • Você precisa de estatísticas de concordância entre anotadores para publicação
  • A tarefa é altamente subjetiva (por exemplo, ofensividade, humor)
  • Você precisa estudar os padrões de discordância entre anotadores
  • Requisitos regulatórios exigem múltiplos anotadores independentes
  • O espaço de rótulos é complexo ou está em evolução (as diretrizes de anotação ainda estão sendo desenvolvidas)

Abordagem híbrida: use o Modo Solo para a rotulagem inicial em massa e, em seguida, atribua a um segundo anotador uma amostra aleatória de 10 a 20% para calcular estatísticas de concordância. Isso combina a eficiência do Modo Solo com a garantia de qualidade da verificação por múltiplos anotadores.

O Modo Solo não tem um bloco de verificação próprio. Execute o segundo anotador como uma passagem comum do Potato sobre os rótulos exportados e calcule a concordância entre os rótulos dele e os do Modo Solo como faria para quaisquer dois anotadores. (icl_labeling tem um bloco verification, mas ele pertence à rotulagem in-context, não ao Modo Solo.)


Leitura adicional

Para detalhes de implementação, consulte a documentação de origem.