🎯 什麼情境該想到我
當你「要 LLM 產一個有結構的東西(圖、設定檔、報表、SQL、IaC),但沒辦法用肉眼一個一個檢查」的時候。
⚙️ 怎麼用(步驟 / 公式)
核心是一句話:不要讓模型產最終產物,讓它產 typed IR,最終產物由確定性的程式編出來。
模型 → typed IR(有 schema 的中介表示)→ 確定性編譯器 → 最終產物
↓
驗證閘(失敗回結構化診斷)
-
切開「判斷」與「計算」。把需要語義判斷的部分留給模型(該有哪些節點、誰接誰、什麼是主路徑),把可以精確算的部分交給程式(座標、間距、繞線、渲染)。模型不擅長的算術,就不要讓它算。
-
給 IR 一份 schema。有 schema 才能自動驗、才能明確告訴模型「欄位長什麼樣」,也才能給它一份範例——但要講清楚「範例是給你看欄位形狀,不是給你抄內容的」。
-
設分級的驗證閘,並明講哪一級才算通過。
例:4 項檢查=基本驗證,9 項全過 + 0 錯誤 + 0 警告=可交付。不明講的話,模型會拿低標當通過。 -
失敗要回「修復收據」,不是堆疊追蹤。一份好的診斷要有三件事:
subject——出問題的確切那一項evidence——量到的數值(不是「看起來怪怪的」)supportedFixes——可用的修法清單(而不是讓模型自由發揮)
然後在指令裡限制:只改被診斷的那一項、一次只套一個修正。
-
寫死收斂條件。例:「持續修正,只要客觀錯誤數還在創新低;若連續兩輪沒有刷新最佳值,就停下來、如實回報未解決的診斷。」
-
通過即凍結、交付要原子。驗證通過的產物不准再編輯;交付時先在私有快照上渲染檢查,通過才原子替換目標檔案,並回報 SHA-256 與 byte count。
★ 為什麼「讓模型直接產最終產物」是錯的
❌ 模型 → 最終產物(SQL、程式碼、設定檔、圖表、報告)
★ 你只能「看」它對不對 —— 而你看不出微妙的錯誤
★ 每次產出都不同,無法 diff、無法回歸測試
★ 錯了只能重新生成,不能修
✅ 模型 → typed IR → 確定性編譯器 → 最終產物
★ IR 有 schema → 可以「程式化驗證」
★ IR 是結構化的 → 可以 diff、可以存版控、可以手動修
★ 編譯器是確定性的 → 同一個 IR 永遠產生同一個產物
★ 核心洞察:把「無法驗證的創造」縮小成「可以驗證的一小步」,其餘交給確定性的程式。
模型負責「決定要什麼」,程式負責「正確地做出來」。
★ 驗證閘的層次(由便宜到貴)
| 層 | 檢查什麼 | 成本 |
|---|---|---|
| ① Schema | 結構對不對、欄位齊不齊、型別對不對 | ★ 極低(約束解碼可以直接保證,見 Function Calling 與結構化輸出) |
| ② 語義/業務規則 | 引用的欄位存在嗎?數值在合理範圍嗎?狀態轉換合法嗎? | 低 |
| ③ ★ 執行 | 編譯得過嗎?測試過嗎?查詢跑得動嗎? | 中——但這一層的訊號最強 |
| ④ 比對 | 和既有的 golden output 比 | 中 |
| ⑤ 人工/裁判 | 主觀品質 | 高(見 LLM-as-Judge) |
★ 關鍵:驗證失敗時要回傳「結構化的診斷」而不是「失敗」。
{ "ok": false, "errors": [
{ "path": "$.filters[0].field", "code": "UNKNOWN_FIELD",
"got": "user_nmae", "expected_one_of": ["user_name","user_id","email"] }
]}★ 模型修正錯誤的能力,取決於錯誤訊息的品質。
validation failed→ 它只能瞎猜;上面那種訊息 → 它幾乎一定能一次修對。
這和 工具-讓測試失敗訊息有用 是同一條原則。
★ 什麼任務適合(判準很明確)
| ✅ 適合 | ❌ 不適合 |
|---|---|
| ★ 有明確的目標語言/格式(SQL、圖表、設定、API 呼叫) | 自由寫作、摘要 |
| ★ 產物的正確性可被程式檢查 | 主觀品質(文案好不好) |
| ★ 同樣的輸入該產生同樣的輸出 | 需要創意多樣性 |
| 產物需要被版控與審查 | 一次性的對話回應 |
典型應用:
自然語言 → 查詢 IR → SQL (見 [[AI 系統設計框架]] 的 Text-to-SQL)
需求描述 → 圖表 IR → Mermaid/SVG
設定意圖 → 設定 IR → YAML/Terraform
資料需求 → 轉換 IR → dbt model
★ IR 該怎麼設計
| 原則 | 說明 |
|---|---|
| ★ 比目標語言「窄」 | 不要讓 IR 能表達 SQL 的全部——只支援你要支援的子集。 ★ 窄 = 好驗證、好編譯、模型也比較不會亂寫 |
| ★ 用判別聯集 | 每個節點有 kind,不合法的組合在型別上就不存在(見 工具-判別聯集) |
| 可序列化 | JSON。可存、可 diff、可 review |
| ★ 人可讀可改 | 使用者要能手動微調 IR 而不是重新產生 |
| 扁平優於巢狀 | 深層巢狀的 schema 會讓模型與約束解碼都變差 |
★ 「IR 比目標語言窄」是最重要的一條:
你不需要支援 SQL 的所有語法,只需要支援「使用者實際會問的那幾種查詢」。
窄的 IR 讓安全性(不會產生 DROP TABLE)、驗證、編譯全部變簡單。
★ 和相鄰概念的關係
| 概念 | 關係 |
|---|---|
| Function Calling 與結構化輸出 | ★ 約束解碼保證「語法合法」,但不保證「語意正確」——IR 的驗證閘補上後者 |
| GRPO 與 RLVR | ★ 同一個思路的訓練版:可驗證的獎勵 |
| 工具-把命令變成可驗證的目標 | 同一條原則用在 agent 的目標設定上 |
| 直譯器模式 | IR 就是一個小 DSL 的 AST |
🧪 我實際套用的紀錄
- 2026-08-27:(待填)
⚠️ 注意 / 什麼時候不適用
- ★ 編譯器本身要被測試。IR 對了但編譯器有 bug → 產物還是錯的,而且更難發現(因為你信任它)。
- ★ IR 的表達力是天花板。IR 不支援的東西,使用者就做不到 → 要有「逃生口」
(允許手寫原生語法,但標記為「未經驗證」)。 - 不要讓 IR 太通用。變成「另一個程式語言」就失去了驗證的價值(見 直譯器模式 的警告)。
- ★ 驗證失敗的重試要有上限。模型修不好就該回報給人,不要無限迴圈(見 ReAct 與 Agent Loop)。
- schema 驗證通過 ≠ 內容正確。
{"limit": 999999}完全合法但可能是災難——業務規則要另外驗。 - 這個模式有前期成本:要設計 IR、寫編譯器、寫驗證器。一次性任務不值得;
★ 它的價值在「同一類任務會重複很多次」。
🔗 相關工具
- Function Calling 與結構化輸出 —— ★ 約束解碼的保證與限制
- 工具-讓測試失敗訊息有用 —— 診斷訊息的品質決定修正能力
- 工具-判別聯集 —— IR 的型別設計
- 直譯器模式 —— IR 就是一個小 DSL
- GRPO 與 RLVR —— 可驗證性用在訓練上
- 工具-把命令變成可驗證的目標 —— 同一條原則用在 agent
- AI 系統設計框架 —— Text-to-SQL 的完整骨架
- 工具-防止agent造假通過驗收 —— 驗證不能由被驗者自己說了算