Solo Mode: cómo un solo anotador puede etiquetar 10 000 ejemplos
Tutorial paso a paso sobre el Solo Mode de Potato: etiqueta tú mismo un conjunto semilla, deja que un LLM etiquete el resto y usa las comprobaciones de precisión para decidir cuándo es suficientemente bueno para parar.
Tienes 10 000 reseñas de productos que etiquetar por sentimiento (Positivo, Neutral, Negativo). Contratar a tres anotadores para etiquetarlas todas lleva semanas y cuesta miles de dólares. Solo Mode permite que un único experto en el dominio obtenga una calidad comparable etiquetando solo entre 500 y 1000 instancias; un LLM se encarga del resto y la persona revisa todo aquello en lo que el LLM tiene dudas.
Este tutorial recorre el proceso completo.
Lo que necesitarás
- Potato 2.3.0 o posterior, con los extras de IA para los proveedores de LLM:
pip install potato-annotation[ai] - Una clave de API de OpenAI o Anthropic (para el componente LLM)
- Tu conjunto de datos en formato JSONL
- Un anotador con conocimiento del dominio (puedes ser tú)
Paso 1: Prepara tus datos
Crea data/reviews.jsonl con una reseña por línea:
{"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, imagina que el archivo contiene 10 000 reseñas.
Paso 2: Crea la configuración
Crea config.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
# The model that labels. A list, so you can give fallbacks.
labeling_models:
- endpoint_type: openai
model: "gpt-4o"
api_key: ${OPENAI_API_KEY}
temperature: 0.1
max_tokens: 1024
embedding:
model_name: "all-MiniLM-L6-v2"
uncertainty:
strategy: direct_confidence
# When you are allowed to stop labeling
thresholds:
end_human_annotation_agreement: 0.93
minimum_validation_sample: 50
confidence_low: 0.5
confidence_high: 0.85
periodic_review_interval: 100
# What decides which instance you see next
instance_selection:
low_confidence_weight: 0.30
disagreement_weight: 0.25
diversity_weight: 0.20
llm_predicted_weight: 0.15
random_weight: 0.10
batches:
llm_labeling_batch: 25
max_parallel_labels: 200
labeling_functions:
enabled: true
auto_extract: true
max_functions: 15
min_confidence: 0.92
min_coverage: 3
edge_case_rules:
enabled: true
auto_extract_on_labeling: true
confusion_analysis:
enabled: true
min_instances_for_pattern: 3
max_patterns: 20
prompt_optimization:
enabled: true
target_accuracy: 0.93
refinement_loop:
enabled: true
trigger_interval: 50
min_improvement: 0.02
max_cycles: 3
state_dir: "solo_state_reviews"
# --- 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
- parquetPaso 3: Inicia el servidor
potato start config.yaml -p 8000Abre http://localhost:8000 e inicia sesión. Aparece el panel de Solo Mode, que muestra el proyecto en configuración, listo para que revises el prompt que ha sintetizado.
Paso 4: Anotación en paralelo (tus primeras 50)
Potato ha elegido 50 reseñas diversas mediante clustering basado en embeddings. No son aleatorias: se eligen para cubrir la distribución de tus datos de la forma más amplia posible.
Etiqueta cada una. Esta es la fase que más importa, porque la calidad de tus etiquetas semilla fija el techo de lo que el LLM puede aprender. Tómate tu tiempo y sé coherente.
Tiempo estimado: 15-25 minutos, a 20-30 segundos por instancia.
Cuando hay suficientes etiquetadas, el LLM empieza a etiquetar a la par que tú sin que se lo pidas.
Paso 5: El LLM se pone al día
Esta fase se ejecuta sola. Potato envía al LLM un lote de 200 instancias con tus 50 etiquetas semilla como ejemplos few-shot y luego compara las predicciones con 10 etiquetas semilla reservadas para estimar la precisión de partida.
En el panel aparece un indicador de progreso. Esto suele tardar 1-2 minutos según el proveedor de LLM.
Resultado típico: El LLM se sitúa en un 75-85% de precisión en la primera calibración. Es lo esperado. Todavía no ha aprendido tu estilo de anotación.
Paso 6: Análisis de confusión
Potato muestra una matriz de confusión con los puntos en que el LLM no coincide con tus etiquetas. Una salida típica:
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%)
Esto señala la principal debilidad del LLM en este caso: sigue subiendo reseñas neutrales a positivas. Es un fallo habitual, ya que los LLM tienden a inclinarse hacia lo positivo.
Tu acción: Revisa los pares de confusión. Haz clic en cada par para ver las instancias concretas en las que el LLM se equivocó, que es la forma más rápida de entender cómo falla.
Paso 7: De vuelta a la revisión del prompt
A partir del análisis de confusión, Potato redacta directrices refinadas para el LLM y las muestra lado a lado: el prompt actual a un lado y, al otro, las ediciones concretas que propone a partir de los patrones de error.
Por ejemplo, Potato podría sugerir añadir:
"Las reseñas que describen un producto como 'bien', 'aceptable' o 'decente' sin una emoción fuerte deben etiquetarse como Neutral, aunque mencionen volver a comprarlo."
Revisa cada edición sugerida y apruébala, modifícala o recházala. También puedes escribir tus propias aclaraciones.
Tiempo estimado: 5-10 minutos.
Paso 8: Funciones de etiquetado
Potato genera funciones de etiquetado programáticas a partir de patrones de tus etiquetas semilla. Son reglas rápidas y deterministas que resuelven los casos fáciles:
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)
Las funciones de etiquetado cubren el 18% de tu conjunto de datos con una precisión de más del 92%. Esas instancias se etiquetan automáticamente, lo que deja al LLM y a la persona libres para los casos más difíciles.
Tu acción: Revisa las funciones generadas y desactiva las que parezcan poco fiables. Este paso es opcional, porque Potato solo conserva de todos modos las funciones que superan el umbral de precisión que configuraste.
Paso 9: Anotación activa (125-375 instancias)
Aquí es donde haces la mayor parte del etiquetado. Potato elige las instancias con los grupos ponderados definidos arriba en instance_selection:
low_confidence_weight(0.30): Reseñas en las que la confianza del LLM es más bajadisagreement_weight(0.25): Reseñas en las que el LLM y las funciones de etiquetado no coincidendiversity_weight(0.20): Reseñas elegidas para repartirse por el espacio de embeddings en lugar de agruparsellm_predicted_weight(0.15): Reseñas etiquetadas por el LLM que se recuperan para compararlas con una personarandom_weight(0.10): Reseñas aleatorias para la calibración
Existen dos pesos más, que aquí se dejan en su valor por defecto de cero y por tanto no aportan nada: edge_case_rule_weight, para instancias que coinciden con una regla de caso límite descubierta, y cartography_weight, para instancias cuya confianza oscila entre rondas. Potato comprueba que los pesos sumen 1.0 y registra una advertencia si no es así, pero usa los valores tal como están escritos, así que asegúrate tú de que sumen 1.0.
Etiquetas estas instancias en lotes de 25. Después de cada lote, Potato actualiza la estimación de precisión del LLM y decide si continuar.
Trayectoria típica:
- Lotes 1-3 (75 instancias): La precisión sube del 82% al 87%
- Lotes 4-6 (150 instancias): La precisión llega al 90%
- Lotes 7-10 (250 instancias): La precisión se estanca en el 91-92%
Si el acuerdo alcanza tu end_human_annotation_agreement, Solo Mode avanza hacia el etiquetado autónomo. Si no, sigue alternando entre revisión y refinamiento.
Tiempo estimado: 45-90 minutos en total, según cuántos lotes hagan falta.
Paso 10: El bucle de refinamiento
Si después del etiquetado activo la precisión sigue por debajo del umbral, Potato ejecuta otra ronda del bucle de refinamiento:
- El LLM vuelve a etiquetar todo el conjunto de datos con las directrices actualizadas y más ejemplos few-shot
- Potato recalcula la precisión frente a todas las etiquetas humanas
- Encuentra los nuevos patrones de confusión
- Vuelve a refinar las directrices
Esta fase apenas requiere intervención. Solo tienes que aprobar los cambios en las directrices.
Resultado típico: La precisión mejora un 2-4% por ronda de refinamiento.
Paso 11: Resolución de desacuerdos
Potato presenta las instancias más discutidas: casos en los que el LLM, las funciones de etiquetado y el análisis de vecinos más cercanos dan respuestas distintas. Para cada instancia ves:
- El texto de la reseña
- La predicción del LLM y su confianza
- Los votos de las funciones de etiquetado
- Los 3 ejemplos etiquetados más cercanos con sus etiquetas
- El razonamiento chain-of-thought del LLM
Estos son los casos difíciles, y tus etiquetas aquí pesan más que en cualquier otro punto del proceso.
Tiempo estimado: 20-30 minutos para 100-150 instancias.
Paso 12: Síntesis de casos límite
Potato genera reseñas sintéticas dirigidas a los patrones de confusión que quedan. Por ejemplo, si el LLM sigue teniendo problemas con "reseñas neutrales que mencionan volver a comprar", genera ejemplos como:
"Es un producto aceptable para lo que cuesta. Puede que compre otro si hay una oferta."
Etiquetas estos ejemplos sintéticos y Potato los añade al contexto few-shot del LLM.
Tiempo estimado: 10-15 minutos para 30 ejemplos.
Paso 13: Revisión periódica
A estas alturas el LLM ha etiquetado la mayor parte del conjunto de datos. Potato ordena todas sus etiquetas por confianza y te envía las de menor confianza en lotes de 25.
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
Cuando la precisión deja de moverse durante tres lotes seguidos, Solo Mode considera fiables las etiquetas de alta confianza restantes. Ten en cuenta que esto es estabilidad, no perfección: la ejecución anterior se detiene después de 92%, 96% y 100% porque la cifra se ha estabilizado, no porque el último lote saliera limpio.
Tiempo estimado: 15-20 minutos.
Paso 14: Optimización del prompt
Esta fase se ejecuta sola. Potato prueba 8 variantes del prompt y se queda con la que obtiene la mayor puntuación F1 sobre las etiquetas humanas que has acumulado:
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
Después usa el mejor prompt para una pasada final de reetiquetado.
Paso 15: Validación final
Potato toma 100 instancias aleatorias etiquetadas por el LLM para que las revises. Tú las etiquetas y Potato compara tus etiquetas con las del LLM.
Final Validation:
Reviewed: 100 instances
LLM correct: 94/100 (94%)
Threshold: 93%
-> PASSED
Si el LLM supera tu umbral, el proyecto está terminado. Si no, vuelve a la anotación activa para otra ronda. Esa vuelta atrás es la única transición que se permite desde la validación final.
Tiempo estimado: 10-15 minutos.
Resumen de resultados
Al final, el panel informa de dónde salieron las etiquetas. Solo Mode no tiene interfaz de línea de comandos (se ejecuta dentro del servidor y se maneja desde sus propias páginas), así que estos datos se leen en la instancia en ejecución y no en una terminal:
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%
La persona etiquetó 612 de 10 000 instancias, alrededor del 6%. El LLM y las funciones de etiquetado se encargaron del resto con una precisión de más del 94%.
Exportación de resultados
Solo Mode escribe en el mismo almacenamiento que cualquier otro proyecto, así que las etiquetas salen con el exportador habitual:
python -m potato.export -c config.yaml -f jsonl -o ./export/Cada línea incluye la etiqueta y su origen:
{"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 exportar a Parquet:
import pandas as pd
df = pd.read_parquet("output/exports/parquet/annotations.parquet")
print(df["sentiment"].value_counts())annotations.parquet tiene una fila por instancia y anotador, con cada esquema de anotación aplanado en su propia columna, así que seleccionas el esquema por su nombre y no mediante una columna genérica value.
Control de calidad: verificación híbrida
Para conjuntos de datos con calidad de publicación, añade un segundo anotador que revise una muestra. La documentación fuente de Solo Mode describe con más detalle las opciones de verificación.
Solo Mode no tiene un bloque de verificación propio, así que se trata de una segunda pasada normal: exporta las etiquetas, vuelve a pasarlas por Potato como un proyecto normal con un revisor sobre una muestra del 10% y calcula el acuerdo entre el revisor y las etiquetas de Solo Mode como lo harías para dos anotadores cualesquiera. (icl_labeling sí tiene un bloque verification, pero pertenece al etiquetado en contexto, no a Solo Mode.)
Solución de problemas
La precisión del LLM se estanca por debajo del umbral
- Aumenta el número de semillas: Prueba con 75-100 instancias semilla en lugar de 50
- Cambia de LLM: Prueba
claude-sonnet-4-20250514en lugar de GPT-4o (o al revés) - Baja el umbral: Si el 93% no es alcanzable, plantéate si un 90% es aceptable para tu caso de uso
- Revisa tus datos: Algunos conjuntos de datos son ambiguos por naturaleza. Si el acuerdo entre dos personas solo llegaría al 90%, no esperes que el LLM lo haga mejor
La anotación activa requiere demasiados lotes
- Aumenta el tamaño de lote: Cambia
batch_sizede 25 a 50 - Ajusta los pesos de los grupos: Si la mayoría de las instancias escaladas vienen del grupo de baja confianza, reduce
low_confidence_weighty subedisagreement_weightodiversity_weight
Las funciones de etiquetado tienen poca cobertura
- Es normal en tareas sin señales léxicas fuertes (p. ej., detección de sarcasmo, sentimiento implícito)
- Las funciones de etiquetado funcionan mejor con patrones explícitos basados en palabras clave
- Solo Mode sigue funcionando sin funciones de etiquetado; en ese caso el LLM cubre esas instancias
Lecturas adicionales
- Documentación de Solo Mode: referencia completa de configuración
- Aprendizaje activo: el algoritmo de selección subyacente
- Soporte de IA: configuración de proveedores de LLM
- Control de calidad: opciones adicionales de control de calidad
- Exportación a Parquet: exportación eficiente de datos