文件導航

什麼必須寫在程式碼裡

置信度門控那一頁講的是「閾值交給程式碼」。這一頁講得更強一層: 有一批檢查根本不該問模型。

最強的一句邊界宣告

公開的做法裡最硬的一條來自一個 agent 迴圈的實現:

風險分高的工具呼叫強制執行人工授權,任何機率都不能覆蓋它。

「任何機率都不能覆蓋」這句話值得單獨拿出來。它說的不是「置信度要很高」, 而是這條規則不在機率空間裡。區分這兩者很重要:

  • 「≥ 0.95 才自動放行」是一條閾值規則 —— 理論上存在一個足夠高的機率能讓它通過。
  • 「高風險必須人工批准」是一條結構性規則 —— 無論模型說什麼都成立。

兩者的可靠性不在一個量級上。你的系統裡應該明確區分哪些檢查屬於哪一類, 而結構性規則要儘量多。

確定性規則先跑,模型只看灰區

同一個模式的另一種表述:

先跑確定性規則:能判清楚的直接 block 或放行,模型只是一個可選後端。 常規命令在本地就決定了,根本不發給模型。

先做規則有一個容易被忽略的好處:它把攻擊面縮小了。一個純粹依賴模型的 判定器,面對提示注入時的行為是不可預測的;而一個先跑規則的判定器, 注入只能影響「規則判不了的那一小撮」。

有一份公開的注入測試報告值 300 次注入嘗試,並且照實說明門擋住了什麼、 什麼又溜過去了。這種報告比一句「防注入」有用得多。

金鑰與敏感資料:本地先攔

一個金鑰檢測器的設計把順序講得很清楚:

情況 處理
已知格式的金鑰 本地攔截,根本不發給模型
未知的高熵字串 先遮罩,再把遮罩後的文本發給模型
模型判定 ≥ 0.80 阻斷
模型判定 ≥ 0.30 問人
模型不可用 也問人

兩條設計決定值得記住:

  • 遮罩在前。 你不能為了判斷「這是不是一個金鑰」而把一個可能是金鑰的東西 發到外部服務上去。判斷本身也有洩露風險。
  • 模型掛了也問人,而不是放行。 這是 fail-closed 的一個具體形態 —— 服務不可用不是一個可以悄悄降低安全等級的理由。

實測:6/6 個金鑰被攔住,0/6 個良性輸入被誤攔。

預算上限、簽名回執與審計

有些檢查與「模型說什麼」完全無關,但必須在同一個系統裡:

  • 一個執行時把危險命令阻斷、預算上限交給確定性程式碼, 並用 Ed25519 簽名回執鏈記錄每一次裁決。
  • 另一個把風險分限制成程式碼控制的 0–100 分,並對每次裁決做 ES256 簽名背書 (540 次呼叫,閾值 65–75 時 99.76%、0 誤報)。

簽名的意義不是防模型,是防事後說不清。當一個自動裁決導致了事故, 「當時模型說了什麼、程式碼怎麼處理的」必須能被獨立驗證,而不是隻能相信日誌。

注入要在兩個位置篩

一個防護層的做法值得單獨列出來,因為它指出了兩個容易漏掉的位置:

在工具呼叫執行之前篩一次,在工具結果被 agent 讀到之前再篩一次。

第二次是關鍵。只篩輸入的話,攻擊可以藏在工具返回的內容裡 —— 一個被 agent 抓取的網頁、一段讀進來的檔案內容,都會進入上下文, 而此時它已經繞過了輸入側的檢查。

同類的另一條規則來自一個檢索增強的實現: 引用來源裡沒有的數字,一律不輸出。

沙箱與許可權

除了篩內容,另一層是限制影響面:受保護的路徑永遠走人工確認; agent 的執行放在隔離的工作區裡(有實現用 Docker); 子 agent 的許可權與父級分開。

一張對照表

檢查 屬於哪一類 出錯時倒向哪邊
已知金鑰格式 確定性規則 攔
高風險操作授權 結構性規則 拒絕(人批准才行)
只讀命令自動放行 閾值規則 退回人工提示
工具輸出裡的注入 確定性過濾 + 模型 攔
「agent 做完沒有」 效率門 放行(fail-open)
格式與風格檢查 效率門 放行

表的第二列是關鍵:越靠近第一行的,越不該讓模型經手。

一句話

能被機率覆蓋的檢查,最終都會被某個機率覆蓋。 先決定哪些檢查不允許被覆蓋,剩下的才輪到調閾值。