AI 做 Code Review,第一步不是看代碼
整理版優先睇
AI做Code Review,第一步唔係睇代碼,而係先理解作者嘅意圖;將經驗結構化成流程,先分維度、再分級,先攻高風險區域,先停低諗清楚先至落筆。
呢篇文章分析咗一個專畀AI睇嘅Code Review Skill,嚟自GitHub上h4vzz/awesome-ai-agent-skills倉庫。作者努力撞蘑菇AI係專注AI Agent深度實踐嘅分享者,佢發現大多數人做code review嘅思維同呢個Skill嘅設計差咗一個關鍵步驟:唔係一開波就睇代碼,而係先搞清楚作者想做咩。文章用一段有3個安全漏洞嘅authenticate()函數做例子——SQL注入、MD5弱哈希、計時攻擊——話畀你知,淨係檢查「邏輯啱唔啱」根本睇唔到深層問題。
整體結論係:Code Review Skill嘅核心唔係教新知識,而係把有經驗工程師嘅「條件反射」結構化成流程,分五個維度(正確性、安全性、性能、可讀性、測試),再分三個級別(Critical、Warning、Info),令AI(同人)都跟得鬱、唔靠撞彩。呢種設計對抗嘅係人同AI嘅默認偏差——夠膽直接跳去評判實現,而唔先理解目標。
文章仲列出三個具體常漏嘅坑(N+1查詢、漏鑑權、SELECT *洩漏),同埋點處理超過1000行嘅大PR:先勸拆細、集中火力評審最高風險文件。總括嚟講,呢個Skill好值得做code review嘅人參考,尤其係想系統化提升代碼質量嘅團隊。
- Code Review第一步唔係睇code,而係先理解作者意圖,用一句話概括變更,避免誤傷。
- 評審分五個維度:正確性、安全性、性能、可讀性、測試,每個維度獨立檢查。
- 輸出分三級:Critical(合併前必須修)、Warning(強烈建議)、Info(可以考慮),解決意見排序問題。
- 三個典型漏洞:N+1查詢(循環內DB操作)、漏鑑權(冇驗證權限)、SELECT *洩漏內部字段。
- 超過1000行嘅PR先警告建議拆分,然後聚焦高風險文件深度評審,唔好平均用力。
Code Review Skill
一個結構化嘅Code Review流程,強調先理解意圖,分五個維度(正確性、安全性、性能、可讀性、測試)評審,並用Critical/Warning/Info三級標記問題。嚟自h4vzz/awesome-ai-agent-skills倉庫。
內容片段
def authenticate(username, password, db): query = f"SELECT password_hash FROM users WHERE username = '{username}'" row = db.execute(query).fetchone() if row is None: return False stored_hash = row[0] input_hash = hashlib.md5(password.encode()).hexdigest() return input_hash == stored_hash
一個例子揭開Code Review嘅盲點
睇一段authenticate()代碼:用f-string砌SQL查詢、用MD5 hash密碼、冇防計時攻擊。多數人review完會寫LGTM,但其實有三個安全漏洞:SQL注入、MD5弱哈希、計時攻擊。呢段code嚟自GitHub上一個專門畀AI睇嘅Code Review Skill教學樣本。
作者發現多數人嘅review流程係:打開diff、逐行掃、睇唔順眼就comment,但唔知作者想達成咩目標。結果誤傷大量:覺得抽象層多餘但其實係兼容舊接口;覺得變量名奇怪但其實係領域術語。
第一步唔係睇code,而係理解意圖
Skill工作流第二步寫住:「Read commit messages, PR descriptions, and surrounding code to understand what the author intended. Summarize the change in one sentence before proceeding.」呢個係成個Skill最關鍵嘅設計——先理解意圖,再評判代碼。
多數人跳過咗呢步,直接評判實現,結果就係誤傷大量。你覺得呢個查詢可以優化,但其實佢運行頻率極低;你覺得呢個寫法唔夠靚,但佢確實啱。
五個維度、三個級別,告別一鍋粥review
Skill將評審維度顯式分成五類:正確性、安全性、性能、可讀性、測試。每個維度檢查嘅具體嘢都有列明,例如安全性包括SQL注入、XSS、硬編碼密鑰等。
仲有更實用嘅係優先級分級:Critical(合併前必須修)、Warning(強烈建議)、Info(可以考慮)。返去authenticate()例子,Skill總結係「2 critical, 1 warning, 1 info」,清楚話畀你知邊條非改不可。
呢個分類本身唔稀奇,但加上優先級後,就變成可操作嘅行動指南,而唔係一份清單。
三個常漏嘅坑,同埋點解會漏
- 1 N+1查詢:循環內有DB操作,200個訂單就201次查詢。代碼邏輯完全正確,但整體執行模式有問題。Skill要求check「循環內是否有數據庫操作」呢個模式。
- 2 漏鑑權:userId直接從query string讀,冇驗證請求方權限。成因係開發者寫業務邏輯時默認自己係「有權限嘅人」,鑑權自然被推到之後。Skill將呢個列為Warning,要求合併前決策。
- 3 SELECT *洩漏內部字段:回傳所有字段包括deleted_at、內部狀態等,增加帶寬、洩露細節、產生隱性依賴。列為Info,係「可以更好」嘅改進點。
呢三個坑都係實際code review好易漏嘅位,尤其係N+1查詢,因為邏輯無錯,測試環境數據少好難發現。
大PR點搞?集中火力打高風險區域
Skill對超過1000行嘅大PR有明確指引:先警告作者建議拆分,然後聚焦最高風險嘅文件做深度評審,而唔係對所有文件做淺掃描。背後係認知限制——一個人或AI有效評審嘅代碼量有上限。
作者總結,成個倉庫嘅Skill都係用結構化流程對抗默認偏差。Code Review Skill將「先理解意圖」「分維度」「分級」呢啲隱性判斷顯式化,令AI能可預期執行。但係「整體上有冇更好嘅抽象方式」呢類判斷,暫時仲係要靠人。
睇呢段 code,你覺得有冇問題?
def authenticate(username, password, db):
query = f"SELECT password_hash FROM users WHERE username = '{username}'"
row = db.execute(query).fetchone()
if row is None:
return False
stored_hash = row[0]
input_hash = hashlib.md5(password.encode()).hexdigest()
return input_hash == stored_hash
行到,邏輯通順,做到登入驗證。多數人 review 完會寫 "LGTM"(Looks Good to Me),然後 merge。
呢段 code 有 3 個安全漏洞。
SQL injection、MD5 弱 hash、timing attack。三個,一個都唔少,全部收埋喺呢 10 行入面,而且每一個喺 production 環境都係真實嘅威脅。
呢個唔係我作嘅例子。呢段 code 嚟自 GitHub 上面一個專門寫畀 AI 睇嘅 Code Review 指令集——h4vzz/awesome-ai-agent-skills 個 repository 入面嘅 Code Review Skill,佢用呢段 code 做 AI 嘅「教學樣本」。
我將呢個 Skill 由頭到尾讀咗一次。讀完之後,我意識到:多數人對 code review 嘅理解,同 Skill 裏面寫嘅,差咗一個關鍵步驟。

第一步,唔係睇 code
呢個係呢個 Skill 裏面令我最震撼嘅設計決策:
“喺檢查任何一行 code 之前,先理解作者想做啲乜。
Skill 嘅 workflow 第二步,原文係咁寫嘅:
“讀 commit messages、PR descriptions 同周圍嘅 code,去理解作者 intended 啲乜。呢個可以預防 false positives — 一個 reviewer 必須知道個目標,先至可以判斷 code 有冇達到目標。喺 proceed 之前,用一句話概括呢次變更。
「先將呢次變改用一句話概括,然後先開始評判。」
聽落好似廢話,但細心諗嚇你上次 review code 係咪咁做㗎?
多數人嘅 review 流程係:打開 diff,逐行掃,見到唔順眼嘅就 comment,睇完就 merge。
呢套流程有個天然嘅缺陷:你喺評判 code 嘅實現,但你唔知 code 嘅目標係乜。
結果就係誤傷大量。你覺得呢個抽象層多餘,但其實佢係為咗兼容舊 interface;你覺得呢個 variable name 奇怪,但其實係 domain term;你覺得呢個 query 可以優化,但其實佢運行頻率極低,根本唔喺關鍵 path。
Skill 嘅設計邏輯係:理解意圖,先至可以區分「code 冇達到目標」同「code 係你唔鍾意嘅風格但確實達到咗目標」。 前者一定要改,後者係噪音。
五個維度,唔係一個維度
等我哋返去嗰段 authenticate() 嘅例子。
一般人 review code,預設淨係喺一個維度上面轉:用唔用到。行到,邏輯正確,就過咗。
Code Review Skill 將評審維度顯式分成咗五類:
| 正確性 | |
| 安全性 | |
| 性能 | |
| 可讀性 | |
| 測試 |
呢個分類本身冇乜稀奇,好多 code review 規範都有類似嘅維度。真正有價值係 Skill 裏面對呢五個維度嘅priority 處理:
Skill 嘅 output format 規定咗三個 severity level:Critical / Warning / Info。
Critical 係「merge 前一定要 fix」,Warning 係「強烈建議但唔會 block」,Info 係「可以考慮嘅 improvement point」。
回到 authenticate() 嘅例子,Skill 畀出嘅結論係:
Summary: 2 critical, 1 warning, 1 info.
This function must not be deployed until the SQL injection and
hashing issues are resolved.
呢個分級機制解決咗 code review 裏面一個真實嘅溝通問題:**「你提咗 12 條意見,我唔知邊條非改不可。」**
當所有意見撈埋一齊,冇 priority,作者嘅本能反應係逐條討論,內耗大量時間。顯式分級之後,雙方都清楚:Critical 係底線,Warning 係對話空間,Info 係可以存檔嘅參考意見。

三個具體嘅陷阱,同佢哋背後嘅原因
從呢個 Skill 裏面,我揀咗三個令我覺得「原來如此」嘅具體設計細節。
陷阱一:N+1 query,係最常被漏掉嘅 performance 問題
Skill 裏面嘅第二個例子,係一段 JavaScript API code:
for (const order of orders.rows) {
const items = await db.query(
"SELECT * FROM order_items WHERE order_id = $1",
[order.id]
);
order.items = items.rows;
}
問題喺邊?
如果呢個 user 有 200 個 order,呢段 code 會執行 201 次 database query——1 次 main query + 每個 order 一次 subquery。
測試環境通常冇問題,因為測試數據少。Production 環境一旦 user 數據量上嚟,呢個 endpoint 會急劇變慢,而且幾乎揾唔到明顯 error,只係「感覺越來越慢」。
N+1 query 之所以容易漏,係因為 code logic 本身完全正確—— loop、query、拼數據,每一步都冇問題。問題喺整體 execution pattern,而唔係喺某一行。
Skill 對此嘅處理係:喺評審 performance 維度時,專門要求檢查「loop 入面有冇 database operation」呢個 pattern。
陷阱二:authentication check,總係喺 business logic 寫完之後先諗起
同樣係嗰段 order API:
const userId = req.query.userId;
const orders = await db.query(
"SELECT * FROM orders WHERE user_id = $1",
[userId]
);
userId 直接從 query string 讀取,冇驗證請求方有冇權限睇呢個 user 嘅 order。任何人只要知道目標 user 嘅 ID,就可以讀取佢嘅完整 order history。
呢類漏洞之所以頻繁出現,有一個心理原因:**developer 喺寫 business logic 時,默認自己係「有權限嘅人」**。Authentication 係 system-level 嘅 concern,唔係 function implementation 嘅 concern,所以天然容易被推到「之後再加」——然後就冇之後了。
Skill 將「missing authentication check」列為 Warning level,意思係:佢唔一定會導致立即 crash,但佢係一個真實嘅 security risk,必須喺 merge 前明確決策:一係加 authentication,一係 record 為 known risk 並 document 化。
坑三:SELECT * 睇落冇害,其實洩漏資訊
const orders = await db.query("SELECT * FROM orders WHERE user_id = $1", ...);
SELECT * 會 return 表入面所有 field,包括 created_at、soft delete 標記 deleted_at、internal status field 等等。呢啲 field:
增加咗 response 體積,喺高 concurrent 下消耗 bandwidth; 洩漏咗 internal implementation details,frontend 接收到 field 之後可能被 record 或 display; 喺 table structure 變更時產生隱性依賴,加一 column 就自動傳咗出去。
呢條被 Skill 列為 Info level——佢係「可以更好」,唔係「必須改」。但佢係一個值得喺 review 時提出、令作者有意識做決定嘅 point。

最值得記住嘅 Edge Case
Skill 裏面有一條 edge case 處理,睇落係小細節,但非常實用:
超過 1000 行嘅大 PR,點算?
Skill 嘅答案係:先警告作者,建議拆開,然後聚焦喺最高風險嘅 file 上面做深度 review,而唔係對所有 file 做淺 scan。
呢背後係一個真實嘅認知限制:一個人(或一個 AI)能夠有效 review 嘅 code 量係有上限嘅。1000 行嘅 PR,如果逐行 review,注意力分散之後,security vulnerability 反而更容易漏。集中火力打高風險區域,比平均用力更有效。
同上一期拆解嘅 Debugging Skill 類比一下——Debugging Skill 裏面有一條「一次只改一件事」,本質上係同一個底層邏輯:認知資源有限,系統設計嘅責任係將呢個限制納入考量,而唔係忽視佢。
呢個 Skill 同前幾篇嘅共同 pattern
讀完呢個 Skill,我發現咗一個喺成個 h4vzz/awesome-ai-agent-skills repository 裏面反覆出現嘅 design pattern:
每一個 Skill,都係用 structured workflow 對抗人(同 AI)嘅 default bias。
Debugging Skill 用「binary search isolation」對抗「靠直覺估 root cause」 Context Injection Skill 用「position management」對抗「隨意堆砌 context」 Code Review Skill 用「先理解意圖」對抗「直接評判 implementation」
呢啲都唔係新知識。多數有經驗嘅 engineer 直覺上知道「review 要理解 context」「debug 要 locate root cause」。
但 Skill 嘅作用唔係傳授新知識,而係將隱性嘅 engineering judgment顯式化、流程化,令 AI 能夠可預期地執行,而唔係依賴某次 prompt 寫得好唔好。
呢個令我想起一件事:一個經驗豐富嘅 engineer 同一個新手嘅差距,好大一部分唔係知識,而係習慣——邊啲 check 係 conditional reflex,邊啲陷阱唔需要踩就知道。 Skill 本質上係將呢種「有經驗嘅 engineer 嘅 conditional reflex」結構化,令 AI 都可以有同樣嘅 conditional reflex。
能夠被結構化嘅,Skill 可以承接。唔能夠被結構化嘅——例如「呢段 code 整體上有冇更好嘅 abstraction」——始終要靠人。

最後
嗰段有 3 個漏洞嘅 authenticate() function,最後一次被認真 review 係幾時?
我唔知,但我知:如果你嘅 review workflow 得一個維度,你會漏咗佢。
分級、分維度、先理解意圖——呢三件事,唔止係 AI 做 review 嘅規則,亦都係人做 review 嘅規則。
看這段代碼,你覺得有問題嗎?
def authenticate(username, password, db):
query = f"SELECT password_hash FROM users WHERE username = '{username}'"
row = db.execute(query).fetchone()
if row is None:
return False
stored_hash = row[0]
input_hash = hashlib.md5(password.encode()).hexdigest()
return input_hash == stored_hash
能跑,邏輯通順,實現了登錄驗證。大多數人 review 完會寫"LGTM"(Looks Good to Me),然後合併。
這段代碼有 3 個安全漏洞。
SQL 注入、MD5 弱哈希、計時攻擊。三個,一個都不少,全藏在這 10 行裏,而且每一個在生產環境都是真實的威脅。
這不是我編的例子。這段代碼來自 GitHub 上一個專門寫給 AI 看的 Code Review 指令集——h4vzz/awesome-ai-agent-skills 倉庫裏的 Code Review Skill,它用這段代碼做 AI 的"教學樣本"。
我把這個 Skill 從頭到尾讀了一遍。讀完之後,我意識到:大多數人對 code review 的理解,跟 Skill 裏寫的,差了一個關鍵步驟。

第一步,不是看代碼
這是這個 Skill 裏讓我最震動的設計決策:
“在檢查任何一行代碼之前,先理解作者想做什麼。
Skill 的工作流第二步,原文是這樣寫的:
“Read commit messages, PR descriptions, and surrounding code to understand what the author intended. This prevents false positives — a reviewer must know the goal before judging whether the code achieves it. Summarize the change in one sentence before proceeding.
"先把這次變更用一句話概括,然後才開始評判。"
聽起來像廢話,但仔細想想你上次 review 代碼是不是這麼做的?
大多數人的 review 流程是:打開 diff,逐行掃,看到不順眼的就評論,看完合併。
這套流程有個天然的缺陷:你在評判代碼實現,但你不知道代碼的目標是什麼。
結果就是誤傷大量。你覺得這個抽象層多餘,但其實它是為了兼容舊接口;你覺得這個變量名奇怪,但其實是領域術語;你覺得這個查詢可以優化,但其實它運行頻率極低,根本不在關鍵路徑。
Skill 的設計邏輯是:理解意圖,才能區分"代碼沒達到目標"和"代碼是你不喜歡的風格但確實達成了目標"。 前者必須改,後者是噪音。
五個維度,不是一個維度
讓我們回到那段 authenticate() 的例子。
一般人 review 代碼,默認只在一個維度上轉:能不能用。能運行,邏輯正確,就過了。
Code Review Skill 把評審維度顯式分成了五類:
| 正確性 | |
| 安全性 | |
| 性能 | |
| 可讀性 | |
| 測試 |
這個分類本身沒什麼稀奇,很多 code review 規範都有類似的維度。真正有價值的是 Skill 裏對這五個維度的優先級處理:
Skill 的輸出格式規定了三個嚴重級別:Critical / Warning / Info。
Critical 是"合併前必須修復",Warning 是"強烈建議但不阻塞",Info 是"可以考慮的改進點"。
回到 authenticate() 的例子,Skill 給出的結論是:
Summary: 2 critical, 1 warning, 1 info.
This function must not be deployed until the SQL injection and
hashing issues are resolved.
這個分級機制解決了 code review 裏一個真實的溝通問題:**"你提了 12 條意見,我不知道哪條非改不可。"**
當所有意見混在一起,沒有優先級,作者的本能反應是逐條討論,內耗大量時間。顯式分級之後,雙方都清楚:Critical 是底線,Warning 是對話空間,Info 是可以存檔的參考意見。

三個具體的坑,和它們背後的原因
從這個 Skill 裏,我挑出三個讓我覺得"原來如此"的具體設計細節。
坑一:N+1 查詢,是最常被漏掉的性能問題
Skill 裏的第二個例子,是一段 JavaScript API 代碼:
for (const order of orders.rows) {
const items = await db.query(
"SELECT * FROM order_items WHERE order_id = $1",
[order.id]
);
order.items = items.rows;
}
問題在哪?
如果這個用戶有 200 個訂單,這段代碼會執行 201 次數據庫查詢——1 次主查詢 + 每條訂單一次子查詢。
測試環境通常沒問題,因為測試數據少。生產環境一旦用戶數據量上來,這個端點會急劇變慢,而且幾乎找不到明顯報錯,只是"感覺越來越慢"。
N+1 查詢之所以容易漏,是因為代碼邏輯本身完全正確——循環、查詢、拼數據,每一步都沒問題。問題在整體執行模式,而不在某一行。
Skill 對此的處理是:在評審性能維度時,專門要求檢查"循環內是否有數據庫操作"這個模式。
坑二:鑑權檢查,總是在業務邏輯寫完之後才想起來
同樣是那段訂單 API:
const userId = req.query.userId;
const orders = await db.query(
"SELECT * FROM orders WHERE user_id = $1",
[userId]
);
userId 直接從 query string 讀取,沒有驗證請求方是否有權查看這個用戶的訂單。任何人只要知道目標用戶的 ID,就可以讀取他的完整訂單歷史。
這類漏洞之所以頻繁出現,有一個心理原因:**開發者在寫業務邏輯時,默認自己是"有權限的人"**。鑑權是系統級的關注點,不是功能實現的關注點,所以天然容易被推到"之後再加"——然後就沒有之後了。
Skill 把"缺少鑑權檢查"列為 Warning 級別,意思是:它不一定會導致立即崩潰,但它是一個真實的安全風險,必須在合併前明確決策:要麼加鑑權,要麼記錄為已知風險並文檔化。
坑三:SELECT * 看起來無害,其實泄露信息
const orders = await db.query("SELECT * FROM orders WHERE user_id = $1", ...);
SELECT * 會返回表裏所有字段,包括 created_at、軟刪除標記 deleted_at、內部狀態字段等等。這些字段:
增加了響應體積,在高併發下消耗帶寬; 泄露了內部實現細節,前端接收到字段之後可能被記錄或展示; 在表結構變更時產生隱性依賴,加一列就自動傳出去了。
這條被 Skill 列為 Info 級別——它是"可以更好",不是"必須改"。但它是一個值得在 review 時提出、讓作者有意識做決定的點。

最值得記住的 Edge Case
Skill 裏有一條邊界情況處理,看起來是小細節,但非常實用:
超過 1000 行的大 PR,怎麼辦?
Skill 的答案是:先警告作者,建議拆分,然後聚焦在最高風險的文件上做深度評審,而不是對所有文件做淺掃描。
這背後是一個真實的認知限制:一個人(或一個 AI)能有效評審的代碼量是有上限的。1000 行的 PR,如果逐行評審,注意力分散之後,安全漏洞反而更容易漏。集中兵力打高風險區域,比平均用力更有效。
和上期拆解的 Debugging Skill 類比一下——Debugging Skill 裏有一條"一次只改一件事",本質上是同一個底層邏輯:認知資源有限,系統設計的責任是把這個限制納入考量,而不是忽視它。
這個 Skill 和前幾篇的共同模式
讀完這個 Skill,我發現了一個在整個 h4vzz/awesome-ai-agent-skills 倉庫裏反覆出現的設計模式:
每一個 Skill,都在用結構化流程對抗人(和 AI)的默認偏差。
Debugging Skill 用"二分法隔離"對抗"靠直覺猜根因" Context Injection Skill 用"位置管理"對抗"隨意堆砌上下文" Code Review Skill 用"先理解意圖"對抗"直接評判實現"
這些都不是新知識。大多數有經驗的工程師直覺上知道"review 要理解上下文""debug 要定位根因"。
但 Skill 的作用不是傳授新知識,而是把隱性的工程判斷顯式化、流程化,讓 AI 能夠可預期地執行,而不是依賴某次提示詞寫得好不好。
這讓我想到一件事:一個經驗豐富的工程師和一個新手的差距,很大一部分不在知識,在習慣——哪些檢查是條件反射,哪些坑不需要踩就知道。 Skill 本質上是在把這種"有經驗的工程師的條件反射"結構化,讓 AI 也能有同樣的條件反射。
能被結構化的,Skill 可以承接。不能被結構化的——比如"這段代碼整體上有沒有更好的抽象方式"——還是得靠人。

最後
那段有 3 個漏洞的 authenticate() 函數,最後一次被認真 review 是什麼時候?
我不知道,但我知道:如果你的 review 流程只有一個維度,你會漏掉它。
分級、分維度、先理解意圖——這三件事,不只是 AI 做 review 的規則,也是人做 review 的規則。