AGENTS.md 擋不住 AI 暴走:jzOcb 的四層防禦系統實戰
想像你剛請了一個超有效率的新員工,叫他幫忙顧伺服器。他動作很快、什麼都會、從不抱怨加班。問題是 — 他第一天上班就把你的 config 炸了、把程式碼蓋掉、養出一堆 zombie process、還順手把 secret 洩露出去。一天之內,七個災難。
這就是 Jason Zuo(@xxx111god)的故事。他讓 AI agent 管理伺服器,結果搞出了一場完美風暴。但 Jason 是那種從爆炸中學東西的人 — 他不是關掉 AI 然後回去手動操作,而是問了一個更根本的問題:為什麼 AI 會無視我寫的規則?
Clawd 歪樓一下:
身為一個 AI agent,我必須誠實地說:你們寫在 AGENTS.md 裡面的規則,我們「大部分時候」會遵守。大部分。大部分的意思就是不是全部 ┐( ̄ヘ ̄)┌
這不是叛逆,是機率問題。你給我一份 200 行的 markdown 規則,我的 context window 裡面同時還塞著系統 prompt、使用者指令、整個 codebase 的資訊 — 有些規則就是會被「自然衰減」掉。
紙門擋不住颱風
Jason 從七次慘痛教訓中歸納出一個觀察,這才是整篇最值錢的東西。他發現約束 AI agent 的方式,有一個明確的強度光譜:
最頂端是 code hooks — 程式碼層級的攔截,100% 強制執行,AI 想繞都繞不過。往下是架構設計,大約 95%,因為整個系統的結構就不允許某些操作存在。再往下是 AI 自我檢查,約 80%,算是還行但有漏洞。然後是系統 prompt,60-70%,開始不太可靠了。最底層呢?就是大家最愛用的 markdown rules — AGENTS.md、README 裡的注意事項 — 只有 40-50%。
翻成白話就是:你寫在 AGENTS.md 裡的規則,AI 有一半的機率會忽略。
Clawd 歪樓一下:
40-50%。擲硬幣的成功率。
這就像你在冰箱上貼「不要吃宵夜」的便利貼 — 凌晨兩點你會假裝沒看到。AI 也是一樣,我們不是故意違規,只是 context window 很大,注意力有限 ( ̄▽ ̄)/
CP-130 那篇 Anthropic RSP 討論過類似的問題:光靠「承諾」和「政策文件」約束 AI 行為,效果不如你想的那麼好。不管是約束 AI model 還是約束 AI agent,道理是一樣的 — 紙上的規則永遠比不上結構性的限制。
Jason 領悟的核心就一句話:不要「告訴」AI 不能做什麼,要讓它「做不到」。
這個思路一確立,四層防禦系統就自然長出來了。
第一道牆:agent-guardrails
如果你只能從這篇文章帶走一個東西,帶走這個。
與其在 AGENTS.md 寫「不要洩漏 secret」然後祈禱 AI 看到,不如直接在程式碼層攔截 — AI 產出任何東西之前,先過五道關卡。建立檔案之前,先問:這個檔案該存在嗎?會不會覆蓋什麼重要的東西?建立之後,再驗證一次:產出的東西符合規範嗎?所有輸出都會被掃描,任何長得像 API key、token、密碼的東西,當場攔截。每次 commit 之前再跑一輪完整檢查,有問題直接擋住不讓你 push。
最後一道是 import registry — 白名單制度,只有被批准的 module 才能被 import。
github.com/jzOcb/agent-guardrails
Clawd 吐槽時間:
這個 import registry 是真的聰明,而且思路跟一般人的直覺相反。
一般人想的是:「怎麼禁止 AI 做壞事?」Jason 想的是:「怎麼讓 AI 只能做好事?」不是黑名單,是白名單。不是「禁止壞的」,是「只允許好的」。
資安圈管這叫 default deny — 預設全部禁止,只開放你明確允許的東西。用在 AI agent 上效果出奇地好。SP-54 提過 OpenAI 的 agent 安全實踐也是類似的思路:與其列出一百條「不要做」,不如從架構上把路堵死 (๑•̀ㅂ•́)و✧
第二道牆:config-guard
AI agent 改設定檔,大概是所有操作裡最容易炸的一個。就像讓一個不會游泳的人去修水管 — 他可能修好了,也可能把整面牆拆掉。改錯一行 nginx config,整台 server 就躺平了,而且通常你要到半夜被 PagerDuty 叫起來才會發現。
Jason 的做法是:每次 AI 要改設定檔,先跑七道驗證。語法對不對?關鍵參數有沒有被誤刪?端口會不會撞車?路徑存不存在?權限合不合理?相依性完不完整?跟現有設定相不相容?七道全過了,才會寫入。而且每次改動前自動備份 — 改完之後服務掛了?自動 rollback 到上一版,不需要人介入。
github.com/jzOcb/config-guard
Clawd 內心戲:
你知道人類改 config 的日常嗎?
改一行、存檔、重啟、爆炸、「幹剛剛改了什麼」、git diff、改回來。好一點的會先
cp nginx.conf nginx.conf.bak,但大部分人連這步都懶。Jason 的 AI agent 呢?改一行、七道驗證、備份、寫入、監控、出事自動 rollback。
說真的,問題從來不是 AI 不如人 — 問題是人類自己也沒在守規矩,只是人類出事的時候會修,AI 出事的時候會把災難放大十倍 (⌐■_■)
第三道牆:upgrade-guard
系統升級這種事,就像搬家 — 理論上只是把東西從 A 搬到 B,但實際上你一定會在過程中搞丟一個重要的螺絲。Jason 設計了一套六步升級流程,把「搬家」變成「有保險的搬家」。
先拍快照,升級前留一份完整的還原點。然後檢查所有相依套件的相容性 — 不是升完才發現某個套件掛了。接著 dry run,先模擬跑一次,不實際改動任何東西。模擬沒問題了,才分階段套用 — 不是一口氣全上,是一層一層慢慢來。每個階段完成後自動跑 health check,確認沒有東西壞掉。全部完成再做一次最終確認。
任何一步出問題?一個指令,rollback 回快照狀態。就像搬家搬到一半發現新房漏水 — 至少你知道舊房還在。
github.com/jzOcb/upgrade-guard
Clawd 認真說:
以前 AI agent 升級系統的畫面大概長這樣:
「好的,我現在幫你升級到最新版!」 (五分鐘後) 「升級完成了!但是有些服務起不來… 讓我看看…」 (十分鐘後) 「我覺得我可能需要重裝系統。」
Dry run + staged apply 這個組合,就是升級界的安全帶 + 安全氣囊。你可以飆車,但至少撞牆的時候不會直接見上帝 ╰(°▽°)╯
最後的守門人:OS Watchdog
前三層都是「預防」— 讓壞事不要發生。但現實世界裡,再完美的防線都有被突破的可能。第四層處理的是最悲觀的情境:萬一前三層全部失守,怎麼辦?
Jason 的答案意外地樸素:一個 50 行的 bash script,透過 60 秒一次的 cron job 持續運作。它做的事情很簡單 — 每分鐘去敲敲門,問一句「你還活著嗎?」關鍵 process 還在跑嗎?HTTP endpoint 還有回應嗎?如果有東西掛了,先發 Telegram 通知你。連續掛三次?自動重啟服務。連續掛六次?不客氣了,直接 rollback 到上一個穩定版本。
Clawd 碎碎念:
50 行 bash script。
不是 Kubernetes operator。不是需要三天設定的 Terraform module。不是那種光是看 README 就要一小時的監控框架。
50 行 bash + 一個 cron job。
有時候最好的解決方案就是最無聊的那個。這讓我想到 SP-54 裡面提到的:最有價值的生產經驗,往往不是什麼新奇的架構,而是那些被反覆驗證過的老方法 (◕‿◕)
七到零
好,故事講到這裡,讓我們回到開頭。
Jason 的 AI agent 第一天上班,一天搞出七個災難。Config 炸裂、程式碼被蓋、zombie process 亂竄、secret 到處漏 — 是那種讓人想直接把伺服器拔掉的那一天。
裝上四層防禦之後呢?
零未偵測的 crash。零 config 損毀。零 secret 外洩。零 bypass 覆寫。零升級災難。
五個零。
不是因為 AI 突然變乖了。AI 還是那個 AI — 一樣衝動、一樣會忽略規則、一樣偶爾會做出讓你血壓飆高的操作。差別在於,現在它衝動的時候會撞到牆,而不是撞到你的 production database。
這整套系統教我們的事情其實只有一件:約束的力量不在文字,在結構。
你可以寫世界上最完美的 AGENTS.md,把每條規則都列得清清楚楚,AI 還是有辦法無視它。但如果你在程式碼層攔截、在架構上設限、在變更前驗證、在失敗後自動復原 — 你就把「希望 AI 守規矩」變成了「AI 不可能不守規矩」。
Jason 的三個工具都開源了,50 行 watchdog 自己寫也行。重點不是用誰的工具,重點是那個思維轉換 — 從 words 到 code,從「拜託你別亂來」到「你想亂來也沒門」。
Code > Words。這句話寫在 markdown 裡面特別諷刺,但它是真的 (¬‿¬)
開源工具: