「json.decoder.JSONDecodeError: Expecting ',' delimiter」というエラーに遭遇したことはありますか?APIから返されたJSONがパース不能だった、あの絶望的な瞬間です。本稿では、AIの構造化出力において避けて通れないこの課題について、HolySheep AIのAPIを活用した実践的な解決策を詳細に解説します。
なぜ構造化出力が重要か
AIアプリケーション開発において、LLMの出力をプログラムで確実に処理できる形式に変換することは、品質と信頼性の要です。特に以下のシナリオでは構造化出力が不可欠となります:
- データベースへの自動入力
- 外部APIとの正確な連携
- フォームや設定ファイルへの動的反映
- 多段階パイプラインにおける後段処理
私の経験では、非構造化テキストをパースする場合、約15〜20%のケースでごく些細な形式崩れが発生し、後段のシステムで予期せぬエラー引起こしてきました。
JSON Mode(構造化JSON出力)
基本的な仕組み
JSON Modeは、LLMに対して「必ずJSON形式で回答する」よう指示する方法です。プロンプトエンジニアリングの一環として、回答の形式を文案で指定します。
実装例:JSON Mode
import requests
base_url = "https://api.holysheep.ai/v1"
headers = {
"Authorization": f"Bearer YOUR_HOLYSHEEP_API_KEY",
"Content-Type": "application/json"
}
payload = {
"model": "gpt-4.1",
"messages": [
{
"role": "system",
"content": "あなたは商品情報を抽出するアシスタントです。\
すべての回答は必ず以下のJSON形式厳守: {\"product_name\": string, \"price\": number, \"currency\": string}"
},
{
"role": "user",
"content": "この製品はApple iPhone 15 Proで、価格は159,800円です。"
}
],
"temperature": 0.3
}
response = requests.post(
f"{base_url}/chat/completions",
headers=headers,
json=payload,
timeout=30
)
result = response.json()
print(result["choices"][0]["message"]["content"])
出力: {"product_name": "iPhone 15 Pro", "price": 159800, "currency": "JPY"}
JSON Modeの制約
JSON Modeは以下の問題を抱えています:
- LMが「JSONの文字列として」ではなく、通常のテキストとして回答する可能性がある
- フィールドの欠落や余計なテキストの混入が防げない
- температура(温度パラメータ)が高いと形式崩れが発生しやすい
- レスポンスのJSONパース失敗率が運用環境で3〜8%存在する
Strict Mode(厳格モード)
基本的な仕組み
Strict Modeは、APIレベルで対応する構造化出力専用の機能です。レスポンスの形式をスキーマとして定義し、API自体がその形式を保証します。
実装例:Strict Mode(JSON Schema指定)
import requests
import json
base_url = "https://api.holysheep.ai/v1"
headers = {
"Authorization": f"Bearer YOUR_HOLYSHEEP_API_KEY",
"Content-Type": "application/json"
}
response_format = {
"type": "json_schema",
"json_schema": {
"name": "product_info",
"strict": True,
"schema": {
"type": "object",
"properties": {
"product_name": {"type": "string"},
"price": {"type": "number"},
"currency": {"type": "string"},
"category": {"type": "string"}
},
"required": ["product_name", "price", "currency"]
}
}
}
payload = {
"model": "gpt-4.1",
"messages": [
{
"role": "user",
"content": "Sony WH-1000XM5ノイズキャンセリングヘッドフォンを\
89,800円で発売します。カテゴリはオーディオ機器です。"
}
],
"response_format": response_format,
"temperature": 0
}
response = requests.post(
f"{base_url}/chat/completions",
headers=headers,
json=payload,
timeout=30
)
result = response.json()
structured_output = result["choices"][0]["message"]["content"]
data = json.loads(structured_output)
print(f"商品: {data['product_name']}")
print(f"価格: {data['currency']} {data['price']}")
print(f"カテゴリ: {data['category']}")
100%有効なJSONが保証される
JSON Mode と Strict Mode の詳細比較
| 評価項目 | JSON Mode | Strict Mode |
|---|---|---|
| 形式保証 | プロンプト依存(Best Effort) | APIレベル保証(100%) |
| パース成功率 | 92〜97% | 99.9%+ |
| 実装複雑度 | 低(プロンプトのみ) | 中(スキーマ定義必要) |
| コスト | 標準 | モデルによる |
| レイテンシ | 低 | やや高め |
| 温度パラメータ | 0.3以下推奨 | 0固定(変更不可) |
| フィールド制御 | 緩い | 厳密(必須/任意指定可) |
| ネスト構造 | 複雑なものは困難 | 深いネストも対応 |
| 後段処理の安全性 | 追加バリデーション必須 | そのまま使用可能 |
向いている人・向いていない人
JSON Mode が向いている人
- シンプルな構造(2〜3フィールド程度)で十分である
- パース失敗時にフォールバック処理を用意できる
- 実装速度を重視し、手っ取り早くプロトタイプを作りたい
- 出力に若干の揺れ(例:「159800」と「159,800」)が許容される
JSON Mode が向いていない人
- 医療・金融など入力の正確性が厳密に求められるシステム
- 後段のデータベースに直接INSERTするパイプライン
- CI/CDにおける自動テストでパース成功率100%が求められる
Strict Mode が向いている人
- ミッションクリティカルな業務システム
- 型安全な言語(TypeScript, Rust, Go)で開発している
関連リソース
関連記事