Skip to content

Latest commit

 

History

History
695 lines (526 loc) · 29.7 KB

File metadata and controls

695 lines (526 loc) · 29.7 KB

LLM 仲裁 (LLM Arbitration)

AI Analysis Concept 圖 1: AI 分析概念圖。決策邏輯樹圖,展示規則裁判無法判定時,路徑如何導向 AI 仲裁節點進行最終決策。

1. 概述

LLM 模組為 PowerBarcoder 提供智慧序列分析與決策輔助,核心定位:

  • QC 模組整合:作為統一仲裁流程中 rule as judge 無結論 (INCONCLUSIVE) 時的仲裁層
  • 序列差異解釋:對既有候選(DADA2 merged 與 Merger 最終結果)進行品質與差異描述
  • 品質佐證:彙總 BLAST identity、ambiguity、lowercase、abundance/proportion 等指標於 prompt

簡化原則:不生成新序列、不進行多序列 consensus、不引入 IUPAC 擴張,只在固定候選集合中做來源選擇與理由生成。

1.1 RuleAsJudge 預篩選機制

1.1.1 機制目的

避免對品質不佳或無足夠候選序列的樣本進行昂貴的 LLM API 調用,透過量化品質閾值進行預先篩選。

1.1.2 篩選 + 決策流程

觸發時機:前端啟用規則時的所有樣本(Rule 1-6),統一進入 RuleAsJudge 品質預篩選

篩選步驟

  1. 品質檢查:對 DADA2 和 Merger 序列應用閾值(abundance / proportion / ambiguity / lowercase / identity)
  2. 決策判斷
    • 0 通過 → 全拒 (manual_review) (confidence: 0.1) → 不進 LLM
    • 僅一方通過 → 直接推薦該來源 (confidence: 0.8 / 若低豐度或 warning -> 0.6)
    • 兩方均通過 → 標記 INCONCLUSIVE;若 llm_analysis_enabled=True → LLM 仲裁;否則 Fallback(比較 DADA2 與 Merger 最高絕對豐度;confidence: 0.30)

1.1.3 品質閾值設定

基於 src/qc/rule_as_judge.pySequenceQualityThresholds 類別:

class SequenceQualityThresholds:
    # ASV 基本要求
    MIN_ABUNDANCE_THRESHOLD = 30        # abundance > 30
    MIN_PROPORTION_THRESHOLD = 0.4      # proportion > 0.4
    
    # Merger 品質要求
    MAX_AMBIGUOUS_SITES = 10           # ambiguous sites < 10
    MAX_LOWERCASE_SITES = 10           # lowercase sites < 10
    
    # BLAST 品質要求
    MIN_BLAST_IDENTITY = 0.9           # BLAST identity > 90%

1.1.4 LLM 使用統計

引入 RuleAsJudge 後的 LLM 使用情況追蹤:

  • rule_as_judge_count:品質過濾成功處理的數量
  • rule_2_quality_filter_rejected_count:Rule 2 品質過濾拒絕的樣本數
  • rule_3_quality_filter_rejected_count:Rule 3 品質過濾拒絕的樣本數
  • llm_available_count:實際調用 LLM 的樣本數
  • llm_fallback_count:LLM 失敗使用後備邏輯的樣本數

1.1.5 推理訊息 / Reasoning 模板

有合格序列,送交 LLM

"Rule 2: Quality filtering applied - 2 sequences passed filtering (1 DADA2, 1 Merger) - LLM arbitration with top2 candidates"

無合格序列,直接放棄

"Rule 3: Quality filtering applied - No sequences passed filtering - DADA2: low abundance/proportion (abundance=25, proportion=0.30), Merger: high ambiguity (18 sites)"

1.2 分層與資料流 (Layering Overview)

層級 模組/來源 角色 輸出 可否跳過
資料收集 QCDataManager / path 提供序列 + QC 欄位 dict
規則分類 recommendation_engine 決定 rule_type (1..6) rule_type
品質預篩 RuleAsJudge 過濾並計算合法 ASVs 數量 decision / confidence / reasoning 否 (統一流程)
LLM 仲裁 LLMAnalysisPipeline + MergeAnalyzer 解釋 & 選擇來源 JSON / fallback 可 (flag 或前端未勾選)
Fallback 比較 DADA2 與 Merger 最高絕對豐度 失敗或停用時退回 recommendation 自動
報告生成 ReportGenerator Markdown 檔案 可 (無 LLM 不生成)

若 RuleAsJudge 已輸出唯一合法 ASV,LLM 層不執行。

2. 核心元件與責任界線

2.1 MergeAnalyzer (核心分析引擎)

  • 檔案位置: src/llm/analyzer.py
  • 主要功能: 取得兩來源(DADA2 merged, Merger final)差異點與品質特徵,建構 prompt,解析回應,不產生新“合併”序列;支援多數決投票以提升穩定性。
  • 輸入驗證: 依 _validate_analysis_data() 的實作,送入 LLM 必須同時滿足:
    • 具備 merger_mergeddada2_merged 任一合併結果的序列(兩者皆需存在)
    • 具備 merger_r1refmerger_r2ref 之參考序列(第二條序列為 ref) 若不滿足,該樣本會被標記為 failed 並跳過 LLM。
  • 關鍵方法:
    • analyze_sample(): (序列提取→差異摘要→品質整合→prompt→LLM→解析→報告)
    • _build_analysis_prompt(): XML/文字格式 prompt 建構
    • _prepare_analysis_data(): 分析資料預處理
    • _parse_analysis_result():單次回應解析(向下相容)
    • _parse_analysis_result_with_majority_vote():多數決回應解析
    • _execute_llm_analysis_with_majority_vote(): 多輪請求與逐輪 log
    • _apply_majority_vote(): 投票統計、平均信心度與共識摘要
    • _write_majority_vote_summary(): 多數決摘要 JSON 輸出
    • _write_prompt_log_with_run_index(): 每輪 prompt/response JSON 紀錄

2.2 LLMClientWrapper (LLM 客戶端)

  • 檔案位置: src/llm/llm_client.py
  • 功能: OpenAI 相容 API 封裝,支援多種 LLM 模型
  • 支援: 同步與異步 streaming 調用,錯誤處理與重試機制

2.3 DataLoader (資料載入器)

  • 檔案位置: src/llm/data_loader.py
  • 功能: 從結果資料中提取序列和 QC 資料,支援多種序列來源

2.4 ReportGenerator (報告生成器)

  • 檔案位置: src/llm/report_generator.py
  • 功能: 統一的 Markdown 報告生成,包含分析結果與推薦理由

2.5 LLMAnalysisPipeline (協調器)

  • 檔案位置: src/llm/llm_pipeline.py
  • 功能: LLM 分析管道簡化協調器,主要負責協調和批量處理操作
  • 關鍵方法:
    • run_single_locus_analysis(): 單個 locus 的完整分析流程
    • analyze_sample_streaming(): 前端 streaming 分析介面

3. 模組整合與控制流

3.1 QC 模組整合 (統一仲裁流程)

推薦決策: SequenceRecommendationEngineRuleAsJudge (過濾與計數) → (可選) LLMAnalysisPipelineMergeAnalyzer → Report

# src/qc/recommendation_engine.py 中的實現
def _process_unified_arbitration(self, sample_id: str, sample_data: Dict[str, Any], rule: int) -> Dict[str, Any]:
    """
    統一仲裁流程:先進行 rule-as-judge 品質過濾,
    若篩出複數 ASVs 且前端勾選規則,則進入 LLM 仲裁。
    """
    # 1. Rule-as-judge 品質過濾
    rule_result = self.rule_judge.evaluate_sample(sample_data, sample_id)
    
    # 2. 智慧化決策分流
    if rule_result.decision != RuleDecision.INCONCLUSIVE:
        # 唯一合法 ASV,直接推薦(不呼叫 LLM)
        return self._create_direct_recommendation(rule_result)
    
    # 3. 複數 ASVs → LLM 仲裁
    if not self.config.llm_analysis_enabled:
        # LLM 未啟用,使用 fallback
        return self._select_highest_abundance_fallback(sample_id, sample_data, rule)
    
    # 4. 進入 LLM 仲裁 (Top2 ASVs)
    llm_pipeline = LLMAnalysisPipeline(self.config)
    top_candidates = self._extract_top2_asvs_from_sample_data(sample_data)
    result = llm_pipeline.run_single_sample_analysis(self.locus, sample_id)
    return self._process_llm_result(sample_id, result, rule)

特點

  • 統一流程:所有樣本都經過相同的 RuleAsJudge 品質過濾。
  • 規則驅動:當前端勾選了除了 rule3 以外的任何規則時,啟用統一仲裁流程。
  • 智慧節省RuleAsJudge 篩選出唯一結果時,避免不必要的 LLM API 調用。
  • 品質保證:僅對通過基本品質標準的序列進行深度分析。
  • 統計透明:詳細記錄每階段的處理數量與決策原因。

3.2 前端 Streaming 分析

調用路徑: app.pyMergeAnalyzerstreaming LLM

# app.py 中的實現
@app.route('/llm_analysis', methods=['POST'])
def llm_analysis():
    # 建立分析器
    analyzer = MergeAnalyzer(llm_client=llm_client, log_dir=temp_dir)
    
    # 準備分析資料
    analysis_data = analyzer._prepare_analysis_data(sample_id, sequences, qc_data)
    prompt = analyzer._build_analysis_prompt(analysis_data)
    
    # 執行 streaming 分析
    def generate():
        for chunk in llm_client.stream_chat(prompt):
            yield chunk
    
    return Response(generate(), mimetype='text/plain')

特點:

項目 現況 與自動仲裁差異
模式 SSE streaming 自動仲裁為函式呼叫
寫入 實時字串 自動仲裁只記錄最終結果
報告 可即時產出 自動仲裁 parse 後一次生成
用途 手動診斷 / demo 生產決策鏈節點

4. 分析流程與狀態

4.0 LLM 分析狀態 (status)

狀態 條件 報告 推薦來源 confidence 基準
completed JSON 解析成功 JSON 指定來源 JSON 或 0.7 預設
completed_with_parsing_error 有文字無法解析 JSON 是 (含警告) Fallback(比較最高絕對豐度) 0.30
error HTTP / 連線 / API 內部 Fallback(比較最高絕對豐度) 0.30
skipped_llm_disabled flag False Fallback(比較最高絕對豐度) 0.30
skipped_rule_judge_direct rule as judge 直接決策 judge 來源 0.8 / 0.6
skipped_no_candidates 0 passed sequences manual_review 0.1

completed_with_parsing_errorerror 都計入 llm_fallback_count

4.1 整體架構流程

graph TB
    subgraph "QC 模組 (Rule 3)"
        QC[SequenceRecommendationEngine] --> LLMP[LLMAnalysisPipeline]
        LLMP --> MA1[MergeAnalyzer]
        MA1 --> QCResult[同步分析結果]
    end
    
    subgraph "前端 Streaming"
        Frontend[前端請求] --> App[app.py]
        App --> MA2[MergeAnalyzer]
        MA2 --> StreamResult[異步流式回應]
    end
    
    subgraph "共用核心元件"
        DataLoader[DataLoader<br/>資料載入器]
        LLMClient[LLMClientWrapper<br/>LLM 客戶端]
        ReportGen[ReportGenerator<br/>報告生成器]
    end
    
    MA1 --> DataLoader
    MA1 --> LLMClient
    MA1 --> ReportGen
    MA2 --> DataLoader
    MA2 --> LLMClient
    MA2 --> ReportGen
Loading

4.2 MergeAnalyzer 核心分析流程

sequenceDiagram
    participant Caller as 調用者 (Rule3/Frontend)
    participant DL as DataLoader
    participant MA as MergeAnalyzer
    participant LLM as LLMClientWrapper
    participant RG as ReportGenerator
    
    Caller->>DL: 載入樣本資料
    DL-->>Caller: sequences + qc_data
    
    Caller->>MA: analyze_sample(sample_id, sequences, qc_data)
    
    MA->>MA: _prepare_analysis_data()
    Note over MA: 提取序列資料<br/>(r1, r2, ref, merger, dada2)
    
    MA->>MA: _build_analysis_prompt()
    Note over MA: 建構 XML 格式 prompt<br/>包含 5 步驟分析任務
    
    MA->>LLM: 發送 prompt (同步/異步)
    LLM-->>MA: LLM 回應 (JSON 格式)
    
    MA->>MA: _parse_analysis_result()
    Note over MA: 解析 LLM JSON 回應<br/>構建分析結果物件
    
    MA->>RG: 生成 Markdown 報告
    RG-->>MA: 報告路徑
    
    MA-->>Caller: 完整分析結果
Loading

4.3 資料處理流程

4.4 Fallback 決策表(PRD 對齊)

層級 條件 行為 統計 reasoning 註記
Rule as judge 0 passed manual_review quality_filter_rejected_count "No sequences passed filtering"
Rule as judge 1 passed 直接推薦該來源 direct_recommendation_count "Exactly one ... passed filtering"
Rule as judge 2+ passed & 前端未勾選 Fallback(選豐度最高;conf=0.30) fallback_no_llm_trigger_count "Fallback: selected highest abundance ASV"
LLM pipeline 2+ passed & 前端已勾選 進入 LLM 仲裁 llm_available_count "... sequences passed, sent to LLM"
LLM pipeline llm disabled Fallback(選豐度最高;conf=0.30) llm_fallback_count "LLM disabled fallback"
LLM pipeline network / HTTP error 同上 Fallback llm_fallback_count 簡述錯誤碼
LLM pipeline parsing error 同上 Fallback + report llm_fallback_count "parsing error"
LLM pipeline schema 缺失 同上 Fallback llm_fallback_count "invalid schema"

4.5 Confidence 映射摘要

場景 Confidence
Rule-as-judge 篩選出單一來源 0.8 / 0.6 (依品質)
LLM 仲裁成功 (JSON) JSON (clamp 0.3–0.9, default 0.7)
所有 Fallback (LLM 失敗/未觸發) 0.30
manual_review 0.1

clamp:若 LLM 提供 <0.3 → 0.3;>0.9 → 0.9。

4.6 JSON Schema(核心片段)

{
    "recommendation_source": "merger | dada2",
    "confidence": 0.72,
    "reasoning": "Merger higher blast identity, fewer ambiguous sites.",
    "differential_observations": [
        {"metric": "blast_identity", "merger": 0.985, "dada2": 0.962},
        {"metric": "ambiguous_sites", "merger": 2, "dada2": 7}
    ],
    "warnings": ["low_abundance_dada2"]
}

解析守則:缺 recommendation_source → fallback;缺/非法 confidence → 0.7;來源不在 {merger,dada2} → fallback;differential_observations 可選。

flowchart LR
    subgraph "輸入資料"
        S1[R1 序列]
        S2[R2 序列]
        REF[參考序列]
        MERGER[Merger 合併結果]
        DADA2[DADA2 合併結果]
        QC[QC 統計資料]
    end
    
    subgraph "MergeAnalyzer 處理"
        subgraph "LLM 分析"
            DIFF[序列差異分析]
            QUAL[品質評估]
            MERGE[智慧合併]
            REC[結果推薦]
        end
        PREP[_prepare_analysis_data<br/>資料預處理]
        PROMPT[_build_analysis_prompt<br/>XML 格式 prompt]
        PARSE[_parse_analysis_result<br/>結果解析]
    end
    
    
    subgraph "輸出"
        JSON[結構化分析結果]
        MD[Markdown 報告]
        LOG[Prompt 日誌]
    end
    
    S1 & S2 & REF & MERGER & DADA2 & QC --> PREP
    PREP --> PROMPT
    PROMPT --> DIFF & QUAL & MERGE & REC
    DIFF & QUAL & MERGE & REC --> PARSE
    PARSE --> JSON & MD & LOG
Loading

5. 重要檔案關係

5.1 核心檔案

  • src/llm/analyzer.py - 核心分析引擎 (MergeAnalyzer,可重用於多種場景)
  • src/llm/llm_pipeline.py - LLM 分析協調器 (LLMAnalysisPipeline)
  • src/qc/recommendation_engine.py - QC 模組集成點 (Rule 3 調用)
  • app.py - 前端 streaming 介面 (即時分析)

5.2 支援檔案

  • src/llm/data_loader.py - 資料載入與序列提取
  • src/llm/llm_client.py - LLM 客戶端封裝
  • src/llm/report_generator.py - 報告生成
  • src/llm/llm_analysis_result.py - 分析結果物件定義

5.3 設定檔案

  • src/config/config_model.py - LLM 相關設定定義

6. 設定參數與成本控制

LLM 模組相關設定在 PowerBarcoderConfig 中:

6.1 基本與成本控制設定

llm_analysis_enabled: bool = True
llm_model: str = "gpt-4"
llm_base_url: str = "https://api.openai.com/v1"
llm_api_key: str = "(env or user)"
llm_temperature: float = 0.3
llm_max_tokens: int = 4000

6.2 多數決投票設定

在配置中新增或調整下列參數(對應 src/config/config_model.pyPowerBarcoderConfig):

# LLM 多數決投票設定
llm_majority_vote_count: 5         # 目標成功投票次數 (允許值: 1, 3, 5, 10)
llm_enable_json_log: true          # 啟用詳細日誌記錄

參數說明

參數名稱 類型 預設值 說明
llm_majority_vote_count int 1 目標成功次數。僅允許 {1, 3, 5, 10},否則會丟出 ValueError。系統會固定蒐集此數量份「有內容的回應」才開始多數決;若持續無法獲得有效回應,總嘗試次數不超過此數值的 3 倍(安全上限)。詳見 9.1 投票與正規化規則 說明。
llm_enable_json_log bool true 是否啟用 per-run 與摘要 JSON 日誌輸出。啟用後會在 log_dir 生成 {sample_id}_prompt_log_run*.json{sample_id}_majority_vote_summary.json

使用場景建議

場景 llm_majority_vote_count llm_enable_json_log 說明
快速/低成本模式 1 false 生產環境預設,追求速度與成本效益。
提升準確性 3 或 5 true 開發或對關鍵樣本進行複核時使用,平衡成本與穩定性。
研究分析模式 5 或 10 true 需要完整可解釋性與最高穩定性時使用,成本較高。

7. 使用方式

7.1 QC 模組調用 (統一仲裁流程)

from src.qc.recommendation_engine import SequenceRecommendationEngine

# 建立推薦引擎(會自動初始化 LLM 分析管道)
engine = SequenceRecommendationEngine(
    locus="COI_1", 
    result_data_path="/path/to/result",
    config=config,
    # 此處的 filter 僅用於分類,不影響仲裁流程
    qc_rules_filter={'rule1': True, 'rule2': True, 'rule3': True} 
)

# 執行推薦流程
# LLM 是否啟用取決於 config.llm_analysis_enabled_by_frontend
results = engine.run_recommendation_pipeline()

7.2 前端 Streaming 分析

# app.py 中的 /llm_analysis 端點會自動處理 streaming 調用
# 前端透過 POST 請求觸發,並接收 streaming 回應

# 範例請求:
# POST /llm_analysis
# Content-Type: application/json
# 
# {
#   "sample_id": "sample001",
#   "locus": "COI_1",
#   "result_data_path": "/path/to/result"
# }

7.3 獨立分析使用

from src.llm.analyzer import MergeAnalyzer
from src.llm.llm_client import LLMClientWrapper

# 建立 LLM 客戶端
llm_client = LLMClientWrapper(
    model="mistralai/mistral-small-2509",
    base_url="https://api.mistral.ai/v1",
    api_key="your-api-key"
)

# 建立分析器(使用多數決投票)
analyzer = MergeAnalyzer(
    llm_client=llm_client, 
    log_dir="/tmp/llm_logs",
    majority_vote_count=5,      # 目標成功次數(允許值: 1, 3, 5, 10)
    enable_json_log=True        # 啟用詳細日誌
)

# 執行分析(會自動進行 5 次 LLM 運行並投票)
result = analyzer.analyze_sample(
    sample_id="sample001",
    sequences=sequences_dict,
    qc_data=qc_data_dict
)

# 檢查結果
if result['status'] == 'completed':
    majority_votes = result['majority_vote_details']['winning_votes']
    total_votes = result['majority_vote_details']['valid_votes']
    print(f"推薦來源: {result['llm_analysis']['selected_sequence_id']}")
    print(f"信心度: {result['llm_analysis']['confidence']:.3f}")
    print(f"投票結果: {majority_votes}/{total_votes}")
    print(f"推薦理由: {result['llm_analysis']['reasoning']}")
else:
    print(f"分析失敗: {result['error']}")

8. 故障排除與錯誤分類

8.1 常見問題

LLM 客戶端初始化失敗

症狀: LLMClientWrapper 建立失敗 解決方案: 檢查 API key、base_url 可達性及模型名稱。

分析結果解析錯誤 / JSON Parsing

症狀: _parse_analysis_result 解析失敗 解決方案: 檢查 LLM 回應格式、查看 prompt 日誌、驗證 JSON 格式。

QC 流程集成失敗

症狀: QC 流程中 LLM 分析失敗 解決方案: 確認 config.llm_analysis_enabled_by_frontend 設定、檢查序列資料完整性、驗證 LLM 服務可用性。

參數驗證錯誤

症狀: 程式啟動時報錯 ValueError: llm_majority_vote_count 必須為 [1, 3, 5, 10] 其中之一 解決方案: 請將 llm_majority_vote_count 調整為允許值之一。

無法寫入日誌

症狀: 未生成 prompt_logmajority_vote_summary JSON 檔案 解決方案: 確認 log_dir 路徑存在且程式有寫入權限,並檢查磁碟空間。

9. 多數決投票:投票邏輯與日誌整合

透過對同一個樣本重複執行多次 LLM 分析,以投票方式選出最一致的推薦來源,並計算該來源的平均信心度,提升穩定性與可解釋性。

9.1 投票與正規化規則

執行邏輯

核心設計原則

  1. 「有效投票」明確定義:一個 LLM 回應被視為有效投票當且僅當:
    • HTTP 請求成功(收到回應內容)
    • JSON 解析成功
    • selected_sequence_id 為有效值(dada2_top1, dada2_top2, merger_top1, merger_top2 等,不含逗號或其他異常格式)
  2. 收集足夠有效投票後立即停止:當收集到 majority_vote_count 個有效投票後,執行提前停止
  3. 安全上限:最大嘗試次數為 majority_vote_count * 2,避免無限重試

執行步驟

  1. 執行 LLM 呼叫 - _execute_llm_analysis_with_majority_vote()
    • 目標:收集 majority_vote_count 個有效投票
    • 每次呼叫後立即驗證是否為有效投票(_is_valid_vote())
    • 有效投票計入 valid_votes;無效回應不計入但會記錄於日誌
  2. 提前停止檢查 - 每次呼叫後檢查
    • valid_votes >= majority_vote_count → 停止執行
    • 否則繼續嘗試,直到達最大嘗試次數
  3. 多數決投票 - _apply_majority_vote()
    • 只處理標記為有效投票的回應
    • 統計各選項得票數
    • 選擇得票最多者,計算平均信心度

統計指標(簡化版)

指標 說明 舉例
target_votes 目標有效投票數(配置值) 5
total_attempts 實際嘗試次數 6
valid_votes 有效投票數 5
invalid_attempts 無效嘗試數(total_attempts - valid_votes) 1

設計哲學:在完全內部可控的系統中,簡化錯誤處理。只區分「有效」與「無效」兩種狀態,無需更細的錯誤分類。

邊界情況

  • 若達最大嘗試次數仍無法收集足夠有效投票 → 使用已有的有效投票進行多數決(若 >= 1)
  • 若完全沒有有效投票 → LLM 分析狀態為 failed,回退至 Fallback(最高豐度)

9.1.1 執行流程圖

graph TD
    Start["開始分析<br/>(analyze_sample)"] --> PrepData["_prepare_analysis_data<br/>準備分析資料"]
    PrepData --> ValidData{"資料驗證"}
    
    ValidData -->|失敗| ErrResult["返回 error 結果"]
    ValidData -->|成功| BuildPrompt["_build_analysis_prompt<br/>建構 XML prompt"]
    
    BuildPrompt --> ExecuteVote["_execute_llm_analysis_with_majority_vote<br/>目標:收集 N 個有效投票"]
    
    ExecuteVote --> RunLoop["FOR 每個 attempt (0 to max_attempts-1)"]
    
    RunLoop --> CallLLM["_execute_llm_analysis<br/>調用 LLM API"]
    CallLLM --> CheckResp{"回應接收?"}
    
    CheckResp -->|否| MarkInvalid["is_valid_vote = false<br/>記錄 API 失敗"]
    CheckResp -->|是| ValidateVote["_is_valid_vote<br/>驗證有效投票<br/>(JSON解析 + selected_id 有效)"]
    
    ValidateVote --> CheckValid{"有效投票?"}
    CheckValid -->|否| MarkInvalid
    CheckValid -->|是| MarkValid["is_valid_vote = true<br/>valid_votes += 1"]
    
    MarkInvalid --> WriteLog["_write_prompt_log_with_run_index<br/>記錄 prompt/response 日誌"]
    MarkValid --> WriteLog
    
    WriteLog --> CheckEarlyStop{"valid_votes >= target?"}
    CheckEarlyStop -->|是| CollectResults["收集所有回應<br/>(提前停止)"]
    CheckEarlyStop -->|否| CheckMaxAttempts{"達最大嘗試次數?"}
    CheckMaxAttempts -->|否| RunLoop
    CheckMaxAttempts -->|是| CollectResults
    
    CollectResults --> CheckSuccess{"有有效投票?"}
    CheckSuccess -->|否| AllFailed["返回 failed<br/>(所有嘗試無效)"]
    CheckSuccess -->|是| ApplyVote["_apply_majority_vote<br/>計算多數決<br/>- 統計有效投票的選擇分布<br/>- 選擇得票最多者<br/>- 計算平均信心度"]
    
    ApplyVote --> WriteSummary["_write_majority_vote_summary<br/>寫入 majority_vote_summary.json"]
    
    WriteSummary --> ReturnResult["返回完整分析結果"]
    ReturnResult --> End["結束"]
    
    ErrResult --> End
    AllFailed --> End
Loading

9.2 日誌輸出檔案

啟用 llm_enable_json_log: trueMergeAnalyzer(log_dir=...) 提供路徑後,會寫入兩類 JSON:

  • Per-run 檔名: {sample_id}_prompt_log_run{N}.json
    • 欄位: sample_idrun_indextarget_votestimestampprompt_contentresponse_contentis_valid_voteerror 等。
  • 摘要檔名: {sample_id}_majority_vote_summary.json
    • 核心結構:

      {
        "sample_id": "...",
        "timestamp": "YYYY-MM-DD HH:mm:ss",
        "target_votes": 5,              // 目標有效投票數
        "total_attempts": 6,            // 實際嘗試次數
        "valid_votes": 5,               // 有效投票數
        "invalid_attempts": 1,          // 無效嘗試數
        "all_runs": [
          {
            "run_number": 1,
            "is_valid_vote": true,
            "selected_sequence_id": "merger_top1",
            "confidence": 0.88,
            "sequence_scores": {"dada2_top1": 0.8, "merger_top1": 0.9, ...},
            "quality_assessment": {"dada2_strengths": [...], "merger_strengths": [...], ...},
            "detailed_analysis": "...",
            "reasoning": "...",
            "raw_response_length": 2048
          },
          {
            "run_number": 2,
            "is_valid_vote": true,
            "selected_sequence_id": "merger_top1",
            "confidence": 0.85,
            "..."
          }
        ],
        "majority_result": {
          "selected_sequence_id": "merger_top1",
          "confidence": 0.877,            # 獲勝選項的平均信心度
          "vote_distribution": {"merger": 3, "dada2": 2},  # 各選項的得票分布
          "winning_votes": 3,              # 獲勝選項的得票數
          "consensus_strengths": {         # 多數決共識優勢(多個 runs 中共現的優勢)
            "dada2_strengths": ["...", "..."],
            "merger_strengths": ["...", "..."]
          },
          "quality_assessment": {          # 彙整的品質評估(多個 runs 的結合)
            "dada2_strengths": ["...", "..."],
            "merger_strengths": ["...", "..."],
            "abundance_factors": ["...", "..."]
          },
          "reasoning": "... (多數決: 3/5 票,來自 runs: 1, 2, 4)"
        }
      }
    • 欄位說明:

      • majority_vote_counttotal_runs 用於理解執行計畫與實際情況
      • successful_runs 用於診斷有多少 runs 成功產生結果(只有這些參與投票)
      • all_runs 中每個運行的完整分析細節都被保留,供事後審查
      • majority_result.consensus_strengthsquality_assessment 是多個 runs 的共識彙整,增強了結果的可信度

10. 相關文件對齊

主題 本文件 其他文件
Rule 分類 僅用於最終標記,與仲裁流程脫鉤 qc.md, locus_qc.md
Confidence LLM / fallback 來源 qc.md 總表
RuleAsJudge 品質過濾器與計數器 locus_qc.md
報告生成 詳細 qc.md 簡述
路徑 入/出檔案 path.md

11. 相關文件

  • QC 整合: 參考 docs/qc.md / docs/locus_qc.md
  • 前端 API: 參考 docs/frontend.md 的 LLM 分析部分
  • 配置管理: 參考 docs/config_flow.md