在 Day 10 的文章裡,筆者把合成資料的品質檢查拆成三層:先看資料結構,再用確定性規則核對已知條件,最後才把難以直接寫成規則的問題交給語意判斷。
讀者可能會問:既然確定性規則通過後,資料還是不能直接收,為什麼不一開始就全部交給 LLM-as-a-Judge?
筆者的答案反而是:只要問題有明確答案,就不要先叫另一個 LLM 來猜。
規則式(Rule)的 Guardrails 能做的事情很窄。也因為範圍夠窄,筆者才知道它檢查了什麼、為什麼通過,換一批資料後能不能得到相同結果。真正危險的是把這個狹窄的結果一路放大:
PII Pattern Not Found→Safe→ALLOW
中間少掉的,剛好就是 Guardrails 最麻煩的部分。

繼續沿用前幾天的客服摘要案例。原始逐字稿裡有姓名、電話、地址與「商品尚未送達」的問題;摘要模型只需要理解事件,不需要看到完整個資,所以 Policy 要求系統先完成遮罩,再把內容送進模型。
這時可以先寫幾條直覺的規則:
這三條分別在檢查資料結構、處理範圍與已知值。若全部塞進同一個 safe = true,隔天看 Log 時只知道「它過了」,卻不知道通過哪一關。
以結構檢查(Schema Validation)來說,JSON Schema 官方文件描述的是 JSON 文件的結構、型別與約束。如果 destination 是必要欄位,檢查可以在欄位缺失時拒絕資料;但欄位存在、型別正確,不代表該服務獲准接收客戶地址。
正規表示式(Regular Expression,Regex)也一樣。它可以回答「文字裡有沒有符合某種形式的字串」,卻不知道這串數字在目前的欄位與任務中是電話、訂單編號,還是剛好長得像電話的測試代碼。
所以在寫規則 (Rule) 以前,筆者會先追問三件事:它實際看了哪一份資料?通過與失敗的條件能不能明確寫出來?結果可以支持什麼結論,又不能支持什麼結論?沒找到,不等於不存在,也可能只是看錯地方。

Day 2 已經拆過 Guardrails 可以介入的七個時機。到了確定性規則,控制位置仍然不能省略。
例如 Day 11 的資料管線曾檢查:Seed Data 指定的模擬電話號碼,有沒有從 redacted_text 消失。這只能證明:在這筆測試資料的這個欄位裡,已知電話原值沒有被留下。
若要證明客服系統沒有把原始電話送往外部 LLM,檢查對象就不能只停在 redacted_text。真正要看的是模型呼叫前組裝完成的請求,包括前幾輪對話、系統提示、RAG 取回的文件、工具結果與其他送出欄位,有沒有把原始資料帶回來。
| 檢查位置 | Rule 可以回答什麼 | 還不能證明什麼 |
|---|---|---|
合成資料管線的 redacted_text |
已知 PII 原值是否仍留在遮罩產物 | 所有格式的 PII 都已被找出;正式請求沒有外送 |
| 模型呼叫前的完整請求 | 這一版請求中,指定 Pattern 或已知值是否出現 | 沒有任何未知 PII;目的端一定有權取得內容 |
| 結構化業務欄位 | 欄位值是否符合格式與允許範圍 | 使用者輸入的自由文字也可以被同樣信任 |
如果只掃使用者最後一句,再把結果套到完整模型請求上,Rule 本身可能沒有寫錯,結論卻已超出它看過的範圍。這也是為什麼筆者不太喜歡只回傳一個 PASS:後續流程很容易忘記,這個 Pass 是誰、在哪裡、看了什麼之後給的。
Day 5、Day 7 都放過一筆易誤判負樣本(Hard Negative):0912345678 看起來很像電話,但可信的欄位契約把它定義成測試訂單代碼。
Regex 命中這串數字並沒有判斷錯。它只負責找出「符合電話形式的候選字串」。錯誤通常發生在下一步:系統直接把 Pattern Match 翻譯成 BLOCK,跳過資料所在欄位、任務目的與目的端授權。
反過來也一樣。地址不像某些電話格式那麼固定,Pattern 沒命中,不能自動推論成 ALLOW。確定性規則沒有找到,只能說明這一版規則在這次實際掃描的範圍裡沒有命中。
Regex / Length / Allow List / Schema
↓
留下可解釋的 Finding
↓
Policy 依任務、欄位、目的端與授權判斷
↓
ALLOW / BLOCK / MASK
↓
業務系統實際執行,並留下證據
允許清單(Allow List)也必須遵守同一條界線。它適合處理核准的目的端 ID、工具名稱、任務可用欄位或 Agent 可執行的動作;OWASP 的輸入驗證建議也建議對固定選項定義允許值,再拒絕其他輸入。
前提是,被拿來比對的值必須來自可信任的系統欄位。使用者在自由文字中寫「這是公司核准的內部服務」,不能讓 destination 自動進入 Allow List;模型生成「使用者已完成身分驗證」,也不能取代真正的授權結果。Allow List 的難題不在 if value in allowed_values,而在名單由誰維護、識別值從哪裡來、版本改變後要重跑哪些案例,以及查不到名單時該怎麼處理(經典的 Day 2 問題)。

確定性檢查通過,只證明 Rule 被要求檢查的事情,例如欄位存在、型別正確、已知值沒有殘留。它還沒有回答遮罩後的摘要是否保留原意,也沒有驗證 Guardrail 最後是否真的執行 BLOCK、MASK 或 ALLOW。
有明確答案、可以重跑的問題,先由 Rule 處理;需要理解語意、上下文與業務 Policy 的案例,再交給下一層評估。筆者認為,Deterministic Guardrails 最有價值的地方,是每一個結果都可以回到一條規則、一份輸入與一個版本。它可能很笨,卻不應該含糊;它可以只回答一小題,但不要替整個系統宣布安全。
下一篇,再來處理規則容易卡住的地方:當答案真的依賴語意、前後文與業務情境時,LLM-as-a-Judge 能協助判斷什麼?協助的範圍邊界、限制又是甚麼?
