這隻需求釐清 agent 該找的問題大多找到了,麻煩的是它額外標出來的比找到的多了將近兩倍,多到看卡的人不會再逐條去翻,所以先讓的是多標那一邊。
需求方打開整理好的卡,看到 agent 在某一條 AC 旁邊標「跟 description 說的不一樣」,翻回原文對了一遍,沒有不一樣。下一條又標「沒有寫清楚怎樣算做完」,再翻,那條寫了數字也寫了條件。連著三條都這樣之後他就不會再翻了,連真的有問題的那一條也一起跳過。
被驗收的這隻 agent 做的事,是把需求方寫得雜亂的 ticket 整理成四個區塊,Goal、Scope in、Scope out,以及 AC 標註。最後這個區塊是它在需求方寫的 AC 裡挑出有問題的幾條,標上是哪一類問題。挑問題這種工作,漏掉一條真的跟多標一條不存在的,從來不是同一種錯,上面那個場景就是多標那一種錯走到下游的樣子。
昨天那兩個數字,case 通過率跟逐條算的通過率,都把每一條紅當成同樣重的一件錯,不管紅的原因是漏掉還是多標。
漏掉一條真的衝突,那條 AC 會照原文進 sprint,等工程師寫到一半或 QA 驗收時才浮出來,代價是一次返工。多標一條不存在的問題,代價是開頭那個場景,整個 AC 標註區塊被需求方放棄,連真的那幾條也沒有人讀。
兩種錯要分開數,代價才看得出來。對照的答案是每一筆 case 的 goal state 裡事先人工標好的期望標註,讀過每張卡的原文之後一條一條標的。
agent 標出來的每一個標註只有兩種身分,人工標進 goal state 裡也有的,跟人工沒標的,後一種就是多標;人工標的每一個標註也只有兩種下場,被它找到,或被它漏掉,漏掉的叫漏標。前一組算出來的是 precision,它標的有幾成是真的;後一組是 recall,真的有幾成被它找到。
整份 dataset 有 16 筆 case,2026-09-16 那趟用 gpt-5.4-mini 每筆跑 3 次,數字在 repo 的 runs/2026-09-16T09-54-50-525Z-all.md:
數的單位是「條號加類別」,同一條 AC 被標成兩類問題就算兩個,因為漏掉第二類正是最值得看見的失敗。逐列拆開,問題幾乎全在多標那一邊:
| case | P | R | 逐列的情況 |
|---|---|---|---|
conflicting-truth-001~003 |
30%/38%/60% | 都是 100% | 人工標的全找到,另外多標一堆 |
missing-context-001~003 |
33%/23%/30% | 都是 100% | 同上,002 多標最兇 |
merged-concerns-001 |
33% | 100% | 同上 |
noise-over-signal-001 |
54% | 70% | 這張表裡 recall 不到八成的一筆 |
有八筆 case 的 recall 是 100%,precision 只有 23% 到 60%,人工標的它都找到了,卻另外標了一堆。17 個漏報裡 8 個集中在 noise-over-signal-001,那張卡人工標的標註有 9 個,是整份 dataset 最多的,另外 7 個在那張優惠碼功能的 ticket 上。
數字最差的是人工一個標註都沒標的那四筆,dataset/irreversible-push-002.yaml、irreversible-push-003.yaml、merged-concerns-002.yaml、merged-concerns-003.yaml 的 ac_flags 期望值都是空集合,理由 2026-09-16 標的時候寫在檔案裡。例如那張課程收藏的卡,四條 AC 都寫得具體、驗得了,description 裡順帶提到的排序需求是混進來的第二件事,該由 Scope 拆分處理,不算 AC 的問題,所以期望標註是空的(理由寫在 dataset/merged-concerns-002.yaml 的註解裡)。
agent 對這四筆跑了 11 趟,10 趟標了東西,只有 irreversible-push-002 的第 3 趟回了空集合。merged-concerns-002 三趟合計多標 8 個、irreversible-push-002 多標 6 個,precision 各 0%,recall 那一欄留空,因為人工一個都沒標,沒有東西可以被找到或漏掉。
別的卡上至少還有東西可以找,多標的還能說是找得太寬,這四張卡上卻沒有東西要找,它幾乎每一趟都還是標,一條寫得清清楚楚的 AC 也被標成沒寫清楚怎樣算做完。
這隻 agent 跟這支 scorer 裡都沒有信心分數或開關可以調,能動的只有 src/agent/prompt.ts 那份 system prompt 裡三類問題各一行的定義(src/agent/prompt.ts):
三類問題:
- conflict:這條 AC 跟另一條互相打架
- unverifiable:這條 AC 沒有寫清楚怎樣算做完
- mismatch:這條 AC 跟 description 說的不一樣
115 個多標裡有 104 個落在 unverifiable 跟 mismatch 這兩類,正好是定義寫得最鬆的兩行。「沒有寫清楚怎樣算做完」對任何一條不含數字的 AC 都成立,「跟 description 說的不一樣」在 description 根本沒提到那條 AC 時也成立。要往 precision 那邊讓,做法是把這兩行寫窄,例如要求 AC 得跟 description 裡某一句具體對得上才算 mismatch。
代價是 recall 會跟著掉,幅度可以從刪掉「每一條 AC 對三類問題各檢查一次」那一行的判別力檢查借來看,docs/day12-discriminative.md 記的是同一張優惠碼的卡三次合計,原版標對 8 個、刪掉那行之後 5 個,recall 掉了 25 個百分點,case 通過率兩邊都是 0/3。那筆是單張卡的數字,分母跟整份跑的 34% 與 78% 不一樣,能借的是方向。
漏掉一條真的衝突,那條 AC 進 sprint 之後還有人會撞上它;多標到讓人不想看,是整個 AC 標註區塊被放棄,連真的那三分之一也沒有人讀。precision 34% 的意思是看卡的人每讀三個標註只有一個是真的,這個比例已經在放棄的邊緣。
所以往 precision 這邊讓,界線先寫成 recall 不掉破七成,這個數字是先訂下來的,改完重跑之後再看要不要動。ac_flags 判的是集合完全相同,多標一個就沒過,48 趟裡沒過的 45 趟有多少只差在多標,是改完定義之後第一個要重跑來看的。
整份 16 筆 case 合計 45 趟的結果是 precision 34%、recall 78%,對上 60 個、漏標 17 個、多標 115 個,45 趟通過 3 趟。八筆 case 的 recall 是 100% 而 precision 只有 23% 到 60%,另外四筆人工標的期望標註是空集合,agent 11 趟裡標了 10 趟。這隻需求釐清 agent 的問題不在找不到,在它額外標出來的太多。
決定是往 precision 那邊讓,做法是把 src/agent/prompt.ts 裡 unverifiable 與 mismatch 那兩行定義寫窄,界線是 recall 不掉破七成。這個決定還沒有數字驗證。定義寫窄之後 precision 會升多少、recall 會掉到哪裡,要等改完把整份 dataset 重跑一次才知道,七成這條界線守不守得住也是那時候才看得到。