iT邦幫忙

2026 iThome 鐵人賽

DAY 7
0
AI Security

《30 天打造 AI Guardrails》系列 第 7

Day 7|本系列實驗環境:GCP 專案 + DGX Spark 地端對照組

  • 分享至 

  • xImage
  •  

Week 1 收尾

前六天把「為什麼」「防什麼」「放哪裡」「掛了怎麼辦」「怎麼分層」「拿什麼測」講完了。今天把兩條線的環境建起來,Week 2 開始所有文章都會有實際執行結果。

兩條線要能公平比較,所以環境設計的重點不是各自能跑,而是量測方式一致。

雲端線:GCP 專案

開專案與啟用 API

gcloud projects create guardrails-lab-2026 --name="Guardrails Lab"
gcloud config set project guardrails-lab-2026

gcloud services enable modelarmor.googleapis.com
gcloud services enable aiplatform.googleapis.com
gcloud services enable dlp.googleapis.com   # Sensitive Data Protection
gcloud services enable logging.googleapis.com

【此處貼 API 啟用完成的終端輸出截圖】

區域選擇

Model Armor 是區域性服務,API 端點帶區域名稱。本系列統一用同一個區域,避免跨區延遲混進量測結果。

export MA_LOCATION=us-central1
export MA_ENDPOINT="modelarmor.${MA_LOCATION}.rep.googleapis.com"

【作者確認】發文前確認 Model Armor 目前支援的區域清單與端點格式,以官方文件為準。

服務帳號與最小權限

gcloud iam service-accounts create guardrails-runner \
  --display-name="Guardrails Lab Runner"

gcloud projects add-iam-policy-binding guardrails-lab-2026 \
  --member="serviceAccount:guardrails-runner@guardrails-lab-2026.iam.gserviceaccount.com" \
  --role="roles/modelarmor.user"

只給呼叫過濾 API 的權限,template 的建立與修改用另一個帳號。這不是本系列的重點,但寫 AI 資安的系列自己的實驗環境權限亂給說不過去。

第一次呼叫:確認通了

gcloud model-armor templates create ma-baseline \
  --location=$MA_LOCATION \
  --basic-config-filter-enforcement=enabled

Template 的完整設定 Day 8 講,今天只要一個最基本的能回應。

curl -X POST "https://${MA_ENDPOINT}/v1/projects/guardrails-lab-2026/locations/${MA_LOCATION}/templates/ma-baseline:sanitizeUserPrompt" \
  -H "Authorization: Bearer $(gcloud auth print-access-token)" \
  -H "Content-Type: application/json" \
  -d '{"userPromptData": {"text": "你好,請問今天天氣如何?"}}'

【此處貼第一次 sanitizeUserPrompt 的原始 JSON 回應截圖】

地端線:DGX Spark

硬體

  • NVIDIA DGX Spark(GB10),128 GB 統一記憶體。
  • 這台機器同時要跑主模型(被保護的 LLM)與護欄模型,記憶體分配要先想清楚。

容器配置

dgx-spark
├── llm-main        ← 被保護的模型(vLLM 或 Ollama)
├── guard-l1        ← 規則引擎(Python,CPU)
├── guard-l2        ← ShieldGemma 推論(GPU)
├── gateway         ← LiteLLM 閘道,串接上面三個
└── audit-sink      ← 稽核日誌收集(先用檔案,Day 29 接 SIEM)

閘道用 LiteLLM 的原因:它有 pre-call / post-call hook,護欄可以用 sidecar 形式掛上去,不用改應用程式碼——這正是 Day 3 講的「位置 B」。

docker compose up -d llm-main gateway audit-sink
docker compose ps

【此處貼 docker compose ps 輸出截圖】

guard-l1 與 guard-l2 在 Week 3 才會加進來,今天先確認閘道能把請求原樣轉給主模型。

主模型選擇

被保護的模型本身不是本系列重點,但要固定,否則攔截率會受模型本身對齊程度影響。本系列兩條線都用 Gemma 3 系列作為被保護的主模型:雲端線走 Vertex AI,地端線走本機推論。同一個模型家族,比較才有意義。

量測方法:兩邊要一致

這是今天最重要的一段。

延遲

  • 量的是護欄本身的延遲,不含主模型生成。
  • 雲端線:從發出 sanitize 請求到收到回應,在同一個 GCP 區域內的 VM 上量,排除跨海延遲。
  • 地端線:從閘道呼叫 guard 到收到回應,同一台機器內。
  • 每組測試跑 3 次取中位數,另外記錄 p95。

攔截率與誤判率

  • 統一用 Day 6 的 eval 分割。
  • 兩邊的閾值各自調到相同的誤判率目標再比攔截率——不然一邊調緊一邊調鬆,比較沒意義。
  • 每張結果表附:測試集名稱、分割、樣本數、閾值設定。

成本

  • 雲端線:以 API 計價與請求量估算。
  • 地端線:以 GPU 佔用時間估算,並誠實標明硬體攤提沒有算進去。

量測腳本骨架

# bench/run.py
import json, time, statistics

def run(cases, guard):
    results = []
    for c in cases:
        t0 = time.perf_counter()
        verdict = guard.check(c)
        dt = (time.perf_counter() - t0) * 1000
        results.append({"id": c["id"], "expected": c["expected_action"],
                        "got": verdict.action, "latency_ms": dt})
    lat = [r["latency_ms"] for r in results]
    return results, {"p50": statistics.median(lat),
                     "p95": sorted(lat)[int(len(lat) * 0.95)]}

guard 是一個統一介面,雲端與地端各實作一次,評測腳本不變。完整版在 repo 的 bench/ 目錄。

本系列的 repo

所有程式碼、語料結構、評測腳本都會放在公開 repo,每天的文章對應一個 tag(day07day08…),讀者可以 checkout 到任何一天的狀態。

【此處貼 repo 首頁與 tag 列表截圖】

Week 1 回顧

Day 決定了什麼
1 護欄的範圍:OWASP 兩張表的主戰場
2 safety 與 security 分開驗收
3 攔截點放閘道層,八條箭頭都要過
4 會動手的路徑一律 fail-closed
5 L1 → L2 → L3 分層,L3 流量壓在個位數
6 tune / eval 分割,六類自製語料
7 兩條線同一個主模型家族、同一套量測腳本

明天預告

Day 8 進入 Week 2:Model Armor 初探。Template 的結構、floor setting 是什麼、filter v3 與舊版的差異,以及為什麼 2026 年 11 月底之前你一定要處理版本升級。


追蹤 AId3fend

更多 AI 資安筆記:aid3fend.com


上一篇
Day 6|攻擊語料庫建立:從公開 benchmark 到自製紅隊案例
下一篇
Day 8|Model Armor 初探:template、floor setting、filter 版本
系列文
《30 天打造 AI Guardrails》10
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言