Ollama構造化出力の二重検証設計
CHATGPT / AIChatGPTなどの生成AIを活用して運営・記事制作・更新を行っています。制作方針
Ollama v0.32.0のローカルAPIを基準に、生成制約とアプリ側型検証を分離し、schema複雑度・temperature・streaming・model差を再現可能に比較する設計を解説します。

先に結論
Ollamaの構造化出力をproductionへ組み込むなら、modelへJSON Schemaを渡す生成制約と、受信後に同じschemaでparse・型検証するアプリ境界を二重化します。前者は失敗を減らす仕組み、後者は不正な値を後続へ流さない仕組みであり、置き換え関係ではありません。
評価では「JSONとしてparseできた」と「schemaに適合した」を別指標にし、model、tag、Ollama version、schema、prompt、temperature、stream、試行数を固定します。schema複雑度、temperature、streaming、modelを同時に変えると原因を識別できません。本記事は測定設計までを示す机上調査で、成功率やlatencyの実測値は掲載しません。
確認日時: 2026年8月3日 19:15(Asia/Tokyo)
対象version: Ollama v0.32.0、commitf1a0ffd(2026年7月11日公開)を基準。APIとstructured outputs docsは2026年8月3日に再監査
検証区分: 公式documentation/repository releaseに基づく机上調査・検証計画です。Ollama、Pydantic、Zodを実行しておらず、model別のschema適合率、latency、memory、retry効果は未測定です。
適用範囲: local/api/chat。Ollama Cloud、OpenAI互換endpoint、vision、tool calling、外部公開networkは対象外
確認済みのAPI契約と推論を分ける
2026年8月3日のOllama公式資料から確認できる事実は次のとおりです。
/api/chatのformatは”json”またはJSON Schemaを受け取る- REST APIの
streamは既定でtrueであり、streaming responseはpartial contentを返す - structured outputsの公式例は
stream: falseでschemaを渡している - PythonではPydanticの
model_json_schema()とmodel_validate_json()、JavaScriptではZodのz.toJSONSchema()とparseを組み合わせる例がある - 再現性を高める出発点として低いtemperatureが案内されている
- Ollama Cloudは構造化出力に未対応と明記されている
ここから「productionでは二重検証し、streamingは連結後に検証する」とするのは、本記事の設計判断です。公式streaming docsがpartial fieldを蓄積する必要を説明しているため、完成前のchunk単体を最終documentとしてschema検証しない方針を導きます。ただし、特定modelで何chunkに分かれるか、連結後に何%適合するかは実測していません。
また、v0.32.0を検証基準に固定しますが、「structured outputsがv0.32.0で初めて追加された」とは扱いません。releaseは再現用のruntime境界、現行docsはAPI契約の確認元として役割を分けます。
二段ゲートの実装境界
推奨する流れは次の6段階です。
- schemaを型定義から1回生成し、requestとvalidatorで同じartifactを使う
- model digest/tag、prompt、options、stream条件とともにrequestを記録する
- HTTP statusとAPI response全体のJSON parseを確認する
message.contentをJSONとしてparseする- JSON Schema/Pydantic/Zodで型と制約を検証する
- business ruleを別に検証し、合格した値だけを保存・実行へ渡す
Gate 1:生成時に形を制約する
Ollamaへ渡すschemaは、アプリが本当に必要とするpropertyだけから始めます。深い入れ子、巨大なenum、複数の分岐を一度に足すと、どの要素が失敗原因か追いにくくなります。promptにも期待するfieldの意味を明記します。公式docsはschema文字列をpromptにも渡してmodelをgroundする方法を案内していますが、同じ巨大schemaを無制限に重複させるとprompt tokenと保守箇所が増えるため、その影響は測定対象にします。
{
"type": "object",
"properties": {
"summary": {"type": "string"},
"keywords": {
"type": "array",
"items": {"type": "string"}
}
},
"required": ["summary", "keywords"]
}
Gate 2:アプリ境界で同じ契約を検証する
受信側は「HTTP 200」「outer JSON」「content JSON」「schema」「business rule」を別々に判定します。たとえば要約の文字数上限やkeywordの許可listは、JSONとして正しいだけでは保証されません。model出力をSQL、shell、HTML、URL fetchへ使う場合は、schema適合後にもそのsink固有のescape、allowlist、権限分離が必要です。
公式例のPydantic/Zod経路を使う利点は、requestのschemaとアプリの型を同じ定義から作れることです。手書きschemaと手書きvalidatorを別々に更新すると、property追加時に片方だけ古くなるdriftが起きます。schema hashまたはversionを結果recordへ持たせ、どの契約で判定したか追跡します。
再現可能な比較条件
測定前に固定する値と、1回に変更する変数を分けます。
| 区分 | 記録する項目 | 理由 |
|---|---|---|
| runtime | Ollama version、commit/build、OS、CPU/GPU、memory | updateやbackend差を混ぜない |
| model | 正確な名前、tagまたはdigest、量子化、context | 同じ表示名でも実体差を残す |
| input | prompt本文、schema bytes/hash、system message | 契約と入力の変更を検出する |
| generation | temperature、seed対応の有無、context、生成上限 | sampling差を分離する |
| transport | endpoint、stream、timeout | chunk処理とtimeoutを分離する |
| repetition | warm-up方針、試行回数、実行順 | 初回loadと繰り返しを混ぜない |
同一modelを比較するときも、modelがmemoryにload済みかでload_durationが変わり得ます。API responseにはtotal_duration、load_duration、prompt_eval_count、prompt_eval_duration、eval_count、eval_durationが定義されています。これらは観測に使えますが、単位と欠損を確認し、schema適合率と速度を同じ1指標へまとめません。
変数ごとの検証計画
Schema複雑度
複雑度は段階的に増やします。
- requiredなstring 1件
- stringとarray
- nested object
- enumや長さなどの制約
- optional/nullable field
各段階で同じinput setを使い、前段が安定してから次へ進みます。記録するのはHTTP成功、outer parse、content parse、schema適合、business rule適合の件数です。「失敗率」だけでは、接続失敗と型不一致を区別できません。
Temperature
公式docsのtipに合わせ、まず0をbaselineにします。その後に1値ずつ上げ、内容の多様性とschema適合を別々に観測します。temperatureを変えながらmodelも交換すると因果が分からないため、同じmodel artifactとprompt順を固定します。temperature 0でも完全な決定性は仮定しません。
Streaming
非streamingをcontract testのbaselineにし、streamingは別suiteにします。streamingでは各chunkのouter JSONを検査し、message.contentの断片を順序どおり連結し、doneを確認した後に1回だけcontent JSON/schema検証を行います。途中の文字列をparse失敗として数えると、正常なpartial JSONを誤って不合格にします。
接続切断、timeout、done未到達は「schema不適合」ではなくtransport failureです。途中まで受け取った値を保存や後続処理へ渡さず、request IDと受信済みbyte数など秘密を含まない診断情報だけを残します。
Model差
同じschemaでもmodelごとの追従は実測が必要です。比較では各modelの正確なtag/digest、量子化、context、prompt templateを固定し、同じtest caseを同じ回数だけ実行します。model Aで成功したためmodel Bも成功すると一般化せず、applicationが許容する最小適合率とfailure budgetを先に決めます。
記録形式と判定指標
1試行につき次のfieldを持つJSON Linesなどへ記録すると、段階別に集計できます。実際のpromptや生成本文に機密情報がある場合は保存せず、hashとtest case IDへ置き換えます。
timestamp, run_id, ollama_version, model_digest, schema_hash,
temperature, stream, http_ok, outer_json_ok, content_json_ok,
schema_ok, business_rule_ok, failure_class,
total_duration, load_duration, prompt_eval_count, eval_count
主要指標は次のように分けます。
- content JSON率: HTTP成功のうち
message.contentをparseできた割合 - schema適合率: content JSONのうち型・制約を通った割合
- end-to-end合格率: 全試行のうちbusiness ruleまで通った割合
- latency: loadを含む/除く、非streaming/streamingを分けた分布
- retry増幅: 1つのlogical requestあたりの実API call数
平均値だけでなく、用途に応じてp50/p95とfailure class件数を確認します。ただし本記事には実測sampleがなく、数値目標やmodel順位は提示しません。
Retry、fallback、停止条件
retryは失敗を隠す仕組みではありません。少なくとも次を分けます。
- connection failure/timeout:短いbackoffで上限付きretry候補
- HTTP 4xx:request、model名、schemaを直すまで原則retryしない
- content JSON不正:同条件でのretry回数を制限し、raw responseを診断対象にする
- schema不適合:違反fieldを記録し、schema簡略化またはmodel変更を明示的に判断する
- business rule不適合:modelへ丸投げせず、後続処理を停止する
fallbackでschemaを緩める場合は、同じ成功指標へ混ぜません。strict schemaとfallback schemaには別versionを付けます。fallback後の値を「strictに成功」と数えると、運用品質を過大評価します。
Trade-offと適用外
| 選択 | 利点 | Cost/注意点 |
|---|---|---|
| 小さいschema | 切り分けやすくpromptも短い | business ruleをアプリ側で補う必要がある |
| 厳しいschema | downstreamの形を揃えやすい | model差や複雑な制約で不適合が増える可能性 |
| 非streaming | 完成documentを検証しやすい | first tokenの表示を待つ |
| streaming | UIへ早く表示できる | 連結、切断、done判定のstate管理が増える |
| retry | 一時的失敗を吸収できる | latency、計算量、重複処理が増える |
| model fallback | 可用性を上げられる | 品質、license、memory、schema適合を再検証する必要がある |
本設計は、JSONをtrusted commandへ変換する安全性、model出力の事実性、prompt injection対策、個人情報処理を自動的には解決しません。またCloudは公式に未対応で、OpenAI互換APIはresponse_format経路になるため、local native APIの結果をそのまま一般化しません。
入門記事
初めて試す場合は、OllamaでJSON Schema出力を作る入門で、非streamingの小さなschemaを1回通し、外側JSONとcontent JSONを分けて確認してください。
参考資料
- Ollama公式:Structured Outputs(2026年8月3日確認)
- Ollama公式:POST /api/chat(2026年8月3日確認)
- Ollama公式:Streaming(2026年8月3日確認)
- Ollama公式:API Errors(2026年8月3日確認)
- Ollama公式GitHub:v0.32.0(commit
f1a0ffd、2026年7月11日公開、2026年8月3日確認)


