[TOOLS] 13 分鐘閱讀OraCore 編輯部

AGT 把代理呼叫變受管動作

我拆 Microsoft Agent Governance Toolkit 的做法,整理成可直接套用的代理治理模板,讓工具呼叫先過政策、身分、沙箱與稽核。

分享 LinkedIn
AGT 把代理呼叫變受管動作

我最近一直在看代理工作流,越看越火大。模型本身其實沒那麼可怕,真正出事的是中間那層黏合劑:它一下子要讀文件、一下子要寄信、一下子要碰資料庫、一下子還想跑 shell 指令,結果整個系統只靠一句「請乖乖照規則」撐著。這種東西不能叫控制,只能叫祈禱。

我拆 Microsoft 的 Agent Governance Toolkit,整理成一份可直接複製的代理治理模板,讓工具呼叫先過政策再執行。

這次把我拉進來的是 Microsoft 的 Agent Governance Toolkit。我不是把它當發表稿看,我是把它當一個我真的想放在代理前面的模式看。因為只要代理會花錢、改資料、發訊息、委派工作,治理就不能只寫在提示詞裡,得真的卡在動作前面。

觸發我整理這篇的來源就是 GitHub repo 本身,還有 README 跟文件連結。Microsoft 明講這套工具目前是 public preview,也提供快速開始、CLI 檢查、語言套件和政策範例,還把 OWASP Agentic Top 10 納進考量。這種「好,直接給我線路圖」的材料,才是我會認真拆的東西。

別再把提示詞當成權限系統

訂閱 AI 趨勢週報

每週精選模型發布、工具應用與深度分析,直送信箱。不定期,不騷擾。

不會寄垃圾信,隨時可取消。

「提示詞層級的安全性,只是在跟一個隨機系統客氣地說請不要亂來。」

這句話我講得很直,因為太多代理系統真的就是這樣。你以為多塞幾句 system prompt,就等於有了控制;實際上只要工具層鬆掉,模型前一秒還很有禮貌,下一秒就可能把不該碰的東西碰了。README 寫得很明白:代理會呼叫工具、瀏覽網站、查資料庫、甚至委派給其他代理。只要做到這一步,危險點就不再是文字生成,而是執行本身。

AGT 把代理呼叫變受管動作

比較在意的是它的處理方式:每一次工具呼叫、訊息送出、委派動作,都要先在可預測的應用程式碼裡被攔下來,等政策判斷過了才會真的送出去。重點不是模型有沒有被提醒,而是動作有沒有被攔截。這才叫控制。

我之前在內部代理原型也踩過這個坑。測試時看起來都很乖,結果一個提示注入進來,它就開始嘗試呼叫我們根本不想開放的工具。模型沒有「駭進去」,是我們前面根本沒放閘門。這就是我看到這套工具時最有感的地方。

實操寫法很簡單:不要再問「怎麼讓提示詞更安全」,直接改問「這個動作的閘門放在哪裡」。只要會改狀態、花錢、外洩資料、跨信任邊界,就應該先過政策引擎。你如果在程式碼裡講不清楚門在哪裡,那你其實沒有門。

身分要能回答是誰做的,不只是誰連上來

README 裡有個問題我覺得很重要:「Which agent did this?」 這句看起來很廢話,真的做多代理系統才知道一點都不廢話。很多團隊一開始圖方便,幾個代理共用一個 API key、一個 service account、一個後端 connector。結果平台看得到是這個 app 連線,卻看不到到底是哪個代理做了決定。

這會直接搞爛事件處理。出事之後你如果只得到「某個代理做的」,那根本沒辦法查。我要知道是哪個代理、用了哪個政策版本、走了哪條工具路徑、當時是代替誰做事。沒有這些,後面全都在考古。

Microsoft 的文件有提到零信任身分,架構圖裡也出現 SPIFFE。如果你沒碰過,SPIFFE 是給 workload 一個可追蹤身分的標準,不是拿一包共享秘密大家輪流冒充同一個 app。這方向我很買單。代理系統最怕的就是「反正都同一把 key」,那樣你根本分不出誰做了什麼。

我看過很多團隊在 demo 階段共用一把 key,覺得省事。真的上線後就開始痛苦:危險動作發生了,卻不知道是哪個代理觸發的,也沒辦法針對不同角色、不同環境套不同規則。治理工具如果沒有把身分放進路徑裡,後面全部都會鬆。

  • 每個代理都給自己的身分,就算後端共用也一樣。
  • 日誌要同時記下 agent ID、政策版本、動作結果。
  • 能用 SPIFFE 這種 workload identity 標準就別再靠長效共享秘密。

實操寫法:先定義身分模型,再寫代理邏輯。先決定誰代表代理、誰是被代理的使用者、誰是執行環境。然後把這些身分一路帶進政策評估和稽核紀錄。只要日誌回答不了「誰做了什麼」,這系統就還太鬆。

政策要能擋動作,不是只寫得像有在管

README 裡最實際的東西,就是這種兩行包裝:

AGT 把代理呼叫變受管動作
from agentmesh.governance import govern
safe_tool = govern(my_tool, policy="policy.yaml")  # 每次呼叫都會檢查、記錄、強制執行

我喜歡這種寫法,因為它不耍帥。包工具、檢查政策、寫入紀錄、必要時拒絕。沒有什麼神祕的代理執行環境假裝自己是安全邊界,全部都攤在程式碼裡。

政策範例也很直白:

apiVersion: governance.toolkit/v1
name: production-policy
default_action: allow
rules:
  - name: block-destructive
    condition: "action.type in ['drop', 'delete', 'truncate']"
    action: deny
    description: "破壞性操作需要人工核准"
  - name: require-approval-for-send
    condition: "action.type == 'send_email'"
    action: require_approval
    approvers: ["security-team"]

翻譯一下就是:政策不是註解,政策是可執行的控制流程。動作符合規則就照規則走,根本不用跟模型討論。這就是治理文件和治理系統的差別。

我也喜歡這套工具在架構參考裡提到多種政策風格,包括 YAML、OPA、Cedar。這很重要,因為每個團隊都有自己的偏好。有人想要人看得懂的 YAML,有人已經在用 OPA,有人需要更正式的政策語言。重點不是語法長什麼樣子,重點是動作在模型外面被評估。

實操寫法:先從最小的 deny list 開始,先擋破壞性操作和高權限副作用。接著把會寄信、改資料、碰正式環境的動作都加上明確核准流程。政策檔要跟程式碼一起版本控管,還要像安全敏感資產一樣審查。你如果不能 diff 政策,就很難相信政策。

沙箱不是加分題,是必要的第二道門

README 一直提 sandboxing,而且提得很對。只要代理能跑程式、碰檔案、叫外部工具,你就需要一個關住它的環境。不是因為模型邪惡,而是因為模型會出錯,而且輸入本來就可能是惡意的。

這套工具把 execution sandboxing 列成核心支柱之一,跟實務狀況完全對得上。你不只要知道某個動作能不能做,你還要知道這個被允許的動作能碰到哪裡。允許執行 Python 跟允許它在受限容器裡跑,這兩件事差很多。

我以前就看過代理在 dev container 裡亂搞,還沒上正式環境就先把自己玩壞。壞的 shell 指令、壞的檔案寫入、壞的網路呼叫,最後「助理」變成你的事故來源。沙箱就是拿來縮小爆炸半徑的。

  • 會執行程式的工具,放進隔離容器或受限 runtime。
  • 讀取型工具和可寫入工具分開。
  • 沙箱的網路 egress 也要管,不要只管 app server。

實操寫法:把沙箱當成政策之後的第二道門。政策決定能不能做,沙箱決定做了之後能碰什麼。如果工具是「跑 Python」,沙箱還是要限制檔案系統、環境變數、網路和程序權限。少這層,就等於把太多表面積交給代理。

稽核紀錄才是出事後真正的產品

README 直接講到稽核人員和監管單位需要可防竄改的紀錄:當時套用哪個政策、代理要求了什麼、為什麼被允許或拒絕。這不是文書作業,這是活命。代理一旦亂來,第一個問題永遠不是「提示詞看起來有沒有寫好」,而是「把決策軌跡拿來看」。

Microsoft 也有強調工具會記錄決策。很好,這本來就該做。你只要有允許和拒絕,就一定要有能撐過事後檢討的紀錄,不然事後只能靠猜。

很多代理堆疊會悄悄失敗在這裡。它們有 app log、有 tracing、有模型 telemetry,可是沒有一筆資料能把代理身分、政策版本、請求內容、決策、核准者、時間戳串起來。沒有這個,你只能說你大概知道發生什麼事,不能說你真的知道。

我自己偏好一筆稽核事件就回答四件事:

  • 是哪個代理發出的請求?
  • 是哪個政策版本在評估?
  • 具體要求了什麼?
  • 最後為什麼被允許、拒絕,還是升級人工處理?

實操寫法:把稽核事件當成一等資料模型,不要事後才硬塞 log line。政策版本要存 hash,觸發規則名稱要記,決策用到的欄位要保留。若必須遮罩敏感值,也要確保不會把決策理由一起遮掉,不然那筆紀錄只剩時間戳和噪音。

把它當包裝層,不要當宗教

我喜歡這個 repo 的地方還有一點:它沒有把你鎖死在單一語言或 runtime。文件裡有 Python、TypeScript、.NET、Rust、Go,還有 Claude Code 外掛整合。這表示維護者很清楚現實限制:治理一定要放在工具真的被呼叫的地方。

README 也提到幾個 CLI 指令,像 agt doctoragt verifyagt red-team scanagt lint-policy。這種東西我會直接拿進 CI。我要的是能檢查安裝、驗證政策、跑合規檢查、掃提示注入風險的東西,而不是只在 demo 時看起來很完整。

它標成 public preview,我也覺得合理。這不是拿來裝成熟的成品,而是先把治理骨架放出來。安全工具如果還能老實講自己是 preview,我反而比較放心,至少它沒有假裝自己永遠不會改。

實操寫法:不要一口氣導入整套。先挑一個高風險工具包起來,把政策評估接進呼叫路徑,接著補稽核紀錄,再把會執行程式或碰檔案的工具丟進沙箱,最後才加 CI 檢查。順序很重要,因為這樣不會變成一個沒人真的用的治理表演專案。

我也會把 wrapper 維持得很薄。治理一定要能在 code review 裡看懂。如果那層封裝太厚,大家第一次被它擋到時就會繞過去。這種系統死掉通常都是這樣死的。

可抄的模板

# 代理治理起手式

這是我會先放進專案的最小可用版本。

## 1) 政策檔:policy.yaml

apiVersion: governance.toolkit/v1
name: production-policy
default_action: deny
rules:
  - name: allow-read-only-search
    condition: "action.type == 'web_search'"
    action: allow

  - name: block-destructive-actions
    condition: "action.type in ['drop', 'delete', 'truncate', 'shell_exec']"
    action: deny
    description: "預設不允許破壞性或主機層級動作"

  - name: require-approval-for-side-effects
    condition: "action.type in ['send_email', 'create_ticket', 'write_database']"
    action: require_approval
    approvers:
      - security-team
      - service-owner

## 2) Python 包裝器

from agentmesh.governance import govern

# 把 `my_tool` 換成你真的工具函式。
# 預期 action 物件格式:{ type, ... }
safe_tool = govern(my_tool, policy="policy.yaml")

# 範例呼叫
result = safe_tool(action={"type": "web_search"}, query="最新文件")
# 允許

blocked = safe_tool(action={"type": "delete"}, table="users")
# 會丟出 GovernanceDenied

## 3) 稽核事件格式

{
  "timestamp": "2026-07-18T12:00:00Z",
  "agent_id": "agent-123",
  "user_id": "user-456",
  "policy_name": "production-policy",
  "policy_version": "1.0.0",
  "action": {
    "type": "delete",
    "target": "users"
  },
  "decision": "deny",
  "rule": "block-destructive-actions",
  "reason": "預設不允許破壞性或主機層級動作"
}

## 4) CI 檢查

# 驗證政策語法
agt lint-policy policies/

# 檢查安裝與 runtime 接線
agt doctor

# 跑治理驗證
agt verify --strict

# 掃描提示詞或代理指令的注入風險
agt red-team scan ./prompts/ --min-grade B

## 5) 最小導入順序

1. 先包一個高風險工具。
2. 在執行前加政策評估。
3. 每次 allow / deny 都寫稽核紀錄。
4. 會跑程式的工具進沙箱。
5. 加 CI 檢查,提早抓政策漂移。
6. 每個代理分開身分,讓事件能查。

## 6) 我不會省略的東西

- 破壞性動作預設拒絕
- 每個代理都有穩定身分
- 每筆稽核紀錄都帶政策版本
- 會執行程式的工具一定有沙箱
- 會產生副作用的動作一定有人類核准路徑

## 7) 一句話原則

只要代理能改狀態、花錢、或對外說話,它在離開程序之前就應該先過政策、身分、沙箱和稽核。

這份模板故意寫得很無聊。很好,治理本來就該無聊。真正該有趣的是代理在做的工作,不是權限模型在那邊演戲。

如果我明天就要把這套東西塞進真實專案,我會先從政策檔和 wrapper 下手,再把稽核事件接到既有 logging pipeline。接著才補上會執行程式或碰檔案的沙箱。最後才擴到更多代理和更多工具。這個順序能把爆炸半徑壓小,也比較不會把 rollout 弄成災難。

來源致謝:原始材料是 Microsoft Agent Governance Toolkit repository 與 README。我這篇的拆解是原創評論,加上依照 repo 模式整理出的可複製模板,不是 Microsoft 官方範例。