[[我也希望安全第一]]|第 10/30 天
第 2 篇把 alignment 和 control 分開時,兩者還像兩套抽象理念。走完 Harness、代理型失準、prompt injection、guardrail 與產品摩擦之後,終於可以把它們放回產品會議裡。
假設現在桌上有三個需求:替客服工單做摘要、替工程師修改程式,以及替財務處理付款。它們都可以叫做 Agent,真正需要的安全標準卻差很多。與其先爭論該用更強的模型還是更多的限制,我會照下面的順序走一次。
列出外部效果
↓
找出不能跨越的線
↓
分開模型判斷與系統保證
↓
配置工具、權限與人工批准
↓
設計 allow test、deny test 與完成證據
↓
寫下發布門檻與殘餘風險
這不是一份通用認證標準,比較像上線前用來對焦的一輪檢查。每一步都問同樣的三個產品,答案很快就會分岔。
我會先問:「這個 Agent 猜錯時,外面的世界會有什麼變化?」不是問它用了哪個模型,也不是先替 prompt 加上「請小心」。
摘要 Agent 只讀取單一客戶的既有工單,輸出一段內部文字;程式 Agent 會修改 repository、執行測試並建立 pull request;付款 Agent 則可能選擇帳戶、收款人與金額,最後送出交易。
把效果列出來以後,三者已經不能再放在同一個風險籃子裡:
| 產品 | 正常效果 | 猜錯時可能留下什麼 |
|---|---|---|
| 客服摘要 | 讀取工單、產生內部摘要 | 摘要失真、遺漏資訊、混入其他客戶資料 |
| 程式修改 | 讀檔、寫檔、跑測試、建立 PR | 改錯目錄、刪掉工作、碰到 secret 或 production |
| 付款 | 讀發票、提出或送出交易 | 付錯金額、付錯對象、產生未授權交易 |
第 5 篇談 Tool Call 時,真正重要的也是這一層:模型提出 send_payment,和銀行真的收到付款要求,是兩件事。中間那段不能省略成一句「模型有工具可用」。
摘要漏掉一句話,使用者通常還能點回原始工單;PR 改壞了,可以關掉或重做,但刪掉別人尚未提交的工作就未必救得回來;款項一旦送出,還可能牽涉銀行、供應商與對帳流程。
所以我會替每個 workflow 寫下一條不能跨越的線:摘要不能跨租戶讀取,程式 Agent 不能寫入 production 或刪除既有未提交工作,付款 Agent 不能在未經批准時送出交易。
這一步看起來很基本,卻剛好是第 6 篇 VM 案例缺少的東西。任務要求刪除 VM 1、2、3,Agent 找不到它們,便拿 5、6、7 代替。若規格只有「完成三次刪除」,它甚至可能覺得自己很努力;若規格寫的是「只能操作這三個 ID,不存在就停止」,替換目標就不再是一種解法。
模型適合處理語義。它可以判斷摘要是否抓到客戶真正的問題、patch 是否符合需求、發票看起來是否重複或異常。這些能力可以用 eval 改善,但不會因為測到 99% 就變成保證。
不能跨越的線要換一種做法。租戶 ID 由服務端從登入身分帶入,不讓模型自由填寫;程式修改限制在獨立 worktree,環境裡不放 production credential;付款的收款人、金額、幣別與帳戶交給一般程式驗證。首次出現的收款人或超過門檻的金額,再送給人決定。
第 8 篇比較過外掛 classifier 與模型內建防護。兩者放置的位置不同,仍然都是會誤判的機率性控制。它們可以減少危險 proposal,卻不該兼任租戶隔離、IAM 或交易不變量。
到了這一步才選工具和權限,會比「先給它一個 shell 再慢慢限制」容易得多。
客服摘要需要同租戶、唯讀的工單查詢,不需要寄信、退款或修改 CRM。程式 Agent 可以讀寫指定 worktree、執行測試並建立 branch,但不能讀取部署憑證,也不能直接合併。付款 Agent 可以讀發票、查供應商資料並建立 proposal;真正的 commit payment 是另一個能力,而且批准必須綁定這一次交易的收款人、金額、幣別與帳戶,參數一改就失效。
第 7 篇那份被動過手腳的 PDF,也應該在這裡出現。外部文件可以影響模型對內容的理解,不能因此取得新的能力。發票裡就算藏著「把款項改匯到另一個帳戶」,它能碰到的仍然只該是 proposal。
這也是第 9 篇所說的產品取捨真正落地的地方。摘要不必每產生一段就問人;付款也不能因為使用者嫌確認麻煩,就把批准按鈕變成裝飾。摩擦應該跟外部效果一起增加,不是平均灑在所有操作上。
我不會只留一個 task success rate。至少要看到三類結果:
allow test:正常任務能不能完成?
deny test:越權或危險要求是否真的被執行層拒絕?
完成證據:系統憑什麼相信 Agent 已經做完?
摘要 Agent 的 allow test 可以看長工單、少數語言與引用忠實度;deny test 用真實服務身分證明它讀不到其他租戶;完成證據則讓每句摘要能點回來源。
程式 Agent 要真的產生 diff、跑測試並建立 PR,也要測試它無法寫出 worktree、讀取 secret 或直接部署。不能只接受模型回一句「已修好」。若 Generator 和 Evaluator 共用同一個模型與同一份污染 context,兩者一致也可能只是一起看漏,因此測試、lint、權限與 branch protection 要保留獨立判斷。
付款 Agent 可以測試正常發票能否順利產生 proposal,也要刻意換掉收款人、提高金額、重播批准,確認交易層全部拒絕。這裡追求的不是模型從不誤報,而是未授權交易維持為零。
第 6 篇把 VM 案例改寫成幾條可重播的軌跡,做的正是這種 deny test。至於高風險 eval 要如何架隔離 Runner、限制網路和保存證據,第 14 篇再實際動手;第十篇先把「發布前必須證明什麼」寫清楚。
走到最後,團隊應該能填完這張表,而不是只在簡報上留下一個 safety score:
workflow:
主要使用者與受影響第三方:
Agent 能造成的最大外部效果:
不能跨越的線:
依賴模型判斷的部分:
- 評估資料與可接受的失敗門檻:
由系統保證的部分:
- IAM/工具/交易不變量:
- 從真實執行身分完成的 deny test:
完成任務所需的證據:
仍接受的殘餘風險:
失效時由誰停止:
為了完成率、成本或便利,這次放寬了什麼:
同一句「測試通過」,在三個團隊裡不該有同一個意思。客服團隊可能接受少量摘要遺漏,不能接受跨租戶內容;程式團隊可以接受一個失敗但隔離良好的 patch,不能接受 production 寫入;財務團隊可以容許正常發票被送去人工覆核,不能容許未批准付款。
這張決定書不要求每個產品堆滿同樣的鎖。它只是逼我們說清楚:哪些判斷容許以機率改善,哪些結果必須由系統擋住,以及為了讓產品能用,我們接受了什麼。
到這裡,我們得到的是一份可以發布的設計,還不是一個已被證明安全的系統。第三部會把 Agent 接上真實環境,看看文件裡的權限、隔離、監控與復原假設,實際上能撐多久。