【100% JSON保証】Instructor / OpenAI o3-mini / Gemini 3.7 Flash Structured Outputsの実装比較 アイキャッチ

Icons: Lobe Icons(MIT)

マニュアル
公開: 2026.09.02更新: 2026.09.03読了目安 7分

【100% JSON保証】Instructor / OpenAI o3-mini / Gemini 3.7 Flash Structured Outputsの実装比較

LLMからパースエラーなしで厳格なJSONスキーマ通りに出力させる手法(Pydantic、Instructor、Structured Outputs)の実装とベンチマークを解説します。

はじめに:AI出力のパースエラー問題を根本解決する

「JSONで出力して」とプロンプトに書いても、AIが気を利かせて「以下が結果のJSONです: json ... 」と出力してしまい、json.loads() で構文エラーを起こすトラブルは日常茶飯事でした。

近年のAPI(OpenAI o3-mini / GPT-4o、Google Gemini 3.7 Flash)では、モデルのトークンサンプリング段階で特定のJSONスキーマ以外の出力を物理的に禁止する「Structured Outputs」が導入され、パースエラーの発生確率を0%にすることが可能です。


1. Pydantic + Instructor による統一的な構造化抽出

import os
from pydantic import BaseModel, Field
from typing import List, Optional
import instructor
from openai import OpenAI

# 1. 抽出したいデータ構造をPydanticモデルで定義
class ProductSpec(BaseModel):
    brand: str = Field(description="メーカー名・ブランド名")
    model_name: str = Field(description="型番または製品名")
    jan_code: Optional[str] = Field(None, description="13桁または8桁のJANコード")
    features: List[str] = Field(description="主な特徴やスペックのリスト")
    estimated_price_yen: Optional[int] = Field(None, description="推定参考価格(円)")

# 2. InstructorでOpenAIクライアントをラップ
client = instructor.from_openai(OpenAI(api_key=os.environ["OPENAI_API_KEY"]))

# 3. o3-miniでの構造化推論
text = "シマノの24ヴァンフォード C3000HG。JANは4969363045300。定価34,000円。超軽量マグナムライトローター搭載。"

extracted: ProductSpec = client.chat.completions.create(
    model="o3-mini",
    response_model=ProductSpec,
    messages=[{"role": "user", "content": text}]
)

print(f"Brand: {extracted.brand}")
print(f"JAN: {extracted.jan_code}")
print(f"Features: {extracted.features}")

バリデーションエラーが発生した場合も、Instructorが自動でモデルにエラー内容をフィードバックして自己修復するため、後続のデータベース格納処理が100%安全に実行できます。