Skip to content

單人模式(Solo Mode)

在 Potato 中由一個人跑完整條標註流水線:一位專家和一個 LLM 沿著階段狀態機推進,涵蓋提示詞編寫、並行標註、分歧解決和最終驗證。

v2.3.0 新增

傳統標註項目需要多名標註者、標註者間一致性計算、仲裁輪次以及大量協調開銷。對許多研究團隊來說,主要瓶頸不是標註介面,而是招聘、培訓和管理團隊這些後勤工作。

Solo Mode 用一位人類專家與 LLM 的協作取代了多標註者範式。人類在一個精心挑選的小子集上提供高品質標籤。LLM 從這些標籤中學習,為其餘資料提出標籤,人類只稽核 LLM 不確定或可能出錯的案例。整個過程由一個階段狀態機編排,按你設定的閾值向前推進,並在發現問題出在提示詞本身時繞回提示詞環節。

在內部基準測試中,Solo Mode 與完整的多標註者流程達到了 95% 以上的一致性,而只需要 10-15% 的人工標籤總量。

工作流程

Solo Mode 是一個狀態機。SoloPhaseController 記錄項目當前處在哪個階段、接下來允許進入哪些階段,所以路線不是一條直線:有好幾個階段在提示詞仍需修改時會繞回去。

設定

任務描述和資料。Generate prompt 會請修訂模型(revision_models)根據任務描述和標註方案寫出第一版提示詞。沒有修訂模型,或者修訂模型什麼也沒返回時,任務描述本身就成為第一版提示詞,提示詞歷史裡會註明這一點。設定階段唯一能進入的下一個階段是提示詞稽核。

提示詞稽核

Potato 根據任務描述合成一個提示詞,由你來編輯。後面有好幾個階段在發現問題出在提示詞上時都會回到這裡,這讓它成為整個工作流的樞紐,而不是一次性的步驟。

從這裡開始,項目要麼走邊緣案例迴圈,要麼直接進入並行標註。

邊緣案例合成,隨後是邊緣案例標註

LLM 生成邊界示例,由你標註。如果這些示例表明提示詞有問題,標註階段可以退回提示詞稽核。

提示詞驗證

把你在邊緣案例上給出的標籤與提示詞產出的結果做對照。之後要麼進入並行標註,要麼退回提示詞稽核。

並行標註

你和 LLM 同時標註同一批資料。這個階段產出的一致性數字,是其他一切的依據。

分歧解決

你和 LLM 給出不同結果的地方,由你來定奪。之後回到並行標註;如果分歧指向的是提示詞而不是個別條目,則回到提示詞稽核。

主動標註

主要的標註階段,實例由 instance_selection 中的加權池挑選。從這裡 Potato 可以進入定期稽核、規則稽核,或繼續到自主標註。

定期稽核

置信度較低的 LLM 標籤,每 thresholds.periodic_review_interval 個條目呈現一次。之後回到主動標註、轉入規則稽核,或退回提示詞稽核。

規則稽核

Potato 從你的標註中提取出的邊緣案例規則,交由你批准。之後回到主動標註或提示詞稽核。

自主標註

LLM 標註剩下的資料。它唯一的出口是最終驗證。

最終驗證

你抽查一部分僅由 LLM 標註的標籤。達到 thresholds.end_human_annotation_agreement 則項目完成;沒達到則退回主動標註。

完成

終止狀態。


配置

快速開始

一個最小的 Solo Mode 配置:

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"

完整配置參考

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"

關鍵能力

混淆分析

每輪標註之後,Potato 會在人類標籤和 LLM 標籤之間構建混淆矩陣。管理面板顯示:

  • 從 LLM 角度看的每類精確率、召回率和 F1
  • 最常見的混淆對(例如"中性被誤分為正面:23 個實例")
  • 每個混淆對的示例實例
  • 展示各最佳化輪次改進情況的趨勢圖

Solo Mode 沒有命令列介面。它執行在伺服器內部,由執行實例下它自己的頁面驅動,所以分析結果是從面板而不是 CLI 讀取的。它報告的內容大致是這樣:

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

自動化最佳化迴圈

最佳化迴圈在 LLM 標註、混淆分析和指南更新之間迭代。每次迭代:

  1. LLM 用當前指南標註完整資料集
  2. Potato 與所有可用的人工標籤做對比
  3. 如果準確率低於閾值,執行混淆分析
  4. LLM 根據錯誤模式提出指南修改建議
  5. 人類審查並批准這些修改
  6. 迴圈重複(最多 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

標註函式(受 ALCHEmist 啟發)

Potato 從人工標註中觀察到的模式生成輕量級的標註函式。它們不是 LLM 呼叫,而是快速、確定性的規則。

生成的標註函式示例:

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

配置標註函式的行為:

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

分歧探索器

分歧探索器呈現不同訊號相互衝突的實例。對每個實例,標註者會看到:

  • LLM 預測的標籤和置信度
  • 標註函式的投票(如果有)
  • 嵌入空間中最近的已標註鄰居
  • 原始文本或內容

這是價值最高的標註活動:每個標籤都解決一處真實的歧義。

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

級聯置信度升級

資料集的大部分被 LLM 標註之後,Potato 按置信度對所有 LLM 標註的實例排序,把置信度最低的升級給人類。這個過程按批次持續進行,直到品質趨於穩定。

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

決策模型

從 Potato 2.11 起,Solo Mode 可以用決策模型來標註。決策模型用一次前向計算回答一道固定選項的題目,併為每個選項返回一個機率,所以它標註起來比 LLM 更快、更便宜,但它寫不了提示詞、規則或解釋。有兩種端點類型可以接入決策模型。laya 在 Potato 程序內用 CPU 執行 Laya,需要 pip install 'potato-annotation[decision]';systemone 則連線任何提供 /v1/systemone API 的伺服器,例如託管的 Jev 或 OpenJev。

決策模型通常放在置信度路由的第一層。它為所有條目打標籤,只有它沒把握的條目才會繼續交給 LLM:

yaml
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/v1

revision_models 必須是生成式模型。它預設等於 labeling_models,所以唯一模型是決策模型的研究必須單獨設定它。決策模型能標註 radio、select、likert 和 slider 方案;如果把決策模型設為標註 multiselect、片段或自由文本方案,Solo Mode 會拒絕啟動。在評分量表上,Laya 的分數幾乎跟不上量表,所以在讓 likert 或 slider 方案經過它之前,先用 Try on 10 items 檢查幾個條目。置信度是模型給它所選選項的機率,它的校準程度因領域而異,所以請根據你自己的資料設定該層的閾值。config-decision-model.yaml 是一個可以直接執行的版本。

盲態建議

預設情況下,標註頁面會在你作答之前顯示 LLM 的標籤、它的置信度和一個 Accept 按鈕。這樣很快,也會把你的答案拉向建議。當你與 LLM 的一致性超過 end_human_annotation_agreement 時,Solo Mode 會把剩餘語料交給 LLM,所以如果一致性是在你看過建議之後給出的標籤上測得的,你那部分工作就可能過早結束。從 Potato 2.11 起,solo_mode.suggestions 控制建議何時出現:

yaml
solo_mode:
  suggestions:
    display: blind_sample      # before_label | after_label | blind_sample
    blind_rate: 0.2
    minimum_blind_sample: 20

blind_sample 在 blind_rate 比例的條目上隱藏建議,after_label 則從不先顯示建議。盲態比較達到 minimum_blind_sample 次之後,交接時會拿盲態一致性與 end_human_annotation_agreement 比較。面板上的 Blind Agreement 卡片把盲態一致性和顯示建議時的一致性並排列出,如果兩者的正差距很大,說明你在能看到 LLM 答案時更常與它一致。

在 Potato 2.11 中,Solo Mode 還會在標註開始前和每個批次之前檢查項目的花費上限(ai_budget.cap_usd),並新增了響應快取(solo_mode.cache)、帶提示詞試驗的金標準集(solo_mode.gold)、提示詞敏感性檢查、標註評審團(solo_mode.jury)和課程式排序(solo_mode.instance_selection.curriculum)。Solo Mode Advanced Features 逐一說明了這些功能。開啟標註引擎時,Solo Mode 還會把它的模型預測寫入引擎的儲存,讓引擎可以校準並認證這些預測。

多訊號實例優先順序

在所有涉及人工標註的階段,Potato 用一套加權池系統挑選資訊量最大的實例。七個池匯入一個統一的優先順序佇列:

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:LLM 的置信度低於 thresholds.confidence_low
  • diversity:在嵌入空間中遠離你已經標註過的內容
  • llm_predicted:LLM 已經給出標籤,但還沒有被核查
  • disagreement:該實例可用的幾個訊號彼此不一致
  • random:少量隨機抽取,用來保持估計的誠實並發現盲區
  • cartography:訓練動態訊號,預設關閉
  • edge_case_rule:匹配從你早先標註中提取出的規則,預設關閉

邊緣案例合成

Potato 用 LLM 生成針對已知弱點的合成示例:

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

LLM 生成在指定標籤對之間存在歧義的示例。人類標註這些示例,這些標籤隨後被加入後續 LLM 標註輪次的少樣本上下文。

提示詞最佳化(受 DSPy 啟發)

Potato 會執行自動化的提示詞最佳化,為 LLM 找出最好的指令格式,並會尋找仍能守住目標準確率的最小模型:

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

監控進度

管理面板即時顯示 Solo Mode 的進度:

  • 當前階段以及各階段內部的進度
  • 已完成的人工標籤數與總預算
  • LLM 準確率隨時間的變化(按輪次)
  • 標註函式的覆蓋率和精確率
  • 置信度分佈直方圖
  • 預計完成時間

沒有 potato.solo 模組,也沒有 Solo Mode 的 CLI:整個工作流都在伺服器自己的路由背後,因此進度是從面板讀取的。它報告的內容是:

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

何時使用 Solo Mode,何時使用傳統多標註者

適合使用 Solo Mode 的情況:

  • 你有一位能提供高品質標籤的領域專家
  • 預算或後勤條件不允許僱用多名標註者
  • 任務的類別清晰、定義明確
  • 你需要標註大型資料集(1,000 個以上實例)
  • 速度比測量標註者間一致性更重要

適合使用傳統多標註者的情況:

  • 你需要標註者間一致性統計用於發表
  • 任務高度主觀(例如冒犯性、幽默感)
  • 你需要研究標註者的分歧模式
  • 法規要求多名獨立標註者
  • 標籤空間複雜或仍在演變(標註指南還在制定中)

混合做法: 先用 Solo Mode 完成初始的批次標註,再指派第二位標註者標註隨機的 10-20% 樣本來計算一致性統計。這樣既有 Solo Mode 的效率,又有多標註者驗證帶來的品質保證。

Solo Mode 自己沒有驗證塊。把第二位標註者當作一次普通的 Potato 流程跑在匯出的標籤上,然後像對待任意兩位標註者那樣,計算他們的標籤與 Solo Mode 標籤之間的一致性。(icl_labeling 確實有 verification 塊,但那屬於上下文內標註,不屬於 Solo Mode。)


延伸閱讀

有關實現詳情,請參閱源文件。