
LLM 結構化輸出是一種機制,確保語言模型的回應符合預定義的架構(schema),不僅僅是有效的 JSON,而是具備您指定的確切欄位、類型和約束的符合架構 JSON。現在每個主要供應商都原生支援此功能,這改變了生產級 LLM 應用程式的建構方式。
快速摘要:結構化輸出一覽
如果您時間有限,以下是 2026 年的現況概覽:
| 面向 | 細節 |
|---|---|
| 這是什麼 | LLM 的架構強制回應,保證結構,而非「盡力而為」 |
| 誰支援它 | OpenAI、Anthropic、Gemini、Cohere、xAI (Grok),以及透過 Ollama/vLLM 的本機端 |
| 關鍵機制 | 約束解碼,在取樣前屏蔽無效 token |
| JSON Mode 與 Strict Mode | JSON Mode = 僅語法有效。Strict Mode = 完全符合架構 |
| Python 函式庫 | Pydantic (BaseModel + Field) 用於架構定義 |
| TypeScript 函式庫 | Zod (z.object + .describe) 用於架構定義 |
| 最佳入門方法 | 透過原生 SDK 使用 OpenAI 搭配 Pydantic 或 Zod |
| 最佳生產環境函式庫 | Instructor (Python) 或原生 SDK (TypeScript) |
| 最大陷阱 | 將推理欄位置於答案欄位之後,導致模型在未思考前就做出決定 |
| 延遲開銷 | 首次呼叫 50-200ms(架構編譯),之後會快取 |
現在讓我們深入探討每個部分。
什麼是 LLM 結構化輸出?
結構化輸出是「希望 LLM 回傳有效 JSON」與「保證 回傳有效 JSON」之間的差異。當您啟用結構化輸出時,模型在物理上無法產生違反您架構的 token。您定義一個 JSON Schema(或 Pydantic 模型,或 Zod 架構),將其傳遞給 API,並每次都能獲得符合該架構的回應。
為什麼這很重要?在結構化輸出出現之前,開發人員編寫脆弱的正則表達式解析器,將每個 LLM 呼叫包裹在 try/catch JSON.parse 區塊中,並且仍然要處理「幾乎正確」的回應——那些缺少欄位或類型錯誤的有效 JSON。那一整類型的錯誤已經消失。
有三個層級的結構強制執行,它們代表了清晰的演進過程:
- 提示工程(Prompt engineering):「請回傳包含這些欄位的 JSON。」不可靠。模型可能只有 80-90% 的時間會配合。
- JSON Mode:保證語法上有效的 JSON,但不強制執行您的架構。您可能預期得到
{"name": string, "age": number},卻收到{"foo": "bar"}。 - Strict Mode / 約束解碼:保證 100% 符合架構。模型 literally 無法輸出無效 token。這就是 2026 年「結構化輸出」的意義。
截至 2026 年初,OpenAI、Anthropic 和 Google Gemini 都支援原生結構化輸出。生態系統已經趨於一致。
結論:如果您仍在生產環境中使用正則表達式或 JSON.parse 來解析 LLM 回應,您正在用困難的方式做事。 原生結構化輸出消除了整個失敗模式。
JSON Mode 與 Strict Mode:實際上有何不同?
這個區別讓許多開發人員感到困惑,因為名稱聽起來很相似。但它們完全不同。
| 功能 | JSON Mode | Strict Mode (結構化輸出) |
|---|---|---|
| API 參數 | type: "json_object" | type: "json_schema" 搭配 strict: true |
| 保證有效 JSON | 是 | 是 |
| 保證符合架構 | 否 | 是 |
| 機制 | 事後 token 偏差 | 約束解碼 (FSM) |
| 可回傳意外欄位 | 是 | 否 |
| 可省略必要欄位 | 是 | 否 |
| 類型強制執行 | 無 | 完整 (string, number, array 等) |
| 何時使用 | 您事先沒有架構 | 生產環境中的所有情況 |
時間軸: OpenAI 於 2023 年底引入了 JSON Mode。這是一個進步,但開發人員很快意識到「有效 JSON」還不夠,他們需要符合架構的 JSON。2024 年 8 月,OpenAI 推出了帶有 Strict Mode 的結構化輸出,使用約束解碼來保證架構合规性。到了 2025-2026 年,每個主要供應商都採用了相同的方法。
JSON Mode 仍有一個狹窄的使用案例:當您真的不知道回應的形狀,且只想要某些有效 JSON 進行非結構化探索時。但這在生產環境中很少見。
結論:在生產環境中對所有情況使用 Strict Mode。 對於受架構約束的使用案例,JSON Mode 實際上已被棄用。如果您有架構(您應該要有),請使用 type: "json_schema" 搭配 strict: true。
約束解碼實際上如何運作?
以下是讓 100% 架構合规成為可能的機制,不是 99.9%,而是字面上的 100%。
當您將 JSON Schema 發送給啟用 Strict Mode 的供應商時,該架構會被編譯成一個有限狀態機(FSM)。這個 FSM 代表了通過您架構的每個有效路徑。在每個 token 生成步驟中,推論引擎會檢查哪些 token 會讓輸出保持在有效路徑上,哪些不會。無效 token 的 logits 會在取樣前被設定為負無窮大,這意味著它們被選中的機率為零。
<!-- IMAGE: constrained-decoding diagram showing FSM token masking during structured output generation -->把它想像成強化版的自動完成功能。如果模型剛剛輸出了 {"rating": 而您的架構規定 rating 是一個整數,那麼接下來允許的唯一 token 就是數字 token。引號、字母、括號全部被屏蔽。即使模型「想」輸出 "five",它也做不到。
這與 XGrammar(vLLM、SGLang 和大多數本機推論伺服器背後的引擎)以及 Outlines(用於約束生成的開源 Python 函式庫)使用的核心機制相同。API 供應商只是將其建構到他們的推論基礎設施中。
有一個權衡需要注意:使用新架構的第一個請求會產生編譯延遲(通常為 50-200ms),因為需要建立 FSM。後續使用相同架構的請求會使用快取的 FSM,並增加幾乎為零的開銷。還有一個微妙的品質考量,限制 token 詞彙偶爾會降低創意或自由格式欄位的輸出品質,因此請讓您的架構專注於真正的結構化資料。
結論:約束解碼是區分「通常有效」與「始終有效」的關鍵。 它是讓結構化輸出達到生產就緒水平的工程技術。
多供應商實作:OpenAI、Anthropic 和 Gemini
這裡有其他指南沒有向您展示的內容:在所有三個主要供應商中實作相同的提取任務。我們將從非結構化文字中提取結構化的產品評論。
Pydantic 架構(在所有供應商之間共享):
from pydantic import BaseModel, Field
from typing import Literal
class ProductReview(BaseModel):
reasoning: str = Field(description="Think through the review before scoring")
rating: int = Field(description="Rating from 1-5", ge=1, le=5)
sentiment: Literal["positive", "negative", "neutral"]
pros: list[str] = Field(description="Key positive points")
cons: list[str] = Field(description="Key negative points")
summary: str = Field(description="One-sentence summary")OpenAI 實作
from openai import OpenAI
client = OpenAI()
response = client.beta.chat.completions.parse(
model="gpt-4o-2024-08-06",
messages=[
{"role": "system", "content": "Extract a structured review from the text."},
{"role": "user", "content": review_text}
],
response_format=ProductReview, # Pydantic model directly
)
review = response.choices[0].message.parsed # Typed ProductReview objectOpenAI 的實作是最成熟的。parse() 方法直接接受 Pydantic 模型並回傳 typed 物件。一個限制:OpenAI 的 Strict Mode 支援 JSON Schema 的子集,不支援 $ref,限制 anyOf,且所有欄位必須是必要的,並設定 additionalProperties: false。
Anthropic 實作
from anthropic import Anthropic
client = Anthropic()
response = client.messages.create(
model="claude-sonnet-4-5-20250514",
max_tokens=1024,
messages=[
{"role": "user", "content": f"Extract a structured review:\n\n{review_text}"}
],
output_config={
"format": {
"type": "json_schema",
"json_schema": ProductReview.model_json_schema()
}
}
)
import json
review_data = json.loads(response.content[0].text)
review = ProductReview(**review_data)Anthropic 的原生結構化輸出使用帶有 JSON Schema 的 output_config.format。它在 2026 年初達到 GA(一般可用性)。Anthropic 也支援較舊的模式,即定義一個「假」工具並透過 tool_use 進行提取,這仍然有效,但對於純提取來說,原生結構化輸出更簡潔。
Gemini 實作
from google import genai
client = genai.Client()
response = client.models.generate_content(
model="gemini-2.0-flash",
contents=f"Extract a structured review:\n\n{review_text}",
config={
"response_mime_type": "application/json",
"response_schema": ProductReview, # Pydantic model directly
}
)
import json
review = ProductReview(**json.loads(response.text))Gemini 在 Python SDK 中直接支援 Pydantic 模型,透過 response_schema。一個獨特的功能:Gemini 尊重架構中的 propertyOrdering,因此您可以控制欄位輸出順序(對於先推理模式很有用)。
供應商比較
| 功能 | OpenAI | Anthropic | Gemini |
|---|---|---|---|
| API 參數 | response_format | output_config.format | response_schema |
| 架構輸入 | Pydantic 或 JSON Schema | JSON Schema | Pydantic 或 JSON Schema |
| Strict mode | strict: true | 使用 json_schema 時隱含 | 隱含 |
| 串流 | 是 (部分 JSON) | 是 | 是 |
| 拒絕處理 | message.refusal 欄位 | 錯誤回應 | 錯誤回應 |
| 工具使用替代方案 | 是 | 是 (原始方法) | 是 |
| 架構編譯快取 | 是 (伺服器端) | 是 | 是 |
| 屬性排序 | 無原生支援 | 無 | 是 (propertyOrdering) |
結論:OpenAI 凭借其 parse() 方法擁有最完善的開發者體驗 (DX)。Anthropic 提供能力最強大的底層模型。Gemini 的屬性排序具有獨特的實用性。 三者都能完成工作,請根據您現有的供應商關係進行選擇。
Python 開發者的 Pydantic 模式
Pydantic 是 Python 中定義結構化輸出架構的事實標準。以下是重要的模式。
帶有描述的基礎架構
from pydantic import BaseModel, Field
from typing import Literal, Optional
class ExtractedEntity(BaseModel):
reasoning: str = Field(description="Think step by step about the entity")
name: str = Field(description="Full name of the entity")
entity_type: Literal["person", "company", "location"]
confidence: float = Field(description="Confidence score 0.0-1.0", ge=0.0, le=1.0)
context: Optional[str] = Field(description="Surrounding context, if relevant")那些 description 字串不僅僅是用於文件說明,它們會成為發送到模型的 JSON Schema 的一部分,並直接影響模型生成的內容。將它們視為架構內部的提示工程。
嵌套模型
class Address(BaseModel):
street: str
city: str
country: str
postal_code: Optional[str] = None
class Company(BaseModel):
reasoning: str = Field(description="Analysis of the company details")
name: str
industry: Literal["tech", "finance", "healthcare", "retail", "other"]
headquarters: Address # Nested model
key_products: list[str] = Field(description="Top 3 products or services")將嵌套限制在最多 2-3 層。深度嵌套的架構會增加錯誤率並減慢架構編譯速度。
先推理模式
這是影響最深遠的架構設計模式。將 reasoning 欄位置於您的答案欄位之前:
# Reliable JSON from Any LLM: Pydantic + Zod Patterns for 2026
class ClassificationBad(BaseModel):
category: Literal["spam", "ham"]
confidence: float
# Good -- model reasons through the problem first
class ClassificationGood(BaseModel):
reasoning: str = Field(description="Analyze the text before classifying")
category: Literal["spam", "ham"]
confidence: float = Field(ge=0.0, le=1.0)LLM 從左到右生成 token。如果 category 在先,模型會先選擇一個類別然後再合理化它。如果 reasoning 在先,模型會先解決問題,然後才確定類別。這是嵌入架構中的思維鏈(chain-of-thought)。
JSON Schema 匯出
# Generate the JSON Schema for any Pydantic model
schema = ProductReview.model_json_schema()
# Pass this to any provider that accepts raw JSON Schema結論:Pydantic + 描述性欄位 + 先推理順序是 Python 結構化輸出的三要素。 掌握這三種模式,您就能處理 90% 的使用案例。
TypeScript 開發者的 Zod 模式
Zod 是 TypeScript 中等同於 Pydantic 的工具,它在結構化輸出工作流程中同樣重要。
帶有描述的基礎架構
import { z } from "zod";
const ProductReview = z.object({
reasoning: z.string().describe("Think through the review before scoring"),
rating: z.number().int().min(1).max(5),
sentiment: z.enum(["positive", "negative", "neutral"]),
pros: z.array(z.string()).describe("Key positive points"),
cons: z.array(z.string()).describe("Key negative points"),
summary: z.string().describe("One-sentence summary"),
});
// Infer the TypeScript type automatically
type ProductReview = z.infer<typeof ProductReview>;就像 Pydantic 的 Field(description=...) 一樣,Zod 的 .describe() 會成為 JSON Schema 的一部分並引導模型的輸出。
與 OpenAI Node SDK 整合
import OpenAI from "openai";
import { zodResponseFormat } from "openai/helpers/zod";
const client = new OpenAI();
const response = await client.beta.chat.completions.parse({
model: "gpt-4o-2024-08-06",
messages: [
{ role: "system", content: "Extract a structured review." },
{ role: "user", content: reviewText },
],
response_format: zodResponseFormat(ProductReview, "product_review"),
});
const review = response.choices[0].message.parsed; // Typed!與 Vercel AI SDK 整合
import { generateObject } from "ai";
import { openai } from "@ai-sdk/openai";
const { object: review } = await generateObject({
model: openai("gpt-4o"),
schema: ProductReview,
prompt: `Extract a structured review:\n\n${reviewText}`,
});
// review is fully typed as ProductReviewVercel AI SDK 透過 generateObject() 原生使用 Zod,使其成為最簡潔的 TypeScript 整合方案。它透過統一的 API 與 OpenAI、Anthropic、Gemini 和其他供應商合作。
JSON Schema 轉換
import { zodToJsonSchema } from "zod-to-json-schema";
const jsonSchema = zodToJsonSchema(ProductReview);
// Use with any provider that accepts raw JSON Schema結論:Zod + .describe() + Vercel AI SDK 是 TypeScript 結構化輸出的技術棧。 如果您處於 Node/Next.js 生態系統中,這是阻力最小的路徑。
結構化輸出與函式呼叫:何時使用哪一個?
這是最常見的混淆來源之一。兩者都涉及架構,都回傳結構化資料,但它們解決不同的問題。
結構化輸出表示:「給我這種確切形狀的資料。」它用於提取、分類和格式化。您是從非結構化文字中提取結構化資訊。
函式呼叫(工具使用)表示:「這裡有一些您可以採取的操作,決定運行哪一個並提供參數。」它用於代理工作流程,模型從多個工具中選擇並觸發操作。
這種混淆在歷史上是有道理的。Anthropic 原始的「結構化輸出」實際上就是函式呼叫,您會定義一個名為 extract_review 的假工具並抓取參數。這仍然有效,但對於純提取來說,原生結構化輸出更簡單。
| 情境 | 最佳方法 | 原因 |
|---|---|---|
| 從文字提取資料 | 結構化輸出 | 直接、較低延遲、單一架構 |
| 分類為類別 | 結構化輸出 | 一個回應,一個架構 |
| 代理決定呼叫哪個工具 | 函式呼叫 | 模型從多個工具中選擇 |
| 多步驟協調 | 函式呼叫 | 順序工具調用 |
| 提取資料並決定下一步操作 | 兩者 | 結構化輸出用於提取,函式呼叫用於協調 |
結構化輸出為 AI 代理系統中的工具呼叫管道提供動力。請參閱我們的 企業 AI 代理指南,了解這些如何融入生產工作流程。
結論:當您知道資料應有的形狀時,使用結構化輸出。當模型需要選擇操作時,使用函式呼叫。 在實踐中,大多數應用程式同時使用兩者:結構化輸出用於資料提取,函式呼叫用於代理協調。
生產模式:錯誤、重試和串流
在示範中讓結構化輸出運作很容易。要在生產環境中保持其可靠性,需要處理三件事:拒絕、驗證失敗和串流。
拒絕處理
有時模型拒絕生成您請求的輸出,通常是因為安全過濾器標記了輸入。當這種情況發生時,結構化輸出 API 不會回傳您的架構。它們會回傳拒絕訊息。
response = client.beta.chat.completions.parse(
model="gpt-4o-2024-08-06",
messages=messages,
response_format=ProductReview,
)
# ALWAYS check for refusal before accessing parsed content
if response.choices[0].message.refusal:
print(f"Model refused: {response.choices[0].message.refusal}")
else:
review = response.choices[0].message.parsed如果您跳過拒絕檢查並嘗試存取拒絕訊息上的 .parsed,您將得到 None 和令人困惑的下游錯誤。務必先檢查。
帶有驗證回饋的重試模式
約束解碼保證了架構合规性,但語義正確性則不然。模型可能會回傳 {"rating": 1, "sentiment": "positive"},這符合架構,但內容矛盾。這就是驗證 + 重試發揮作用的地方。
import instructor
client = instructor.from_openai(OpenAI())
# Instructor handles retries automatically
review = client.chat.completions.create(
model="gpt-4o",
response_model=ProductReview,
max_retries=3, # Retries with validation error feedback
messages=[
{"role": "user", "content": review_text}
],
)Instructor 在重試時將驗證錯誤回饋給模型,以便它可以自我修正。對於沒有 Instructor 的手動重試模式:
from pydantic import ValidationError
for attempt in range(3):
try:
response = client.beta.chat.completions.parse(
model="gpt-4o-2024-08-06",
messages=messages,
response_format=ProductReview,
)
review = response.choices[0].message.parsed
# Run additional semantic validation here
break
except ValidationError as e:
messages.append({"role": "assistant", "content": str(response)})
messages.append({"role": "user", "content": f"Validation error: {e}. Fix it."})串流結構化輸出
對於大型結構化回應、長陣列、許多欄位、複雜的嵌套物件,串流允許您逐步渲染部分結果。
import instructor
client = instructor.from_openai(OpenAI())
# Stream partial results as fields populate
review_stream = client.chat.completions.create_partial(
model="gpt-4o",
response_model=ProductReview,
messages=[{"role": "user", "content": review_text}],
)
for partial_review in review_stream:
# Fields populate one by one as tokens stream in
if partial_review.summary:
print(f"Summary so far: {partial_review.summary}")一個陷阱:單個串流區塊本身不符合架構。reasoning 欄位可能已填充,而 rating 仍為 None。相應地規劃您的 UI,為未填充的欄位顯示載入狀態。
結論:拒絕檢查是不可或缺的。帶有驗證回饋的重試可以捕捉語義錯誤。對於任何耗時超過幾秒鐘的回應,串流都是值得的。
結構化輸出函式庫比較
您可以透過原生 API 使用結構化輸出,但函式庫增加了驗證、重試、串流和多供應商支援。以下是現況概覽。
Instructor 是最受歡迎的選項,擁有 11K+ GitHub stars 和 300 萬+ 每月下載量。它包裝了 OpenAI、Anthropic、Gemini、Cohere、Ollama 等,提供統一的基於 Pydantic 的介面。主要功能:帶有驗證回饋的自動重試、透過 create_partial() 進行串流,以及極其簡單的設定(instructor.from_openai(client))。如果您是 Python 團隊,請從這裡開始。
BAML 採取不同的方法:透過自訂 DSL 實現架構優先。您在 .baml 檔案中定義架構,並為 Python、TypeScript、Ruby 等自動生成客戶端。其 SAP(架構對齊解析)演算法能優雅地處理混亂的模型輸出。最適合跨語言團隊,或當您希望在 LLM 層和應用程式層之間建立合約時。權衡:額外的建置步驟和需要學習的新語法。
LangChain 為供應商無關的結構化輸出提供 .with_structured_output(schema)。如果您已經處於 LangChain 生態系統中,這很方便。權衡:這是一個沉重的依賴項,且抽象層可能會隱藏您可能需要的供應商特定功能。
原生 API,直接使用 response_format / output_config 進行呼叫,除了供應商 SDK 外不需要零依賴項。您獲得完全的控制权和完全的可見性。最適合簡單的使用案例或偏好最小抽象的團隊。
| 函式庫 | 語言 | 供應商 | 自動重試 | 串流 | GitHub Stars | 學習曲線 |
|---|---|---|---|---|---|---|
| Instructor | Python, TS | 15+ | 是 | 是 | 11K+ | 低 |
| BAML | Python, TS, Ruby, Go | 所有 (DSL 無關) | 是 | 是 | 7K+ | 中 |
| LangChain | Python, TS | 20+ | 部分 | 是 | 100K+ | 中-高 |
| 原生 API | 任意 | 每個 SDK 1 個 | 否 | 是 | N/A | 低 |
選擇正確的結構化輸出函式庫是更廣泛的 AI 技術棧決策的一部分。我們在 SaaS 最佳 AI 技術棧指南 中分解了完整的技術棧。
請參閱我們的 LLM 結構化輸出最佳函式庫 [即將推出],以獲得 Instructor、BAML、Mirascope 等的深入比較。
結論:Python 從 Instructor 開始,TypeScript 使用原生 API。 如果您需要跨語言架構合約,請轉移到 BAML。避免僅為了結構化輸出而使用 LangChain,這有點殺雞用牛刀。
架構設計最佳實踐(和常見錯誤)
您的架構設計直接影響輸出品質。以下是重要的模式和會損害準確性的錯誤。
將推理置於答案之前
我們在 Pydantic 部分討論過這一點,但值得重複強調,因為這是影響最大的設計決策:
# Before: model guesses the answer, then rationalizes
class Bad(BaseModel):
answer: str
reasoning: str
# After: model thinks first, then commits
class Good(BaseModel):
reasoning: str = Field(description="Think step by step")
answer: strLLM 從左到右生成。欄位順序就是提示順序。先推理意味著模型在確定答案之前必須先解決問題。
反模式表
| 錯誤 | 問題 | 修正 |
|---|---|---|
| 推理欄位在答案之後 | 模型在未思考前就做出決定 | 將推理移至答案之前 |
| 深度嵌套 (4+ 層) | 更高的錯誤率,編譯更慢 | 展平至 2-3 層 |
| 無欄位描述 | 模型猜測您的需求 | 添加 .describe() / Field(description=...) |
| 缺少 null 處理 | 模型幻覺出一個值來填充欄位 | 使用 Optional / .nullable() |
| 過大的架構 (50+ 欄位) | 編譯超時,品質下降 | 拆分為多個呼叫 |
| 模糊的 enum 選項 | 模型選擇錯誤的類別 | 使用具體、不重疊的選項 |
明確處理 Nulls
如果欄位在來源文字中可能沒有資料,請將其設為可選。當資料不存在時強制要求必要欄位會導致幻覺:
class PersonInfo(BaseModel):
name: str # Always present
email: Optional[str] = Field(None, description="Email if mentioned, null otherwise")
phone: Optional[str] = Field(None, description="Phone if mentioned, null otherwise")保持架構專注
一個任務一個架構。不要試圖在單個巨大的架構中提取所有內容。如果您需要 50+ 個欄位,請拆分為多個提取呼叫。OpenAI 的 Strict Mode 對架構複雜度有實際限制,即使它能運作,非常大的架構也會降低輸出品質。
結論:先推理、描述性欄位、明確的 nulls 和專注的架構。 做好這四點,您的結構化輸出準確率將顯著提升。
本機 LLM 的結構化輸出
您不需要 API 供應商來進行結構化輸出。本機推論引擎透過基於語法的約束解碼支援它,這是相同的基本機制,在您自己的硬體上運行。
Ollama
本機結構化輸出的最簡單路徑。Ollama 透過 format 參數接受 JSON Schema:
import ollama
from pydantic import BaseModel
class Country(BaseModel):
name: str
capital: str
languages: list[str]
response = ollama.chat(
model="llama3.2",
messages=[{"role": "user", "content": "Tell me about Japan."}],
format=Country.model_json_schema(),
)
import json
country = Country(**json.loads(response.message.content))Ollama 在底層使用 XGrammar 進行約束解碼。與 API 供應商相同的保證:100% 架構合规。
vLLM 和 SGLang
對於生產級本機推論,vLLM 和 SGLang 都透過 guided_json 和 guided_regex 參數支援結構化輸出。XGrammar 是預設後端,在 JSON 生成上提供幾乎為零的開銷,比替代語法引擎快高達 3.5 倍。
Outlines
Outlines 是開創基於語法的約束生成的開源 Python 函式庫。它適用於任何 Hugging Face 模型,並支援 JSON Schema、正則表達式和完整的上下文無關文法 (CFG/EBNF) 約束。它也作為語法後端選項整合到 vLLM 和 SGLang 中。
與 API 供應商的關鍵區別:本機結構化輸出沒有架構子集限制。您完全控制語法。但模型品質變化較大,7B 參數的本機模型在複雜提取任務上無法與 GPT-4o 或 Claude 匹敵。架構始終有效;內容品質取決於模型。
結論:開發使用 Ollama,生產使用 vLLM/SGLang 搭配 XGrammar。 本機結構化輸出已足夠成熟,適用於大多數使用案例,需要注意的是較小的模型在架構內產生的內容品質較低。
FAQ
什麼是 LLM 中的結構化輸出?
結構化輸出是一種機制,保證 LLM 的回應符合預定義的 JSON Schema。與純文字甚至 JSON Mode 不同,結構化輸出使用約束解碼來確保您架構中的每個欄位、類型和約束都得到滿足——100% 的時間,而不是「通常」。
JSON Mode 和結構化輸出有什麼區別?
JSON Mode 保證語法上有效的 JSON,但不強制執行您的架構,您可能會得到任何有效的 JSON 物件。結構化輸出(Strict Mode)透過約束解碼保證完全符合架構。在生產環境中使用 Strict Mode;僅當您事先沒有架構時,JSON Mode 才相關。
哪些 LLM 供應商原生支援結構化輸出?
OpenAI(自 2024 年 8 月起)、Google Gemini(2024 年,2026 年擴展)、Anthropic(2025 年 11 月 beta,2026 年初 GA)、Cohere 和 xAI (Grok) 都支援原生結構化輸出。在本機端,Ollama、vLLM 和 SGLang 透過基於語法的約束解碼支援它。
約束解碼如何保證架構合规性?
JSON Schema 被編譯成有限狀態機(FSM)。在每個 token 生成步驟中,只允許讓輸出保持在 FSM 有效路徑上的 token,無效 token 的 logits 被設定為負無窮大。這意味著無效 token 被生成的機率為零,為您提供數學保證,而非統計保證。
我應該使用結構化輸出還是函式呼叫?
當您想要特定形狀的資料時,使用結構化輸出進行提取和分類。當模型需要決定採取哪種行動時,使用函式呼叫進行代理工作流程。許多生產應用程式同時使用兩者:結構化輸出用於資料提取,函式呼叫用於協調。
我可以串流結構化輸出嗎?
是的。OpenAI 支援使用 parse() 方法進行串流,而 Instructor 提供 create_partial() 用於串流逐欄位填充的 Pydantic 模型。請記住,單個串流區塊本身不符合架構,欄位是增量填充的。
什麼是 Instructor 函式庫?
Instructor 是最受歡迎的結構化輸出函式庫(11K+ GitHub stars,300 萬+ 每月下載量)。它使用基於 Pydantic 的驗證、帶有驗證回饋的自動重試和串流支援來包裝供應商 SDK。它適用於 OpenAI、Anthropic、Gemini、Cohere、Ollama 和 10+ 其他供應商。
結構化輸出適用於本機 LLM 嗎?
是的。Ollama 透過帶有 JSON Schema 的 format 參數支援結構化輸出。vLLM 和 SGLang 透過 guided_json 參數支援它。這三者都使用 XGrammar 或 Outlines 進行約束解碼。架構合规保證與 API 供應商相同;內容品質取決於模型。
常見的架構設計錯誤有哪些?
頂級錯誤:將推理欄位置於答案欄位之後(模型在未思考前就做出決定)、深度嵌套架構(4+ 層增加錯誤)、缺少欄位描述(模型猜測意圖)、可選資料無 null 處理(強制幻覺)以及過大的架構(50+ 欄位降低品質)。
結構化輸出會增加延遲嗎?
第一個請求會有架構編譯開銷,通常在建立 FSM 時為 50-200ms。後續使用相同架構的請求使用快取的 FSM,並增加幾乎為零的延遲。對於大多數應用程式來說,與整體模型推論時間相比,這是可以忽略不計的。
我可以將結構化輸出與圖像或多模態輸入一起使用嗎?
是的。結構化輸出適用於回應格式,而非輸入。您可以將圖像發送給 GPT-4o 或 Gemini,並附上結構化輸出架構,並回傳符合架構的圖像分析。這對於視覺提取工作流程非常強大,例如從收據、表單或產品圖像中提取結構化資料。