iT邦幫忙

2026 iThome 鐵人賽

DAY 29
0

前幾天一路在補文件,今天回到會動的東西:題庫。

起點是 Day 28 那條新寫下的限制——題庫會用完。出題改成從題庫挑之後,
10 題做完就沒得換了。

但打開來數才發現,我對問題的描述是錯的。

先數,再說

我原本以為「有些弱點根本沒題目可挑」。實際數完:

control-flow    8    io-parse        5
loop            7    io-eof          3
off-by-one      6    indentation     2
output-format   5    type-confusion  1

每一個代碼都至少有 1 題。 閉環沒有斷,只是很薄。

而薄的後果不一樣:shortlist() 一次取 6 個候選,學生做掉 5 題就開始見底;
type-confusion 只有 1 題,代表這個弱點的「針對性練習」總共只有一次。

沒斷但很薄,跟斷掉,要用不同的方式修。 我差點照著錯的描述去修。

今天真正的主題:測資的正確性要有證據

加題很單純,寫就是了。真正卡住我的是另一件事:

我怎麼知道我寫的測資是對的?

data/README.md 開頭就寫著測資錯是這個系統裡最貴的錯,那條傳染鏈我寫過三次了:

測資錯了
   → 評測照著錯的測資判(而且是「實際執行」,看起來非常確定)
   → summary 把錯的結果寫成一句話
   → 導師引用那句話去引導學生
   → 學生對著一份正確的程式碼,被要求找出不存在的錯

而在今天之前,這件事的全部保證是:我說我驗過了。

一句話,沒有任何東西撐著。這跟 Day 21 那條「判定是事實還是推測要明講」
是同一個毛病——只是這次不誠實的對象是我自己。

做法:用系統自己的執行器來驗自己的題庫

每一題附一份參考解答 data/solutions/<id>.py,測試把它丟進 sandbox.run_all
跑過該題全部測資,必須全過:

results = sandbox.run_all(path.read_text(encoding="utf-8"), problem["tests"])
failures = [... for i, r in enumerate(results) if not r.passed]
assert not failures

沒有新的機制,就是那個 Day 20 寫的執行器。它本來的工作是跑學生的程式,
現在多一份工作:跑我的程式,來證明我的測資。

有意思的是這兩件事共用同一條判定規則(problems.outputs_match())。
所以這支測試順便驗了一件別的事:如果比對規則哪天改壞了,題庫會整批變紅。

它抓到的第一個錯,是我自己的

新題 own-001 的第二組測資,我手寫預期輸出:

1234567890123 × 2 = 2468135780246

跑出來是 2469135780246。

我手算錯了一位。

這個錯如果活到學生面前會發生什麼:他寫了一份完全正確的程式,被判「第 2 組
wrong-output」,導師接著引用這份判定開始引導他去找一個不存在的 bug。
他愈認真看自己的程式,愈找不到。而且系統的每一層都在說同一件事,
他沒有任何辦法發現是題目錯了。

一個手滑,一路走到底就是這樣。

寫測試的時候我當然不知道會抓到什麼——抓到的是自己十分鐘前的失誤,
這比抓到三個月前的舊 bug 更有說服力:這種錯不是偶爾發生的,是隨時在發生的。

一條寫進測試 docstring 的規矩

"""**解答跑不過時不要改測資去配合解答,也不要反過來。**
兩邊都可能是錯的,要回去看題目本身。"""

紅燈的第一反應是「改哪邊比較快」。但這支測試比對的是兩份獨立的東西,
紅燈只說「它們不一致」,沒說誰錯。改哪一邊都能變綠,而其中一種會讓錯誤
從此有測試背書——比沒有測試更糟。

今天這次是我確認過 1234567890123 × 2 之後才改的測資,不是因為改測資比較快。

既有 10 題全過——這也是資訊

補完既有 10 題(UVa)的參考解答之後,第一次跑就全綠。

有點失望,因為我本來期待揪出一兩個舊測資的錯,那會是更好的文章素材。
但這件事本身是資訊:現有的題庫是自洽的,之前手工驗測資的那次沒有出包。

誠實記錄「這次沒抓到東西」跟記錄抓到東西一樣重要。一支從來沒紅過的測試
可能是沒必要,也可能是它守的東西剛好都還沒壞——差別在你有沒有看過它紅。
今天它紅過了(own-001),所以我知道它是會動的。

兩個刻意的取捨

門檻定 3 不定 5。 覆蓋率測試要求每個 skill 至少 3 題。

定 5 的話,測試會逼我現在就生出更多題——而被測試逼出來的題目會是灌水的。
門檻要守的是「這個弱點挑得到不重複的題」,不是「題庫夠豐富」。
一個會逼人交垃圾的門檻,比沒有門檻更糟。

新題是原創題,不是 UVa 題。 我可以憑記憶寫 UVa 題的摘要與測資,
但我可能記錯輸入格式或邊界,而錯的測資沒人發現得了。原創題我自己出、
自己寫解答、跑過才入庫——用「可驗證」換掉「是真題」。

對這個系統來說,題目真不真實不重要,測資對不對是生死問題。

今天學到的

  1. 先數,再描述問題。 我以為是「有弱點沒題目」,實際是「有題目但很薄」,
    兩者要用不同的方式修。
  2. 「我驗過了」不是證據。 這跟 UI 不能謊稱跑過測試是同一條原則,
    只是不誠實的對象換成自己。
  3. 一支從沒紅過的測試,你不知道它會不會動。 今天它在寫完的十分鐘內
    就抓到我自己的手算錯誤,所以我知道它是活的。
  4. 紅燈只說「兩邊不一致」,沒說誰錯。 改哪邊都能變綠,其中一種會讓
    錯誤從此有測試背書。
  5. 會逼人交垃圾的門檻,比沒有門檻更糟。

題庫 10 → 18 題,type-confusion 1 → 5、indentation 2 → 4。
測試 327 → 372 支全綠。


上一篇
Day 28
下一篇
Day 30:最後一天
系列文
基於 Multi-Agent 協作之蘇格拉底式程式學習與自動化評測系統 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
mengbai
iT邦新手 5 級 ‧ 2026-10-13 13:42:05

太強了吧

我要留言

立即登入留言