솔로 모드: 한 명의 어노테이터가 10,000개의 예시를 레이블링하는 방법
Potato의 솔로 모드를 사용하여 사람-LLM 협업으로 대규모 데이터셋을 효율적으로 레이블링하고 어노테이션 비용을 최대 90%까지 줄이는 단계별 튜토리얼.
여러분에게 감성(긍정, 중립, 부정)을 레이블링해야 할 제품 리뷰 10,000개가 있다고 합시다. 세 명의 어노테이터를 고용해 전부 레이블링하면 몇 주가 걸리고 수천 달러가 듭니다. 솔로 모드를 사용하면 한 명의 도메인 전문가가 500-1,000개의 인스턴스만 레이블링해도 비슷한 품질을 얻을 수 있습니다. 나머지는 LLM이 처리하고, 사람은 LLM이 확신하지 못하는 부분만 검토합니다.
이 튜토리얼은 전체 과정을 안내합니다.
필요한 것
- 솔로 모드 추가 기능이 포함된 Potato 2.3.0 이상:
pip install potato-annotation[solo] - OpenAI 또는 Anthropic API 키(LLM 구성 요소용)
- JSONL 형식의 데이터셋
- 지식이 있는 어노테이터 한 명(여러분 자신일 수도 있습니다)
1단계: 데이터 준비하기
한 줄에 리뷰 하나씩 담아 data/reviews.jsonl을 만듭니다.
{"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"}이 튜토리얼에서는 이 파일에 리뷰 10,000개가 들어 있다고 가정합니다.
2단계: 구성 만들기
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
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/"3단계: 서버 시작하기
potato start config.yaml -p 8000http://localhost:8000을 열고 로그인합니다. 솔로 모드 대시보드가 나타나며, 현재 1단계인 시드 어노테이션에 있음을 보여 줍니다.
4단계: 1단계 -- 시드 어노테이션(50개 인스턴스)
Potato는 임베딩 기반 클러스터링을 사용해 다양한 리뷰 50개를 선택했습니다. 이것들은 무작위가 아니라 데이터 분포를 최대한 폭넓게 포괄하도록 선택된 것입니다.
각각을 레이블링하십시오. 이 단계가 가장 중요한데, 시드 레이블의 품질이 LLM이 학습할 수 있는 상한을 정하기 때문입니다. 시간을 충분히 들이고 일관성을 유지하십시오.
예상 소요 시간: 인스턴스당 20-30초로 15-25분.
50번째 인스턴스를 마치면 Potato가 알아서 2단계로 넘어갑니다.
5단계: 2단계 -- 초기 LLM 보정
이 단계는 알아서 진행됩니다. Potato는 여러분의 시드 레이블 50개를 few-shot 예시로 삼아 200개 인스턴스 배치를 LLM에 보내고, 따로 떼어 둔 시드 레이블 10개와 예측을 비교해 기준 정확도를 추정합니다.
대시보드에 진행 표시기가 나타납니다. LLM 제공자에 따라 보통 1-2분이 걸립니다.
일반적인 결과: LLM은 첫 보정에서 75-85% 정확도에 머뭅니다. 이는 예상된 일입니다. 아직 여러분의 어노테이션 방식을 학습하지 못했기 때문입니다.
6단계: 3단계 -- 혼동 분석
Potato는 LLM이 여러분의 레이블과 어디에서 어긋나는지 보여 주는 혼동 행렬을 표시합니다. 일반적인 출력은 다음과 같습니다.
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%)
이는 이 경우 LLM의 주된 약점을 가리킵니다. 즉, 중립 리뷰를 계속 긍정으로 끌어올린다는 점입니다. 이는 흔한 일인데, LLM이 긍정 쪽으로 기우는 경향이 있기 때문입니다.
여러분의 작업: 혼동 쌍들을 살펴보십시오. 각 쌍을 클릭하면 LLM이 틀린 구체적인 인스턴스를 볼 수 있으며, 이것이 LLM이 어떻게 실패하는지 가장 빠르게 이해하는 방법입니다.
7단계: 4단계 -- 가이드라인 개선
혼동 분석을 바탕으로 Potato는 LLM을 위한 개선된 가이드라인을 작성하여 나란히 보여 줍니다. 한쪽에는 현재 프롬프트가, 다른 쪽에는 오류 패턴에서 제안한 구체적인 수정 사항이 표시됩니다.
예를 들어 Potato는 다음을 추가하도록 제안할 수 있습니다.
"Reviews that describe a product as 'fine', 'okay', or 'decent' without strong emotion should be labeled Neutral, even if they mention buying again."
제안된 각 수정 사항을 살펴보고 승인, 수정 또는 거부하십시오. 직접 설명을 추가로 작성할 수도 있습니다.
예상 소요 시간: 5-10분.
8단계: 5단계 -- 레이블링 함수 생성
Potato는 시드 레이블의 패턴에서 프로그래밍적 레이블링 함수를 생성합니다. 이것들은 쉬운 사례를 처리하는 빠르고 결정론적인 규칙입니다.
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)
레이블링 함수는 92% 이상의 정밀도로 데이터셋의 18%를 포괄합니다. 이 인스턴스들은 자동으로 레이블링되어 LLM과 사람이 더 어려운 사례에 집중할 수 있게 합니다.
여러분의 작업: 생성된 함수들을 살펴보고 신뢰성이 없어 보이는 것은 비활성화하십시오. Potato는 어차피 여러분이 구성한 정밀도 임계값을 넘는 함수만 유지하므로 이 단계는 선택 사항입니다.
9단계: 6단계 -- 능동 레이블링(125-375개 인스턴스)
여기에서 레이블링의 대부분을 수행합니다. Potato는 6개 풀 우선순위 시스템을 사용해 인스턴스를 선택합니다.
- 불확실(Uncertain) (30%): LLM의 신뢰도가 85% 미만인 리뷰
- 불일치(Disagreement) (25%): LLM과 레이블링 함수가 서로 다른 레이블을 내놓는 리뷰
- 경계(Boundary) (20%): 임베딩 공간에서 결정 경계 근처에 있는 리뷰
- 새로움(Novel) (10%): 지금까지 레이블링한 그 무엇과도 다른 리뷰
- 오류 패턴(Error pattern) (10%): 알려진 혼동 패턴과 일치하는 리뷰(예: 미온적 긍정)
- 무작위(Random) (5%): 보정을 위한 무작위 리뷰
이것들을 25개씩 배치로 레이블링합니다. 각 배치 후 Potato는 LLM의 정확도 추정치를 업데이트하고 계속할지 결정합니다.
일반적인 궤적:
- 배치 1-3(75개 인스턴스): 정확도가 82%에서 87%로 상승
- 배치 4-6(150개 인스턴스): 정확도가 90%에 도달
- 배치 7-10(250개 인스턴스): 정확도가 91-92%에서 정체
정확도가 93%(여러분의 임계값)에 도달하면 솔로 모드는 10단계로 건너뜁니다. 그렇지 않으면 7단계로 넘어갑니다.
예상 소요 시간: 필요한 배치 수에 따라 총 45-90분.
10단계: 7단계 -- 자동화된 개선 루프
능동 레이블링 후에도 정확도가 여전히 임계값 미만이면 Potato는 개선 루프를 한 번 더 실행합니다.
- LLM이 업데이트된 가이드라인과 더 많은 few-shot 예시로 전체 데이터셋을 다시 레이블링합니다
- Potato가 모든 사람 레이블과 비교해 정확도를 다시 계산합니다
- 새로운 혼동 패턴을 찾아냅니다
- 가이드라인을 다시 개선합니다
이 단계는 대부분 손이 가지 않습니다. 여러분은 가이드라인 변경 사항만 승인하면 됩니다.
일반적인 결과: 개선 라운드마다 정확도가 2-4% 향상됩니다.
11단계: 8단계 -- 불일치 탐색
Potato는 가장 논쟁적인 인스턴스를 제시합니다. LLM, 레이블링 함수, 최근접 이웃 분석이 모두 서로 다른 답을 내놓는 경우입니다. 각 인스턴스에 대해 다음을 볼 수 있습니다.
- 리뷰 텍스트
- LLM 예측 및 신뢰도
- 레이블링 함수 투표
- 레이블이 달린 가장 가까운 예시 3개와 그 레이블
- LLM의 사고 사슬 추론
이것들은 진정으로 어려운 사례이며, 여기에서의 여러분의 레이블은 전체 과정의 다른 어떤 레이블보다 가치가 큽니다.
예상 소요 시간: 100-150개 인스턴스에 20-30분.
12단계: 9단계 -- 엣지 케이스 합성
Potato는 남아 있는 혼동 패턴을 겨냥한 합성 리뷰를 생성합니다. 예를 들어 LLM이 여전히 "다시 구매를 언급하는 중립 리뷰"에서 어려움을 겪는다면 다음과 같은 예시를 생성합니다.
"It's an okay product for the price. I might get another one if there's a sale."
여러분이 이 합성 예시들을 레이블링하면 Potato가 이를 LLM의 few-shot 컨텍스트에 추가합니다.
예상 소요 시간: 예시 30개에 10-15분.
13단계: 10단계 -- 단계적 신뢰도 에스컬레이션
이 시점이면 LLM이 데이터셋의 대부분을 레이블링한 상태입니다. Potato는 모든 레이블을 신뢰도순으로 정렬하고, 신뢰도가 가장 낮은 것들을 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
연속 세 배치에서 LLM이 모두 맞히면, 솔로 모드는 남은 고신뢰도 레이블을 믿을 수 있는 것으로 취급합니다.
예상 소요 시간: 15-20분.
14단계: 11단계 -- 프롬프트 최적화
이 단계는 알아서 진행됩니다. Potato는 8개의 프롬프트 변형을 시도하고, 누적된 사람 레이블에서 F1 점수가 가장 높은 것을 유지합니다.
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
그런 다음 최선의 프롬프트로 최종 재레이블링 패스를 수행합니다.
15단계: 12단계 -- 최종 검증
Potato는 여러분이 검토할 LLM 레이블 인스턴스 100개를 무작위로 추출합니다. 여러분이 이를 레이블링하면 Potato가 여러분의 레이블을 LLM의 레이블과 비교합니다.
Final Validation:
Reviewed: 100 instances
LLM correct: 94/100 (94%)
Threshold: 93%
-> PASSED
LLM이 여러분의 임계값을 넘으면 데이터셋이 완성됩니다. 그렇지 않으면 솔로 모드는 6단계로 되돌아가 능동 레이블링을 한 번 더 진행합니다.
예상 소요 시간: 10-15분.
결과 요약
12개 단계를 모두 마친 뒤 최종 통계를 확인합니다.
python -m potato.solo status --config config.yamlSolo 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%
사람은 10,000개 중 612개, 약 6%를 레이블링했습니다. LLM과 레이블링 함수가 나머지를 94% 이상의 정확도로 처리했습니다.
결과 내보내기
최종 레이블링된 데이터셋을 내보냅니다.
python -m potato.solo export --config config.yaml --output final_labels.jsonl각 줄에는 레이블과 그 출처가 포함됩니다.
{"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}Parquet 내보내기는 다음과 같습니다.
import pandas as pd
df = pd.read_parquet("output/parquet/annotations.parquet")
print(df["value"].value_counts())품질 보증: 하이브리드 검증
출판 품질의 데이터셋을 위해서는 표본을 검토할 두 번째 어노테이터를 추가하십시오. 솔로 모드 원본 문서에서 검증 옵션을 더 자세히 설명합니다.
solo_mode:
verification:
enabled: true
sample_fraction: 0.10
annotator: "reviewer_1"이는 무작위 인스턴스 1,000개를 두 번째 어노테이터에게 보냅니다. 그런 다음 솔로 모드 레이블과 검토자의 레이블 사이의 어노테이터 간 일치도를 계산할 수 있습니다.
문제 해결
LLM 정확도가 임계값 아래에서 정체됨
- 시드 개수 늘리기: 50개 대신 75-100개의 시드 인스턴스를 시도해 보십시오
- LLM 교체하기: GPT-4o 대신
claude-sonnet-4-20250514를 시도해 보십시오(또는 그 반대) - 임계값 낮추기: 93%가 달성 불가능하다면, 여러분의 사용 사례에 90%가 받아들일 만한지 고려해 보십시오
- 데이터 점검하기: 일부 데이터셋은 본질적으로 모호합니다. 사람-사람 일치도가 90%에 그칠 정도라면, LLM이 그보다 더 잘하기를 기대하지 마십시오
6단계가 너무 많은 배치를 소요함
- 배치 크기 늘리기:
batch_size를 25에서 50으로 바꾸십시오 - 풀 가중치 조정하기: 에스컬레이션된 인스턴스 대부분이 "불확실" 풀에서 온다면, 그 가중치를 줄이고 "불일치"와 "오류 패턴"을 늘리십시오
레이블링 함수의 커버리지가 낮음
- 강한 어휘적 신호가 없는 작업(예: 풍자 탐지, 암시적 감성)에서는 이것이 정상입니다
- 레이블링 함수는 명시적이고 키워드 중심적인 패턴에서 가장 잘 작동합니다
- 솔로 모드는 레이블링 함수가 없어도 여전히 작동합니다 -- LLM이 그 공백을 메웁니다
더 읽어 보기
- 솔로 모드 문서 -- 전체 구성 레퍼런스
- 능동 학습 -- 기반이 되는 선택 알고리즘
- AI 지원 -- LLM 제공자 구성
- 품질 관리 -- 추가적인 품질 보증 옵션
- Parquet 내보내기 -- 효율적인 데이터 내보내기