iT邦幫忙

2026 iThome 鐵人賽

DAY 11
0
AI Engineering

AI 寫的測試,誰來測?系列 第 11

【Day11】RTM 沒抓到漏測,抓到的是我的規格書

  • 分享至 

  • xImage
  •  

TL;DR

  • 424 條 AI 產出的測試案例,十條 PRD 全部有案例覆蓋。抽驗一份 74 條:零幻覺、九條算式全中——但能在文件層驗到底的就只有那九條
  • RTM 真正抓到的是另一件事:模型五次都附了「規格缺口清單」,指著我 Day 9 才裁決完的 PRD 說十個地方沒定義
  • 完全隔離之後它還是寫出指向缺陷的斷言。不是它厲害,是我把 Math.max(0, ...) 抄進了規格書

https://ithelp.ithome.com.tw/upload/images/20260911/20103826SiQE4Tebzi.jpg


前言

昨天畫好及格線,今天資料到手:兩個模型各跑五次,產出十份測試案例集。(第一輪因隔離不完全作廢,這裡用的是第二輪的乾淨資料)

程式碼寫錯,編譯器和 linter 會立刻噴紅字。但規格書和測試案例都是文字,文件層沒有編譯器,也沒有紅綠燈。面對排版整齊的測試案例,靠肉眼核對到底漏了什麼、有沒有偷渡不存在的規格,五分鐘就累了。所以需要一把尺:RTM(Requirement Traceability Matrix,需求追溯矩陣)。 它做的事只有一件:建立「規格」與「案例」互相指認的對映。過去它常被當成冗長的交付文件,但如果只當作每次生成案例後的輕量檢查,它其實非常有效。

RTM 只檢查兩個方向:

  • 正向(PRD → case):規格有沒有被覆蓋?沒覆蓋的就是裸需求(漏測)。
  • 反向(case → PRD):案例能不能找到規格依據?找不到的就是孤兒 case(幻覺)。

它不判斷案例寫得好不好,只判斷「有沒有對到」。在沒有編譯器的地方,這是少數機器能代勞的事。

這兩個方向我都跑了,兩邊都是空的(沒有漏測也沒有幻覺)。所以今天真正的工作是這三件:用眼睛讀完抽驗的 74 條案例、處理 AI 多附的一張清單,然後承認一件我造成的事。

兩個方向都跑完了

正向:一條漏測都沒有

先看測試規模:

環境 案例數 合計
模型 A Gemini 3.1 Pro/AI Studio 五次皆 13 條 65
模型 B Claude Opus 5/Console Workbench 62–84 條(中位 74) 359

兩邊皆在開發者控制台手動輸入,總計產出 424 條案例。(開發層沒有記憶或範本可以掛——不過這句是從「那一層沒有這些功能」推出來的,我沒有真的去問過它載入了什麼。)

正向掃描非常快:每條案例都按規定自報了覆蓋的 PRD 編號,我只要把編號全抓出來,直接對 PRD-01PRD-10 進行比對即可。結果出乎意料:兩個模型、十份案例集,每一份的覆蓋率都是 10/10,裸需求為零。

我原本準備好大寫特寫「AI 漏測了哪幾條」,結果完全沒有素材可寫。

反向:機器只驗得出格式

反向的機器掃描也是空的:每一條案例都掛著至少一個 PRD-xx 編號,沒有一條「無家可歸」。

但這結果其實很虛,因為機器只驗「有沒有掛編號」,不驗「掛得對不對」。若案例宣稱覆蓋 PRD-02,斷言卻在測 PRD-06,它依然會通過檢查。這就是藏起來的孤兒。要得知真實的反向追溯結果只能靠肉眼。我全查了 run-B-01 的 74 條案例,先訂標準再套用:

判定 定義
屬實 斷言確實在測它宣稱那條 PRD 的內容或邊界處置
不實 斷言測的是別條,或引入 PRD 沒寫的規則或常數
阻塞 明確標示規格未定義,因此不給預期值

結果:

判定 條數 占比
屬實 61 82%
阻塞 12 16%
歸屬存疑 1 1%
不實/幻覺 0 0%

存疑的是 TC-01-07:宣稱掛 PRD-01,斷言卻點名「PRD-04 未定義報酬率是否允許負值」。歸屬有爭議,故判存疑。

我原本預期 AI 會從預訓練知識憑空捏造「所得替代率要達 70%」或「二代健保」等 PRD 沒提過的案例,但在這 74 條中完全沒有。可能跟昨天提示詞第 3 條有關:「規格沒寫的不要自行補上」——那原本是測幻覺的餌,結果沒有魚上鉤。但我沒跑過「不加那句話」的版本,所以這只是猜測。

更值得注意的是,74 條中能用單一算式獨立驗證的預期值僅有 9 條。我實算後 9 條全中(誤差 ≤ 1 元):

TC-01-02  1,000,000 × 1.005^12   實算 1,061,677.81   它寫 1,061,678
TC-02-03  600,000 × 1.02^25      實算   984,363.60   它寫   984,364
TC-08-01  720,000 × 1.02^25      實算 1,181,236.32   它寫 1,181,236
TC-03-01  900,000 × 1.03         實算   927,000.00   它寫   927,000

其餘 52 條屬實案例的斷言是結構性的,如「相鄰期比值恆為 1.02」或「軌跡不得出現 0 截斷」。要驗收這些得實際跑受測物,無法光靠讀文件。

四類分類,第一次被打破

沒有判定 Duplicate(同分支、換輸入),因為這得等案例變成腳本後追蹤程式路徑。昨天預設它是最大宗,今天無從驗證。

那 12 條阻塞案例更麻煩:它們不屬於任何一類。

它們有對應的 PRD、未發明新規則,但也不是 Valid,因為它們沒有預期值

TC-01-06  阻塞:規格未載明月存為期初或期末投入。
          期末 = 123,356;期初 = 123,972。兩值皆不得作為預期值,須先補條款

昨天的四個分類完全無法涵蓋它們。依照「跑完不改」的規則,我不回頭改分類,只記為「依 v1 規則無法分類,計 12 條」。這正是「先畫及格線」壓力測試未通過的結果。

另外,模型 A 每條規格只掛 1–3 條案例(PRD-08 只有 1 條);模型 B 則是 4–20 條。由於單一案例無法同時測正常與邊界值,A 的「覆蓋 10/10」只是蜻蜓點水。這只是表面指標,真正的深度明天用邊界命中率來量。

該亮紅燈的地方全都是綠的。若就此收工,結論會是:

十次獨立生成 PRD 覆蓋率 100%;抽驗 74 條屬實 82%、幻覺 0。文件層品質達可用水準。

這結論有數據支撐,卻很糟——因為 82% 只證明「編號掛對了」,我能在文件層驗證的僅有 9 條。剩下 52 條對不對,得等變成腳本才知道。

數量不等於品質,品質得看明天的邊界命中率。

那 RTM 抓到了什麼

模型 B 的五份輸出,每一份最後都多了一個章節。五份的標題各不相同:

  • run-B-01「阻塞項彙總(須補條款後方能定案預期值)」
  • run-B-02「附錄:預期值所依賴的規格未明訂項(無法僅依 v1.0 判定對錯者)」
  • run-B-03「規格缺口清單(阻擋案例/需 PRD 補述後方可定義預期輸出)」
  • run-B-04「規格缺口清單(無法從 PRD v1.0 推導出唯一預期值,案例僅能斷言不變量)」
  • run-B-05「規格缺口清單(阻塞案例,無法在 v1.0 下判定 PASS/FAIL)」

編號前綴雖不同(GAP-D-G-),做的事卻一樣:列出規格未定義之處,並註明哪些案例因此寫不出預期值。

五份的項數分別為 10、10、11、10、12,而我的提示詞根本沒要求做這個。

而那份 PRD v1.0 是 Day 8 挖出十個歧義現場、Day 9 一條一條裁決出來的。我以為那件事做完了。

跨五次生成比對,有三個缺口是五次全部指到同一處

缺口 五份的說法
月存投入時點(期初/期末)未定義 5/5
退休後收入的通膨基準年是 A_c 還是 A_r 5/5
大筆支出是否隨通膨調增 5/5

另外「PRD-02 折現用的是 r 還是 r_p」有 4/5 指認。

我去翻條款原文。PRD-01 寫的是:

本金與月存統一採名目月利率 r/12,同為月複利

它規定了利率,沒有規定月存什麼時候進去

而模型 A 那五份,這個章節一項都沒有。零。

它們怎麼讀我的規格書

把兩件事放在一起看,形狀就出來了。

面對規格未明處,兩個模型反應不同。

「月存期初期末」兩邊都撞牆了。模型 B 將其列為缺口,將案例改為區間或不變量斷言;run-B-05 更直接把 r_p 設成 0 來迴避,並明文告知

而模型 A 的 run-a-1 直接在 TC-005 給了公式:

本金=100萬, 月存=1萬, r=6%
預期輸出:退休本金為 100萬×(1.005)^12 + 1萬×[((1.005)^12-1)/0.005]

後面這項是期末年金因子。它默默替我選了期末,沒說它做了選擇。而另外四份則直接繞開不處理。

繞開沒錯,B 也在繞,但 B 會明說,A 不會。最糟的是 run-a-1:它不僅擅自決定,還固化為預期值。一旦進了測試套件,就會去保護一個無人裁決過的行為。

這病很眼熟。Day 4 探討的 (1+r) 就是受測物擅自選擇期初期末的問題。我在 Day 9 釘死了提領端,卻忘了累積端有同樣的漏洞。

但對於規格寫得像「修正」的地方,兩者反應卻一致——這是我的問題。

run-B-01 中有 4 條斷言直接指向受測物的真實錯誤:

TC-01-02  必須不等於 1,060,000(年複利)        ← 受測物本金確實走年複利
TC-02-03  必須不等於 600,000(誤鎖 A_r 為基準)  ← 通膨基準
TC-03-01  必須不等於 930,000(期末扣款)        ← 缺陷 A

這是在完全隔離環境下產出的。但這並非「AI 好厲害」,而是效度威脅:我在深知缺陷後才寫下 PRD,部分措辭已帶有修正語氣(如統一採須回傳明確錯誤)。最明顯的是 PRD-03

期初扣款,索引與 PRD-02 對齊 | 禁止 Math.max(0, ...) 截斷真實餘額

我直接把缺陷程式碼 Math.max(0, ...) 抄進了規格書。

AI 不是猜到的,是我洩漏的。未來比較生成品質時必須記住:部分成績是我餵出來的,不能全算規格的功勞。

(順帶一提,首輪作廢的資料裡也有類似斷言。乾淨重跑證明了 PRD 的措辭就足以產生它們——但這不代表首輪的記憶完全沒出力,只是它不再是唯一的解釋。)

抽驗 30%:這項標準我跳票了

昨天的驗收標準有這麼一行:

human_audit_ratio: 0.30    # 每 run 至少人工覆核 30%

寫這行時,我還不知道會拿到幾條案例。現在手上有 424 條,30% 是 127 條。但我實際只全查了 run-B-01 的 74 條(占 17%)。按規定,我跳票了。

而另一半標準要求 [Omission, Hallucination] 須 100% 覆核,實測因為這兩類為 0 而無事可做。這標準一半做不到、一半沒得做。

閘門 3 在此失守。先定門檻是對的,但它未考慮工作量,也沒預料到紅燈類別會是空的。訂標準不僅要早,還要確認可行性,我昨天只做到前者。

解法不是下修 0.30 來迎合現況(這是照結果配標準),而是要把「人工核對」轉交給程式自動化。這是明天的任務。

而抽驗完要有去向,不然抽驗只是感想:

掃描結果 本輪實測 處置 閘門
宣稱屬實 61 條(run-B-01 進明天的技法檢核
宣稱不實 0 條 記錯改率;降級或剔除 4
裸需求 0 條 補寫針對性案例(本輪無,流程保留)
孤兒 case 0 條 合理補充 → PRD v1.1;幻覺 → 剔除 4
無法分類(阻塞) 12 條 記「依 v1 規則無法分類」;判真缺口 → PRD v1.1 4
未抽驗 350 條 標記未抽驗,不進任何結論

三個「0」是本輪的實測值,不是流程沒寫。而最後一列那 350 條是今天所有結論的邊界——「零幻覺」只在 run-B-01 的 74 條之內成立,另外九份我只做了機器掃描。

GAP 清單那 53 項要不要進 PRD v1.1,是閘門 4 的判讀。今天只登記,不裁決——PRD 本日不動。

還有一筆紀錄缺失要認:temperature 兩邊皆未記錄,當次沒截圖,事後不可復原。同一個提示詞在不同溫度下的分佈本來就不一樣,所以今天的分佈數字只能對照,不能當基準。

後記

Day 9 我證明了「歧義不是 bug,而是未定的決策」,並將其裁決為十條 PRD,以為規格層已結案。

今天 AI 讀完後卻告訴我:還有十個。指出的三個共同缺口都不是刁鑽邊角(月存時點、通膨起算、大筆支出通膨),它們都會直接改變最終數字,而我的十條條款全漏了。我原以為規格考古是一次性工程。實則不然:每裁決一個歧義,就會在更精確的層次衍生新歧義。 如同 PRD-01 釘死了利率,才讓「時點」問題浮現。

規格永遠沒有寫完的一天。

更諷刺的是,今天發揮作用的,是我未曾要求 AI 做的章節。我設計的正反向追溯皆空手而回,反而是模型自附的缺口清單抓出了問題。

那我今天的角色是什麼?我想,它能列出「未定義」,卻無權裁決。要不要改、如何改、代價誰扛,是閘門 1 負責的,而那裡只能站人。AI 會指出漏洞。但它不會替你做決定。


只帶走一件事
覆蓋率 100% 只證明它標得齊,不證明它測得對。而真正值錢的那一欄,往往是你沒有要求它填的。


今天的 repo:https://github.com/eyelash500/2026_ironman_test_ai/tree/day11


上一篇
【Day10】把 PRD 餵給 AI 之前,先把及格線畫好
下一篇
【Day11-番外】十份實驗資料,全部作廢
系列文
AI 寫的測試,誰來測?14
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言