目錄
Ollama 結構化輸出:讓模型回傳固定格式的 JSON
把模型整合進程式時,我們常常需要的不是一段文字,而是程式可以直接讀取的資料。例如從一封客訴信中取出姓名、訂單編號、問題類型。
Ollama 的 format 參數可以強制模型的輸出符合你指定的 JSON 格式。
最簡單:只要求 JSON
curl http://localhost:11434/api/chat -d '{
"model": "qwen3:8b",
"messages": [{ "role": "user", "content": "列出台灣三個城市和人口,用 JSON 回答" }],
"format": "json",
"stream": false
}'
輸出保證是合法的 JSON,但欄位名稱和結構由模型自己決定,每次可能不同。
指定 JSON Schema
把 JSON Schema 放進 format,就能精確規定欄位:
curl http://localhost:11434/api/chat -d '{
"model": "qwen3:8b",
"messages": [{ "role": "user", "content": "介紹台北市" }],
"format": {
"type": "object",
"properties": {
"city": { "type": "string" },
"population": { "type": "integer" },
"landmarks": { "type": "array", "items": { "type": "string" } }
},
"required": ["city", "population", "landmarks"]
},
"stream": false
}'
message.content 會是一個符合格式的 JSON 字串。
Python:用 Pydantic 定義格式
from ollama import chat
from pydantic import BaseModel
class Complaint(BaseModel):
customer_name: str
order_id: str | None
category: str # 例如:物流、品質、退款、其他
urgency: int # 1~5
summary: str
email = """
您好,我是王小美,訂單編號 A20261012-88 的吹風機收到時外盒破損,
插電後完全沒有反應。下週要出國很急,請盡快處理退換貨,謝謝。
"""
response = chat(
model="qwen3:8b",
messages=[
{"role": "system", "content": "從客訴內容擷取資訊。category 只能是:物流、品質、退款、其他。"},
{"role": "user", "content": email},
],
format=Complaint.model_json_schema(),
options={"temperature": 0},
)
data = Complaint.model_validate_json(response.message.content)
print(data)
print(data.urgency)
customer_name='王小美' order_id='A20261012-88' category='品質' urgency=4 summary='吹風機外盒破損且無法通電,要求盡快退換貨'
4
model_validate_json 會再驗證一次型別,確保程式拿到的資料一定正確。
限定選項:用 Literal 或 Enum
from typing import Literal
class Complaint(BaseModel):
category: Literal["物流", "品質", "退款", "其他"]
這樣模型只能從這四個值中選一個,比在提示詞裡說明更可靠。
JavaScript:用 Zod 定義格式
npm install ollama zod
import ollama from "ollama";
import { z } from "zod";
const Product = z.object({
name: z.string(),
price: z.number(),
tags: z.array(z.string()),
});
const response = await ollama.chat({
model: "qwen3:8b",
messages: [{ role: "user", content: "這款 iPhone 手機殼售價 590 元,防摔、輕薄、支援 MagSafe" }],
format: z.toJSONSchema(Product),
});
const product = Product.parse(JSON.parse(response.message.content));
console.log(product);
(Zod 4 內建 z.toJSONSchema;舊版 Zod 3 可使用 zod-to-json-schema 套件。)
範例:批次分類
from typing import Literal
from ollama import chat
from pydantic import BaseModel
class Review(BaseModel):
sentiment: Literal["正面", "負面", "中立"]
topics: list[str]
reviews = [
"餐點很好吃,但是等了快一個小時。",
"服務人員態度很好,下次還會再來!",
"價格普通,味道普通。",
]
for text in reviews:
r = chat(
model="qwen3:8b",
messages=[{"role": "user", "content": f"分析這則評論:{text}"}],
format=Review.model_json_schema(),
options={"temperature": 0},
)
print(text, "→", Review.model_validate_json(r.message.content))
從圖片擷取資料
搭配視覺模型,可以從發票、名片、截圖中擷取結構化資料:
class BusinessCard(BaseModel):
name: str
company: str | None
title: str | None
phone: str | None
email: str | None
r = chat(
model="gemma3",
messages=[{"role": "user", "content": "擷取名片上的資訊", "images": ["./card.jpg"]}],
format=BusinessCard.model_json_schema(),
options={"temperature": 0},
)
print(BusinessCard.model_validate_json(r.message.content))
提升正確率的技巧
- temperature 設為 0,讓輸出更穩定。
- 在提示詞中也說明格式與欄位意義,不要只靠 schema。例如:「urgency 是 1~5 的整數,5 最緊急」。
- 欄位名稱取得清楚易懂(
order_id比oid好)。 - 可能沒有資料的欄位設為可為空(
str | None),避免模型為了填欄位而編造內容。 - 結構化輸出保證的是格式,不保證內容正確。重要資料仍需要驗證。
更新於 2026年10月12日