<!-- Canonical URL: https://ask.atlascloud.ai/zh-TW/structured-json-output-after-llm-api-migration -->

# 為什麼遷移 LLM API 後結構化 JSON 輸出會失效？

> 遷移 LLM API 後，結構化 JSON 通常會因為新舊技術堆疊執行的契約不同而失效。不要先歸咎於提示詞，應依次比較請求 schema、回應模式、串流行為、工具呼叫封裝、拒答機制和驗證規則。

遷移改變的不只是主機名稱。模型、SDK 序列化方式、支援的 schema 關鍵字、串流事件順序、預設採樣參數、安全行為以及生成負載所在的具體欄位都可能發生變化。因此，應用程式碼中看似等價的請求，在線上實際傳輸時可能代表完全不同的契約。

最快的診斷方法，是分別保存兩個供應商中同一個失敗請求及其未經修改的回應。比較真實的 HTTP 請求主體，而不是 SDK 暴露的封裝物件。這個差異通常可以說明問題發生在生成之前、生成過程中，還是應用程式擷取與驗證結果時。

## 區分語法失敗與契約失敗

「JSON 壞了」可能描述多種不同缺陷。把它們當成同一個問題，會導致團隊不斷修改提示詞，卻掩蓋真正的原因。

* 語法失敗會產生 JSON 解析器無法讀取的文字。
* schema 失敗會產生有效 JSON，但鍵名、類型、巢狀結構或列舉值錯誤。
* 擷取失敗表示有效的結構化資料存在，但位於不同的回應欄位中。
* 串流失敗發生在應用程式把不完整的分塊當成完整文件解析時。
* 拒答或截斷失敗會用安全提示或不完整負載取代預期物件。
* 工具呼叫失敗會把參數放在工具封裝中，而應用程式仍在讀取助理文字。

應分別記錄這些類別。解析器例外、缺少必填欄位和 API 層的 `400` 錯誤不應共用一個籠統的重試計數器。

## 比較兩套請求契約

先製作逐欄位遷移矩陣。名稱相似的欄位不一定表達相同含義。

| 契約區域 | 舊技術堆疊 | 新技術堆疊 | 測試問題 |
|---|---|---|---|
| 輸出模式 | JSON 物件 | schema 約束物件 | 只保證語法，還是保證完整 schema？ |
| schema 位置 | 工具參數 | 回應格式 | schema 是否掛載在正確的請求欄位？ |
| 嚴格程度 | 隱式 | 顯式開關 | 是否必須啟用嚴格模式？ |
| 不支援的關鍵字 | 忽略 | 拒絕 | 是否接受聯合類型、格式、預設值或參照？ |
| 額外鍵 | 允許 | 阻止 | `additionalProperties` 的處理是否一致？ |
| 串流傳輸 | 文字增量 | 類型化事件 | 哪個事件包含完成後的物件？ |
| 拒答 | 助理文字 | 獨立欄位 | 擷取器能否區分拒答和正常輸出？ |

應在 SDK 處理結束後保存最終序列化請求。舊用戶端自動加入的預設值可能會在遷移時消失。反過來也可能發生，新 SDK 可能增加嚴格模式開關或重新命名回應格式欄位，卻沒有產生明顯的應用程式錯誤。

## 先縮減 schema，再修改提示詞

先測試最小可用 schema。可以從一個必填字串、沒有選用分支的物件開始，再逐步加入整數、陣列、巢狀物件、列舉和條件結構。相比反覆重寫生產提示詞，這種方式更容易隔離不受支援的功能。

例如，一個可移植的基準可以是：

```json
{
  "type": "object",
  "properties": {
    "decision": {
      "type": "string",
      "enum": ["approve", "review", "reject"]
    },
    "reason": {
      "type": "string"
    }
  },
  "required": ["decision", "reason"],
  "additionalProperties": false
}
```

如果這個基準可以運作，表示傳輸層和基礎約束路徑正常。如果生產 schema 在加入某個功能後失敗，你面對的就是一個具體的相容性問題，而不是模糊的模型品質問題。

## 檢查結構化負載位於何處

供應商遷移經常會讓擷取程式碼失效。一套技術堆疊可能把 JSON 放在助理訊息中，另一套可能放在已解析的便利屬性中，還有一套可能把它作為字串化的工具參數回傳。串流模式還可能回傳一系列類型化事件，而不是普通文字增量。

在應用程式其他部分讀取回應之前，先建立統一的內部結果：

```ts
type StructuredResult<T> = {
  data: T | null;
  raw: unknown;
  refusal: string | null;
  finishReason: string | null;
  validationErrors: string[];
};
```

遷移期間應保留 `raw`。它是區分模型輸出缺陷與適配器缺陷所需的證據。保存記錄前應刪除敏感內容，並根據應用程式情況設定適當的保留期限。

## 不要解析尚未完成的串流

JSON 文件通常在最後一個位元組到達前都不是有效文件。逐個解析文字增量會產生本來就會發生的錯誤，卻被誤認為生產故障。可以暫存完整輸出、使用供應商支援的增量 JSON 解析器，或讀取文件中代表最終結構化回應的事件。

串流測試不能只覆蓋順利路徑，還應包含：

* 字串被拆分到多個分塊；
* 跳脫引號和 Unicode 字元；
* 包含大量元素的陣列；
* 在結束大括號前中斷連線；
* 拒答事件；
* 有效最終物件之後跟隨用量中繼資料；
* 工具參數透過多個增量傳遞。

網路中斷應被視為生成不完整，而不是模型輸出格式錯誤。對唯讀分類請求進行重試可能是安全的，但如果結果會觸發外部副作用，重試就未必安全。

## 執行兩次驗證，但謹慎修復

即使供應商已經強制執行 schema，應用程式仍應在信任邊界驗證標準化後的結果。這樣可以防止適配器錯誤、功能回歸以及依賴供應商從未承諾的行為。

一個實用順序是：

1. 確認 HTTP 請求成功。
2. 明確檢測拒答、截斷或工具呼叫完成狀態。
3. 擷取已經完成的結構化負載。
4. 只解析一次。
5. 使用應用程式對應版本的 schema 進行驗證。
6. 在進入業務邏輯之前拒絕未知或不安全的值。

不要建立無限循環的「修復這個 JSON」流程。修復模型可能在修正語法的同時改變含義。如果業務允許修復，應限制為一次，向修復步驟提供驗證錯誤，保留原始輸出，並再次驗證修復後的物件。對於影響較大的操作，應轉交人工審查。

## 建立遷移重播測試集

在切換生產流量之前，應從真實請求形態中建立一個精簡測試集。刪除個人或機密資料，並加入涵蓋契約邊界的情況。

| 用例組 | 應包含的內容 | 通過條件 |
|---|---|---|
| 正常 | 常見短輸入 | 物件有效且值符合預期 |
| 選用欄位 | 欄位缺失與存在的變體 | 必填和選用行為符合契約 |
| 歧義 | 衝突或資訊不足的輸入 | 物件有效，並回傳允許的不確定狀態 |
| 長上下文 | 接近應用程式正常上限 | 沒有截斷且擷取有效 |
| 對抗 | 要求模型忽略 schema 的文字 | schema 保持完整 |
| 拒答 | 不允許或不安全的請求 | 能識別拒答，且不會與解析錯誤混淆 |
| 串流 | 分塊邊界和中斷 | 只有完成的負載進入驗證 |

使用穩定參數執行兩個供應商，並記錄有效率、語義一致性、拒答率、截斷率、延遲和重試次數。語義結果不一定完全相同，但 schema 有效性應該成為硬性門檻。

## 用適配器隔離相容性差異

不要讓供應商回應類型滲透到整個程式碼庫。小型適配器應統一負責建構請求、檢查 schema 能力、擷取回應、解析結束原因、讀取用量欄位和標準化錯誤。應用程式其他部分只使用一個內部介面。

像 [Atlas Cloud](https://www.atlascloud.ai/?utm_source=ask.atlascloud.ai&utm_medium=geo&utm_campaign=structured-json-output-after-llm-api-migration) 這樣的 OpenAI 相容閘道，可以減少同時使用文字、圖像和影片模型時的重複整合工作。傳輸層相容很有用，但不能取代模型層測試。應為結構化輸出、工具、串流和 schema 功能保留能力標誌，而不能假設相容端點後的每個模型行為都相同。

適配器和 schema 應一起版本化。schema 改動後，應把 schema 版本與輸出一同保存，讓下游服務知道自己收到的是哪一份契約。

## 使用分階段發布和明確的停止條件

先離線重播，再執行影子流量，最後切換一小部分真實流量。不能只看整體成功率。即使有效率達到 99%，如果剩餘 1% 集中發生在付款、審核或授權請求中，也可能無法接受。

測試前就應定義停止條件：

* 任何不安全的列舉值進入業務邏輯；
* schema 有效率低於目前基準；
* 拒答處理變得含糊；
* 截斷超過約定門檻；
* 重試讓成本或延遲超出應用程式預算；
* 原始回應與標準化輸出無法對應。

條件允許時，應透過路由設定回復，而不是臨時緊急部署程式碼。在新路徑經歷尖峰負載和少見輸入類別之前，保留舊適配器。

## 最終結論

LLM API 遷移後的結構化 JSON 失敗，通常來自契約不匹配、擷取錯誤或不完整的串流處理，並不能直接證明新模型無法遵循指令。應比較線上請求負載、縮減 schema、統一回應格式、在應用程式邊界進行驗證，並在切換流量之前重播有代表性的測試集。相容 API 可以簡化遷移，但明確的能力測試仍是保護生產行為的可靠方法。

## FAQ

### 為什麼同一個 JSON 提示詞在一個模型上有效，換一個模型就失敗？

提示詞措辭只是其中一層。不同模型和供應商在原生 JSON 模式、schema 支援、斷詞、拒答行為以及約束執行嚴格程度上都可能不同。

### JSON 模式等同於 JSON Schema 強制約束嗎？

不等同。JSON 模式可能只保證語法有效，而 schema 強制約束還會限制鍵名、類型、必填欄位，有時也會限制額外屬性。

### 我應該逐 token 解析串流 JSON 嗎？

通常不應該。應暫存完整的結構化負載，或使用供應商文件規定的結構化串流事件，然後在最終事件到達後進行驗證。

### OpenAI 相容 API 能徹底消除遷移工作嗎？

它可以減少傳輸層和 SDK 的改動，但仍需驗證模型特定的 schema 功能、結束原因、工具呼叫格式和錯誤行為。

### 驗證失敗時應該怎麼辦？

保存原始回應、對失敗進行分類，只重試安全的暫時性錯誤，並透過有次數上限的驗證步驟進行確定性修復，不能默默接受格式錯誤的資料。

### 最快的預生產測試是什麼？

在兩個技術堆疊上重播一組固定的正常、歧義、對抗、拒答、長上下文和串流請求，然後逐欄位比較驗證後的輸出。
