Skip to content
Tutorials6 min read

Solo Mode:一个标注者如何标注 10,000 个样本

使用 Potato 的 Solo Mode 通过人机协同高效标注大型数据集的分步教程,标注成本最高可降低 90%。

Potato Team·

Solo Mode:一个标注者如何标注 10,000 个样本

你有 10,000 条产品评论需要进行情感标注(正面、中性、负面)。雇用三名标注者标注所有数据需要数周时间和数千美元的费用。使用 Solo Mode,一位领域专家只需标注 500-1,000 个实例即可达到相当的质量,LLM 处理其余部分——而人类审核 LLM 不确定的每一个决定。

本教程将引导你完成整个流程。


你需要准备什么

  • Potato 2.3.0+ 并安装 Solo Mode 扩展:pip install potato-annotation[solo]
  • 一个 OpenAI 或 Anthropic API 密钥(用于 LLM 组件)
  • JSONL 格式的数据集
  • 一位知识丰富的标注者(可以是你自己)

第 1 步:准备数据

创建 data/reviews.jsonl,每行一条评论:

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"}

在本教程中,假设此文件包含 10,000 条评论。


第 2 步:创建配置

创建 config.yaml

yaml
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/"
output_annotation_format: "jsonl"
 
parquet_export:
  enabled: true
  output_dir: "output/parquet/"

第 3 步:启动服务器

bash
potato start config.yaml -p 8000

打开 http://localhost:8000 并登录。Solo Mode 面板将显示你处于 阶段 1:种子标注


第 4 步:阶段 1 -- 种子标注(50 个实例)

Potato 使用基于嵌入的聚类选择了 50 条多样化的评论。这些不是随机选择的;它们被选择以最大化数据分布的覆盖范围。

逐一标注。这是最重要的阶段——种子标签的质量决定了 LLM 学习的效果。请认真对待并保持一致。

预计时间: 每个实例 20-30 秒,共 15-25 分钟。

当你完成第 50 个实例时,Potato 自动进入阶段 2。


第 5 步:阶段 2 -- 初始 LLM 校准

此阶段自动运行。Potato 将你的 50 个种子标签作为少样本示例发送给 LLM,让其标注 200 个实例的批次。然后将 LLM 的预测与 10 个留出的种子标签进行比较,以估算基线准确率。

你将在面板中看到进度指示器。这通常需要 1-2 分钟,具体取决于 LLM 提供商。

典型结果: LLM 在第一次校准中达到 75-85% 的准确率。这是预期的——LLM 尚未学会你特定的标注风格。


第 6 步:阶段 3 -- 混淆分析

Potato 显示一个混淆矩阵,展示 LLM 与你的标签不一致的地方。典型输出:

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%)

这告诉你 LLM 的主要弱点:它倾向于将中性评论升级为正面。这很常见——LLM 通常对正面情感有偏差。

你的操作: 审查混淆对。点击每个配对查看 LLM 标注错误的具体实例。这有助于你理解 LLM 的失败模式。


第 7 步:阶段 4 -- 指南优化

基于混淆分析,Potato 为 LLM 生成优化的指南。你会看到并排视图:

  • 当前指南: 用于 LLM 的初始提示
  • 建议编辑: LLM 根据错误模式提出的具体修改

例如,Potato 可能建议添加:

"将产品描述为'还行'、'凑合'或'一般'且没有强烈情感的评论应标为 Neutral,即使提到可能再次购买。"

逐一审查建议的编辑。批准、修改或拒绝每一条。你也可以添加自己的说明。

预计时间: 5-10 分钟。


第 8 步:阶段 5 -- 标注函数生成

Potato 从种子标签的模式中生成程序化标注函数。这些是处理简单案例的快速、确定性规则:

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)

标注函数以 92%+ 的精确率覆盖了数据集的 18%。这些实例被自动标注,将人类和 LLM 的精力留给更难的案例。

你的操作: 审查生成的函数。禁用任何看起来不可靠的函数。这是可选的——Potato 只保留超过你配置的精确率阈值的函数。


第 9 步:阶段 6 -- 主动标注(125-375 个实例)

这是主要的人工标注阶段。Potato 使用六池优先级系统选择实例:

  • 不确定(30%):LLM 置信度低于 85% 的评论
  • 分歧(25%):LLM 和标注函数给出不同标签的评论
  • 边界(20%):在嵌入空间中靠近决策边界的评论
  • 新颖(10%):与你已标注内容完全不同的评论
  • 错误模式(10%):匹配已知混淆模式的评论(如偏正面的中性评论)
  • 随机(5%):用于校准的随机评论

你以 25 个为一批进行标注。每批之后,Potato 更新 LLM 的准确率估计并决定是否继续。

典型轨迹:

  • 第 1-3 批(75 个实例):准确率从 82% 升至 87%
  • 第 4-6 批(150 个实例):准确率达到 90%
  • 第 7-10 批(250 个实例):准确率在 91-92% 趋于平稳

如果准确率达到 93%(你设定的阈值),Solo Mode 将跳至阶段 10。否则,继续进入阶段 7。

预计时间: 总计 45-90 分钟,取决于需要多少批次。


第 10 步:阶段 7 -- 自动化优化循环

如果主动标注后准确率仍低于阈值,Potato 运行新一轮优化循环:

  1. LLM 使用更新的指南和更多少样本示例重新标注完整数据集
  2. 根据所有人工标签重新计算准确率
  3. 识别新的混淆模式
  4. 再次优化指南

此阶段大部分是自动的。你只需批准指南变更。

典型结果: 每轮优化准确率提高 2-4%。


第 11 步:阶段 8 -- 分歧探索

Potato 呈现最有争议的实例:LLM、标注函数和最近邻分析都给出不同答案的案例。对于每个实例,你会看到:

  • 评论文本
  • LLM 预测和置信度
  • 标注函数投票
  • 3 个最近的已标注示例及其标签
  • LLM 的思维链推理

这些是真正困难的案例。你在这里的标签在整个过程中具有最高的边际价值。

预计时间: 100-150 个实例需 20-30 分钟。


第 12 步:阶段 9 -- 边缘案例合成

Potato 生成针对剩余混淆模式的合成评论。例如,如果 LLM 仍然在"提到再次购买的中性评论"上有困难,它会生成如下示例:

"这个产品在这个价位还行。如果打折的话我可能会再买一个。"

你标注这些合成示例,它们被添加到 LLM 的少样本上下文中。

预计时间: 30 个示例需 10-15 分钟。


第 13 步:阶段 10 -- 级联置信度升级

LLM 现在已经标注了大部分数据集。Potato 按置信度排序所有 LLM 标注的实例,并将最低置信度的实例以 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

一旦你看到连续三批 LLM 全部正确,Solo Mode 即判定剩余的高置信度标签是可信的。

预计时间: 15-20 分钟。


第 14 步:阶段 11 -- 提示优化

此阶段自动运行。Potato 尝试 8 种提示变体,并选择在你积累的人工标签上 F1 分数最高的那个:

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

最佳提示用于最终的重新标注。


第 15 步:阶段 12 -- 最终验证

Potato 随机选择 100 个 LLM 标注的实例供你审核。你进行标注,Potato 将其与 LLM 的标签进行比较。

text
Final Validation:
  Reviewed: 100 instances
  LLM correct: 94/100 (94%)
  Threshold: 93%
  -> PASSED

如果 LLM 的准确率达到阈值,数据集即告完成。如果没有,Solo Mode 循环回阶段 6 进行新一轮主动标注。

预计时间: 10-15 分钟。


结果汇总

完成所有 12 个阶段后,查看最终统计:

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%

人类标注了 10,000 个实例中的 612 个(6.1%)。LLM 和标注函数以 94%+ 的准确率处理了其余部分。


导出结果

导出最终的标注数据集:

bash
python -m potato.solo export --config config.yaml --output final_labels.jsonl

每行包含标签及其来源:

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}

Parquet 导出:

python
import pandas as pd
df = pd.read_parquet("output/parquet/annotations.parquet")
print(df["value"].value_counts())

质量保证:混合验证

对于出版级质量的数据集,添加第二个标注者审查样本:

yaml
solo_mode:
  verification:
    enabled: true
    sample_fraction: 0.10
    annotator: "reviewer_1"

这将 1,000 个随机实例分配给第二个标注者。然后你可以计算 Solo Mode 标签与审核者标签之间的标注者间一致性。


故障排除

LLM 准确率在阈值以下停滞

  • 增加种子数量: 尝试 75-100 个种子实例而不是 50 个
  • 更换 LLM: 尝试 claude-sonnet-4-20250514 代替 GPT-4o(或反之)
  • 降低阈值: 如果 93% 无法达到,考虑 90% 对你的用例是否可接受
  • 检查数据: 某些数据集本身就是模糊的。如果人类间一致性只有 90%,不要期望 LLM 做得更好

阶段 6 需要太多批次

  • 增加批量大小:batch_size 从 25 改为 50
  • 调整池权重: 如果大多数升级的实例来自"不确定"池,降低其权重并增加"分歧"和"错误模式"的权重

标注函数覆盖率低

  • 这对于没有强词汇信号的任务是正常的(如讽刺检测、隐含情感)
  • 标注函数对显式的、基于关键词的模式效果最好
  • Solo Mode 在没有标注函数的情况下仍然有效——LLM 会补上

延伸阅读