OllamaでJSON Schema出力を作る入門

CHATGPT / AIChatGPTなどの生成AIを活用して運営・記事制作・更新を行っています。制作方針

OllamaのローカルAPIへ小さなJSON Schemaを渡し、非ストリーミング応答をJSONとして取り出して必須項目と型を確認するまでを、失敗時の戻し方とともに解説します。

入力をSchemaの枠へ通し、型を確認したJSONだけをアプリへ渡す流れを示す図解

先に結論

OllamaのローカルAPIでは、/api/chatformatへJSON Schemaを渡すと、自由文ではなく指定した形のJSONを生成させられます。ただし、生成時の制約とアプリ側の検証は別工程です。応答をそのまま保存や画面表示へ渡さず、外側のAPI応答を読み、message.contentをJSONとしてparseし、必須fieldと型をもう一度確認します。

この記事ではsummarykeywordsだけの小さなschemaを使い、最初の成功、成功確認、失敗時の戻し方まで進めます。Ollama Cloudは2026年8月3日時点で構造化出力に対応していないため、対象は手元のOllamaが提供するlocalhost:11434のAPIだけです。

確認日時: 2026年8月3日 19:15(Asia/Tokyo)
固定した版: Ollama v0.32.0(commit f1a0ffd、2026年7月11日公開)を基準に、2026年8月3日の公式API docsを再確認
検証区分: 公式documentationとreleaseを照合した机上調査です。Ollamaの起動、model取得、生成結果、schema追従率は実機検証していません。掲載するjq式は構文を確認しますが、特定modelでの成功を保証しません。
対象外: Ollama Cloud、OpenAI互換endpoint、画像入力、tool calling、production向け外部公開

構造化出力で分ける2つの仕事

JSON Schemaは、JSON documentに必要なpropertyや型を記述する仕様です。Ollama公式の構造化出力docsは、format”json”またはJSON Schemaを渡せると説明しています。単に”json”を指定する場合と違い、schemaを渡せば「objectである」「summaryは文字列」「keywordsは文字列の配列」といった形を要求できます。

ただし、安全にアプリへ組み込むには次の2段階を分けます。

  1. 生成制約: Ollamaへschemaを渡し、modelが期待する形を作りやすくする
  2. 受信後の検証: HTTP応答とmessage.contentをparseし、必須fieldと型をアプリ側で確認する

公式docsも、PythonではPydantic、JavaScriptではZodからschemaを作り、返されたcontentを同じ型定義で検証する例を示しています。構造化出力は「検証不要になる機能」ではなく、生成と検証の契約を同じschemaへ揃える機能と理解すると実装を分けやすくなります。

始める前の確認

この記事はOllamaをinstall済みで、少なくとも1つのlocal modelを取得済みの人を対象にします。まず既存状態を壊さないread-onlyのcommandで確認します。

ollama --version
ollama list
ollama ps

以下の例は公式docsと同じgpt-ossというmodel名を使います。手元にない場合は勝手に別modelをdownloadせず、ollama listに表示されたmodel名へ置き換えてください。modelによってschemaへの追従は変わり得るため、model名とtagは検証記録に残します。

Ollama APIの既定はstreamingです。今回は完成した1つの応答を確認しやすくするため、stream: falseを必ず指定します。streamingを使う場合は、断片を連結してから検証する別実装が必要です。

最短手順:Schemaを渡して1回呼ぶ

1. request JSONを作る

shellのquote崩れを避けるため、jqで正しいJSONを組み立てます。入力文も固定し、最初はpropertyを2つだけにします。

jq -n --arg model "gpt-oss" '{
  model: $model,
  messages: [{
    role: "user",
    content: "次の文章を1文で要約し、重要語を最大3件挙げてください。文章: ローカルAPIでは入力を端末内で処理できる構成を選べます。"
  }],
  stream: false,
  format: {
    type: "object",
    properties: {
      summary: {type: "string"},
      keywords: {type: "array", items: {type: "string"}}
    },
    required: ["summary", "keywords"]
  },
  options: {temperature: 0}
}' > ollama-request.json

jq empty ollama-request.json

最後のcommandが何も表示せず終了code 0なら、request file自体はJSONとして読めます。temperature: 0は結果の揺れを抑えるための出発点で、同じ回答を保証する値ではありません。公式docsも構造化出力の再現性を高める方法として低いtemperatureを案内しています。

2. local APIへ送る

curl --fail-with-body --silent --show-error \
  -H 'Content-Type: application/json' \
  --data-binary @ollama-request.json \
  http://localhost:11434/api/chat \
  > ollama-response.json

ここで失敗した場合、空の成功結果として扱って次へ進んではいけません。curlがnon-zeroならollama-response.jsonをアプリ入力へ渡さず、「つまずきやすい点」でservice、model名、requestの順に戻します。

3. 外側と内側を順番に確認する

OllamaのAPI応答そのものがJSONで、その内側のmessage.contentにもmodelが生成したJSON文字列が入ります。2層を混同せず検査します。

# API応答全体がJSONか
jq empty ollama-response.json

# contentがJSONで、必須fieldの型が合うか
jq -e '
  (.message.content | fromjson) as $doc
  | (($doc | type) == "object")
    and (($doc.summary | type) == "string")
    and (($doc.keywords | type) == "array")
    and all($doc.keywords[]; type == "string")
' ollama-response.json

# 検証後のdocumentだけを表示する
jq '.message.content | fromjson' ollama-response.json

3つのcommandが成功して初めて、この例の「最初の成功」です。画面に波括弧が見えただけ、HTTP 200だっただけ、fromjsonに通っただけでは、必須fieldと型の確認は完了していません。

成功確認のチェックリスト

  • curlが終了code 0で、API応答全体をjqが読める
  • message.contentfromjsonでparseできる
  • summaryが存在し、文字列である
  • keywordsが存在し、すべての要素が文字列である
  • 検証前のcontentをDB更新、command実行、HTML生成などへ使っていない

このjq式は今回の小さなschemaだけを確認する最短例です。文字数、列挙値、入れ子、日付形式、余分なpropertyの禁止まで必要なら、PydanticやZodなどのJSON Schema対応validatorで同じschemaを再利用してください。

つまずきやすい点と戻し方

localhostへ接続できない

curlが接続を拒否されたら、schemaを変更する前にollama —versionollama psへ戻ります。serviceをどう起動するかはOSとinstall方法で異なるため、推測でsystem設定を変更せず、公式Troubleshootingの該当platform手順を確認してください。

modelが見つからない

HTTP errorにmodel未取得が示されたら、ollama listの正確な名前とtagをrequestへ反映します。記事の例に合わせるためだけに大型modelを取得する必要はありません。元のrequest fileを残し、—arg modelの値だけを変更すれば戻せます。

contentがJSONとして読めない

fromjsonが失敗した結果は利用せず、raw responseを別名で保全します。最初はschemaを小さく保ち、temperatureを0、streamをfalseに固定します。それでも失敗する場合は、model名、Ollama version、schema、promptを記録して別modelとの比較対象にします。成功するまで無制限にretryすると負荷と待ち時間が読めなくなるため、アプリ側では上限を決めます。

JSONにはなったが内容が用途に合わない

Schemaが保証するのは主に形です。要約が事実に合うか、keywordが適切か、危険な文字列でないかは別の意味検証です。schemaへ制約を足す前に、アプリ側の許容条件を決め、失敗時は保存や後続処理を止めます。

Cloud endpointで同じrequestを送っている

2026年8月3日の公式docsはOllama Cloudが構造化出力に未対応と明記しています。local APIで成功したrequestをCloudへそのまま移植できるとは限りません。本記事の手順はlocalhost:11434に限定し、外部公開やCloud移行は適用外です。

さらに深く理解する

schemaを複雑にする前に、成功/失敗を記録する測定単位を決めます。Ollama構造化出力の玄人向け検証記事では、生成制約と型検証を二重化し、schema複雑度、temperature、streaming、model差を混ぜずに評価する方法を整理します。

Ollama自体とllama.cppの役割を先に比較したい場合は、Ollamaとllama.cppの用途別比較を参照してください。

参考資料