這是什麼、解決什麼問題

稽核不會問技術問題。

不會問你用 KServe 還是 Seldon,不會問模型架構。 會問的是:

「這個在跑的模型,是誰決定要上線的?根據什麼?」

而這類問題的共同特徵是:答案要嘛當時留了,要嘛就是沒有。 沒有一題是可以事後補的。

這篇是七個問題,和每一題的證據長什麼樣。


什麼時候你會用到

  • 內稽、外稽、主管機關檢查之前
  • 模型上線之前(這才是有用的時機)
  • 要設計證據保存機制

七個問題

Q1:線上跑的是哪一個模型、哪一版?

證據:

oc get isvc -A -o custom-columns=\
'NS:.metadata.namespace,NAME:.metadata.name,\
VER:.metadata.labels.model-registry/version,\
SHA:.metadata.annotations.model/sha256'

⚠️ label 是約定不是機制(Day 16 講過)。 要它可信,得有機制去驗——或至少留下驗過的紀錄。

而「約定」的實際下場長這樣——同一條指令在我自己的 lab 上跑:

NS               NAME           VER      SHA
llm-serve-demo   iris-sklearn   <none>   <none>
llm-serve-demo   llm-platform   <none>   <none>
llm-serve-demo   llm-scratch    <none>   <none>

三行全是 <none>,因為沒有人貼那個 label——包括我。 我的 isvc 上只有 opendatahub.io/dashboard=true 和兩個 KServe 自己加的 annotation。

稽核問「線上是哪一版」,而答案的來源是一個沒有人負責貼的 label, 那就等於沒有答案。

⭐ 比較可靠的做法是讓服務自己回答(Day 18 的做法):

curl -s https://<你的服務>/model
# {"serving_digest":"sha256:4d694be9…","in_registry":true,"status":"production",
#  "metrics":{"test_loss":3.462,"perplexity":31.88}}

這個端點是跑在容器裡的程式算出來的,不是誰記得要貼的標籤。 label 當索引可以,當證據不行。

Q2:這一版是怎麼訓練出來的?

證據:pipeline run 的紀錄、訓練資料的 digest、參數、程式碼 commit。

這一題檢驗的是 Day 16 的血緣做得夠不夠。 只有路徑沒有 digest,等於答「大概是那份資料」。

Q3:誰核准它上線的?

證據:變更單、PR 的 approver、或部署紀錄裡的執行者。

⚠️ 這一題最常沒有答案,因為部署常常是「工程師手動 oc apply」。 技術上完全合理,稽核上完全不合格。

最低成本的補法:部署走 GitOps(Day 25), 那麼「誰按了 merge」就是核准紀錄。

Q4:上線前做了哪些檢查?

證據:Day 28 五道門各自的執行紀錄, 含「被擋下來」的案例。

全部都通過的紀錄說服力有限—— 稽核會想看門真的擋過東西。

Q5:模型上線後表現如何?

證據:監控的歷史資料、漂移報告、 以及「什麼都沒發生」的那段紀錄。

留存期限要和資料保存政策一致。

Q6:出問題時怎麼處理?

證據:回滾演練的紀錄(Day 19)、事故處理紀錄、 負責人是誰。

Q7:舊模型下線了嗎?

證據:Day 19 的下線清單, registry 的狀態不再是 LIVE。

⚠️ 這一題常常被漏,然後 registry 上有五個 LIVE 但實際只跑一個。 一份會說謊的清單,比沒有清單更糟——因為有人會相信它。


⭐ 哪些只能事前留

把七題分成兩類,這個分法比七題本身有用:

  問題 事後補得回來嗎
Q1 線上是哪版 ✅ 現在就查得到
Q2 怎麼訓練的 ❌ 當時沒記就沒了
Q3 誰核准的 ❌ 當時沒留就沒了
Q4 做了哪些檢查 ❌ 同上
Q5 上線後表現 ⚠️ 只能從現在開始
Q6 怎麼處理問題 ✅ 可以現在寫
Q7 舊的下線了嗎 ⚠️ 查得到,但對不對得起來要看紀錄

Q2、Q3、Q4 是硬的。 它們就是「當時做了沒有」,沒有第二次機會。

所以這篇真正的用途是在模型上線之前讀,不是在稽核前讀。


證據該怎麼留

原則 說明
自動產生 人工整理的證據,稽核前才生的那種,說服力最低
不可篡改 至少要有時間戳;理想上是 append-only
可重現 給定同樣的輸入,能重新產生一次
有保存期限 太久也是風險(尤其含個資)
找得到 ⭐ 存在但找不到,等於沒有

最後一項最容易被低估。證據散在五個系統裡、每個都要不同權限, 實際上就是答不出來。

一個實用的做法:每次上線產生一份 manifest, 把七題的答案(或指標)收在同一份文件裡, 以模型的 digest 當主鍵。


怎麼確認你準備好了

  檢查 判準
1 七題都有答案 寫下來,不是「應該可以查」
2 證據是自動產生的 不是稽核前才整理
3 Q2/Q3/Q4 的機制已就位 ⭐ 這三題補不回來
4 registry 沒有說謊 LIVE 的數量對得上實際
5 ⭐ 自己先演練一次 見下

第 5 項:

隨機挑一個線上模型,計時,把七題答完。

超過三十分鐘答不完,稽核當天就會有問題。

這個演練的價值不在於答完,在於它會精準指出你缺哪一塊。 而且它很便宜——一個下午。


常見問題

Q:這些是哪一部法規要求的? A:我沒有列法條,這是刻意的。 不同行業、不同國家適用的規範不同,而且會變。 這七題是共通的骨架——各種 AI 治理框架問的東西大同小異。 你的合規要求要去問法遵,不要問工程師(包括我)。

Q:留這麼多證據不會很麻煩嗎? A:自動產生就不麻煩。 麻煩的是人工整理。 如果你覺得麻煩,通常表示流程裡有太多手動步驟—— 那本身就是稽核會問的事。

Q:小團隊也要做到這樣嗎? A:看受不受監理。不受監理的話, Q1、Q2、Q7 是划算的最小集合—— 它們對你自己除錯的價值就超過成本了。

Q:稽核發現問題會怎樣? A:不知道,這超出我的經驗範圍。 但可以確定的是:「我們沒有紀錄」比「紀錄顯示我們做錯了」難處理—— 後者至少證明你有在管。


這七題,你們現在幾題答得出來?

🧪 這篇的實驗環境與 lab 檔案(最後更新 2026-08-30)

本篇在 ODH 3.6.0-ea.1 上對帳(共用區塊寫的 3.5.0 是 Day 1–9 的版本)。

叢集

  • CRC 2.63.0 · OpenShift 4.22.7 · Kubernetes v1.35.6
  • 單節點:13 vCPU / 40 GiB RAM / 120 GB disk
  • 宿主:Framework Laptop 16(Ryzen AI 7 350 · 8C/16T · 64 GB RAM · 1 TB NVMe · RTX 5070 顯卡模組)
  • ⚠️ 叢集內看不到 GPU(CRC 是 VM,RTX 5070 未 passthrough)

Operator

  • opendatahub-operator.v3.5.0 ← 即 RHOAI 3.x 的上游開源版
  • cert-manager-operator.v1.20.0(3.x 的必要相依;2.x 不需要)
  • openshift-pipelines-operator-rh.v1.23.2、openshift-gitops-operator.v1.21.3

DataScienceCluster 開啟的元件

  • kserve、aipipelines、dashboard、workbenches、modelregistry、kueue(Unmanaged)
  • 其餘(ray/trustyai/feast/aigateway…)為 Removed

叢集外的依賴(跑在宿主的 podman 上,crc start 不會帶起來)

  • Harbor v2.15.2(私有 registry)· MinIO(S3)

模型端

  • Python 3.12.13 · PyTorch 2.11.0+cu128 · FastAPI + uvicorn · prometheus-client

lab 檔案

⚠️ ODH ≠ RHOAI:元件同源,但 namespace 與部分名稱不同 (我這裡是 opendatahub,商用版是 redhat-ods-* 那一套)。 指令的邏輯可以照用,字串要自己對一次。