問題
Evaluator.shuffle_question_options()(twinkle_eval/runners/evaluator.py:211)重建題目字典時,只保留 question / A–D / answer,其餘欄位全部被丟棄:
new_data = {"question": question_data["question"]}
for (old_key, text), (new_key, _) in zip(options, [...]):
new_data[new_key] = text
if text == correct_option_text:
new_data["answer"] = new_key
return new_data
而 vision 路徑在 shuffle 之後才讀圖片欄位(evaluator.py:783):
if self.shuffle_options:
q = self.shuffle_question_options(q)
...
image_path = q.get(image_field) or q.get("image_url") or q.get("image")
if not image_path:
log_error(f"問題 {idx + 1} 缺少圖片欄位 '{image_field}',跳過")
continue
影響
evaluation_method: vision_mcq + shuffle_options: true → 每一題的 image_path 都在 shuffle 時被清掉,全部命中「缺少圖片欄位」分支被 skip,評測到零題。
由於 _evaluate_dataset() 在 results 為空時才拋 EvaluationError,使用者看到的是「所有檔案評測均失敗」這種與實際原因無關的訊息,不易定位。
同樣的欄位遺失也會影響任何依賴額外欄位的路徑(例如 id、category 等後續分析欄位)。
重現
evaluation:
dataset_paths: ["datasets/example/vision_mcq/"]
evaluation_method: "vision_mcq"
shuffle_options: true
建議修法
shuffle 時保留所有非選項欄位(以 dict 複製為基礎,只覆寫選項鍵與 answer),而不是從空 dict 重建。
次要問題(同函式)
以文字比對決定新正解:
if text == correct_option_text:
new_data["answer"] = new_key
當兩個選項文字完全相同時,answer 會被指到最後一個相符的選項。改為以「原始鍵」比對更穩健。
相關:#140(同一函式的硬編碼 A/B/C/D 問題)
問題
Evaluator.shuffle_question_options()(twinkle_eval/runners/evaluator.py:211)重建題目字典時,只保留question/ A–D /answer,其餘欄位全部被丟棄:而 vision 路徑在 shuffle 之後才讀圖片欄位(
evaluator.py:783):影響
evaluation_method: vision_mcq+shuffle_options: true→ 每一題的image_path都在 shuffle 時被清掉,全部命中「缺少圖片欄位」分支被 skip,評測到零題。由於
_evaluate_dataset()在results為空時才拋EvaluationError,使用者看到的是「所有檔案評測均失敗」這種與實際原因無關的訊息,不易定位。同樣的欄位遺失也會影響任何依賴額外欄位的路徑(例如
id、category等後續分析欄位)。重現
建議修法
shuffle 時保留所有非選項欄位(以
dict複製為基礎,只覆寫選項鍵與answer),而不是從空 dict 重建。次要問題(同函式)
以文字比對決定新正解:
當兩個選項文字完全相同時,
answer會被指到最後一個相符的選項。改為以「原始鍵」比對更穩健。相關:#140(同一函式的硬編碼 A/B/C/D 問題)