Back to blog
    微調結構化輸出:從 JSON 模式到有保證的 Schema
    fine-tuningstructured-outputjsonschemasegment:developer

    微調結構化輸出:從 JSON 模式到有保證的 Schema

    JSON 模式讓你得到有效的 JSON。微調讓你得到有保證的 schema 合規性——每個欄位、每種類型、每次都正確。以下是如何訓練模型輸出你的應用程式所期望的確切結構。

    EErtas Team·

    你的應用程式期望一個包含確切 8 個欄位的 JSON 物件,每個欄位有特定類型,其中兩個為枚舉值,以及一個帶有自身 schema 的巢狀物件陣列。你要求 GPT-4 生成它。大多數時候,你得到了你想要的。有時你得到 7 個欄位。偶爾你得到一個字串而不是預期的整數。偶爾模型會發明一個不存在的枚舉值。

    在 95% 的 schema 合規率下,每 20 次 API 呼叫就有 1 次產生你的解析器無法處理的輸出。如果你的應用程式每天進行 10,000 次結構化輸出呼叫,那就是每天 500 次失敗。每天都是。你的錯誤處理代碼變得比你的實際業務邏輯更複雜。你添加重試、備用提示、後處理修復器。系統可以工作,但很脆弱——靠膠帶和重試循環維持。

    微調改變了這個方程式。一個在 500-1,000 個你確切 schema 範例上訓練的模型不會偏移、不會幻覺欄位、不會發明枚舉值。Schema 合規率從提示的 95% 提升到微調後的 99.5% 以上。在每天 10,000 次呼叫的情況下,這是 500 次失敗和 50 次之間的差異。

    結構化輸出的層次

    結構化輸出有一個層次體系,從最不可靠到最可靠:

    第 1 級:基於提示(「請輸出 JSON」)

    在提示中要求模型生成 JSON。包含範例。期望最好的結果。

    • 合規率: 80-90%
    • 失敗模式: 無效的 JSON(缺少引號、尾部逗號)、缺少欄位、錯誤類型、額外欄位、Markdown 包裝
    • 何時使用: 僅用於原型開發

    第 2 級:JSON 模式

    OpenAI 的 JSON 模式,或其他 API 中的等效設定。強制模型輸出語法有效的 JSON。

    • 合規率: 95-98%(有效 JSON,但 schema 合規性有所不同)
    • 失敗模式: 不符合你的 schema 的有效 JSON——缺少必填欄位、錯誤欄位名稱、類型不匹配、額外欄位
    • 何時使用: 當你需要有效 JSON 但可以容忍 schema 偏移時

    第 3 級:Function Calling / Structured Outputs API

    OpenAI 搭配 JSON schema 的結構化輸出,或 function-calling 端點。API 在解碼層面強制執行 schema。

    • 合規率: schema 結構 99% 以上
    • 失敗模式: 結構正確但值錯誤——幻覺的枚舉值、語義錯誤的內容、預期有內容的地方卻是空字串
    • 何時使用: 當你需要來自雲端 API 的 schema 合規性,且可以接受每 token 成本時

    第 4 級:微調模型

    在數百個你確切 schema 範例上訓練的模型。了解欄位名稱、類型、有效值和語義期望。

    • 合規率: 99.5-99.9%
    • 失敗模式: 訓練分佈之外的遠端輸入上的罕見邊緣案例
    • 何時使用: 高流量的生產系統,可靠性和成本很重要

    第 5 級:微調模型 + 約束解碼

    帶有約束解碼的微調模型(llama.cpp grammar、Outlines 或 guidance),使無效 token 成為不可能。

    • 合規率: 100% 結構合規性
    • 失敗模式: 結構完美的 JSON,但值在語義上錯誤(微調後很少見)
    • 何時使用: 當你需要零結構失敗且正在運行本地推論時

    為何提示有上限

    基於提示的結構化輸出的根本問題:模型按順序生成 token,沒有任何機制阻止它生成違反你的 schema 的 token。

    當你提示 GPT-4 輸出 {"status": "approved" | "denied" | "pending"} 時,模型可能在一次呼叫中生成 "status": "approved",在下一次生成 "status": "Approved"。或者 "status": "approve"。每個都是有效的 JSON 字串——模型沒有限制說「只有這三個確切值是可接受的」。

    更詳細的提示有更詳細的 schema 有幫助,但它們達到收益遞減:

    • 1 行 schema 描述:約 85% 合規率
    • 詳細 schema 帶範例:約 92% 合規率
    • Schema + 少樣本範例 + 明確約束:約 95-97% 合規率

    你無法通過提示達到 99.5%。模型的 token 生成是概率性的。無論你的提示多好,生成錯誤 token 的概率永遠不會恰好為零。

    微調直接改變模型的概率分佈。在 500 個範例訓練後,其中 status 始終恰好是 "approved""denied""pending",模型為該欄位的任何其他值分配接近零的概率。合規性來自權重,而不是提示。

    構建符合 Schema 的訓練資料集

    訓練資料的品質決定了你的 schema 合規性品質。以下是如何構建產生可靠結構化輸出的資料集。

    第 1 步:正式定義你的 Schema

    從 JSON Schema 規範開始:

    {
      "type": "object",
      "required": ["id", "status", "score", "category", "findings", "metadata"],
      "properties": {
        "id": {"type": "string", "pattern": "^RPT-[0-9]{6}quot;},
        "status": {"type": "string", "enum": ["approved", "denied", "pending", "review"]},
        "score": {"type": "number", "minimum": 0, "maximum": 100},
        "category": {"type": "string", "enum": ["financial", "operational", "compliance", "technical"]},
        "findings": {
          "type": "array",
          "items": {
            "type": "object",
            "required": ["description", "severity", "recommendation"],
            "properties": {
              "description": {"type": "string"},
              "severity": {"type": "string", "enum": ["low", "medium", "high", "critical"]},
              "recommendation": {"type": "string"}
            }
          }
        },
        "metadata": {
          "type": "object",
          "required": ["analyst", "date", "version"],
          "properties": {
            "analyst": {"type": "string"},
            "date": {"type": "string", "format": "date"},
            "version": {"type": "string"}
          }
        }
      }
    }

    第 2 步:生成多樣化的有效範例

    你需要 500-1,000 個訓練範例。每個都必須是你的 schema 的完全有效實例。生成它們有三種方法:

    來自生產資料: 如果你有遵循此 schema 的現有資料(來自資料庫、來自之前的 API 輸出),將其轉換為訓練範例。這是最佳來源,因為它反映了真實世界的值分佈。

    來自 GPT-4 加驗證: 使用 GPT-4 生成多樣化範例,然後根據你的 JSON Schema 驗證每個範例。丟棄任何未通過驗證的範例。在 GPT-4 95% 合規率下,你將丟棄約 1/20——對資料集生成來說可以接受。通過你的實際解析器再次檢查已驗證的範例。

    程序化生成: 編寫一個腳本,隨機生成你的 schema 的有效實例。這保證了結構有效性,但可能缺乏語義連貫性。用它來補充真實範例,而不是作為唯一來源。

    第 3 步:讓輸入多樣化,而不僅僅是輸出

    你的訓練資料需要與符合 schema 的輸出配對的多樣化輸入。如果每個輸入都是「分析這份財務報告」,模型學到了 schema 但無法泛化到新的輸入措辭。

    包含變體:

    • 不同的輸入長度(一句話到三段)
    • 不同的輸入格式(正式請求、隨意問題、結構化指令)
    • 不同的上下文級別(完整資訊 vs. 部分資訊)
    • 邊緣案例(模糊輸入、缺少資訊的輸入、應該生成空陣列的輸入)

    第 4 步:明確包含邊緣案例

    提示模型失敗最多的地方是邊緣案例。確保你的訓練資料覆蓋:

    • 空陣列:findings 應該是 [] 因為沒有發現時
    • 最小/最大值: score: 0score: 100——模型傾向於避免極端值
    • 長字串值: 有 200 個以上字元的欄位(模型有時會截斷)
    • 特殊字元: 字串欄位中的引號、換行、unicode
    • Null 處理: 如果你的 schema 允許可空欄位,包含帶 null 值的範例

    第 5 步:格式化為訓練配對

    將每個範例結構化為 system/user/assistant 對話:

    {
      "messages": [
        {
          "role": "system",
          "content": "You are a report analysis system. Analyze the provided report and output a structured assessment."
        },
        {
          "role": "user",
          "content": "Report: Q3 revenue declined 12% due to supply chain disruptions. Two compliance violations were identified in the procurement process. The technical infrastructure handled the load increase from the holiday promotion without incidents."
        },
        {
          "role": "assistant",
          "content": "{\"id\": \"RPT-004521\", \"status\": \"review\", \"score\": 62, \"category\": \"operational\", \"findings\": [{\"description\": \"Revenue decline of 12% attributed to supply chain disruptions\", \"severity\": \"high\", \"recommendation\": \"Diversify supplier base and establish backup procurement channels\"}, {\"description\": \"Two compliance violations in procurement process\", \"severity\": \"medium\", \"recommendation\": \"Audit procurement workflows and retrain staff on compliance requirements\"}], \"metadata\": {\"analyst\": \"system\", \"date\": \"2026-03-15\", \"version\": \"1.0\"}}"
        }
      ]
    }

    助理的回應必須是原始 JSON——無 Markdown 格式,無解釋性文字,無程式碼塊。訓練模型只輸出 JSON,僅此而已。

    測量 Schema 合規性

    不要依賴「看起來對」的判斷。以程式方式測量合規性:

    結構合規性

    通過 JSON Schema 驗證器執行每個輸出。統計通過的百分比。這能捕獲缺少的欄位、錯誤的類型、無效的枚舉值和 schema 結構違規。

    語義合規性

    結構有效性並不意味著內容是正確的。模型可以輸出 {"status": "approved", "score": 0}——結構上有效,但語義上可疑(得 0 分卻被批准?)。建立語義檢查:

    • 枚舉值是否與其他欄位正確關聯?
    • 數值是否在現實範圍內?
    • 字串值是否包含相關內容(不是 lorem ipsum 或空字串)?
    • 陣列長度是否與輸入相稱?

    比較指標

    微調後,與你的基線進行比較:

    指標提示 GPT-4o微調 8B微調 8B + Grammar
    有效 JSON99.5%99.8%100%
    Schema 合規性93-96%99.2-99.7%100%
    語義準確率90-94%93-97%93-97%
    平均 tokens/回應350280280
    每 1K 呼叫成本$2.50-$8.00$0(本地)$0(本地)

    微調模型更符合 schema,使用更少 tokens(它不會用不必要的冗長填充回應),且每次呼叫零成本。

    結合微調與約束解碼

    對於即使 99.5% 都不夠的應用——金融交易、醫療記錄、法律文件——將微調與約束解碼結合。

    約束解碼(也稱為 grammar 引導生成)限制模型的輸出 token 只能是根據 grammar 規範產生有效輸出的那些。llama.cpp 透過 GBNF grammars 支援此功能。Outlines 和 guidance 為基於 Python 的推論提供類似功能。

    你的 schema 的 GBNF grammar:

    root   ::= "{" ws "\"id\":" ws string "," ws "\"status\":" ws status "," ws "\"score\":" ws number "," ws "\"category\":" ws category "," ws "\"findings\":" ws findings "," ws "\"metadata\":" ws metadata ws "}"
    status ::= "\"approved\"" | "\"denied\"" | "\"pending\"" | "\"review\""
    category ::= "\"financial\"" | "\"operational\"" | "\"compliance\"" | "\"technical\""
    ...
    

    使用微調模型 + grammar,你可以得到:

    • 100% 結構合規性(grammar 防止無效結構)
    • 99.5% 以上語義準確率(微調教導正確值)
    • 零每 token 成本(本地推論)
    • 快速推論(grammar 約束實際上通過減少 token 搜索空間稍微加速生成)

    grammar 處理結構。微調處理內容。兩者結合產生你的解析器可以無條件信任的輸出。

    效能影響

    生成結構化輸出的微調模型通常比提示模型更快,原因有兩個:

    1. 更短的輸出: 提示模型通常在 JSON 周圍包含解釋性文字、Markdown 格式或元評論。微調模型只輸出原始 JSON。這將輸出 tokens 減少 20-40%。

    2. 更自信的生成: 當模型「了解」schema 時(來自微調),它以更高的信心生成每個 token。在採樣過程中較少回溯。可測量地降低首個 token 時間和更快的 token 生成速率。

    客戶支援票證分類 schema 的基準測試(8 個欄位,2 個枚舉,1 個巢狀物件):

    設置平均輸出 Tokens平均延遲結構有效性
    GPT-4o + 提示420 tokens1.8s96.2%
    GPT-4o + structured outputs API310 tokens1.4s99.8%
    微調 8B (Ollama)270 tokens0.4s99.5%
    微調 8B + grammar265 tokens0.35s100%

    微調的本地模型快 4 倍,且產生更短、更可靠的輸出。

    Schema 微調中的常見錯誤

    錯誤 1:訓練資料不一致

    如果你的 80% 訓練範例使用 "date": "2026-03-15",而 20% 使用 "date": "March 15, 2026",模型會學習兩種格式並概率性地在它們之間切換。每個欄位、每種格式、每個慣例在所有訓練範例中必須 100% 一致。

    錯誤 2:不在空/Null 案例上訓練

    如果你的 schema 允許可選欄位或空陣列,但所有訓練範例都有填充值,模型將幻覺值而不是輸出 null[]。包含 10-15% 的每個可選欄位設為 null 和每個陣列為空的範例。

    錯誤 3:輸入過於同質

    如果你所有的訓練輸入長度、複雜性和主題大致相同,模型會過擬合到該輸入分佈。當它在生產中看到明顯不同的輸入時,schema 合規性下降。積極地讓你的輸入多樣化。

    錯誤 4:在格式化的 JSON 上訓練

    如果你在帶縮排的格式化 JSON 上訓練,模型在空白上浪費 tokens。在壓縮 JSON 上訓練:{"id":"RPT-004521","status":"approved",...}。這將輸出 tokens 減少 15-25% 並提高生成速度。

    錯誤 5:不驗證訓練資料

    如果即使一個訓練範例有 schema 違規,模型也會學習違規是可以接受的。在將每個訓練範例加入資料集之前,針對你的 JSON Schema 驗證每個範例。自動化這個過程。沒有例外。

    開始使用

    1. 將你的目標 schema 定義為正式的 JSON Schema
    2. 收集或生成 500-1,000 個已驗證的訓練範例
    3. 格式化為 JSONL 訓練配對(system/user/assistant)
    4. 以程式方式驗證每個範例——丟棄任何有 schema 違規的範例
    5. Ertas 上微調——Llama 3.1 8B 或 Qwen 2.5 7B 對結構化輸出來說都是很好的選擇
    6. 在 100 個以上的保留範例上評估,測量結構和語義合規性
    7. 透過 Ollama 部署,可選地使用 GBNF grammar 保證結構
    8. 監控生產輸出,並將失敗案例加入你的訓練資料以進行下一次迭代

    目標很簡單:你的應用程式的 JSON 解析器永遠不應該因為模型而失敗。微調讓你達到這個目標。


    Ship AI that runs on your users' devices.

    Ertas early bird pricing starts at $14.50/mo — locked in for life. Plans for builders and agencies.

    延伸閱讀

    Ship AI that runs on your users' devices.

    Early bird pricing starts at $14.50/mo — locked in for life. Plans for builders and agencies.

    Keep reading