iT邦幫忙

2026 iThome 鐵人賽

DAY 10
0
AI Engineering

AI 的駕馭之道:一個 AI Code Reviewer 的養成、評測與邊界實錄系列 第 10

Day 10|第一份 Skill:作者說「我不同意」之後?先過我這六關!

  • 分享至 

  • xImage
  •  

簡短回顧

昨天把 GitLab API 的端點與 Note / Discussion 的資料模型整理完了。

但報告發出去並不是結束:今天處理「發出去之後」的兩件事:作者反駁怎麼處理,以及版本怎麼控管。兩件事底下是同一個要求:AI 改變立場可以,但每一次改變都要留下能被程式檢查的痕跡。

作者反駁怎麼辦?(Pushback)

報告發出去之後,作者回了一句「這個我不同意」。很多 Code Review 流程的說明會停在報告發佈;但另一個難點是在發佈之後:作者不同意時,AI 要怎麼重新判斷,又要留下哪些紀錄?

這時 AI 有兩種最容易犯的極端:過度順從(作者皺個眉頭就全面撤回)和過度固執(聽不進作者帶來的新資訊)。兩者都偏離了「讓 Codebase 變好」這個核心目標。

我的做法是要求 AI 收到反駁後,先走一輪六題自我審查。這六題是我參考 Google 工程實踐的 Handling pushback in code reviews 後,為 AI Code Review 重新整理出的判斷程序。前半保留它對作者脈絡、證據與 reviewer 立場的判準;後半再補上規則與適用情境、連鎖效應,以及這份 Skill 所需的欄位與結果:

  1. 作者有沒有帶來我不知道的新資訊?(「這是內部工具」「前面有 middleware 擋」)→ 有,作者很可能是對的
  2. 作者是不是離 Code 更近的人?(owner/原作者)→ 預設他的脈絡比我完整
  3. 作者的論點有事實依據(指向 code/文件/spec),還是「我覺得」、「我們一直都這樣」?
  4. 原始意見是硬規則(Critical)還是 Suggestion/Nit?硬規則不因立場讓步
  5. 反駁改變的是規則本身還是適用情境?(「這個端點只在內網、有 mTLS」:情境變了、嚴重度可降、但規則沒有錯)
  6. 連鎖效應:若照作者說的撤回,其他相似的 finding 是不是也要一併處理?

六題不是建議,是欄位。報告 schema 裡 pushback 紀錄的 review 是六個必填字串(new_informationauthor_proximitygrounded_in_evidencerule_or_preferencerule_versus_contextknock_on_effects),連同作者原話、結果(withdrawholdsplit)、回覆內容與時間一起存。少答一題,report_model.py validate 不放行,這條 pushback 就進不了報告。

AI 可以被說服,但不能只用一句「你說得對」帶過。

走完六題,結局通常只有三種,每種都有明確的做法:

  • 作者對 → 大方撤回:「你說得對,這條撤回,理由是 {新資訊}」:並且在已存的報告上加註而不是偷偷改寫歷史
  • 我(AI)對 → 進一步解釋 why:「我聽到了+我維持立場+理由是 {tradeoff}」,而不是軟化或放棄;2~3 輪沒共識就停下來,升級給 tech lead 裁決,不進「誰大聲誰贏」的迴圈
  • 各對一半→ 把議題拆開:「嚴重度我同意降為 Suggestion,但這條仍建議處理,因為 {理由}」:不要用「那就算了」打混,那是沒有立場

撤回還有一個容易被跳過的後果:它會動到結論。 報告的 conclusion 不是 AI 挑的,是從仍然存活的 findings 算出來的:只要還有一條有效的 Critical,結論就是 Request Changes;否則只要還有 Suggestion,就是 Approved with Comments;只剩 Nit 或沒有 finding,才是 Approved。撤回把那條 finding 的狀態改成 withdrawn,它就不再算數;如果它是最後一條活著的 Critical,結論跟著變。所以撤回不是刪一行,是重跑一次 report_model.py conclusion 取新結論回填;結論欄與 findings 對不上的報告,validator 直接拒收。

貫穿三種結局的底線:對事不對人、用「這段 code/這個 MR」而不是「你」、作者情緒上來時 AI 保持冷靜。還有一條防線值得寫死:作者用「這個很趕」、「單位在等」施壓時,時程壓力不改變技術判斷,很急不等於緊急,等級不因此下修。

Versioning

Skill 本身當然應跟隨 Commit 進行控管,但同時也該有對應的版本號。

我將版本號格式訂為:YYYY.mm.dd.{流水號-例如01, 02, ...},例如:2026.08.03.01,寫在 SKILL.md 開頭的 version: 欄位。

但版本號真正要跟著走的不是 skill,是每一份報告。報告 meta.skill_version 是必填欄位,空著就過不了驗證。理由很實際:三個月後有人回頭問「這條漏掉的問題,當時是哪一版規則在跑」,答案得在報告裡,不能靠回憶或 git blame 去對時間。這個追溯成立的前提,是每次規則異動都同步更新版本號,並讓該版本能在 repo 裡回指到對應內容;版本號是索引,不是規則內容本身。規則會改(後面會講到規則怎麼退場),改了之後舊報告還要能被讀懂是在哪套規則下寫的。

報告本身存哪、檔名怎麼組,那是 Day 8 交付流程的一部分,已經在那天講完了。

明天要交出去的東西,長這樣

從 Day 3 到今天,八天寫的全是規格:萃取、流程、工具、九面向、報告、API、反駁。明天這一整份會交給 LLM,讓它把 skill 生出來。所以這裡不是複習,是交接前把東西攤開來看一遍。

先講定位:我不是要打贏市面上既存的 LLM Code Review Solution,我是要打造一套懂你,符合你甚至是像你的 AI Agent 流程。另一個角度,可以借**康威定律(Conway's Law)**來說明。

Conway's Law:設計系統的組織,產出的設計必然複製該組織的溝通結構。

我借 Conway's Law 做一個類比:工具往往帶著設計者的組織假設,而審查標準還必須容納你的團隊慣例、環境與風險現實。通用工具可以提供共同的核心,但組織特定的部分仍需要另外補上;對我來說,這份 Skill 就是承接那一層差異的地方。

與其繼續試用第 N 個「只差一點」的工具,我選擇把自己的組織情境、慣例與風險偏好,編進一份工具讀得懂的文件裡。這個 Skill 就是這麼來的。

下面這張圖是同一件事的全貌:六個 Phase,每一個只回答一個問題。順序不能對調——每一步都在替下一步限縮範圍。

一次審查的完整流程:六個 Phase,每一個只回答一個問題

AI Code Review 的全流程

  1. 使用者貼入 GitLab MR URL
  2. AI 收到 GitLab MR URL 後,交由 Python script 解析出 hostproject path 與 MR iid。呼叫 GitLab API 的 /projects/:id 時,:id 可使用數字 project ID 或 URL-encoded project path;目前流程使用從 MR URL 取得的 project path,並由 urllib.parse.quote(..., safe="") 完成編碼,不交給 LLM 手動替換字元

一條 GitLab MR URL 的結構:https://gitlab.example.com/his/abc/abc-backend/-/merge_requests/61
host: gitlab.example.com
project path: his/abc/abc-backend
iid: 61

quote('his/abc/abc-backend', safe='')his%2Fabc%2Fabc-backend

  1. 藉由 GitLab API 取回 MR 詳細資訊;若有附件檔案,亦可透過 API 取回,後續作為 LLM 審查時的佐證資訊。取得來源與目標分支後,Skill 要求 AI 將儲存庫 clone 到 /tmp 中該 MR 的獨立工作目錄,並以 git diff --merge-base 在本地產生 diff。實作上,session 會把一般 GitLab HTTPS/SSH URL 自動改寫至每位使用者的憑證代理,GitLab token 不會交給 AI session。AI 隨即依標題、說明與異動範圍快速自問三題:該不該做?該在這個 MR 做?該在這個時機做?有疑慮不擋審查,但必須寫進最終報告,把決策留給人
  2. 查看報告資料夾,判定這是第一次還是第二次以後的審查。若為第二次之後,啟動反蒙蔽(blind pass):先不讀前次報告、當作全新 MR 審完才回頭比對,避免被前次結論定錨;並於背景取回前次報告發佈後 MR 上新增的留言、討論串。判定完成後,平行派出 Subagents 進行掃描
  3. Subagents 呼叫的確定性掃描工具(trivy、opengrep、lint)應生成對應的掃描報告,按照前述路徑與命名規範以 JSON 格式歸檔。主 AI Agent 逐條驗證(誤報把關)後,才回填最終完整報告 JSON 的對應欄位
  4. 進入深度審查階段:先由一個不帶任何清單限制的 fresh-eyes subagent 盲讀 diff、回報線索,主 AI Agent 逐條驗證。接著盤點這次變更會觸及哪些危險操作,找出所有能抵達這些操作的路徑,確認每一條路徑都經過必要的驗證、授權或其他防護;最後再按九面向 Checklist 逐項審查,將確認後的結果回填至最終報告 JSON 的對應欄位
  5. 使用預先制定好的 Pydantic 模型進行 JSON 資料驗證,若有問題即刻修復
  6. 啟動品質自檢 subagent 針對 最終完整報告 JSON 進行品質、用語、驗證 Findings 是真實存在 等
  7. 流程完成,詢問是否 發佈報告到 GitLab MR 上
  8. (若不要,流程結束),若要,呼叫 Python script 將 JSON 套用 template 轉換成 Markdown 格式。轉換完畢後,呼叫對應的 GitLab API 進行報告發佈。成功後將報告 discussion_id 與時間回填到最終完整報告 JSON 的對應欄位中
  9. 報告發佈後若作者反駁,AI 走六題自我審查,判定撤回/維持/拆分,六題答案與結果寫進報告 JSON 的 pushback 紀錄,重算 conclusion 後再驗證一次,不偷偷改寫歷史

明天開始,我們就把 Day 3 到今天所寫下的這些內容,全部交給 LLM,讓它幫我們把 skill 真的生出來🤩!


上一篇
Day 9|第一份 Skill:怎麼延續前次審查?能不能直接接上,在發佈那一刻就決定了
下一篇
Day 11|第一份 Skill:交由 LLM 開工!Claude Code 26 分鐘生出整份 Skill
系列文
AI 的駕馭之道:一個 AI Code Reviewer 的養成、評測與邊界實錄11
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言