iT邦幫忙

2026 iThome 鐵人賽

DAY 8
0
AI Engineering

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

Day 8|第一份 Skill:審查報告怎麼交付?結論由程式決定,不由 AI 語氣決定

  • 分享至 

  • xImage
  •  

簡短回顧

昨天的主軸在於將深度分析的環節撰寫出來。今天進入最後一個環節:產生與交付報告,並補上先前尚未明確設計、可能斷鏈的流程。

先講一次撞車

這套流程剛跑起來沒多久就遇到:同一個專案、兩份 MR、同時交給 AI 審。當時的設計是同一個 repo 共用一份 clone,於是兩個 AI 得在同一個工作目錄裡各自 git checkout 到自己要審的分支,互相踩掉對方的工作狀態。

今天要收的就是這類東西:報告以什麼形狀存在、檔案放在哪裡、哪些要隔離、哪些要留下來。沒有明確設計好的流程,就會用這種方式提醒你。

Phase 4:報告交付與發布

我一開始的設計,是由主 AI Agent 直接輸出 Markdown 報告。

正式完成前還會自檢一次;AI Agent 必須把整份報告重新放進 context,修正內容與行號後再輸出,因此又會消耗一輪 token。

發布前自我審查:確認報告內容正確,語氣正面且具建設性。

所以後面我採用的方式是:在完整 MR/branch review 中,各階段確認後要進入主報告的內容,統一寫進一份 report JSON;scanner raw output 則分開保存。要產生發布到 GitLab 的回饋時,再由 Python script 把 report JSON 轉換成 Markdown。

發布前需要問過使用者,使用者同意後才發布。發布後需要提供直接連結,方便使用者點擊。

發布完成後有些資料要回填到 JSON 中,例如本次報告發布在 GitLab 上的留言 ID。

報告 JSON

這份報告使用 Pydantic 定義欄位格式,確保 AI 在審查期間生成、寫入的內容,從中間狀態到最終報告都符合預期的結構與資料型態。

另外,整份 Skill 以英文撰寫,並要求 AI Agent 使用英文工作與思考;呈現給使用者的內容,例如輸出在 terminal 上的文字以及最終報告,則統一使用繁體中文(zh-TW)。

這個分工的理由 Day 3 講過:Claude 的 tokenizer 處理中文約為英文的 1.65 倍,skill 全文英文化後從 ~40K 降到 ~29K tokens。這件事主要對 Claude 成立(中文的跨家平均只有 1.02 倍,Anthropic 是離群值)。所以規則這樣切:給機器讀的用英文,省的是 token;報告是給人讀的,用繁體中文。

報告有幾條硬規則
  1. 結論由 findings 機械決定:有任何仍有效(newreconfirmed)的 Critical → 結論必為 Request Changes,不得 Approve;沒有仍有效的 Critical、但有仍有效的 Suggestion → Approved with Comments其餘 → Approved。不讓 AI 在「發現了 Critical」和「給出結論」之間自由發揮
  2. 自我完備:報告會被貼到 MR 上給所有人看,內容只能引用 repo/MR 內的資源(如 app/api/account.py:34),不得出現審查機器本機路徑(/tmp/ncr/...
  3. 對事不對人:每一句都要經得起公開檢視,基於程式碼證據、指向程式碼而非作者
  4. 只點問題不給出路的 finding 不合格:每個發現除了「哪裡有問題」,必須附上可參考的修復方向或範例程式碼。

第 1 條後來真的被繞過一次 😅

我不定期會對整套 skill 做一次健檢,通常是體感變動累積多了、或是新模型發布之後。其中一場健檢造出了一份結構合法的報告:掃描驗出的 Critical CVE 只寫在「靜態分析」那一段,沒進 findings 清單。結論只數清單,所以它是 Approved,信心 95%。

修法分兩步:先規定掃描驗出的 Critical 一定要進清單;後來直接取消「掃描結果自成一段」的設計,所有驗證過的發現都進同一條清單,這條繞道就不存在了。

機械規則只鎖得住它數得到的東西。

「報告改成 JSON、渲染交給 script」這個決定值多少,現在講只是省 token 而已。

等到後面把這條流程接上 profiler,我會用秒數跟金額算給你看 🫡

檔案路徑規劃

這邊說明 AI 審查期間的檔案路徑規劃,分成工作期間跟報告位置:

工作目錄:暫時性資料

  1. 將待審查 MR 的 repository clone 到 /tmp/ncr/{group}-{repo}-mr{iid}/repo
  2. 審查過程中暫存的檔案可以置於:/tmp/ncr/{group}-{repo}-mr{iid}/ 中,獨立於 repo

為何目錄要帶 iid 而非同一個 repo 共用?

就是開頭那場撞車,因此改用「一個 MR 一個目錄」進行隔離。

為何要帶 {group}?
同名 repo 可能存在於不同 group 底下(his/abc-backendlis/abc-backend),只用 repo 名會撞在同一個目錄。

為何放 /tmp?
這是刻意的:clone 是用完即棄的工作副本,因此放在執行環境的暫存目錄。Skill 目前沒有額外實作清理流程,檔案何時移除取決於該環境的暫存目錄政策;若執行環境會長期運作,仍需另外設定定期清理機制。

歷史報告:永久性資料

歷史報告是下一輪判定「首次 vs re-review」的依據,屬永久資料,因此不放 /tmp,存放於:$HOME/ncr/{gitlab-group}/{subgroup}/{repo}/

一次掃描的檔名前綴:mr{mr-iid}_from_{source_branch}_to_{target_branch}_{YYYY-mm-dd_HHMM}

注意:branch 名稱中常帶 /(如 feature/xxx),組檔名前須將 / 替換為 -,否則會被當成子目錄。

  • 最終報告:.json
  • Opengrep 掃描結果:.opengrep.json
  • Trivy 掃描結果:.trivy.json
  • Lint 掃描結果:.lint.json(ruff/ty/oxlint)

一次審查歸檔後的資料目錄:同一個前綴底下三個檔案,主報告 .json,以及 opengrep 與 trivy 各一份掃描結果

圖中是加入 lint artifact 前的版本;現行歸檔會再多一份 .lint.json

本日小結

今天把報告這一段收掉了:在完整 MR/branch review 中,各階段確認後要進入主報告的內容統一寫進同一份 report JSON,scanner raw output 則分開保存;要發布的時候才用 Python script 套模板渲染成 Markdown。這樣做省的不只是 token,更重要的是結論不再由 AI 自由發揮:有仍有效的 Critical 就一定是 Request Changes,這件事由程式決定,不由語氣決定。

另外四條報告硬規則(機械結論、自我完備、對事不對人、只點問題不給出路不合格),以及昨天 CodeGraph 那段「先寫清楚它看不見什麼」,其實是同一個姿態:先講清楚邊界,再決定它能負責什麼。

明天處理讓這一切真的跑起來的東西:GitLab API 要用到哪些端點、Note 跟 Discussion 差在哪裡。


上一篇
Day 7|第一份 Skill:AI Code Review 九面向(下)與兩道閘
下一篇
Day 9|第一份 Skill:怎麼延續前次審查?能不能直接接上,在發佈那一刻就決定了
系列文
AI 的駕馭之道:一個 AI Code Reviewer 的養成、評測與邊界實錄9
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言