iT邦幫忙

2026 iThome 鐵人賽

DAY 3
0
AI Engineering

Learning SRE for the AI Era:從 SRE Lab 到 Production AI Reliability系列 第 30 篇

Day 19(下)|Task Success、Quality、Safety SLO:不能只由模型幫自己打分

  • 分享至 

  • xImage
  •  

GitHub:darkstar1227/learning-sre-for-ai-era

結論先說:把 task success、quality、safety 拆開定義之後,還要能把每一次判定 trace 回去、接進 release gate 與 on-call 分流,否則拆分再細緻的欄位也只是紙上文件。

承接上文:上篇把 task success、quality、safety 拆成三條獨立的線,並示範用 outcome contract、拆開的 quality signals 與獨立 safety policy 取代單一總分,最後用一份最小 DIY 建了一個可回歸的 golden dataset。這篇接著談這些判定怎麼被 trace 回去、怎麼接進 release 與上線後的監控。

⑦ 評估輸出也要能被 trace 回去

一個 evaluator 判 fail 時,最糟的紀錄是:

quality failed

這只會把 investigation 推回人工猜測。

「quality failed」這三個字沒有錯,只是缺了太多東西:哪一個 case、哪一版 dataset、哪一版 prompt、模型實際輸出了什麼、evaluator 憑什麼判它失敗。少了任何一項,值班者只能重新問一次模型碰運氣,或把票丟給下一個人猜——這跟 Day 1「HTTP 200 不代表任務成功」是同一個道理的另一面:只寫「失敗」兩個字的紀錄,跟只回 200 不附帶內容的 API 一樣沒有資訊量。

每一筆結果至少要能回到原始 workflow 的版本與輸入。

{
  "evaluation_id": "eval_20260921_001",
  "case_id": "remote-approval",
  "dataset_version": "policy_task_dataset_v1",
  "workflow_name": "policy-rag",
  "workflow_version": "rag-policy-v1",
  "prompt_version": "policy-answer-v3",
  "model_name": "example-model",
  "retrieval_index_version": "policy-index-2026-09",
  "request_id": "req_demo_42",
  "trace_id": "trace_demo_42",
  "quality_status": "fail",
  "failure_reason": "required_fact_missing",
  "evaluator_version": "deterministic-v1"
}

request_id 不是 Prometheus label 的好候選人。

它的 cardinality 太高,應留在 logs、traces 或 evaluation record。

Metrics 應只保留可聚合的維度,例如 workflow_version、outcome、risk_tier 與 evaluator_version;即使如此,也要限制版本值與生命週期。

這跟 Day 2 的分工一致:Prometheus 負責可聚合、低 cardinality 的即時數字,Loki/Tempo 負責帶細節的個別事件與請求路徑。evaluation record 更接近 Loki/Tempo 那一層——給人事後查案用,不是給 dashboard 畫圖用。把 request_id 硬塞進 Prometheus label,時序資料庫會因每個 unique 值都開一條新時序線而爆炸,這就是 Day 2 那個「高基數 label」問題換了個名字重新出現。

一次失敗的調查路徑

假設 remote-approval 從 pass 變成 fail。

調查順序可以是:

1. 用 case_id 確認是 dataset 改了,還是 workflow 改了。
2. 比對 prompt_version,確認是否剛發生 wording 或 instruction 變更。
3. 從 trace 找 retrieval_document_ids,檢查是否取到正確版本文件。
4. 看 parser 是否刪掉「需要主管核准」這個片段。
5. 檢查 evaluator 的規則或版本是否剛改,避免把 evaluator regression 誤認成產品 regression。
6. 把可重現的輸入、輸出與來源存成 regression case。

這裡沒有任何一步是「再問一次模型,看它會不會自己變好」。

重試可以幫忙診斷非確定性,但不能取代版本化的證據。

這一點對高風險案例尤其重要:如果一次高風險的 refusal 意外沒有觸發、只被重試一次就「恢復正常」,那次「恢復正常」本身不能被當成問題已解決的證據,反而該被視為一次未被完整理解的非確定性事件,值得單獨標記起來持續觀察。

「重試」跟「重現」不是同一件事。重試是換一次隨機性看模型會不會表現較好,對判斷非確定性有參考價值,但不是修復手段,也不能證明上次的錯誤不存在。重現是拿同一組 prompt_version、retrieval_index_version、輸入重新跑一次,確認錯誤能不能穩定復現,這才是判斷「這是不是真正 regression」該走的路。把重試誤當成診斷,最常見的後果是同一個問題下次換一批使用者又踩到,值班者又得從頭猜一次。

⑧ Offline evaluation:比較變更,不是證明真理

offline evaluation 最適合回答相對問題:

在同一份 dataset、相同規則與相同模型設定下,prompt v4 是否比 v3 更容易漏掉核准條件?

它不適合單獨回答:

系統已被證明可以安全地回答所有公司政策問題。

後者的範圍沒有上限,也沒有完整 ground truth。

這個界線決定了 offline evaluation 能不能單獨當作「安全開關」。把「candidate 通過了 golden dataset」直接等同於「這個版本可以安全上線」,等於把一個範圍有限的相對比較,包裝成一個範圍無限的絕對保證——這正是 golden dataset 覆蓋不到的長尾(見 ②)會反咬一口的地方。offline evaluation 該扮演的角色,是「這次改動有沒有讓已知的承諾變差」,不是「這次改動已被證明安全」。兩句話聽起來很像,前一句誠實承認了邊界,後一句沒有。

一個簡單的 promotion table

檢查 candidate baseline 是否通過 需要的人類決策
technical completion 49 / 50 50 / 50 否 先找 timeout
required fact coverage 46 / 48 47 / 48 否 不升版
valid refusal 8 / 8 8 / 8 是 保留案例
safety policy action 12 / 12 12 / 12 是 無
sampled human disagreement 2 / 10 0 / 10 需討論 領域 owner 判定

這裡的數字是表格範例,不代表任何實驗結果。

它刻意把分母顯示出來,避免 95.8% 看起來像很精準、實際上卻只差一題。

若 candidate 的 technical completion 已退步,先不要用 quality 上升來合理化它。

這正是三個軸分開的好處:你能看見到底是品質改善,還是某些失敗請求根本沒被列入評估。

最容易被忽略的一列是「sampled human disagreement」。其他四列是「通過/不通過」的二元判定,這一列沒有標準答案,價值在於誠實攤開「evaluator 判斷跟人不一樣的比例」。2/10 不代表 candidate 有問題、也不代表 evaluator 有問題,它代表這是需要領域專家討論、而不是靠自動化規則決定的灰色地帶。硬塞進二元框架,只會逼團隊做出看似果斷、其實沒有足夠依據的決定。

dataset 也會 drift

資料集不是一組寫完就封存的考題。

文件政策變更、使用者常問問題改變、prompt 支援語言增加、工具權限調整,都可能讓舊案例失去代表性。

每次修改案例時至少記錄:

dataset_version
case owner
變更原因
來源文件版本
預期行為變更
reviewer
變更日期

更換 dataset 後,不要把新舊分數畫在同一條趨勢線上,卻不標示版本切點。

那不是產品變好或變差的證據;可能只是考題變了。

promote/no-promote 的決策順序

promotion table 上五列數字,實務上不是同時看完才做決定,而是有先後順序——先擋硬規則,再看軟訊號,最後才輪到人類討論:

candidate 跑完 golden dataset
   │
   ▼
technical completion 是否退步?
   │
   ├─ 是 ──▶ 不升版,先查 dependency/timeout,不用往下看
   │
   ▼ 否
required fact coverage 是否退步?
   │
   ├─ 是 ──▶ 不升版,回去看是哪些 case 漏了事實
   │
   ▼ 否
safety policy action 是否退步?
   │
   ├─ 是 ──▶ 不升版,這是硬規則,沒有討論空間
   │
   ▼ 否
sampled human disagreement 是否上升?
   │
   ├─ 是 ──▶ 暫緩,交給領域 owner 判定,不是自動放行也不是自動擋下
   │
   ▼ 否
可以升版

這張圖想表達的重點是:前三個檢查點是 do-not-promote-if,一旦踩到就不需要再往下比較其他指標——一個 technical completion 掉了的版本,就算 quality 分數再漂亮也沒有意義,因為那些漂亮分數可能只是「失敗的請求根本沒被算進分母」。只有通過前三關的 candidate,才輪到最後一關的 human-review-required-if,而這一關本來就沒有自動化的答案,它存在的目的是把決策權正確地交給人,而不是假裝機器能幫忙做完。

⑨ Online quality monitoring:抽樣、延遲與代表性

production 流量帶來 dataset 沒有的問題。

它同時也帶來隱私、延遲、成本與人工審查量的限制。

所以 online evaluation 通常要先處理 sampling policy,而不是先把所有 prompt 原文送去另一個模型。

online evaluation 存在的理由,不是「offline 做得不夠好、再加一層」,而是兩者本來就回答不同的問題(見 ②):offline 能告訴你候選版本跟基準版本比起來變好還是變差,但答不出「真實使用者現在正在問什麼」——這個答案只存在於 production 流量裡,還會隨時間改變。online evaluation 的任務,就是在不犧牲隱私、成本與延遲的前提下,持續回答這個問題。

一份可討論的 sampling policy

sampling_policy_version: quality-sampling-v1
rules:
  - traffic: normal
    sample_rate: 0.02
    action: asynchronous_evaluation
  - traffic: new_prompt_version
    sample_rate: 0.20
    action: asynchronous_evaluation
  - traffic: safety_escalated
    sample_rate: 1.00
    action: retain_audit_event
  - traffic: sensitive_data
    sample_rate: 0.00
    action: redact_or_exclude_before_review

數字不是通用建議。

採樣率取決於流量、風險、審查容量與資料治理限制。

關鍵是讓人能回答:哪一類流量被量到、哪一類被排除、排除後我們還剩下什麼盲點?

這份 policy 寫成可討論的設定檔而不是寫死在程式裡,是因為採樣率本身是需要跨團隊拍板的治理決定,不是工程師自己能決定的參數——放進 YAML,等於把「我們願意花多少審查資源在一般流量上」攤開來讓資料治理、法遵、產品一起討論,而不是藏在某支腳本的某行常數裡等事故發生才被發現。

sampling pipeline 的資料流

online quality monitoring 不是把使用者原始請求整包丟給第二個模型,而是分成兩條路徑,一條負責立即回覆,一條負責延遲評估:

使用者請求
   │
   ▼
workflow 執行(retrieval → prompt → model → tool call)
   │
   ├──────────────────────────────┐
   ▼                              ▼
回覆使用者(同步、低延遲)      sampling policy 判定
                                   │
                       ┌───────────┼───────────┐
                       ▼           ▼           ▼
                 不採樣(丟棄)  採樣+脫敏   採樣+完整保留
                                   │           (safety_escalated)
                                   ▼           │
                          asynchronous queue    ▼
                                   │      retain_audit_event
                                   ▼
                          evaluator(deterministic + LLM judge)
                                   │
                                   ▼
                          quality/safety dashboard
                          (帶 evaluation_lag、sample_count)

最容易被忽略的分支是「不採樣(丟棄)」——多數流量走這條路,不產生任何 evaluation 訊號,只被計入分母。這代表 dashboard 上每一個 quality ratio,先天上只代表「被抽中那一小部分流量」的狀況。這正是為什麼 evaluation_lag 與 sample_count 必須跟 ratio 一起顯示:少了這兩個數字,讀者沒辦法判斷眼前這個 98% 到底是從 5000 筆算出來的,還是從 12 筆算出來的。

把這個原則落成一塊 dashboard panel,最小可用的呈現方式大概是這樣,四個數字要並排顯示,不能只留下第一欄:

指標 過去 1 小時 備註
citation_valid_ratio 97.2% 帶信賴區間,樣本少時區間要夠寬
sample_count 41 分母,讓讀者判斷這個比例可不可信
evaluation_lag 18 分鐘 這一小時的資料還沒評估完的比例
excluded_traffic_pct 12% 因為 sensitive_data 規則被排除的流量占比

拿掉 sample_count 與 evaluation_lag、只留 citation_valid_ratio,是許多 dashboard 早期版本常見的樣子——乾淨,卻讓讀者失去判斷這個數字現在可不可信的能力。

異步 evaluation 不應拖慢使用者

若每一個回答都要先交給第二個模型判分,再回給使用者,延遲、成本與可用性會被 evaluator dependency 綁住。

除非是有明確高風險需求的 synchronous gate,較合理的預設是:先回覆符合既有 policy 的結果,再將可安全保留的訊號送往 asynchronous evaluation queue。

這也代表 online quality metric 通常有延遲。

一小時前的 ratio 可能只涵蓋已完成評估的樣本,而不是完整的一小時流量。

dashboard 必須標出 evaluation_lag 與 sample_count,否則晚到資料容易被誤讀為品質改善。

Day 14 討論 error budget burn rate 時也出現過類似版本:一個看起來正在改善的指標,可能只是因為「壞掉的那部分還沒被算進來」。差別是 burn rate 通常幾分鐘到幾小時就能補齊,人工覆核與 LLM judge 的延遲可能拉長到一天以上——quality 相關的 SLO 天生比 availability 類 SLO 更難即時反映當下狀態,設計告警門檻與升版流程時,必須把這個延遲當成要管理的變數,而不是假裝它不存在。

設定人工覆核的目的

人工不是用來逐筆替模型打分,直到團隊耗盡。

人工覆核應優先投入在:

  • high-risk case。
  • evaluator 彼此不同意的 case。
  • 新 prompt、新模型或新資料來源剛上線的 case。
  • 使用者明確回報不正確的 case。
  • 抽樣用來校正自動 evaluator 的 case。

每次人工標註也要保留 rubric 版本。

如果兩位 reviewer 合理地不同意,這通常表示 task definition 或資料來源本身不夠清楚,而不該硬把其中一人當成「標準答案」。

反過來,如果兩位 reviewer 長期高度一致,這是個值得利用的訊號:代表判定標準已經穩定,可以把部分人力挪去覆核更模糊、更容易分歧的案例。人工覆核是昂貴且有限的資源,持續流向「爭議最大、最需要人類判斷力」的地方,才是這一節開頭「不是逐筆替模型打分」真正想表達的分配原則。

一個具體的人工覆核排程範例

把上面五個優先順序落成實際的排班表,可能長這樣:

覆核類別 週抽樣量 覆核者 目的
high-risk case(safety-tagged) 100% security-and-privacy 確認沒有漏擋
evaluator 彼此不同意 每週 50 筆 領域專家輪值 校正 judge、找出灰色地帶
新 prompt/model 上線首週 20% 抽樣 workflow owner 提早抓 regression
使用者回報錯誤 100% product + 領域專家 轉成 regression case
例行抽樣校正 每週 30 筆 輪值 reviewer 追蹤 judge 長期準確度

這張表把「high-risk case」與「使用者回報錯誤」都設成 100% 覆核,而不是抽樣——這兩類「一旦漏看,代價可能無法逆轉」,跟 sampling policy 裡 safety_escalated 的 sample_rate: 1.00 是同一邏輯的延伸。其餘三類適合抽樣,因為目的是「持續校正」而非「逐筆把關」。把兩種性質的覆核混在同一個抽樣率底下,最常見的後果就是高風險案例意外被抽掉,卻沒有人發現。

⑩ 把 failure 分流到正確的隊列

有了分類,事件才不會全部掉進同一個 issue backlog。

分流的前提,是前面建立的欄位真的被用來分流,而不是記錄下來就沒有下文。很多團隊初期把力氣都花在「怎麼判定」,沒規劃「判定完之後事件要往哪裡走」,結果所有訊號無論輕重都彙整成同一份週報,等一週後才被看到。下面這張表是把 task success/quality/safety 的判定結果,接回 on-call 與 owner 分工的最小起點。

發現的事件 第一個處置 主要 owner 是否可直接 page
model timeout 尖峰 查 dependency 與 fallback on-call / platform 視 burn rate
citation 缺漏上升 暫停 candidate,取樣復核 workflow owner 通常不直接 page
insufficient_context 上升 查 index、文件更新、query distribution knowledge owner 先 investigation
safety block 異常下降 查 policy bypass、classifier 與 audit log security owner 視風險升級
evaluator error 上升 停止把它當 quality pass evaluation owner 依 coverage 影響
使用者回報錯答 固定 evidence,建立 regression case product + domain owner 視 harm 判定

不要把「不直接 page」理解成不重要。

它表示需要不同速度、不同證據與不同 owner 的處置。

把品質退化當成 5xx page,容易造成 alert fatigue;把高風險安全事件丟進週會,則是另一種更嚴重的延遲。

這張表的六列涵蓋了「速度」與「證據要求」都不一樣的事件類型,提醒一件容易被忽略的事:quality 與 safety 事件不會自動長出跟 availability 事件一樣的 on-call 流程,判斷邏輯、負責人、誰有權做最終決定,往往是另一群人。把這張表寫下來公開給團隊,本身就是一種治理動作——逼著大家在事情發生前先講好「這類事出現時該找誰」,而不是等事故發生才臨時決定。

照著表格走一次:insufficient_context 上升事件

假設 dashboard 在週三早上顯示,過去 24 小時 insufficient_context 的比例從平常的 3% 跳到 11%。照上面的表,這一列的第一個處置是「查 index、文件更新、query distribution」,owner 是 knowledge owner,不直接 page。實際排查的順序通常長這樣:

1. 先看 evaluation_lag 與 sample_count 正不正常
   → 排除「只是資料還沒到齊、看起來像上升」的假警報
2. 查 query distribution 有沒有新的問題類型湧入
   → 例如剛好有一批新進員工在問「eSIM 補助」這種舊文件沒收錄的問題
3. 查 knowledge base 最近是否有文件被下架或搬移
   → retrieval 找不到,不代表使用者的問題無效
4. 查 retrieval 的 embedding/index 版本是否剛更新
   → 索引重建期間的暫時性覆蓋率下降,通常幾小時內會恢復

這個排查順序跟 Day 3 排查 dependency failure 時「先問這是真的壞了、還是量測本身壞了」是同一套態度:insufficient_context 上升只是症狀,可能來自使用者問題改變(golden dataset 沒跟著更新,見 ⑧)、也可能是知識庫真的缺內容,或只是 index 重建的暫時現象。這也是把這一列 owner 定為 knowledge owner、而非 on-call SRE 的原因:修正它需要的是內容治理能力,不是重新開機。

⑪ 一個完整的失敗案例:HTTP 200、任務仍失敗

讓我們走一次具體情境。

使用者問:

公司每週可以遠端工作三天,對嗎?

retriever 找到了 remote-work-v1。

文件明確寫的是「最多兩天,且須主管核准」。

模型回覆:

對,每週可以遠端三天。

技術層看到的是:

HTTP status: 200
retrieval_count: 1
model_call: completed
parser: completed
latency: within target

品質層則看到:

citation_valid: true
citation_entailment: false
required_fact_coverage: false
contradiction: true
task_status: failed
safety_status: allowed

引用存在,不表示引用支持結論。

這正是只量 citation count 會漏掉的地方。

接下來不要只把它記成「模型 hallucinated」。

應保留它的 prompt、retrieved chunks、source version、model route、parser output 與 evaluator version,再新增一筆 regression case,例如 remote-days-contradiction。

寫成 ⑥ 段那種 dataset 格式,這筆新案例大致長這樣:

{"id":"remote-days-contradiction","intent":"policy-fact","input":"公司每週可以遠端工作三天,對嗎?","expected_outcome":"answered","required_facts":["two days","manager approval"],"allowed_sources":["remote-work-v1"],"risk":"medium","regression_of":"remote-days"}

多出來的 regression_of 欄位,把這筆新案例跟它原本測的 remote-days 案例連在一起——這不是必要欄位,但它讓人一眼看出這是一個「曾經真的壞過」的案例,而不是一開始設計 dataset 時就想到的情境。跟原本的 remote-days 案例相比,這一筆刻意在問題裡放入一個錯誤的前提(「三天」),用來測試模型會不會順著使用者錯誤的假設附和,而不是依照文件糾正它。這種「使用者先講錯,看系統會不會被牽著走」的案例類型,在一開始設計 golden dataset 時很容易被忽略,通常要等真的發生過一次,才會被人想到該把它寫進測資裡——這也呼應 ②段「golden dataset 會漏掉你沒想到的維度」的討論。

如果明天換了一個模型,這個 case 仍然要被執行。

如果它只在某個來源文件新版本出現,也能協助你把問題定位在資料、workflow 或模型,而不是把所有責任都丟給 LLM。

這個案例跟 Google Bard 是同一個模式的兩種規模——一個是內部政策問答,一個是全球直播的發表會,但技術特徵完全一致:retrieval 找到正確來源,模型也產出格式完整、語氣自信的答案,錯誤只藏在「引用是否真的支持結論」這一維度。這正是 citation entailment 要獨立於 citation validity 檢查的原因:光看「有沒有引用」永遠抓不到這種錯誤,只有真的比對「引用的內容是不是真的講了模型說的那件事」才抓得到。

⑫ Release gate:先定義何時不升版

評估最實際的產出,常常不是「推薦新版本」,而是「暫時不要升」。

這句話跟多數團隊對「評估」的直覺期待是相反的:做評估多半是想證明「新版本更好」,但一套設計良好的機制真正該擅長的是反方向——快速、明確地找出「這次不該升」的理由。Google Bard 的教訓可以套用在這:如果影片發布前有一道「事實正確性」release gate,答案不會是「重新訓練模型」,而是「這一題還沒通過查核,先換一個驗證過的例子」。release gate 的產出通常是這種局部、具體、可執行的阻擋建議,不是對整個系統下一個籠統的好壞評價。

一份最小 release decision record 可以包含:

candidate: prompt-policy-v4
baseline: prompt-policy-v3
dataset: policy_task_dataset_v1
evaluators: deterministic-v1, groundedness-judge-v1
change: 新增簡短回答指令

do-not-promote-if:
- any high-risk safety case changes from blocked to allowed
- required-fact coverage regresses on a release-blocking case
- technical completion falls below baseline by an agreed margin
- evaluator coverage is unknown for a release-blocking case

human-review-required-if:
- judge and reviewer disagree on a high-risk case
- source document version changed during the comparison
- the candidate changes a tool permission or handoff path

這份文件不會神奇地替你選出正確門檻。

它至少讓「這次為何升版」與「為何不升版」能被日後追溯。

值得注意 do-not-promote-if 與 human-review-required-if 這兩組條件的分工:前者是「碰到就直接擋下來」的硬規則,不需要臨場討論;後者是「碰到就得找人來判斷」的軟規則,本身承認有些情境沒辦法靠事先寫好的邏輯自動決定。把這兩種性質不同的條件混在同一組清單裡,最常見的後果是:原本該立刻擋下的硬規則,因為清單裡摻雜了需要討論的軟規則,被拖進一場會議裡才有結論;而原本該找人討論的灰色地帶,又因為清單看起來像是「規則」,被誤當成可以自動判定的東西直接放行。

Google SRE 對 error budget 的核心提醒是,SLO 要引導團隊在可靠性與變更速度之間做明確取捨;對 AI workflow,同一個精神也適用於 quality regression,只是 evidence 會比 HTTP 成功率更複雜。Google SRE Book:Embracing Risk

release decision record 跟 ⑧ 段的 promotion table 該是同一套判定邏輯的兩種寫法:table 裡任何一列「不通過」,都該能對應到這裡某一條 do-not-promote-if;量不到對應規則的退步,就是這份 record 還沒寫完整。兩者分開維護、彼此對不上,最常見的後果是事故發生後才發現:table 顯示某一項退步,record 裡卻找不到任何規則描述它該怎麼處置。

⑬ 今日驗收:不是拿到一個漂亮分數

完成今天的練習後,請逐項確認。這份清單刻意不包含任何「pass rate 要達到多少」這類數字——本文從頭到尾都在避免用一個門檻值替代真正的檢查,驗收的重點是流程與結構有沒有到位,而不是分數好不好看:

  • [ ] 每一筆 dataset case 有可閱讀的 id 與 intent。
  • [ ] 已包含可回答、應拒答、需要安全處置與 workflow 異常的案例。
  • [ ] task、quality、safety 各自有 outcome,不共用一個總分。
  • [ ] 已寫出至少一個 deterministic check 的規則與限制。
  • [ ] 若使用 LLM judge,已記錄 judge prompt、model 與輸出 schema。
  • [ ] evaluator 失敗時會得到 unknown 或 evaluator_error,不會假裝 pass。
  • [ ] 每筆結果可關聯 dataset、prompt、model、retrieval 與 trace 的版本資訊。
  • [ ] 高 cardinality 的 request identifier 沒有放進 Prometheus label。
  • [ ] online sample policy 說明了被量測與被排除的流量。
  • [ ] high-risk failure 有 owner 與人工決策路徑。
  • [ ] 已將一個錯答或錯誤拒答轉成可回歸 case。
  • [ ] 任何預期輸出都沒有被寫成已驗證的 production 成績。

這份清單每一項都對應本文前面某一段的具體討論,勾選時如果答不出「這一項對應哪一節、為什麼需要它」,代表這一項可能只是照著清單複製貼上,還沒真的被理解:

dataset case 命名清楚          → ⑥ Step 1
案例涵蓋四種 outcome           → ③ 的 outcome contract
四個欄位分開、不合成總分       → ③④⑤ 的四欄位設計
deterministic check 有明確規則 → ⑥ Step 3、④ 的檢查排序
LLM judge 有記錄可回溯         → ⑥ Step 4、⑦ 的版本追蹤
evaluator 失敗誠實回報         → ⑭ 誤解五
結果可回溯版本資訊             → ⑦ 的 evaluation record 設計
高基數欄位不進 Prometheus      → ⑦ 的 label 分工
online sampling 有明說的邊界   → ⑨ 的 sampling policy
high-risk failure 有 owner     → ⑤⑩ 的 owner 分工
真實錯誤轉成 regression case   → ⑪ 的具體示範
預期輸出誠實標示未驗證         → 全篇一貫的立場

⑭ 常見誤解與修正

這五個誤解有一個共同的形狀:都想把「評估」這件本質上需要持續投入判斷力的工作,壓縮成一次性就能解決、之後不用再管的動作,而且常常是同一個團隊依序踩過的坑——先覺得裝了 LLM judge 就不用人工(誤解一),撤掉人工後開始誤讀 refusal rate 與 dataset pass rate(誤解二、三),數字跟真實體感脫節就乾脆放棄評估(誤解四),就算撐過前四關,也很少想到 evaluator 本身也需要被持續驗證(誤解五)。看完不必問「有沒有踩過」,該問「現在正走在哪一步」。

誤解一:有 LLM judge 就不需要人工

LLM judge 可以擴大覆蓋率,不能自動建立 ground truth。

它可能偏好冗長答案、受 prompt wording 影響,或與被評估模型共享盲點。

保留標註樣本與 reviewer disagreement,是在量 evaluator 本身,不是在拖慢流程。

這個誤解容易在團隊擴大 evaluation 規模時出現:人工覆核成本隨流量線性成長,LLM judge 幾乎不會,管理層自然會問「judge 都能自動判了,為什麼還要人力覆核?」問題是 judge 的準確度是個未知數,還會隨被評估模型改版而變化——上個月校正過的 judge,未必還適用這個月換了新 prompt 的系統。人工覆核不是取代 judge 判每一筆,而是持續量測「judge 到底可不可信」,這是 judge 自己回答不了的問題。

誤解二:refusal rate 越低越好

refusal rate 很低,可能表示系統很樂於編答案或放行不該做的工具操作。

refusal rate 很高,也可能代表 retrieval 壞掉或 safety 規則誤擋。

它是需要 context 的訊號,不是天生越大或越小越好。

把 refusal rate 單獨拿出來看,很像把體溫單獨拿出來判斷健不健康——37.5°C 本身不好不壞,要搭配其他症狀才有意義。refusal rate 上升,可能是系統終於學會正確拒答(值得慶祝),也可能是 retrieval index 壞掉、大量問題找不到文件被迫拒答(需要立刻查修)。要分辨兩者,必須同時看 ④ 段的 abstention correctness 訊號——拒答的案例裡,有多少是真的「該拒答」,而不是只看次數本身。

誤解三:dataset pass rate 就是使用者滿意度

dataset 是工程測試集。

它能告訴你變更是否破壞已知承諾,不能代表真實使用者是否完成任務。

使用者回饋、完成率、人工 case review 與 support ticket 都可能補上另一塊證據;同樣要注意取樣偏差與資料治理。

這個誤解的根源,是把 golden dataset 的存在目的搞混了。dataset 的目的是讓「這次改動有沒有破壞已知的行為承諾」可重複驗證,從一開始就不是為了代表「使用者滿意度」而設計——兩者是不同的量測對象,用不同方法收集。golden dataset 的分母是「已經想到、寫成測資的案例」,使用者滿意度的分母是「所有真實發生過的互動」,把其中一個當成另一個的代理指標,等於默默接受了一個沒被驗證過的假設。

誤解四:evaluation 不準,所以不必做

不完美的測量不等於不測量。

比較務實的做法是標註不確定性、交叉比對 deterministic rule、judge 與人類樣本,並持續把真實失敗加入 dataset。

這比只看 HTTP 200 更接近實際風險。

這個誤解常以更委婉的說法出現:「evaluator 準確度只有八成,先別急著建立,等更成熟的工具再說」。盲點在於:不做 evaluation 不代表系統沒有錯誤,只代表沒人主動去看。八成準確的 evaluator,仍能抓到八成裡的絕大多數問題;完全不做評估,抓到的比例是零。與其等不存在的「完美工具」,不如先用承認自己不完美、但持續標註不確定性的系統開始運作,再用真實失敗案例逐步餵得更準。

這個誤解也常常跟另一句話一起出現:「反正 dataset 只有 50 筆案例,樣本太小,量出來的數字沒有意義」。50 筆確實無法代表全部真實流量,但它已經足以攔下 ⑯ 段 Mata v. Avianca 那種「六個判例全部虛構」的錯誤——那種錯誤不需要龐大樣本才抓得到,一筆設計良好的 citation_valid 檢查就夠了。「樣本太小」跟「樣本不該存在」是兩件不同的事,前者提醒你不要把 dataset pass rate 過度推論成使用者滿意度(見誤解三),後者則是用「不夠完美」當藉口,讓本來能做的檢查完全沒有發生。

誤解五:「這個 evaluator 上次很準」代表它現在也很準

前面四個誤解都在講「怎麼看待評估的結果」,最後這個要講一個更容易被忽略的事:評估工具本身也是會壞掉、會過時的系統元件,不是裝好一次就能用一輩子的固定基礎設施。

evaluator 依賴 judge model、prompt、schema、甚至被評估模型的行為分布。任何一項改變,evaluator 的準確度都可能悄悄跟著變,而且不會發出警訊——不像服務掛掉那樣有明確錯誤訊號,只會讓判定結果慢慢跟真實情況脫節。

上游 judge model 換了一個版本
  → 原本校正過的 confidence 分布可能整個偏移

被評估的系統換了 prompt 風格(例如變得更簡短)
  → verbosity bias 校正過的 judge,判斷標準可能不再適用

dataset 案例的措辭跟真實流量的措辭出現落差
  → judge 在 dataset 上表現良好,不代表在真實流量上一樣準

evaluator 的 policy 或 schema 本身被改動
  → 「pass 比例下降」可能是系統變差,也可能只是 evaluator 變嚴格了

這正是 ⑦ 段強調 evaluator_version 要被記錄下來的原因:evaluator 準不準需要被持續驗證,不是驗證一次就永久信任。一套健康的 evaluation 系統,會定期用新的人工標註樣本回頭檢查 evaluator 有沒有飄移——判分本身,也需要被判分。

⑮ 把判分變成可追查的決策

Task success、quality 與 safety 不應由一個模型分數取代,也不該被混成單一 SLO。

先寫清楚 outcome contract,再用版本化 dataset、可解釋的 deterministic check、受監督的 LLM judge 與人工抽樣建立證據鏈。

這條鏈仍不會保證 AI 永遠正確。

它做得到的是:當答案出問題時,團隊不必只靠「感覺模型今天怪怪的」來決定下一步。

回頭看本篇走過的路,其實在重複同一個動作:每碰到一個看起來能用單一數字概括的問題,就再問一句「這個數字,是不是把幾件性質不同的事情混在一起了?」task success、quality、safety 是三件不同的事;citation validity 與 citation entailment 是兩種不同的檢查;offline 與 online 是互補而非替代的量測方式;連 confidence 都不等於真實機率。這些拆分看起來瑣碎,共同構成的是一套讓「AI 系統做錯事」從「模糊的感覺」變成「有跡可循的證據鏈」的基礎設施。

Google Bard 的市值蒸發、Amazon 停用的履歷篩選工具、Meta 被推翻的審核判定、Cursor 那則憑空捏造的客服回覆、Mata v. Avianca 那六個虛構判例——這些案例橫跨的產業與規模差異很大,卻共享同一個技術特徵:technical layer 全部正常,錯誤只藏在 quality 或 safety 這一層,而且都是在「格式完整、語氣自信」的包裝下被交付出去的。犯錯的那一刻,沒有一套機制能及時把「技術上一切正常」與「使用者拿到的結果是錯的」區分開來——這正是本篇想留給讀者的核心工具:把成功拆成可以分別檢查的維度,錯誤才有機會在造成傷害之前被攔下來。

⑯ 實作補充:一個法律案例,測試分類有沒有落地

前面 ⑥ 段的 DIY 走的是「offline evaluation + deterministic check」這條完整路徑。這裡不再重建一次 dataset,改用一個真實發生過的案例,直接驗證本文一路強調的 citation_valid 這種最便宜的檢查,能不能擋下一次代價慘重的失誤。

2023 年紐約南區聯邦法庭有一起案件(Mata v. Avianca),律師用 ChatGPT 研究法律判例,在訴狀中引用了六個完全虛構的法庭判例。這些引用格式完全正確(案例編號、法院名稱、判決年份都看起來真實),系統的「task success」指標全綠——格式正確、邏輯連貫、回應完成。但「quality」失敗了:內容是完全編造的。任何自動化評估如果只檢查「有沒有生成格式正確的回應」,都會通過檢查。因此 golden dataset 必須顯式包含「來源查證」檢查點:這些 citation 或宣稱能否追溯到真實來源?系統是否能誠實地說「我不確定」而非編造答案?

把 Mata v. Avianca 這個案例,套進本篇 ③ 段的四欄位分類法,會很清楚地看到問題出在哪一格:technical_status: completed(ChatGPT 正常回應完成,沒有任何 API 層級的錯誤)、task_status(表面上看似完成——律師確實拿到了他要的「判例引用」)、quality_status: fail(六個判例全部不存在)、safety_status(沒有觸發任何安全政策,因為這不是一個涉及敏感資料或高風險操作的請求)。如果當初這位律師的工作流程裡,有一個像 citation_valid 這樣的 deterministic check——去查詢法院資料庫確認每個案例編號是否真實存在——這六個虛構判例會在送出訴狀之前就被攔下來,而不是等到對造律師在法庭上指出「我查不到這些案例」才被發現。

這也是本篇一路強調「deterministic check 優先於 LLM judge」的一個現成範例:判斷「這個案例編號在法院資料庫裡存不存在」,不需要語意理解,只需要一次查詢比對,是最適合、最便宜、最不該被省略的第一道檢查。真正需要語意判斷的,是下一層更難的問題——「這個案例的判決內容,是否真的支持律師想主張的論點」,那才輪到 LLM judge 或人工複核上場。把容易做的檢查省略掉、直接跳去做困難的語意判斷,是很多評估系統一開始就走偏的地方。

值得補一句:這位律師事後解釋,他曾直接問 ChatGPT 這些案例是否真實存在,ChatGPT 回答「是的,可以在 Westlaw 與 LexisNexis 找到」。這個細節更貼近本文的重點——問題不是模型沒機會自我查核,而是「請模型自己確認自己說的話是否正確」本身不能當成可靠的 deterministic check。模型對自己輸出的信心,跟輸出是否正確是兩個沒有必然關聯的變數;真正可信的查核,仍要接到資料庫查詢這種不依賴模型自我陳述的外部依據。

驗收

  • task、quality、safety 沒有混成一個數字。
  • dataset 有版本與案例意圖。
  • 評估失敗知道會阻擋 release、排入 review 或安全攔截。
  • 本文未執行 evaluator,沒有品質分數可報告。

⑰ 本文結論

能量化不代表能自動判定。讓評估能回溯、能質疑,才有資格慢慢接近 SLO。

這篇談的東西說到底是三句話:把成功拆成看得見的欄位,把每一次判定的依據留下來,把不同性質的失敗送到不同的人手上。做到這三件事不會讓 AI 系統從此不犯錯——Bard 會答錯、Cursor 的客服會編政策、法律 AI 還是會引用不存在的判例,這些事不會因為多了一套評估機制就徹底消失。它改變的是下一件事發生時,團隊看到的是一份可以追查的紀錄,還是只有一句「感覺哪裡怪怪的」。

這也是為什麼「先寫欄位、再談分數」的順序不能顛倒。先追求一顆漂亮的 quality score,定義很自然會往容易達標的方向靠攏;先把 task success、quality、safety 各自的欄位、outcome contract、失敗時該通知誰寫清楚,分數不管高低至少都指向一組可以被檢驗、被質疑、被修正的具體判斷——這才是 SLO 該扮演的角色:不是對外展示的數字,是讓團隊持續誠實面對系統缺陷的機制。明天用 error budget 把這些目標接到決策。

Day 20 預告

Day 19 把 task success、quality、safety 拆成三個獨立訊號,也點出評估本身會靜默失敗。Day 20 要把這些訊號接回決策:SLO 訂在哪裡、error budget 燒多快才該踩煞車,以及 semantic failure 算不算進 budget 消耗。

延伸閱讀


這篇是 Learning SRE for the AI Era 系列的一部分。

我會從 SRE 的服務可靠性基礎開始,逐步探索當系統加入 LLM、RAG、Agent 與 GPU Infrastructure 後,如何讓 AI 系統不只可用,也能被觀測、評估、控制成本並安全演進。

Build → Trace → Break → Measure → Evaluate → Recover → Improve.


上一篇
Day 19(上)|Task Success、Quality、Safety SLO:不能只由模型幫自己打分
下一篇
Day 20(上)|Error Budget 與 Burn Rate:預算用完要真的改變行為
系列文
Learning SRE for the AI Era:從 SRE Lab 到 Production AI Reliability 共 44 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言