ローカルでLLMを動かす Ollama は、手軽さの一方で「戻り値が安定しない」という悩みがつきまといます。
特に JSON を返してほしい場面で、コードフェンスや前置きが混ざってパースに失敗した経験はないでしょうか。
この問題は、プロンプトの工夫ではなく Ollama の「構造化出力(structured outputs)」で根本から解決できます。
今回は format パラメータと Pydantic を組み合わせ、型安全な JSON を確実に受け取る方法を整理しました。
なぜプロンプトで JSON を頼むと崩れるのか
「JSON で返して」と指示する方法(JSONモード)は、出力が整形済みである保証がありません。
公式ブログによれば、従来の JSON モードで正しく整形された JSON が返るのは約4割程度だったとされています。
残りはコードフェンスや説明文が混ざり、json.loads でそのまま落ちてしまうわけです。
プロンプトを工夫してもこの不安定さは消えにくく、後処理のパース用コードが膨らみがちでした。
format パラメータにスキーマを渡す
Ollama 0.5(2024年12月6日リリース)から、format パラメータに JSON スキーマそのものを渡せるようになりました。
スキーマを渡すと constrained decoding(制約付きデコード)が働き、トークン生成の段階でスキーマに合わない出力が弾かれます。
つまりモデルは「スキーマに従った文字列しか吐けない」状態になるのです。
結果として、整形済みの JSON が 100% 返るようになります。
最小の例を見てみましょう。
from ollama import chat
schema = {
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer"},
},
"required": ["name", "age"],
}
res = chat(
model="llama3.2",
messages=[{"role": "user", "content": "山田太郎は30歳です"}],
format=schema,
)
print(res.message.content)
format に渡すのは、普通の dict で表現した JSON スキーマです。
戻り値の content は、もう余計な装飾のない JSON 文字列になっています。
Pydantic でスキーマを生成・検証する
スキーマを手書きするのは骨が折れるので、Pydantic と組み合わせるのが実用的です。
BaseModel を定義し、model_json_schema() でスキーマを生成して format に渡します。
戻ってきた文字列を model_validate_json() に通せば、生成と検証が一気通貫になるのです。
from ollama import chat
from pydantic import BaseModel
class Person(BaseModel):
name: str
age: int
res = chat(
model="llama3.2",
messages=[{"role": "user", "content": "山田太郎は30歳です"}],
format=Person.model_json_schema(),
)
person = Person.model_validate_json(res.message.content)
print(person.name, person.age)
これで person は型付きのオブジェクトとして扱え、フィールド名の打ち間違いもエディタが教えてくれます。
スキーマの定義と検証が一箇所にまとまり、保守もずいぶん楽になりました。
速度面の副次効果
構造化出力は信頼性だけでなく、速度にも効くことがあります。
ある検証では、同じプロンプトが format 指定なしで約31.8秒、指定ありで約5.0秒と、6倍以上速くなった例も報告されています。
整形の判断にトークンを使わなくなる分、生成が短く済むという理屈なのでしょう。
ただし速度はモデルやハードウェアに左右されるため、数値はあくまで一例として捉えてください。
最後に
ローカルLLM から構造化データが欲しいときは、プロンプトで JSON をお願いするより、推論そのものをスキーマで縛る方が確実です。
これは Ollama に限らず、クラウドAI の structured outputs にも共通する発想だと感じています。
Ollama 自体の導入がまだの方は、別記事の入門編も参考にしてみてください。
以上です。










コメントを残す