---
title: "LLMから狙った通りの構造化データ（JSON）を打率高く抽出するためのTips備忘録"
description: "LLMから狙い通りの構造化データを最も打率高く（確実かつ低レイテンシで）抽出するためのアプローチとTipsを整理してメモしておきます。"
lang: "ja"
canonical: "https://llm-lab.dev/posts/generative-ui-correct-json-output/"
source: "https://llm-lab.dev/posts/generative-ui-correct-json-output.md"
publishedAt: "2026-01-18"
updatedAt: "2026-01-18"
category: "技術検証"
tags:
  - "llm"
  - "structured-outputs"
  - "json"
  - "prompt-engineering"
---

# LLMから狙った通りの構造化データ（JSON）を打率高く抽出するためのTips備忘録

> [!NOTE]
> この記事で確認したこと: LLMから安定してJSONを取り出すには、プロンプトだけで頑張るのではなく、API機能とスキーマ設計の問題として扱う方が堅実です。対応モデルならStructured OutputsやTool Callingが最も強く、JSON Modeを使う場合も明示的な指示とパース後バリデーションが必要です。`description`、`enum`、推論用フィールドの有無は、精度・速度・コストを調整する主要なレバーになります。

## LLMに「綺麗なJSON」を吐かせる難しさ

LLMを使ったアプリケーション開発（特にエージェントやバックエンドの自動化パイプライン）において、出力を綺麗な構造化データ（JSON）として受け取ることは必須要件です。

しかし、プロンプトで「JSONで出力して」と頼むだけでは、不要な解説テキストが混ざったり、スキーマが微妙にズレたりしてパースエラーになるのが日常茶飯事。
今回は、LLMから狙い通りの構造化データを最も打率高く（確実かつ低レイテンシで）抽出するためのアプローチとTipsを整理してメモしておきます。

---

## 1. 構造化データ抽出の「3つのアプローチ」

現在、主要なLLM APIで構造化データを取得する方法は大きく分けて3つあります。

| 手法 | 特徴と使い所 |
| --- | --- |
| **Structured Outputs**<br /> | **最強の選択肢。** モデルの出力自体をJSON Schemaに強制的に固定するため、スキーマ違反が原則100%発生しない。 |
| **JSON Mode** | 出力フォーマットをJSONに縛る。ただし、プロンプト側でも「JSONで返せ」と明示する必要があり、キーの型や構成までは完全強制できないため、パース後のバリデーション（Zod等）が必須。 |
| **Tool Calling（関数呼び出し）** | 本来は外部ツール連携用だが、「ツール（関数）の引数」として構造化データを定義できるため、間接的に確実なJSON抽出手段として機能する。 |

> 💡 **結論:** スキーマの完全性を担保したい、かつ対応モデルであるなら **Structured Outputs（またはTool Callingのハック）** の一択。

---

## 2. 精度を高めるためのスキーマ定義・プロンプトのTips

ただ仕組み（Structured Outputsなど）を使うだけでなく、「LLMが迷わないスキーマ」を設計することが、ハルシネーションの抑制や抽出精度の向上に直結します。

### ① `description`（説明文）をサボらない

JSON SchemaやZodでオブジェクトを定義する際、各プロパティ（キー）に必ず具体的な `description` を付与します。
LLMはこの説明文を強力な指示（プロンプト）として読み解くため、「何を、どういう基準で抽出してほしいか」をここに言語化するのが最も効果的です。

### ② あいまいな「自由記述」を減らし、`enum`（列挙型）を活用する

例えば、テキストの感情分析をさせる場合、`string` で自由に返させるのではなく、`['positive', 'negative', 'neutral']` のように `enum` で選択肢を制限します。
これにより、LLMの思考のブレ（「ポジティブ」「高評価」などの表記揺れ）を完全に防ぐことができます。

### ③ 思考フェーズ（Chain of Thought）をスキーマに内包させる

「思考プロセスを踏んでから結論を出させたいが、最終出力はJSONにしたい」という場合、スキーマの中に `reasoning`（思考・理由）というフィールドをあらかじめ用意しておくテクニックが有効です。
LLMはJSONを上から順に出力していくため、先に `reasoning` で推論を行わせることで、最終的な `result`（結論）の精度が劇的に向上します。

```json
// スキーマ構造のイメージ
{
  "reasoning": "なぜその結論に至ったかの思考プロセス（ここに先に書かせる）",
  "final_answer": "最終的な抽出結果・判定"
}

```

---

## 3. 実装・運用時の注意点（LLM Opsの視点）

* **トークン消費量とレイテンシのトレードオフ:**
思考フェーズ（`reasoning`）をJSONに含めると、出力トークン数が大幅に増えるため、その分レスポンスが遅くなり、APIコストも上がります。リアルタイム性が求められる画面では、あえて思考を省くか、軽量モデル（Flash系など）を叩くといった割り切りが必要です。
* **スキーマ変更時の互換性:**
アプリケーション側のコード（Zod定義など）を変更した際、LLM側に渡すスキーマ定義も追従させないと、本番環境で予期せぬパースエラーを吐く原因になります。スキーマのロジックは一元管理するのが安全。

---

## まとめ

LLMからの構造化データ抽出は、プロンプトの工夫（泥臭いアプローチ）から、APIの機能（堅牢なシステム）へと完全にシフトしています。
`description` の記述や `enum` の固定といった基本を徹底しつつ、用途に応じて「速度重視か」「精度重視か」を切り替えていくのが良さそうです。
