· Paul Lukic · 1 分鐘閱讀 · code-reviewclaude-codeagentscoographai-spend

找到審查漏掉的東西的那次審查:針對大改動的可選深度審查

一個審查者看一遍 diff 會放行的東西,幾個對抗式審查者加反駁者不會放行。這篇文章講一次多代理審查在常規審查已經通過的 176 次提交上找到了什麼、它花多少錢、為什麼它是可選的,以及哪種迴圈形狀能防止它吃光你的預算。

本文目錄

上週,一疊 21 個 pull request、大約 176 次提交,走完了每個 Coograph 專案都在跑的常規審查:一個唯讀審查者看一遍 diff,每條發現都有一段來自新讀取檔案的引用做支撐。通過了。然後它走了另一種審查,那一次找到了一把被釋放了兩次的鎖、一個拿掉修復也能通過的測試,以及一個可能覆蓋客戶檔案的佇列任務。這三個,之前都被核准了。

這篇文章講的就是第二種審查。它隨 Coograph 1.6.0 發布,叫 /coograph-ultra-review,刻意做成可選,並附帶一條什麼時候該停的規則——因為用它的第一週教會了我們沒有這條規則會發生什麼。

一個審查者漏掉什麼

常規審查代理讀 diff,讀檔案,過一遍清單,出報告。它擅長的正是一個細心的人擅長的:慣例、明顯的邏輯錯誤、一個沒處理的 null。它不擅長的也正是細心的人不擅長的:一處改動和一個不在螢幕上的程序之間的相互作用。

上面三條發現全是這一類。被釋放兩次的鎖,是一個 goroutine 先明確釋放了一個佔用,然後在 defer 裡又釋放了一次——只要中間沒有第二個請求拿走這個佔用,就沒事。拿掉修復也能通過的測試,是它的準備步驟跑在被測程式碼重新讀取那一列之前,於是它本該釘住的那件事從未發生。佇列任務則是在一次二十分鐘的等待之前檢查過一次自己還擁有這台伺服器,之後再也沒檢查;客戶在等待期間裝了別的東西,就被覆蓋了。

這些在 diff 裡都看不到。它們只在有人問一個很窄的問題——重新投遞會對這裡做什麼?——然後另一個人試圖證明答案是錯的時候,才會現身。

深度審查換了什麼做法

/coograph-ultra-review 就是這個,以 Claude Code 裡一個儲存好的工作流程的形式。

一個偵察代理把 pull request 或提交列表解析成檔案和改動的行,並向程式碼圖查詢被改內容的呼叫方和匯入方。然後每個維度一個審查者,在被審查的提交上讀程式碼,腦子裡只裝一個問題:狀態與並行;資料遺失路徑;契約與相容性;怎麼都能通過的測試。每人回傳發現,附原文引用、檔案和行號,以及一個具體的失敗情境——一邊是輸入和狀態,另一邊是錯誤結果。沒有引用,就不算發現。

然後是讓它不一樣的那部分。每條 Critical 和 Warning 都交給反駁者——一群獨立代理,唯一的任務是從一次新的讀取出發證明這條發現是錯的,每人一個不同的視角:引用的那行存在嗎、真的做了聲明裡說的事嗎;情境真的會發生,還是有守衛擋住了它;有沒有現成測試與這個解讀矛盾。只有沒人能反駁,發現才算成立。被反駁的發現仍然留在報告裡,附反駁者的理由,因為反駁者有時也會錯。

一份報告,每個提交一個結論,頁尾寫著它花了多少。

成本是最該放在前面說的誠實數字:一次完整執行是 120 萬到 160 萬 token,大約二十分鐘。一個 33 個提交的 pull request 花了 310 萬、39 分鐘。所以代理被要求的是提議它——當改動超過十五個檔案、當它要交給人核准、當它碰到佇列任務、鎖、狀態流轉、遷移或兩個服務之間的契約時——而絕不自己執行。

吃掉一天的迴圈

先說我們最初做錯了什麼,你就不必再錯一次。

用這種工具最順手的方式是:跑一次,修它找到的,再對修復跑一次,重複到乾淨為止。我們就是這麼做的。一個修復跑了四次完整執行,大約 500 萬 token,每一輪都找到真問題。第一輪找到了那個沒有真正測到修復的測試。第二輪找到七個問題,全在第一輪的修復新加的程式碼邊緣。第三輪在第二輪的修復裡找到一個 Critical。它收斂了,但很慢,而且第二、三輪找到的大部分東西都在原始改動根本沒碰的程式碼裡。

要盯的就是這個模式:一個對每次修復都全幅度審查的審查,會永遠找到上一次修復的邊緣,而且每一條都真實到值得修。工具沒錯。錯的是迴圈。

所以發布版有三種模式和一條停止規則。

模式什麼時候成本
plan在寫會碰生命週期或並行的程式碼之前和一次完整執行差不多的價錢,但它在程式碼存在之前執行
full一批改動的第一次審查,以及所有修復到位後對整個 PR 的那一次120 萬–160 萬 token
delta一批修復,對照上次執行的發現檢查:修好了嗎,改動的行又弄壞了什麼約 50 萬

落在改動行之外的發現作為後續項回傳,不是阻塞項。停止規則:修 diff 裡的,記錄其餘的,最多兩輪 delta,對整個 PR 跑一次 full,然後交給人。同樣幾行上出現第三輪機器發現,不是跑第四輪的理由;它是設計需要被看一眼的訊號,而 plan 模式是看這一眼最便宜的地方。

我們在已經建好的設計上測了 plan 模式,用的是第三輪之前它的原樣記錄。它僅憑方案文字、在任何程式碼之前,就找到了第三輪的那個 Critical,外加兩件程式碼審查漏掉的事。它也花了一次完整執行的錢。方案審查的價值在時機,不在價格。

為什麼它是可選的

因為大多數改動不需要它,而一個每次要花 100 萬 token 的工具必須賺回每一次。常規審查仍是預設。當改動符合條件時,代理會提一句深度審查——一句話,帶著成本——然後把決定留給你。衡量審查是否發生過的 retro 把它算作一次審查;其他什麼都不變。

如果你跑它,就按停止規則說的方式跑,然後把 pull request 交給人。這仍然是最後一步,而用了它一週之後,這一步我們信得更多而不是更少:交到人手上的,是一份生命週期問題已經被書面問過、答過的 diff。

1.6.0 裡還有

一位使用者寄來的兩個修復,如果你在跑程式碼圖,都值得知道。

增量圖更新一直在刪除早先執行已解析出的每一條呼叫邊:連結器把節點 id 當成名字重新解析,找不到匹配,就把它們丟了。如果你的圖在一次提交之後丟了 calls 邊,就是這個原因。拉取,用 --build 重建一次,之後的更新會保留它們。

另外,uv run 會按機器的預設 Python 解析。在預設版本低於 3.10 的機器上,MCP 伺服器啟動時就死於 your requirements are unsatisfiable,主程式報成 CONNECTION_CLOSED,真正的原因躺在沒人讀的日誌裡。現在 Coograph 寫出的每個 uv run 都帶 -p 3.12;uv 會按需下載直譯器。同步腳本也不再整個覆蓋專案的 .mcp.json;它只合併 code-graph 條目,檔案其餘部分不動。

試試

Coograph 1.6.0 在 Claude 外掛市集和初始化器裡都有。在一個 Coograph 專案裡,/coograph-ultra-review(外掛裡是 /coograph:coograph-ultra-review)加上一個 PR 編號或一個提交列表;skill 會在任何東西執行之前先提出模型方案和成本。工作流程檔案是 .github/skills/coograph-ultra-review/ 裡的普通 JavaScript,維度隨你改。參數、模式和停止規則在文件裡。

削減你的 AI 編程帳單 67–78%。Coograph 採用 MIT 授權、永久免費。Pro 提供客製服務。