Solo Mode
Ejecuta en Potato un pipeline de anotación completo en solitario: un experto y un LLM avanzan por una máquina de estados de fases que abarca el prompt, la anotación en paralelo, la resolución de desacuerdos y la validación final.
Nuevo en v2.3.0
Los proyectos de anotación tradicionales requieren varios anotadores, el cálculo del acuerdo entre anotadores, rondas de adjudicación y un esfuerzo de coordinación considerable. Para muchos equipos de investigación, el principal cuello de botella no es la interfaz de anotación, sino la logística de contratar, formar y gestionar a un equipo.
Solo Mode sustituye el paradigma de varios anotadores por un único experto humano que colabora con un LLM. El humano aporta etiquetas de alta calidad sobre un subconjunto pequeño y elegido de forma estratégica. El LLM aprende de esas etiquetas y propone etiquetas para el resto, y el humano revisa solo los casos en los que el LLM duda o probablemente se equivoca. Una máquina de estados de fases orquesta el proceso. Avanza según los umbrales que fijes y vuelve al prompt siempre que resulta que el problema es el propio prompt.
En pruebas internas, Solo Mode alcanzó un acuerdo superior al 95% con pipelines completos de varios anotadores y necesitó solo entre el 10 y el 15% del total de etiquetas humanas.
El flujo de trabajo
Solo Mode es una máquina de estados. SoloPhaseController registra en qué fase está un proyecto y a qué fases puede pasar a continuación, así que el recorrido no es una línea recta. Varias fases pueden volver atrás cuando el prompt todavía necesita trabajo.
Configuración inicial
Descripción de la tarea y datos. Generate prompt pide a un modelo de revisión (revision_models) que escriba el primer prompt a partir de la descripción y de los esquemas de anotación. Si no hay modelo de revisión, o si este no devuelve nada, la propia descripción pasa a ser el primer prompt y el historial de prompts lo indica. La única fase a la que puede pasar la configuración inicial es la revisión del prompt.
Revisión del prompt
Potato sintetiza un prompt a partir de la descripción de la tarea y tú lo editas. Varias fases posteriores vuelven aquí cuando resulta que el problema es el prompt, por lo que esta fase es el eje de todo el flujo de trabajo y no un paso que se hace una sola vez.
Desde aquí, el proyecto pasa por el bucle de casos límite o va directamente a la anotación en paralelo.
Síntesis de casos límite y, después, etiquetado de casos límite
El LLM genera ejemplos de frontera y tú los etiquetas. El etiquetado puede volver a la revisión del prompt si los ejemplos muestran que el prompt está mal.
Validación del prompt
Tus etiquetas sobre los casos límite se comparan con lo que produce el prompt. Desde aquí se avanza a la anotación en paralelo o se vuelve a la revisión del prompt.
Anotación en paralelo
Tú y el LLM anotáis los mismos datos a la vez. Esta es la fase que produce la cifra de acuerdo de la que depende todo lo demás.
Resolución de desacuerdos
Donde tú y el LLM discrepáis, decides tú. La fase vuelve a la anotación en paralelo, o a la revisión del prompt cuando los desacuerdos apuntan al prompt y no a elementos concretos.
Anotación activa
La fase principal de anotación, con instancias elegidas por los pools ponderados de instance_selection. Desde aquí Potato puede pasar a la revisión periódica, a la revisión de reglas o al etiquetado autónomo.
Revisión periódica
Etiquetas del LLM con baja confianza, que aparecen cada thresholds.periodic_review_interval elementos. Vuelve a la anotación activa, pasa a la revisión de reglas o retrocede a la revisión del prompt.
Revisión de reglas
Las reglas de casos límite que Potato extrajo de tu etiquetado, presentadas para su aprobación. Vuelve a la anotación activa o a la revisión del prompt.
Etiquetado autónomo
El LLM etiqueta lo que queda. Su única salida es la validación final.
Validación final
Compruebas una muestra de las etiquetas que solo puso el LLM. Superar thresholds.end_human_annotation_agreement completa el proyecto; no superarlo lo devuelve a la anotación activa.
Completado
Estado final.
Configuración
Inicio rápido
Una configuración mínima de Solo Mode:
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"Referencia completa de configuración
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"Capacidades principales
Análisis de confusión
Después de cada ronda de etiquetado, Potato construye una matriz de confusión entre las etiquetas humanas y las del LLM. El panel de administración muestra:
- Precisión, recall y F1 por clase desde la perspectiva del LLM
- Los pares de confusión más frecuentes (por ejemplo, "neutral clasificado como positivo: 23 instancias")
- Instancias de ejemplo para cada par de confusión
- Gráficos de tendencia con la mejora a lo largo de las rondas de refinamiento
Solo Mode no tiene interfaz de línea de comandos. Se ejecuta dentro del servidor y se maneja desde sus propias páginas en la instancia en ejecución, así que el análisis se lee en el panel y no en una CLI. Lo que muestra tiene este aspecto:
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
Bucle de refinamiento automatizado
El bucle de refinamiento alterna entre el etiquetado del LLM, el análisis de confusión y la actualización de las directrices. En cada iteración:
- El LLM etiqueta el conjunto de datos completo con las directrices actuales
- Potato compara el resultado con todas las etiquetas humanas disponibles
- Si la precisión está por debajo del umbral, se ejecuta el análisis de confusión
- El LLM propone cambios en las directrices a partir de los patrones de error
- El humano revisa y aprueba los cambios
- El ciclo se repite (hasta
max_cycles)
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 stoppingFunciones de etiquetado (inspiradas en ALCHEmist)
Potato genera funciones de etiquetado ligeras a partir de patrones observados en las anotaciones humanas. No son llamadas al LLM, sino reglas rápidas y deterministas.
Ejemplo de funciones de etiquetado generadas:
# 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 NoneConfigura el comportamiento de las funciones de etiquetado:
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 disagreeExplorador de desacuerdos
El explorador de desacuerdos presenta instancias en las que las distintas señales entran en conflicto. Para cada instancia, el anotador ve:
- La etiqueta predicha por el LLM y su confianza
- Los votos de las funciones de etiquetado (si los hay)
- Los vecinos etiquetados más cercanos en el espacio de embeddings
- El texto o contenido sin procesar
Es la actividad de anotación de mayor valor, porque cada etiqueta resuelve una ambigüedad real.
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.1Escalado de confianza en cascada
Cuando el LLM ya ha etiquetado la mayor parte del conjunto de datos, Potato ordena todas las instancias etiquetadas por el LLM según su confianza y escala al humano las de menor confianza. Esto continúa por lotes hasta que la calidad se estabiliza.
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: 200Modelos de decisión
Desde Potato 2.11, un modelo de decisión puede etiquetar en Solo Mode. Un modelo de decisión responde a una pregunta de opciones fijas en una sola pasada hacia delante y devuelve una probabilidad para cada opción, lo que lo hace más rápido y más barato que un LLM a la hora de etiquetar, y no puede escribir prompts, reglas ni explicaciones. Hay dos tipos de endpoint para llegar a uno. laya ejecuta Laya dentro del proceso de Potato en CPU y necesita pip install 'potato-annotation[decision]', y systemone se comunica con cualquier servidor que tenga la API /v1/systemone, como Jev alojado u OpenJev.
El sitio habitual de un modelo de decisión es el primer nivel del enrutamiento por confianza, donde etiqueta todo y solo los ítems de los que no está seguro pasan al LLM:
solo_mode:
labeling_models:
- endpoint_type: laya
model: convaiinnovations/laya
revision_models: # required: decision models cannot write text
- endpoint_type: vllm
model: google/gemma-4-12B-it-qat-w4a16-ct
base_url: http://localhost:8001/v1
confidence_routing:
enabled: true
tiers:
- name: laya
confidence_threshold: 0.9
model:
endpoint_type: laya
model: convaiinnovations/laya
device: cpu
- name: llm
confidence_threshold: 0.5
model:
endpoint_type: vllm
model: google/gemma-4-12B-it-qat-w4a16-ct
base_url: http://localhost:8001/v1revision_models tiene que ser un modelo generativo. Su valor por defecto es labeling_models, así que un estudio cuyo único modelo es un modelo de decisión tiene que definirlo. Los modelos de decisión etiquetan esquemas radio, select, likert y slider, y Solo Mode se niega a arrancar si se configura uno para etiquetar esquemas multiselect, de spans o de texto libre. En las escalas de valoración, las puntuaciones de Laya apenas siguen la escala, así que revisa unos cuantos ítems con Try on 10 items antes de pasar por él un esquema likert o slider. La confianza es la probabilidad que el modelo asignó a la opción elegida, y su calibración varía según el dominio, así que fija el umbral del nivel con tus propios datos. config-decision-model.yaml es una versión ejecutable.
Sugerencias a ciegas
Por defecto, la página de anotación muestra la etiqueta del LLM, su confianza y un botón para aceptarla antes de que respondas, lo que agiliza el trabajo y a la vez arrastra tu respuesta hacia la sugerencia. Solo Mode entrega el resto del corpus al LLM cuando tu acuerdo con él supera end_human_annotation_agreement, así que un acuerdo medido sobre etiquetas que diste después de ver la sugerencia puede dar por terminada tu parte del trabajo demasiado pronto. Desde Potato 2.11, solo_mode.suggestions controla cuándo aparece la sugerencia:
solo_mode:
suggestions:
display: blind_sample # before_label | after_label | blind_sample
blind_rate: 0.2
minimum_blind_sample: 20blind_sample oculta la sugerencia en una fracción blind_rate de los ítems, y after_label nunca la muestra primero. Cuando hay minimum_blind_sample comparaciones a ciegas, el traspaso compara el acuerdo a ciegas con end_human_annotation_agreement. La tarjeta Blind Agreement del panel muestra lado a lado el acuerdo a ciegas y el acuerdo con la sugerencia visible, y una diferencia positiva grande significa que coincides con el LLM más a menudo cuando puedes ver su respuesta.
En Potato 2.11, Solo Mode también comprueba el tope de gasto del proyecto (ai_budget.cap_usd) antes de empezar a etiquetar y antes de cada lote, y se añaden una caché de respuestas (solo_mode.cache), un conjunto de referencia con pruebas de prompts (solo_mode.gold), una comprobación de la sensibilidad al prompt, un jurado de etiquetado (solo_mode.jury) y un orden por currículo (solo_mode.instance_selection.curriculum). Funciones avanzadas de Solo Mode documenta cada una. Cuando el motor de etiquetado está activado, Solo Mode también escribe sus predicciones de modelo en el almacén del motor, para que el motor pueda calibrarlas y certificarlas.
Priorización de instancias con varias señales
En todas las fases en las que etiqueta el humano, Potato usa un sistema de pools ponderados para elegir las instancias más informativas. Siete pools alimentan una única cola de prioridad:
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: la confianza del LLM está por debajo de
thresholds.confidence_low - diversity: lejos de lo que ya has etiquetado, en el espacio de embeddings
- llm_predicted: el LLM tiene una etiqueta y nadie la ha comprobado
- disagreement: las señales disponibles para la instancia no coinciden
- random: una pequeña muestra aleatoria, para que la estimación sea honesta y para detectar puntos ciegos
- cartography: señal de dinámica de entrenamiento, desactivada por defecto
- edge_case_rule: coincide con una regla extraída de tu etiquetado anterior, desactivada por defecto
Síntesis de casos límite
Potato usa el LLM para generar ejemplos sintéticos dirigidos a debilidades conocidas:
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: 2El LLM genera ejemplos ambiguos entre los pares de etiquetas especificados. El humano los etiqueta, y esas etiquetas se añaden al contexto few-shot de las siguientes rondas de etiquetado del LLM.
Optimización del prompt (inspirada en DSPy)
Potato ejecuta una optimización automática del prompt para encontrar el mejor formato de instrucciones para el LLM, y busca el modelo más pequeño que siga alcanzando la precisión objetivo:
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.2Seguimiento del progreso
El panel de administración muestra el progreso de Solo Mode en tiempo real:
- La fase actual y el progreso dentro de cada fase
- Etiquetas humanas completadas frente al presupuesto total
- Precisión del LLM a lo largo del tiempo (por ronda)
- Cobertura y precisión de las funciones de etiquetado
- Histograma de la distribución de confianza
- Tiempo estimado hasta la finalización
No existe un módulo potato.solo ni una CLI de Solo Mode. Todo el flujo de trabajo funciona a través de las rutas propias del servidor, así que el progreso se lee en el panel. Este muestra:
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
Cuándo usar Solo Mode y cuándo varios anotadores
Usa Solo Mode cuando:
- Tienes un experto del dominio capaz de aportar etiquetas de alta calidad
- El presupuesto o la logística impiden contratar a varios anotadores
- La tarea tiene categorías claras y bien definidas
- Necesitas etiquetar un conjunto de datos grande (más de 1000 instancias)
- La velocidad importa más que medir el acuerdo entre anotadores
Usa el enfoque tradicional con varios anotadores cuando:
- Necesitas estadísticas de acuerdo entre anotadores para una publicación
- La tarea es muy subjetiva (por ejemplo, ofensividad, humor)
- Necesitas estudiar los patrones de desacuerdo entre anotadores
- La normativa exige varios anotadores independientes
- El espacio de etiquetas es complejo o está cambiando (las directrices de anotación aún se están elaborando)
Enfoque híbrido: usa Solo Mode para el etiquetado masivo inicial y después asigna un segundo anotador a una muestra aleatoria del 10-20% para calcular estadísticas de acuerdo. Así obtienes la eficiencia de Solo Mode con el control de calidad de la verificación con varios anotadores.
Solo Mode no tiene un bloque de verificación propio. Ejecuta al segundo anotador como una pasada normal de Potato sobre las etiquetas exportadas y calcula el acuerdo entre sus etiquetas y las de Solo Mode como lo harías con dos anotadores cualesquiera. (icl_labeling sí tiene un bloque verification, pero pertenece al etiquetado en contexto, no a Solo Mode).
Lecturas adicionales
- Tutorial de Solo Mode: etiquetar 10 000 ejemplos: guía paso a paso
- Aprendizaje activo: el sistema de aprendizaje activo subyacente
- Soporte de IA: configuración de la integración con LLM
- Control de calidad: control de calidad de las anotaciones
- MACE: estimación de la competencia (útil para la verificación en modo híbrido)
Para los detalles de implementación, consulta la documentación del código fuente.