- Published on
Kiro SDD 入門(三):為什麼 AI 修 bug 越修越壞
Table of Contents
前兩篇講了 Specs 基礎跟 PBT,這篇要講一個用 AI 修 bug 的人幾乎都踩過的坑。
上一篇:
你一定遇過這個情況
你叫 AI 修一個 bug,它交回來的 patch 你一看:
- 重構了三個 helper function
- 加了一堆
if (x == null)的防禦性檢查 - 寫了一堆本來就會過的測試
- 順便改了幾個根本沒壞的地方
你只是想修一個小 bug,結果 AI 給你一個大改動,改完之後原本正常的功能反而壞了。
Kiro 官方把這個現象叫 Bug Fix Paradox。
為什麼會這樣
不是 AI 笨,是你跟 AI 之間缺少一個共識:哪裡要改、哪裡不能動。
你心裡知道「我只是要修這個 edge case,其他地方不要動」,但你沒有把這件事寫下來。AI 沒有讀心術,它只看到「這裡有 bug,修掉」,然後用它覺得最安全的方式去修 => 加 guard clause、重構、擴大改動範圍。
根據統計,AI agent 加防禦性 null check 的機率是人類的將近兩倍。人類遇到 null 會先問「為什麼這裡是 null?」,AI 直接加 if (x == null) 就繼續走了。而且跟 AI 來回對話越多次,它越容易偏離原本的意圖。
Kiro 的解法:修之前先把三件事寫清楚
Kiro 的 Bugfix Spec 在修 code 之前,會先產出一份文件,把三件事寫清楚:
1. 現在錯在哪(Current Behavior)
不是「有時候會怪怪的」,是具體寫出什麼條件下會觸發、觸發之後會發生什麼錯誤。
比如一個二元搜尋樹(BST)的刪除功能有 bug:
WHEN 刪除一個有兩個子節點的節點,而且右子節點沒有左子樹
THEN 系統會 crash,報 AttributeError
2. 修完要怎樣(Expected Behavior)
修完之後的正確行為,寫成明確的條件:
WHEN 刪除一個有兩個子節點的節點,而且右子節點沒有左子樹
THEN 系統應該正常刪除,用右子節點的值取代被刪除的節點
3. 哪裡不能動(Unchanged Behavior)
這段是最重要的,也是最多人跳過的。明確列出哪些功能必須維持原樣:
WHEN 刪除葉節點或只有一個子節點的節點
THEN 系統應該維持原本的行為,正常移除節點
你把這三段 review 完,Kiro 才會開始動手。
Kiro 修 bug 的完整流程
跟一般 AI 不一樣,Kiro 不會看到 bug 就直接跳去寫 patch。它的流程是:
第一步:先證明 bug 存在
Kiro 會根據「現在錯在哪」寫測試,跑在還沒修的 code 上。這些測試應該要 fail => 如果 pass 了,代表 bug 描述有問題,要先回去修正。
第二步:記錄正常行為的 baseline
Kiro 會根據「哪裡不能動」寫測試,一樣跑在還沒修的 code 上。這些測試應該要 pass => 這就是修完之後的對照基準。
第三步:修 code
有了前兩步的測試當護欄,Kiro 才開始修。
第四步:重跑兩組測試
- 第一組(bug 測試):現在應該要 pass => 代表 bug 修好了
- 第二組(正常行為測試):應該還是 pass => 代表沒有壞其他東西
如果 bug 測試修完還是 fail => 代表 root cause 判斷錯了,Kiro 會重新分析,不會硬修。如果正常行為測試 fail => 代表改太多了,Kiro 會縮小 patch 範圍。
這整套流程的重點是:先寫測試、先確認問題、再修、再驗證,不是直接衝進去改 code。
什麼時候該用 Bugfix Spec
不是每個 bug 都需要開 Bugfix Spec:
- 適合用:複雜 bug、root cause 不明確、改動可能影響其他地方、之前修過但又 regression 的
- 不需要用:5 分鐘能修完、只改 1-2 行、你很確定不會影響其他地方的小 bug
坑點提醒: 最容易被跳過的是「哪裡不能動」那段。很多人覺得「我只是修一個小 bug,不用寫那麼多」,但偏偏就是那些你覺得不會動到的地方最容易被 AI 順手改掉。先花幾分鐘把最重要的不變行為列出來(安全相關的、對外 API、資料一致性),後面省的時間遠比你想的多。
參考
https://kiro.dev/blog/bug-fix-paradox/https://kiro.dev/docs/specs/bugfix-specs/https://kiro.dev/docs/specs/correctness/
支持作者 ☕
透過 LINE Pay 支持
透過 Ko-fi 支持