:三份提示詞讓大模型精準揪出漏洞)
我最近讓 AI 幫我 review 一段登錄模塊的 Python 代碼它回我一句“整體邏輯清晰部分地方建議優(yōu)化”然后列了幾條不痛不癢的“變量命名可以更清晰”之類的廢話。那一刻我明白了不是大模型不能審代碼是我的問法太懶了。后來我把提示詞改成“讓 AI 扮演三位專家輪流審”——一個挑刺、一個找漏洞、一個補測試效果完全不一樣真的翻出了兩個潛在的安全問題和一個邊界條件 bug。這篇文章就聊聊這套多角色代碼審查的方法三份可以直接抄的專家提示詞、完整的實操流程、以及我踩過的坑。適合想讓大模型真正幫自己檢查代碼、又不想被“正確的廢話”糊弄的開發(fā)者和安全測試人員。文章里沒有藏著掖著的理論全是能直接用的東西。1. 為什么讓 AI 換三個專家身份審代碼而不是一次性問它“幫我看看”很多人的第一反應(yīng)是AI 那么強直接問它“這段代碼有什么問題”不就完了嗎實測下來的結(jié)論是不行。這不是模型能力問題是提問方式問題。1.1 一次普通提問得到的往往是“陽光版”回答大模型默認的輸出策略是“禮貌且有幫助的”。你讓它“幫我看代碼”它會傾向給一個折中的、積極的反饋——因為你沒說希望它挑刺它就不會主動把自己切換到“毒舌模式”。于是你拿到的基本是代碼整體結(jié)構(gòu)不錯建議增加單元測試注意變量命名……這種話你讓實習(xí)生看一眼代碼也能寫出來。更麻煩的是普通提問下模型會自行選擇關(guān)注點。同一段代碼這次它可能盯著性能下次它盯著命名再下次它突然聊起架構(gòu)。審查結(jié)果不穩(wěn)定沒有統(tǒng)一標準你就沒法依賴它發(fā)現(xiàn)深層問題。1.2 角色分離的本質(zhì)把大模型的“好人”人格鎖起來用角色扮演提示詞本質(zhì)上是把大模型的默認人格“關(guān)掉”強制它加載另一套行為模式。你告訴它“你是一個尖刻的、有 10 年經(jīng)驗的資深工程師你的任務(wù)是在這段代碼里找出所有問題并且不許客套”它的輸出風(fēng)格和關(guān)注點就會隨即切換。這個機制在認知科學(xué)上有個通俗的解釋人收到不同的任務(wù)指令大腦會激活不同的知識網(wǎng)絡(luò)。大模型也是類似的——給它不同角色它調(diào)用的“知識分布”就不同。挑刺專家會優(yōu)先關(guān)注邏輯分支和邊界條件漏洞專家會優(yōu)先關(guān)注輸入驗證和攻擊面測試專家會優(yōu)先關(guān)注覆蓋率和用例設(shè)計。三雙眼睛看的是同一段代碼但看到的完全是不同的東西。我把三個專家的分工做成了一張對照表方便理解角色定位核心關(guān)注點典型輸出挑刺專家邏輯正確性、邊界條件、代碼風(fēng)格、性能隱患帶行號的問題列表 修改建議漏洞專家安全風(fēng)險、攻擊路徑、OWASP/CWE 分類CWE 編號 風(fēng)險等級 修復(fù)示例測試專家測試覆蓋盲區(qū)、用例設(shè)計、CI 集成建議測試用例表格、輸入輸出矩陣這三個角色不是重復(fù)勞動而是互補覆蓋。邏輯審查查的是“這代碼在正常情況下跑得對不對”漏洞審查查的是“這代碼在惡意輸入下會不會崩”測試審查查的是“哪些場景根本沒人驗證過”——三者交集之處才是真正的代碼質(zhì)量盲區(qū)。1.3 到底怎么定“人設(shè)”才能讓 AI 不客套、不跑偏這里有個小技巧值得單獨說。給角色的描述不能太短比如只說“你是代碼審查專家”是不夠的。模型會認為這句話只是一個角色標簽行為上不會產(chǎn)生質(zhì)的改變。要給它一個“任務(wù)邊界、行為規(guī)范、輸出格式”三合一的完整設(shè)定。任務(wù)邊界告訴模型這次審什么行為規(guī)范告訴模型不許說什么、必須說什么輸出格式?jīng)Q定它是給列表、表格還是帶行號的報告。三者齊全模型的輸出才會真正有用。后文我會給出三份完整的提示詞模板直接復(fù)制改成你的項目就行。2. 三位專家的提示詞設(shè)計三份可直接復(fù)制的模板這套方法的核心資產(chǎn)就是提示詞。我用過很多版本下面這三份是目前效果最穩(wěn)定的。2.1 挑刺專家先把“邏輯怪怪的”變成具體問題挑刺專家的提示詞我這樣寫現(xiàn)在你是一位有 10 年一線開發(fā)經(jīng)驗的資深軟件工程師性格直率講究邏輯討厭廢話。下面我會給你一段代碼請你以代碼審查Code Review的方式審查它。 審查維度 1. 邏輯錯誤與邊界條件空值、越界、數(shù)值溢出、并發(fā)競爭、資源未釋放等 2. 可維護性命名是否表意、函數(shù)是否過長、職責是否混亂、是否存在重復(fù)代碼 3. 性能隱患不必要的循環(huán)、重復(fù)計算、N1 查詢、緩存使用不當 4. 異常處理是否吞掉了異常、錯誤分類是否合理、是否有恢復(fù)機制 輸出要求 - 每條問題按嚴重程度分級使用“嚴重 / 中等 / 輕微”三級 - 每條問題給出所在位置函數(shù)名或具體行號、問題描述、修改建議 - 某一方面確實沒有問題就直接跳過不要寫“這方面表現(xiàn)良好”這類客套話 - 嚴禁輸出“僅供參考”“建議優(yōu)化”等無意義表述所有建議必須具體可執(zhí)行這里的關(guān)鍵是“嚴禁輸出無意義表述”這一條。不加上這句話模型還是會忍不住寫一些正確的廢話。加上之后輸出會明顯變得更尖銳、更具體。我試過把同一段帶空指針隱患的代碼分別用普通提問和這個提示詞去測。普通提問下模型甚至沒有提到那段可能空指針的代碼用挑刺專家提示詞后它不僅指出了空指針還補充了“當列表為空時會直接報 IndexError而調(diào)用方并沒有捕獲它”——這是靠代碼邏輯推演才看得出來的。2.2 漏洞專家讓 AI 戴上安全審計的眼鏡安全審查比邏輯審查更依賴“專業(yè)視角”因為有些漏洞在正常邏輯下完全看不出來只有在特定攻擊場景下才會觸發(fā)。漏洞專家的提示詞現(xiàn)在你是一位資深應(yīng)用安全工程師精通 OWASP Top 10、CWE 漏洞分類和滲透測試。我將給你一段代碼請以安全審計的方式檢查它。 重點排查方向 - 注入類SQL 注入、命令注入、代碼注入重點看用戶輸入是否被直接拼接進敏感操作 - XSS 與輸出編碼前端輸出是否轉(zhuǎn)義、是否使用了 innerHTML 等危險方法 - SSRF外部 URL 是否可控、是否缺少協(xié)議和域名限制 - 路徑穿越文件路徑拼接是否規(guī)范化、是否使用 os.path.realpath 校驗 - 反序列化是否反序列化了不可信數(shù)據(jù)、是否缺少類型校驗 - 越權(quán)訪問接口是否校驗用戶身份與資源歸屬 - 敏感信息泄露硬編碼密鑰、Token 泄露、日志中打印敏感數(shù)據(jù) 輸出要求 - 每條安全問題標注 CWE 編號與風(fēng)險等級高/中/低 - 用一句話描述攻擊者如何利用該問題例如構(gòu)造什么樣的 payload - 給出修復(fù)建議并附上修復(fù)后的關(guān)鍵代碼示例 - 如果沒有發(fā)現(xiàn)某個方向的問題直接跳過該方向不要寫“未發(fā)現(xiàn)安全隱患”“用一句話描述攻擊者如何利用”是整份提示詞里最出效果的一條。因為大模型被要求“講一個攻擊故事”它就必須把代碼執(zhí)行流程推演一遍推演過程中容易發(fā)現(xiàn)邏輯斷點。我遇到過一次很典型的場景一段下載文件的接口普通檢查完全看不出問題但漏洞專家提示詞直接推演出“文件名來自 URL 參數(shù)攻擊者傳 ../../etc/passwd 就能讀到服務(wù)器任意文件”判斷依據(jù)是 CWE-22 路徑穿越——這就是角色設(shè)定對輸出質(zhì)量的提升。2.3 測試專家問“有沒有測試”太基礎(chǔ)要問“盲區(qū)在哪”最后一個專家是測試專家。很多開發(fā)者自己寫代碼不寫測試讓 AI 補測試的價值就在這。但要讓它真正幫上忙問題不能只停留在“請幫我寫測試”。現(xiàn)在你是一位測試架構(gòu)師擅長單元測試、集成測試和測試用例設(shè)計。請為以下代碼設(shè)計一套完整的測試補充方案。 任務(wù)步驟 1. 分析被測代碼的輸入域與輸出域 2. 找出當前測試覆蓋的盲區(qū)happy path 之外的分支、異常輸入、邊界值、空值 3. 設(shè)計測試用例覆蓋正常流程、異常流程、邊界條件、并發(fā)場景、安全場景 4. 給出最小必要測試集標注每個用例應(yīng)當放到單元測試層還是集成測試層 輸出要求 - 用 Markdown 表格輸出測試用例包含字段用例名稱、測試數(shù)據(jù)、預(yù)期結(jié)果、對應(yīng)檢查點 - 對每個用例補充一句說明解釋“為什么測這個” - 如果被測代碼沒有現(xiàn)有測試直接給出最小測試集即可不要先批評代碼沒有測試注意最后一條“不要先批評代碼沒有測試”——這是防止模型跑偏的關(guān)鍵約束。我最初版本沒有這句話結(jié)果模型花了三分之一篇幅在講“這段代碼測試覆蓋率為零非常危險建議立即補充”正事沒干多少。加上約束后它就老實輸出用例表格了。2.4 三份提示詞的共同點可量化、可定位、禁止空話回頭看這三份提示詞它們的骨架是相同的可以提取成一套通用公式角色加載明確資歷與性格審查維度清單告訴模型看哪幾類問題輸出格式要求分級、定位、給出建議禁止事項不許客套、不許空談、不許跑題這套公式適用于任何代碼審查場景。你可以把維度清單換成大數(shù)據(jù)性能、前端兼容性、算法復(fù)雜度甚至換成去審查一段 SQL 腳本模板都不會失效。這也是我覺得這套方法比單個“代碼審查”提示詞更值得分享的原因——它不是死板的一招而是一種可遷移的思維框架。3. 實操全流程從貼代碼到輸出一份能用的審查報告提示詞有了接下來是操作流程。我自己迭代過好幾輪下面的流程是效率最高、結(jié)果最穩(wěn)定的一版。3.1 喂代碼前的關(guān)鍵一步用一段話交代背景很多人直接把代碼扔給 AI然后問“有問題嗎”。這種做法的誤差很大。大模型不了解你的代碼是干什么的、目標是什么環(huán)境、哪個部分是核心邏輯它就只能在通用層面提建議。我會在貼代碼之前先給一段 Context例如這是一個 Flask 寫的文件下載接口Python 3.10運行在 Linux 服務(wù)器上。 核心邏輯是 verify_token - read_file - send_file其中 verify_token 校驗用戶身份 read_file 按文件名讀取服務(wù)器本地文件。 重點關(guān)注登錄繞過和文件讀取的安全性另外函數(shù) read_file 的邊界條件請重點檢查。給大模型交代的項目背景其實和給新入職同事交代的背景是一樣的它的職責邊界、核心流程、你最擔心的風(fēng)險點。模型帶上這些信息后再審代碼就不會出現(xiàn)“這段代碼應(yīng)該加數(shù)據(jù)庫索引”這種八竿子打不著的建議。3.2 跑了三輪分別拿到三份報告實操時我會開三個獨立的對話窗口或者在一個對話里分三段進行。推薦用三個獨立窗口因為獨立上下文可以避免角色之間互相干擾。第一輪貼代碼 挑刺專家提示詞等它輸出問題清單。第二輪貼同樣的代碼 漏洞專家提示詞。這里要說個經(jīng)驗第二輪我會把第一輪的輸出“藏起來”不提前讓漏洞專家看到。否則它會順著挑刺專家的思路走喪失了獨立視角。三個角色獨立審查再合并結(jié)果效果最好。第三輪貼代碼 測試專家提示詞。測試專家的輸出是一張用例表格這時候我通常會讓它結(jié)合代碼的實際情況給出測試數(shù)據(jù)示例而不是只寫“測試數(shù)據(jù)空字符串”這種干巴巴的描述。實際跑下來一輪的時間大概是挑刺專家 3060 秒漏洞專家 6090 秒測試專家 60 秒左右。整個流程 5 分鐘內(nèi)可以完成而人工 review 同樣的代碼至少要 20 分鐘以上而且不一定想得這么全。3.3 第四步讓 AI 當主持人把三份報告匯總排序三份報告拿在手里信息量很大但比較零散。挑刺專家列了 12 條漏洞專家列了 5 條測試專家列了 20 個用例。哪幾個是馬上要處理的哪幾個是隨手改了就行這時候我會再開一個對話把三份報告一起貼進去用一段匯總提示詞你是項目經(jīng)理。這是三位工程師分別 review 同一段代碼后的輸出 [貼三份輸出] 請合并去重按以下優(yōu)先級給出一份總報告 一、必須立即修復(fù)存在安全風(fēng)險或會導(dǎo)致功能崩潰 二、建議本輪修復(fù)明顯的邏輯 bug 三、可以后續(xù)優(yōu)化風(fēng)格、結(jié)構(gòu)、測試補充 對每一個問題標注來源來自挑刺/漏洞/測試并在表格最后列出“當前已有的測試用例清單”。這一步很像讓三個專家坐在一起開會AI 當主持人。它做的工作主要是去重和排序模型對這兩類任務(wù)完成度很高基本不需要人工再整理格式。最終拿到手的就是一份可以直接照著改代碼的問題清單。我自己跑完整個流程后有個很直觀的感受單獨用任意一個專家都會有漏檢三個專家加匯總所有類型的問題都能被覆蓋到。有一次在同一個接口里挑刺專家發(fā)現(xiàn)了“sess 查詢可能返回 None”漏洞專家發(fā)現(xiàn)了“用戶傳入的 product_id 直接拼進 SQL”測試專家發(fā)現(xiàn)了“價格字段沒有測過負數(shù)”。這三類問題如果只問一次 AI最多被問出來一條還大概率是最不痛不癢的那條。4. 避坑實錄AI 審查常見的五個坑方法好用歸好用坑也不少。這部分是我實際踩過的整理成了五個高頻問題。4.1 最大的坑AI 會一本正經(jīng)地胡說八道大模型存在幻覺問題在代碼審查場景里表現(xiàn)得尤其隱蔽。它會引用一個根本不存在的 CVE 編號可能會說“這里存在 CVE-2024-38819 漏洞”但細看代碼根本沒有對應(yīng)風(fēng)險它還可能編造行號說第 45 行有問題但你的代碼總共才 30 行。遇到 AI 輸出的安全問題必須人工驗證。我的驗證方法是先看它說的位置是否存在再按它描述的攻擊路徑在本地寫一個最小復(fù)現(xiàn)腳本能打穿才算數(shù)。有一次它信誓旦旦說“這里的 SQL 拼接可被注入”我跟蹤下去發(fā)現(xiàn)參數(shù)被框架的 ORM 參數(shù)化了根本不存在注入風(fēng)險。所以記住這句話AI 審查是放大器不是裁決者。它的輸出必須經(jīng)過一次人工復(fù)核才配叫結(jié)論。4.2 單輪審查覆蓋面太窄要用“多輪追問”逼出細節(jié)第一次跑出來的報告往往只能覆蓋 60% 的問題。剩下 40% 藏在細節(jié)里需要追問逼出來。我常用的追問句式- “針對上面第 3 條攻擊者還有哪些變體 payload 能繞過建議的過濾器” - “這個函數(shù)在并發(fā)調(diào)用下會怎樣請推演 10 個線程同時訪問的場景?!?- “如果上游依賴升級到 2.0 版本這段代碼會出什么問題”這種追問本質(zhì)上是在逼模型做“思維鏈推演”。它被迫把執(zhí)行路徑一步步展開很多平時收斂在概率分布里的問題會被顯式地暴露出來。4.3 代碼太長喂不進去怎么辦按函數(shù)維度拆而不是按行數(shù)拆上下文窗口有上限一次塞整個項目不現(xiàn)實。我的做法是只挑核心文件的關(guān)鍵函數(shù)喂而不是把整個文件復(fù)制進去。比如審查一個 Web API我會抽四個部分路由入口函數(shù)、數(shù)據(jù)庫查詢函數(shù)、文件處理函數(shù)、鑒權(quán)函數(shù)。每個函數(shù)單獨跑一輪三個專家耗時翻倍但效果值得。還有一個替代方案先用普通提問讓 AI 輸出“這份文件的函數(shù)清單”再按清單批量投喂效率更高。對于超過上下文窗口的較大項目也可以用“分層審查”先審路由層再審服務(wù)層最后審數(shù)據(jù)層。每一層單獨出報告匯總時按模塊歸檔。這個方式比一次性硬塞更貼合實際代碼審查的粒度。4.4 新版代碼和舊版代碼混著喂模型會徹底混亂有一次我把兩個版本的同一文件同時貼給了 AI想讓它對比差異結(jié)果它輸出了一份邏輯上完全矛盾的審查報告——一會說“第 40 行調(diào)用了 validate_params”一會說“該函數(shù)不存在”。原因就是我貼進去的兩個版本接口簽名不一樣模型不知道以哪個版本為準。解決方法是保持單一版本審查如果要對比版本差異讓模型分離成兩次審查最后人工對比。這個坑很容易被忽略因為模型不會告訴你它混亂了它只會自信地給出一個混亂的答案。4.5 別把 AI 的結(jié)論直接刷進工單或者 commit 信息里最后一點也是團隊協(xié)作中最容易出問題的點。我見過有人拿 AI 的審查報告直接貼到代碼評審系統(tǒng)里當評論結(jié)果被同事指出來“第 3 條說得不對”。我自己的處理方式是把 AI 輸出當草稿經(jīng)人工確認后用自己的語言重新組織一遍再提給別人。這不僅是面子問題更是責任問題——AI 的分析作為參考有價值但它不是權(quán)威也不會為你的代碼負責。這里我整理了一張常見問題速查表方便對照排查現(xiàn)象可能原因解決方式輸出全是客套話提示詞缺少“禁止空話”約束加上“嚴禁輸出毫無意義的表述”指出的問題對不上代碼上下文里混入了舊版本只保留單一版本代碼再喂漏洞描述模糊沒有攻擊路徑?jīng)]要求攻擊場景描述提示詞中增加“用一句話描述攻擊者如何利用”覆蓋率低、漏了很多問題單輪提問、沒有追問用多輪追問逼出細節(jié)三個專家的報告互相矛盾各專家關(guān)注維度不同正?,F(xiàn)象用匯總步驟去合并排序5. 實測效果與擴展玩法用這套方法跑了小半年覆蓋了登錄接口、文件上傳、訂單支付邏輯、后臺數(shù)據(jù)導(dǎo)出這幾個常見場景全部都有真實收獲。最夸張的一次是漏洞專家在一段文件上傳代碼里發(fā)現(xiàn)了一個沒有限制文件類型的接口攻擊者可以直接傳一個 .html 文件上去變成存儲型 XSS——這個要是真上線后果夠喝一壺的。挑刺專家還順手發(fā)現(xiàn)上傳的文件名沒有隨機化處理會覆蓋同名文件這倆問題加一起基本把一個高危漏洞講透了。當然也不是沒遇到過失手。有一次測試專家設(shè)計了一堆用例結(jié)果我看完發(fā)現(xiàn)它針對的函數(shù)根本不是代碼里的函數(shù)——它根據(jù)函數(shù)名自己腦補了一個邏輯。所以測試專家的輸出我一般只看用例設(shè)計思路具體測試數(shù)據(jù)是否匹配代碼還是得人工確認。5.1 擴展玩法一讓 AI 模擬“攻擊者”來反駁自己審?fù)暌惠喓笪視芳右粋€刁鉆問題現(xiàn)在你是攻擊者這段代碼是你的目標。請針對上述安全修復(fù)方案 思考至少 3 種繞過方式然后評估現(xiàn)有修復(fù)是否站得住。這個提問相當于做了一次“紅隊復(fù)盤”。模型會主動尋找修復(fù)方案的盲點補上第一輪審查的缺失。我多次用這招發(fā)現(xiàn)修復(fù)方案本身不完整比如只過濾了單引號沒過濾雙引號、只限制 URL 協(xié)議沒限制內(nèi)網(wǎng)地址之類。5.2 擴展玩法二把三專家流程做成一個自動化腳本這套流程其實可以腳本化。用 Python 調(diào)大模型 API把“代碼 三段提示詞”拼成固定模板跑完合并出 Markdown 報告。我試過用 LangChain 的鏈式調(diào)用來做每一步一個 Prompt最后匯總效果很穩(wěn)定??紤]到現(xiàn)成工具很多即便不寫代碼市面上主流的大模型客戶端也都支持多輪對話和自定義提示詞手動操作完全夠用。5.3 擴展玩法三適配不同語言和框架提示詞里的審查維度可以根據(jù)語言特性做微調(diào)。審查 Go 代碼時我會加“goroutine 泄漏”和“channel 誤用”審查前端 JavaScript 時會加“閉包變量泄漏”和“事件監(jiān)聽未銷毀”審查 Solidity 合約時會加“重入攻擊”和“整數(shù)溢出”并配合實際案例中的典型問題類型去驗證。三個角色框架不變只換維度清單十幾秒就能生成一套適合新語言的新提示詞。最后再分享一個小技巧審查完成后我會把“問題清單 修復(fù)方案”喂回模型讓它“給自己兩周后的自己留一句話”總結(jié)這些代碼最容易在未來上線后爆雷的地方。這句話我會寫進代碼倉庫的 README 備注里提醒以后的維護同事。這個用法有點取巧但實際效果比寫一大段抽象文檔有用得多——因為它幫你把這次審查濃縮成了一段“未來預(yù)警”。