Claude Code 的 /simplify 讓四個 AI 代理並行整理變更的程式碼 — 之後再交給 /code-review 檢查

Claude Code 的 /simplify skill 會讓四個 AI 代理並行審查變更的程式碼並套用修正,之後再用 /code-review 檢查修改後的程式碼有沒有錯誤。

白色卡片上的赭紅色 Claude 星形標誌與黑色字樣
本頁目錄

引言

/simplify 是 Claude Code 內建的 skill。這個 skill 我已經用了好幾個星期,卻不知道它到底在做什麼。我只知道它還有個雙胞胎 skill 叫 /code-review,很多人建議把兩者搭配使用。這兩個 skill 看起來很像,但它們各自怎麼分工,我卻說不上來。

/simplify 是只做程式碼整理的審查。四個 AI 代理會同時運行,讀取差異,各自負責一個角度:重複使用、簡化、效率,以及抽象層級,也就是判斷各項變更是否放在正確的分層。它們的修正會直接寫進工作目錄,不會先列出來讓使用者挑選要套用哪些。

/simplify 不會去挑程式碼的錯誤,所以 /code-review 要在它之後執行,檢查它處理過的程式碼。我用這個部落格的一個真實的 commit 把兩者都執行了一次,看看各自能抓到什麼。

/simplify 的運作方式

/simplify 是 Claude Code 內建(bundled)的 skill。內建 skill 是一段寫在 Claude Code 裡的提示詞,告訴模型怎麼用自己的工具完成審查和修正。指令參考文件對它的說明如下(中譯):

審查變更過的程式碼,找出可以整理的地方並套用修正。四個審查用的 AI 代理會並行執行,涵蓋既有輔助函式的重複使用、簡化、效率,以及變更是否位於正確的抽象層級。這項審查不找正確性方面的錯誤,要找錯誤請使用 /code-review。

/simplify 載入的提示詞分成三個階段:

  1. 收集差異。以 upstream 分支為基準執行 git diff,再加上尚未 commit 的變更;如果以參數傳入路徑或 pull request,就改以那個目標為準。
  2. 審查。四個 AI 代理同時啟動,並被交付上個步驟收集的差異以及應該以哪個角度進行審查。
  3. 套用。針對同一行的審查意見會先合併成一項,再逐項直接套用到工作目錄。

每個 AI 代理都會從提示詞拿到一份分工說明:

AI 代理提示詞要它找什麼下文實測中的例子
重複使用新程式碼是否重寫了專案裡已經有的輔助函式;會去搜尋共用模組和鄰近的檔案scripts/indexnow.ts 也建立了 new URL(SITE),但沒有地方匯出解析好的結果可以直接匯入
簡化多餘或可推導的狀態、只差一點的複製貼上、過深的巢狀、遺留的無用程式碼resolveMark 組出一個物件,唯一的呼叫端卻馬上把它拆開
效率重複的運算或 I/O、可以並行卻依序執行的步驟、加在頻繁執行路徑上的工作luminance(DARK_BACKGROUND) 在每一頁的每個圖示上都重算一次,其實可以在模組載入時算一次就好
抽象層級只在表面修補症狀、根本原因其實在更深一層;或在共用程式碼上疊加特殊情況部落格舊的主機名稱寫死在 logo 對照表裡,而不是放在 site.ts

提示詞也寫明了,主代理在套用階段可以略過哪些審查意見,以下是原文的中譯:

如果某項審查意見的修正會改變預期的行為、需要在審查的差異之外大幅改動,或是被判斷為誤報,就可以直接略過。只要記錄略過了哪些審查意見即可,不必逐條說明為什麼不採用。

找錯誤的工作則交給同樣內建的 /code-review skill:

/simplify/code-review
尋找的內容重複使用、簡化、效率、抽象層級正確性方面的錯誤;依模型和 effort 等級,也會涵蓋程式碼整理
是否修改檔案一律套用自己的修正只回報,除非傳入 --fix
執行方式四個審查用的 AI 代理並行執行擁有獨立脈絡視窗的背景子代理
接受的參數路徑,或 pull request 的編號或網址low 到 max 或 ultra 的 effort 等級、--fix、--comment、--max-findings,以及 pull request、分支或路徑

2026 年 3 月那篇文章出自 Ruby 程式碼分析與格式化工具 RuboCop 的作者 Bozhidar Batsov。他說 /simplify 是「我最常用的 skill」,會在「完成較大規模的重構之後,或一次接受一批 AI 產生的程式碼之後」馬上執行它(引文為中譯)。

拿真實的 commit 來測試 /simplify

我挑的是一個已經正式上線的 commit。這個部落格有一個 rehype 外掛(在建置時加工 HTML 的外掛)rehype-link-icons.ts,會在連結旁邊畫出品牌的 logo;這個 commit 替它加了四個新的 logo:Qiita、Zenn、DevelopersIO,以及在這個部落格上其他文章的連結加上的印章。

我在另一個工作樹裡,把過去的 commit 重新套用成還沒 commit 的變更,這樣就能放手讓 /simplify 去修改,也不會影響到真正的程式碼以及正在進行的工作:

終端機視窗
git worktree add --detach ../simplify-trial <commit>^
git -C ../simplify-trial cherry-pick -n <commit>

接著在 ../simplify-trial 工作樹裡,用 Claude Code 2.1.310 執行:

/simplify src/lib/rehype-link-icons.ts

四個 AI 代理一共回報了九項審查意見,/simplify 套用了其中三項:

AI 代理審查意見已套用
重複使用00
簡化32
效率00
抽象層級61

重複使用和效率兩列是 0,因為這兩個 AI 代理提出的都只是觀察(像前面表格裡的例子),沒有這次差異需要修改的地方。

套用的三項修正

最大的一項就是上表簡化那一列的例子,刪掉了 MarkSymbol 型別。這個型別唯一的用途,是把 id 欄位從 resolveMark 傳給唯一呼叫它的地方。負責組出 sprite(集中放置所有 logo 的隱藏 <svg>)的程式碼,一拿到回傳值就立刻把它拆開:

src/lib/rehype-link-icons.ts (before)
function resolveMark(key: MarkKey): MarkSymbol {
if (isLocal(key)) return { id: symbolId(key), ...LOCAL_MARKS[key]() };
return { id: symbolId(key), viewBox: "0 0 24 24", children: [markPath(key)] };
}
// …
children: [...used].map((key) => {
const { id, viewBox, children } = resolveMark(key);
return element("symbol", { id, viewBox }, children);
}),

/simplify 把 resolveMark 換成直接回傳 <symbol> 節點的 symbol(),MarkSymbol 型別也就不需要了:

src/lib/rehype-link-icons.ts (after)
function symbol(key: MarkKey): HastNode {
const { viewBox, children } = isLocal(key)
? LOCAL_MARKS[key]()
: { viewBox: "0 0 24 24", children: [markPath(key)] };
return element("symbol", { id: symbolId(key), viewBox }, children);
}
// …
children: [...used].map(symbol),

另外兩項比較小:

  • favicon 的讀取方式:外掛會從 favicon 讀取印章的形狀。原本 <svg> 標籤用另外一行讀取,<circle>、<g>、<path> 則用同一個 .map;現在四個標籤都用同一個 .map 讀取,結果不變。
  • 舊的主機名稱:部落格舊的網址 oharu-tech-blog.vercel.app 原本直接寫在 logo 對照表裡,但網站的網址都應該放在 site.ts。這就是上表抽象層級那一列的例子。現在它移到 site.ts 的 LEGACY_HOSTS,以後網址有變動,只要改 site.ts 一個檔案就好。

略過的六項

/simplify 略過的六項審查意見,以及略過的原因:

審查意見的建議略過的原因
讓自行繪製的 logo(DevelopersIO 和印章)也經過對比度檢查會改變行為:深色模式下這兩個 logo 會被改色
先解析連結再分類,讓 ./other/ 這類連結也加上印章會改變行為:目前沒有圖示的連結會多出印章
拿掉每個圖示外層 <svg> 上 24×24 的 viewBox會改變行為:圖示顯示的大小可能改變
讓品牌產生器直接把印章形狀輸出成模組,而不是用正規表示式解析 public/favicon.svg超出差異範圍:要改的是另一個產生 favicon 的腳本
在既有的節點建構函式裡也改用新的 element() 輔助函式超出差異範圍:要改的是這次差異沒有動到的程式碼
用一個形狀一致的 logo 物件取代 isLocal 分支部分已經處理:改成 symbol() 之後,這個分支已經少了一處

/simplify 不會執行它修改過的程式碼,所以 Claude Code 另外確認了這三項修正沒有改變頁面上的任何東西。做法是拿六種連結(GitHub、根目錄相對路徑、舊主機、DevelopersIO、Zenn 和一個註腳)分別交給修改前後的外掛處理,輸出完全相同。

對 /simplify 處理過的程式碼執行 /code-review

對 /simplify 改過的 rehype-link-icons.ts 和 site.ts 執行 /code-review 之後,回報了十項審查意見。

其中九項在那次 commit 正式上線時就已經存在,這九項裡有三項可以直接重現:

輸入外掛的行為原因
href="/\github.com/x"畫出 GitHub 的 logo根目錄相對路徑的判斷排除了 //,卻沒有排除 /\,而解析 URL 時會把反斜線當成斜線
href="http://constructor/"拋出 TypeError: key.slice is not a function,整個建置失敗logo 對照表是一般物件,所以這個主機名稱會查到 Object.prototype.constructor
DevelopersIO 的 #cbd31e 區塊在淺色主題的白底上,對比度只有 1.63:1,低於 WCAG 要求的 3:1自行繪製的 logo 不經過對比度檢查

負責抽象層級的 AI 代理其實也看過 markFor 裡判斷根目錄相對路徑的正規表示式,但它只指出這段判斷放錯了地方。這個正規表示式會不會讓格式錯誤的 href 通過,屬於正確性的問題,不在它負責的範圍內,所以反斜線的錯誤要到 /code-review 才被發現。

/simplify 和 /code-review 該在什麼時候執行?

正確的做法是先執行 /simplify,最後才執行 /code-review。/simplify 會直接修改工作目錄裡的程式碼,而審查只看得到執行當下的程式碼;如果順序反過來,/simplify 做的修改就在沒有經過任何審查的情況下被 commit。

先執行 /simplify,最後執行 /code-review四張卡片由左到右排列。程式碼的變更先交給 /simplify,4 個 AI 代理從重複使用、簡化、效率和抽象層級四個角度同時審查,再由主代理把修正套用到工作目錄。接著 /code-review 檢查 /simplify 處理後的程式碼有沒有錯誤。最後由你修正回報的審查意見,再確認 git diff。/simplify 會修改檔案,所以審查要放在它之後程式碼的變更commit 前或 commit 後都可以/simplify把整理程式碼的修正直接套用到工作目錄/code-review檢查 /simplify處理後的程式碼有沒有錯誤你修正回報的審查意見,再確認 git diff4 個 AI 代理並行審查重複使用簡化效率抽象層級
/simplify 會修改程式碼,所以要讓 /code-review 審查修改後的結果,而不是反過來。

Batsov 在 3 月那篇文章裡介紹的工作流程,順序正好相反:「先修改,用 /review 找出問題,把指出的問題都修好,最後才用 /simplify 整理」(中譯)。

總結

/simplify 會把差異交給四個 AI 代理,從重複使用、簡化、效率和抽象層級四個角度同時審查,再由主代理套用修正,但會略過改變行為或超出差異範圍的部分。它完全不找錯誤,也不會執行它修改過的程式碼。

接著再對 /simplify 處理過的程式碼執行 /code-review。如果想拿已經正式上線的 commit 試試這兩個 skill,可以用 git cherry-pick -n 把它重新套用到另一個工作樹,在那裡執行。

參考連結

分享這篇文章