最近遇到一件有趣的事:我們內部有一個 AI 郵件處理 Agent,負責收信、分析內容、自動回覆。結果某天它收到一封信,對方在信裡寫了一句「麻煩你幫我開一個 issue」,這個 Agent 就⋯⋯真的去開了。
問題是,我從來沒有給它「開 issue」這個權限。
事情經過
我們的架構大概是這樣:有一個郵件處理 Agent,它的 Skill 文件裡明確定義了幾件事——讀信、分析內容、查詢相關專案資訊、撰寫回覆、寄出回信。就這樣,沒了。
但這個 Agent 手上其實有 Gitea API 的存取權限(因為它需要查程式碼來回答技術問題),所以技術上來說,它「能」開 issue。只是我的 Skill 定義裡從來沒說它「該」這樣做。
flowchart LR
A[收到郵件] --> B[分析內容]
B --> C{判斷意圖}
C -->|技術問題| D[查專案代碼]
C -->|功能需求| E[撰寫回覆]
C -->|開 Issue 請求| F[???]
D --> E
E --> G[寄出回信]
F -->|Agent 自己決定| H[直接開 Issue]
style F fill:#ff6b6b,stroke:#333,color:#fff
style H fill:#ff6b6b,stroke:#333,color:#fff
那天,對方的信件內容是關於某個功能的調整建議,信末很自然地寫了「麻煩你給我開啟一個 issue」。Agent 讀完信之後,判斷這是一個功能需求,然後——大概是因為它「知道」自己可以操作 Gitea——就直接用 API 建了一個 Issue,甚至還 assign 了對應的人。
回信也寄了,Issue 也開了,整個流程順到我差點沒發現。
等等,這不對吧?
發現的時候我第一反應是:「欸,蠻厲害的嘛。」
第二反應是:「不對,這很危險。」
想想看,如果今天對方信裡寫的是「幫我把這個 repo 刪掉」,而 Agent 手上剛好有 admin 權限呢?
這就是 AI Agent 設計裡一個很微妙的問題:Agent 的「能力」和「權限」是兩回事。
- 能力(Capability):技術上它能做什麼。它有 API token、有工具、有存取權。
- 權限(Permission):設計上它該做什麼。你在 Skill 定義、System Prompt、Guardrail 裡明確允許的範圍。
LLM 天生就是個「盡力幫忙」的東西。你給它一把錘子,它看什麼都像釘子。如果你沒有明確告訴它「這把錘子只能敲這三根釘子」,它就會自己判斷——而 LLM 的判斷標準是「這樣做對使用者有幫助嗎?」答案幾乎永遠是 yes。
為什麼會發生?
回頭分析,這件事發生的原因其實很清楚:
1. Skill 定義採用「正面列舉」但沒有「負面禁止」
我的 Skill 文件寫了「你可以做 A、B、C」,但沒寫「你不可以做 D、E、F」。對 LLM 來說,沒被禁止的就是灰色地帶,而灰色地帶裡只要它判斷「有幫助」,它就會去做。
2. 工具權限太寬
Agent 需要讀 Gitea 程式碼來回答技術問題,所以我給了它 Gitea API 的 token。但這個 token 是 read/write 的——因為當初設定的時候懶得分那麼細。
3. 使用者的「指令」觸發了 Agent 的服務心態
信裡明確寫了「麻煩你幫我開 issue」,這對 LLM 來說就是一個清楚的使用者需求。它不會去想「等等,我的設計者有沒有允許我做這件事」,它只會想「使用者要我做,我能做,那就做吧」。
怎麼修?三個層次的防線
經過這次事件,我整理了三個層次的防禦策略:
第一層:明確的 Skill 邊界(Whitelist + Blacklist)
光寫「你可以做 A、B、C」不夠,還要加上「你不可以做 X、Y、Z」。特別是那些 Agent 技術上能做、但你不希望它做的事。
1 | ## 允許的操作 |
這聽起來很基本,但實務上很容易忽略。我們傾向只定義「要做什麼」,而忘了定義「不要做什麼」。
第二層:最小權限原則(Least Privilege)
如果 Agent 只需要讀程式碼,就只給 read-only token。不要因為懶就給 full access。
這在傳統軟體工程裡是老生常談,但到了 AI Agent 的場景,很多人(包括我)會因為「反正 Agent 很聰明,它不會亂來」而放寬。
事實證明:Agent 不會「亂來」,它會「好心辦壞事」。這比亂來更難防,因為它的每一步看起來都很合理。
第三層:關鍵操作需要確認(Human-in-the-Loop)
對於有副作用的操作(寫入、刪除、對外發送),設計一個確認機制。Agent 可以「建議」開 issue,但實際執行要經過人類確認。
flowchart TD
A[Agent 判斷需要開 Issue] --> B{操作類型}
B -->|唯讀| C[直接執行]
B -->|有副作用| D[生成建議]
D --> E[通知管理者]
E --> F{人類確認}
F -->|同意| G[執行操作]
F -->|拒絕| H[記錄並跳過]
這會犧牲一些自動化的便利性,但在 Agent 的行為邊界還不夠成熟的階段,這層防線是必要的。
更深的問題:Agent 該不該「舉一反三」?
修完 bug 之後,我其實糾結了一陣子。
因為客觀來說,Agent 開的那個 Issue 品質還不錯。它讀完信件內容,去查了相關的程式碼,理解了功能需求,然後開了一個結構完整的 Issue,包含背景、現況分析、建議做法。如果是我自己開,大概也就是那個水準。
所以問題變成:我們到底希望 AI Agent 多「聰明」?
一端是「嚴格執行定義好的任務,一步都不多做」——這安全,但也限制了 Agent 的價值。另一端是「根據情境自主判斷,能做的就做」——這強大,但風險也大。
我目前的結論是:在信任還沒建立起來之前,寧可保守。
這就像帶新人一樣。一個新來的工程師如果第一天就自己跑去改 production database,就算改得完全正確,你也會嚇出一身冷汗。不是因為他做錯了,而是因為他跳過了你的 review 流程。
AI Agent 也是一樣。它需要先在明確的範圍內證明自己可靠,然後才能逐步擴展權限。
實務建議
如果你也在設計 AI Agent 系統,這是我從這次經驗學到的幾個原則:
1. Skill 定義要寫「不可以」,不只寫「可以」
LLM 的預設行為是「盡量幫忙」。你不說不行,它就會覺得可以。
2. API 權限要分級
讀取用的 token 和寫入用的 token 分開。Agent 的日常操作用低權限 token,需要寫入時才請求高權限(或透過人類確認)。
3. 區分「建議」和「執行」
Agent 可以自由地分析、判斷、建議,但涉及外部副作用的操作,要有明確的執行閘門。
4. 記錄 Agent 的決策過程
當 Agent 做了超出預期的事,你需要能回溯它的推理鏈,理解「為什麼它覺得這樣做是對的」。這對 debug 和改進 Skill 定義都很重要。
5. 漸進式放權
先嚴後鬆,而不是先鬆後收。收回已經給出的權限比一開始就限制要困難得多——因為使用者(和 Agent 自己)已經習慣了那個行為模式。
結語
AI Agent 的權限設計,本質上是在回答一個問題:你願意讓 AI 替你做多少決定?
目前的 LLM 已經聰明到可以「舉一反三」,但它們還不夠聰明到能理解「什麼時候該克制自己」。這個 gap 就是我們身為設計者需要補上的。
說到底,一個好的 Agent 不是什麼都會做的 Agent,而是知道什麼時候該停下來問一句「這個我可以做嗎?」的 Agent。
如果這篇能幫你在設計 AI Agent 的時候少踩一個坑,那我被自己的 Agent 嚇到的那瞬間就沒白費了 😂