LLM・RAG

LLM構造化出力とは?JSON Schemaで形式を保証する仕組みとBedrock・各社APIの実装【2026年10月】

LLM構造化出力とは?JSON Schemaで形式を保証する仕組みとBedrock・各社APIの実装【2026年10月】

LLMが返した文章から正規表現でJSONを切り出し、パースに失敗したらもう一度投げる。この後処理を丸ごと捨てる仕組みが、LLMの構造化出力(Structured Outputs)です。スキーマをAPIに渡すと、モデルはそれに違反するトークンを生成できなくなります。この記事ではJSONモードとの保証範囲の違い、OpenAI・Claude・Geminiで異なるスキーマの制限、2026年10月20日にAmazon Bedrockの全Claudeモデルへ広がった構造化出力の指定方法、vLLMでのバックエンド選択、そして「形は正しいのに中身が誤っている」失敗の扱い方を、2026年10月時点の一次情報で整理します。

まとめ:構造化出力の保証範囲と、スキーマ設計で先に決める3点

構造化出力が保証するのは「形」だけです。キー名・型・必須項目・列挙値の範囲はデコード時点で強制されますが、そこに入る値が事実として正しいかは保証されません。導入で消えるのはパースエラーであって、誤った値の混入ではない。この前提を設計の最初に共有してください。

スキーマを書く前に決めるのは3点あります。第1に任意項目の表現方法で、OpenAIのstrictモードは全フィールドを必須にするよう求めるため、任意項目はnullとの合併型で表します。第2に自由文をどのフィールドへ閉じ込めるか。判定や分類をenumで固定できれば、下流の分岐が壊れません。第3に、理由を書かせるフィールドを結論より前へ置くかどうか。この並びで精度が変わります。

Amazon BedrockでClaudeを使っている場合も、同じ設計がそのまま通ります。2026年10月20日以降、Claudeの全モデルでbedrock-runtimeとbedrock-mantleの両エンドポイントから構造化出力を指定できるようになりました。違いはAPIごとの指定先の名前と、初回のスキーマコンパイルに数分かかりうる点の2つです。

採否はシンプルです。出力を型付きのプログラムが受け取り、件数が日次で数百を超え、人手レビューを挟まないなら採ってください。逆に自由文が成果物で、スキーマが案件ごとに変わり、処理が1日数件なら、後処理で拾うほうが安く済みます。

LLM構造化出力の定義と、JSONモードや関数呼び出しとの担当範囲の違い

言葉の指す範囲が製品ごとにずれているため、定義と隣接機能との線引きから固めます。

制約デコーディングでスキーマ違反トークンを落とす仕組みと保証の範囲

LLMの構造化出力とは、モデルの生成結果をあらかじめ定義した機械可読フォーマットへ準拠させる仕組みです。実現方法は2種類。プロンプトで「JSONだけを返して」と依頼する方法と、デコードの各ステップでスキーマに違反するトークンの選択確率をゼロへ落とす方法があります。前者に保証はなく、後者では文法上そもそも違反トークンを選べません。後者を制約デコーディング(constrained decoding)と呼びます。

OpenAIがこの方式をAPIとして提供したのは2024年8月でした。response_format に json_schema を指定して strict を真にすると、スキーマ準拠が保証されます。2026年10月時点では主要3社に加えAmazon Bedrockもスキーマを文法へコンパイルする方式で揃っており、プロンプトでの依頼は旧モデル向けの代替手段です。

JSONモードとの違いは、構文の妥当性とスキーマ準拠のどちらを保証するか

混同されやすいのがJSONモード(json_object)との違いです。JSONモードが保証するのは「返ってきた文字列がJSONとして壊れていないこと」だけで、キー名も型も必須項目も保証しません。スキーマに status と書いても state が返る余地が残ります。

比較軸 JSONモード 構造化出力
構文の妥当性 保証あり 保証あり
キー名と型の一致 保証なし 保証あり
必須項目の充足 保証なし 保証あり
列挙値の範囲 保証なし 保証あり
値の事実正しさ 保証なし 保証なし
2026年の位置づけ 後方互換の旧方式 本番の既定

下流のコードがキーを直接参照しているなら、JSONモードのままではKeyErrorの可能性が残ります。

関数呼び出しとの関係は、引数の検証と最終出力の固定で役割が分かれる

関数呼び出し(Function Calling)は、モデルに「どの関数を呼ぶか」を選ばせ、引数を生成させる仕組みです。構造化出力は「最終的な返答の形」を固定する仕組みで、目的が違います。仕組みそのものの解説はFunction Callingの仕組みとOpenAI APIでの実装に譲ります。

両者は排他ではありません。Claude APIではツール定義側に strict を真で置くと、引数を定める input_schema にも同じ強制が掛かります。Bedrockでも同じで、Converse APIなら toolSpec に strict を置くとツール名と入力がスキーマで検証されます。ツールを呼ぶ経路と最終回答を返す経路の両方で型を固定したいなら、2つを併用してください。

OpenAI・Claude・GeminiのAPI差分と、スキーマに掛かる数値上限の比較

同じJSON Schemaを渡しても、通るスキーマの範囲は3社で異なります。移植時に最初に踏むのがここです。

OpenAIのstrictモードで通らないスキーマと、ネスト10段の上限

OpenAIのstrictモードには、公式ドキュメントに明記された構造上の制約があります。全フィールドを required に列挙すること、オブジェクトには必ず additionalProperties を偽で置くこと。規模の上限はネスト最大10段、オブジェクトプロパティ最大5,000個です。

文字列側の上限も見落としやすい箇所でしょう。プロパティ名・定義名・列挙値・定数値の合計文字長は12万文字まで、列挙値はスキーマ全体で最大1,000個です。商品カテゴリのような大きなマスタをそのままenumへ展開すると、ここで弾かれます。

非対応のキーワードは allOf、not、dependentRequired、dependentSchemas、if、then、else です。既存の検証用スキーマを流用すると、条件分岐を if で書いた箇所が引っかかります。再帰は自己参照と定義参照の両方が使え、木構造なら表現できる。モデルが安全上の理由で拒否したときは専用のフィールドが返るため、パース前に分岐を置いてください。

Claude APIの現行指定と、SDKが非対応制約を説明文へ移す挙動

Claude APIでは、現行の指定方法が output_config の下の format へ移りました。以前の output_format と専用のbetaヘッダはレガシー扱いです。2026年8月時点で、Opus 5・Sonnet 4.6・Haiku 4.5をはじめとする主要モデルで一般提供されていました。2026年10月時点のAWSのドキュメントは、Sonnet・Opus・Haiku・Fable・Mythosの各系列を構造化出力の対象として挙げています。

スキーマのサポート範囲はOpenAIと一致しません。再帰スキーマ、minimum や maximum といった数値制約、minLength と maxLength の文字列長制約は非対応で、配列の minItems は0か1しか受け付けません。挙動が独特なのは、公式SDKが非対応の制約を削除したうえで、その内容をフィールドの説明文へ書き足して送る点でしょう。制約は文法ではなくプロンプトとして伝わります。

性能面では、スキーマから文法をコンパイルする初回リクエストだけが遅くなります。コンパイル結果は最終使用時点から24時間キャッシュされ、スキーマ構造かツール定義を変えると破棄される仕様です。

Geminiの応答スキーマ指定と、プロパティ順の一致という固有の前提

Geminiは生成設定の2つのフィールドで指定します。JSONを強制する応答MIMEタイプの指定と、形を決める responseSchema の組み合わせが基本形で、JSON Schemaをそのまま渡したいときは responseJsonSchema を使います。responseSchema が受け取るのはOpenAPI 3.0のスキーマオブジェクトのサブセットです。

Gemini固有の注意点として、公式ドキュメントはプロンプト側に書いた項目の説明や例示の順序を、スキーマのプロパティ順と揃えるよう求めています。順序がずれるとモデルが混乱し、不正な出力につながると明記されている。3社で唯一、プロンプトとスキーマの並びに依存関係がある実装です。

観点 OpenAI Claude Gemini
指定先 response_format output_config.format 生成設定
スキーマ方言 JSON Schema部分集合 JSON Schema部分集合 OpenAPI 3.0部分集合
全項目required 必須 推奨 requiredで指定
再帰スキーマ 対応 非対応 制限あり
数値の範囲制約 非対応 説明文へ退避 一部のみ
拒否時の応答 専用フィールド 通常応答で判別 安全性の理由で終了

Amazon BedrockでClaudeの構造化出力を使う手順とAPI別の指定先

AWS上でClaudeを呼んでいるなら、Anthropicの直接APIと同じ保証をBedrock経由で得られます。ただしリクエストの形はAPIごとに異なるため、Bedrock側の仕様として加わる固有の制約についても、利用するAPIに合わせた確認が必要です。BedrockからClaudeを呼ぶ経路そのものの選び方はAWSでClaudeを使う方法とBedrock・Claude Platform on AWSの違いで比べています。

2026年10月20日の発表で、全Claudeモデルと2つのエンドポイントへ拡大

Bedrockの構造化出力は、2026年2月4日のAWS発表で一般提供が始まりました。このときの対象はClaude 4.5系のモデルと一部のオープンウェイトモデルで、Converse・ConverseStream・InvokeModel・InvokeModelWithResponseStreamの4つのAPIから使えました。

2026年10月20日のAWS What’s Newで、対象がAnthropic Claudeの全モデルへ広がり、従来のbedrock-runtimeに加えてAnthropic Messages API互換のbedrock-mantleエンドポイントでも使えるようになりました。提供リージョンは「Claudeのモデルが使えるリージョン」とされています。料金表への言及はなく、構造化出力の指定そのものに別料金がかかるという記載も見当たりません。

Claude向けのユーザーガイドによると、モデルによってbedrock-runtimeだけ、bedrock-mantleだけ、両方のいずれかで提供されます。使いたいモデルがどちらに載っているかは、モデルカードで先に確かめてください。

ConverseとInvokeModelで異なるスキーマの指定先と受け渡し形式の比較

同じBedrockでも、APIによってスキーマの置き場所と渡し方が違います。Bedrockの構造化出力ガイドに載っている指定先を表にまとめます。

API 指定先 スキーマの形
Converse outputConfig.textFormat JSON文字列
InvokeModel(Claude) output_config.format JSONオブジェクト
InvokeModel(オープンウェイト) response_format JSONオブジェクト
mantleのMessages API output_config.format JSONオブジェクト
ツール定義(各API) strict を真にする 入力スキーマ

つまずきやすいのはConverseです。textFormat の下の structure.jsonSchema.schema には、スキーマを辞書のままではなく文字列へシリアライズして入れます。InvokeModelはAnthropic本来のリクエスト本文をそのまま送るため、Claude APIと同じ書き方をそのまま流用できる形式です。Converse APIの基本的な呼び方やIAM権限はAmazon Bedrock Converse APIの使い方とboto3実装、InvokeModelとMessages APIの使い分けはBedrock Claudeの使い方:Messages API・InvokeModelの設定で扱っています。

boto3のConverseで請求書の項目をスキーマ通りに抜き出す実行例

請求書のテキストから取引先・発行日・合計金額・担当者・費目を抜き出す例です。前章までの設計どおり、根拠を書くフィールドを先頭に置き、担当者は「文字列かnull」の合併型、費目は列挙で固定しています。モデルIDはAWSのガイドに載っているグローバル推論プロファイルの表記で、自社のアカウントで有効なIDとリージョンに置き換えて実行してください。

import json
import boto3

# リージョンとモデルIDは、モデルカードで構造化出力の対応を確かめてから決める
client = boto3.client("bedrock-runtime", region_name="us-east-1")

schema = {
    "type": "object",
    "properties": {
        "reasoning": {"type": "string", "description": "抽出の根拠を1〜2文で書く"},
        "vendor_name": {"type": "string", "description": "請求元の会社名"},
        "invoice_date": {"type": "string", "format": "date", "description": "発行日"},
        "total_amount": {"type": "integer", "description": "税込合計(円)。0以上の整数"},
        "contact_person": {
            "anyOf": [{"type": "string"}, {"type": "null"}],
            "description": "担当者名。記載がなければnull",
        },
        "category": {"type": "string", "enum": ["外注費", "通信費", "消耗品費", "その他"]},
    },
    "required": ["reasoning", "vendor_name", "invoice_date", "total_amount", "contact_person", "category"],
    "additionalProperties": False,
}

invoice_text = "株式会社サンプル 請求書 発行日2026年10月1日 クラウド利用料 合計55,000円"

response = client.converse(
    modelId="global.anthropic.claude-sonnet-5-5",
    messages=[{"role": "user", "content": [{"text": "次の請求書から項目を抜き出してください。\n" + invoice_text}]}],
    inferenceConfig={"maxTokens": 1024},
    outputConfig={
        "textFormat": {
            "type": "json_schema",
            "structure": {
                "jsonSchema": {
                    "schema": json.dumps(schema, ensure_ascii=False),  # Converseは文字列で渡す
                    "name": "invoice_extraction",
                    "description": "請求書の項目抽出",
                }
            },
        }
    },
)

stop = response["stopReason"]
if stop == "end_turn":
    data = json.loads(response["output"]["message"]["content"][0]["text"])
    # minimum はBedrockで使えないため、範囲はアプリ側で検証する
    if data["total_amount"] < 0:
        raise ValueError("合計金額が負の値です")
    print(json.dumps(data, ensure_ascii=False, indent=2))
elif stop == "max_tokens":
    print("出力が上限で切れました。maxTokensを上げるかスキーマを分割します")
else:
    raise RuntimeError(f"想定外の終了理由: {stop}")

実行前に確かめる点は2つあります。outputConfig 引数を受け付けないと言われたらboto3が古いので更新してください。もう1つは、パースの前に終了理由を見る分岐です。Claude向けガイドのサンプルも、stop_reason が出力上限なら再試行を促す形で書かれています。

Bedrock固有の注意点:引用機能との併用不可・初回コンパイル・推論プロファイル

Anthropicの直接APIと比べて、Bedrockには固有の制約が4つあります。いずれも構造化出力ガイドに明記されているものです。

1つ目はスキーマ検証のタイミングです。BedrockはJSON Schema Draft 2020-12のサブセットに照らしてスキーマを検証し、非対応の機能があれば400エラーを即座に返します。非対応は再帰スキーマ、外部への $ref、minimum・maximum・multipleOf、minLength・maxLength、偽以外の additionalProperties です。Pydanticで ge や max_length を付けたモデルから生成したスキーマは、そのままでは通りません。Anthropic公式SDKのように説明文へ退避してくれる前提は置かず、送る前に該当キーワードを外してください。

2つ目はコンパイル時間です。新しいスキーマは文法のコンパイルに最大で数分かかることがあり、成功した文法は初回アクセスから24時間キャッシュされます。同じアカウントの同一スキーマなら、2回目以降は通常のリクエストに近い遅延で返ります。Claude APIの説明が「最終使用時点から24時間」なのに対し、Bedrockのガイドは「初回アクセスから」と書いている点に注意してください。タイムアウトの短いLambdaから呼ぶ構成なら、デプロイ直後にスキーマを温めるリクエストを1本流しておくと、本番の初回で詰まりません。

3つ目は引用(citations)機能との併用で、有効にした状態で構造化出力を指定すると400エラーになります。根拠となる文書の位置を返させたい場合は、スキーマ側に根拠の抜粋を入れる文字列フィールドを用意してください。

4つ目は推論プロファイルです。クロスリージョン推論とバッチ推論は追加設定なしで使えますが、地域別のクロスリージョン推論プロファイルの中には、一部のモデルで構造化出力に対応しないものがあります。ガイドではインド向けプロファイル経由のClaude Haiku 4.5が例に挙がっています。データの所在地を理由に地域別プロファイルを選ぶ場合は、モデルカードで対応を確かめてから設計に入ってください。

スキーマ設計の実務:任意項目・列挙・説明文・ネスト分割の決め方

APIの制限を踏まえると、書けるスキーマの形はかなり絞られます。実装で毎回問題になる4点を順に決めます。

任意項目はnullとの合併型で表し、キーの有無で分岐させない

全フィールド必須という制約は、一見すると業務データと相性が悪く見えるでしょう。実際には、任意項目を「型かnullのどちらか」を取る合併型として宣言すれば表現できます。請求書から取引先の担当者名を抜く処理なら、担当者名は文字列またはnullとし、記載がなければnullを返させます。キーの有無で表現しようとすると、OpenAIのstrict指定は通りません。

副次的な利点もあります。キーが存在しないケースが消えるため、下流のコードから存在チェックの分岐が丸ごと落ちる。テストで作るべき入力パターンも減り、結果的にコードも短くなります。

判定と分類はenumとconstで固定し、自由文フィールドは1つに閉じ込める

スキーマの効果が最も出るのは、下流が分岐に使うフィールドです。承認・保留・却下のような判定は必ず enum で列挙し、文字列型のまま返させないでください。列挙にしておけば、想定外の値が来たときの分岐がそもそも発生しません。文章を生成せず、定義した選択肢の確率だけを返す判断専用のモデルという別の選択肢もあり、TypeSafe Jevの仕組みと採用条件で整理しています。

一方で理由や要約のような自由文は避けられないでしょう。これは1つのフィールドに閉じ込めます。複数持たせると、モデルが同じ内容を別のフィールドへ書き分け、後段で重複排除が必要になる。マスタ由来の分類コードは前述の列挙値上限に当たるため、上位カテゴリだけを列挙してください。

数値の下限や文字列長は説明文で伝え、検証はアプリ側で二重に行う

スコアを0から100の整数で返させたいとき、数値の範囲制約は3社ともBedrockも十分にはサポートしていません。フィールドの説明に上限と下限を明記し、そのうえでアプリ側でも範囲を検証する二重構えにしてください。

Pythonなら、Pydanticでモデルを定義してスキーマを生成する構成が一般的でしょう。2026年8月9日時点のPydanticは v2.13.4(2026年5月6日公開・MIT)で、検証エラーの内容がそのまま再送プロンプトの材料になります。文法で縛れない制約も、ループの中で吸収できます。

10段のネストに当たる前に、抽出を2回へ分けて浅いスキーマに倒す

契約書や仕様書を1回のリクエストで完全に構造化しようとすると、ネストが深くなりプロパティ数も膨らみます。上限の10段に実際に当たる設計は稀ですが、その手前でモデルの精度が落ちる。実務では抽出を2段に分けるほうが安定します。1回目は章の見出しと種別だけを浅いスキーマで抜き、2回目で章ごとに詳細スキーマを当ててください。

セルフホストLLMでの構造化出力:vLLMの指定方法とバックエンドの選び分け

商用APIを使わない構成でも同じ保証は得られます。むしろ制約デコーディングの実装は、オープンソース側のほうが選択肢の広い領域です。

vLLMで指定できる5種類の制約と、旧フィールド廃止による移行の注意

vLLMは公式に構造化出力へ対応しており、2026年8月9日時点の最新リリースは v0.26.0(2026年7月27日公開・Apache-2.0・GitHubスター88,535)です。OpenAI互換サーバでは、JSON Schemaに加えて正規表現、選択肢からの単一選択、文脈自由文法、指定タグ内でのJSON強制という5種類の制約を掛けられます。分類タスクで選択肢を数個に絞るだけなら、選択肢指定のほうが素直に書けるでしょう。

移行時の注意として、guided_json のような旧フィールド名は v0.12.0 で削除済みです。古いサンプルコードをそのまま持ち込むと動きません。スループットやレイテンシを詰める段階の設計と推論基盤の選定は、LLM推論の仕組みと高速化・推論基盤の選び方で扱っています。

xgrammarとoutlinesとllguidanceの性格差と版数の実測

バックエンドは3つあり、性格が違います。xgrammarは文法を再利用する場面でキャッシュが効き、1トークンあたりの生成時間が短く済みます。outlinesは有限状態機械のコンパイルコストを前払いする方式で、複雑なスキーマを何千回も使い回す構成に向く。llguidanceはトークン単位で制約を計算し、初回応答までの時間が短い点が持ち味です。

  • mlc-ai/xgrammar:v0.2.5(2026年7月22日公開・Apache-2.0・スター1,813)
  • dottxt-ai/outlines:1.3.3(2026年8月6日公開・Apache-2.0・スター15,540)
  • guidance-ai/llguidance:リリースタグなし・MIT・スター830(最終更新2026年8月6日)

迷ったら既定の自動選択のまま始めてください。切り替えを検討するのは、同じスキーマを大量に回すバッチで生成時間が読めないときか、初回応答の待ち時間が体感へ響く対話用途の2択です。

構造化出力の導入後に起きる4つの失敗と、リトライ設計での吸収の仕方

導入後に持ち込まれる不具合は、種類がほぼ決まっています。原因の切り分け順に並べます。

スキーマには従うのに値が誤る、という最も多い失敗の切り分け方

最も件数が多いのは、形式は完璧なのに中身が違うケースです。請求書の金額フィールドに合計ではなく小計が入る。日付フィールドに発行日ではなく支払期日が入る。どちらもスキーマ上は正当な出力なので、制約デコーディングでは止められません。

対処はスキーマではなく評価の側にあります。抽出結果を正解データと突き合わせるテストセットを作り、フィールド単位で一致率を見てください。形式エラーがゼロになると動いているように見えるため、内容の精度を測らないと、誤った値が静かに業務データへ流れ込みます。

本番の応答ごとに値の妥当性をコードで検査し、落ちたら再生成させる仕組みとしては、Pydanticモデルと組み合わせられるGuardrails AIがあります。手順はGuardrails AIとは:LLM出力をバリデーターで検証するPythonの使い方と0.11の変更点【2026年11月】で確認できます。

生成トークン上限での打ち切りと、安全上の拒否をパース前に分岐する

構造化出力を使っていても、壊れたJSONが返ることはあります。原因の大半は生成トークン数の上限に達した打ち切りでしょう。文法上は正しい途中まで生成し、閉じ括弧に到達する前に止まるためパースは失敗します。長い配列を返させる設計ほど起きやすい。

実装では、パースを試みる前に終了理由を確認してください。Bedrockの例で示したとおり、Converseなら stopReason、InvokeModelなら stop_reason を見ます。上限到達の場合の対処方法は、スキーマの分割かトークン上限の引き上げです。安全上の拒否も別形式で返るため、この分岐を持たない実装は例外で落ちます。

形式の縛りが推論品質を下げる場合に、思考用フィールドを先頭へ置く

出力フォーマットの制約が推論タスクの性能を下げうることは、arXiv:2408.02442 をはじめとする研究で報告されています。厳しい形式を課すと、モデルが答えに至るまでの中間的な検討を書く場所を失うためです。

回避策はスキーマの並び順にあります。結論フィールドの前に、根拠を書くための文字列フィールドを1つ置いてください。JSONは定義順に生成されるので、先に理由を書かせてから結論を出させる流れが作れる。逆に結論を先頭へ置くと、モデルは検討前に答えを確定させ、判定が難しいタスクほど精度が落ちます。

検証エラーを添えて再送し、リトライ回数を2回で打ち切る設計にする

アプリ側の検証で弾かれた出力は、エラーメッセージを添えて再送すると多くが通ります。Pythonでこの再送を定型化するライブラリが instructor で、2026年8月9日時点の版は v1.15.4(2026年6月28日公開・MIT・スター13,702)です。Pydanticモデルを渡すと、検証失敗時に例外内容をモデルへ戻して再試行します。

回数は2回で打ち切ってください。3回目以降で通るケースは少なく、待ち時間と費用だけが積み上がります。打ち切ったレコードは失敗として記録し、人手のキューへ送る。再試行をエージェントの制御ループへ組み込む設計はエージェントループと終了条件の設計で整理しています。

構造化出力を採らない条件と、受託開発で要件定義に書かせる項目

ここからは判断です。全案件で構造化出力を使うべきかというと、そうではありません。

自由文が成果物・スキーマが毎回変わる・日次数件、この3条件なら見送る

次の3つのいずれかに当たるなら、構造化出力は入れないでください。第1に、記事下書きやメール文面のように自由文そのものが最終成果物である場合。JSONで包む意味がなく、文字列フィールド1つのスキーマを維持する手間だけが残ります。

第2に、スキーマが案件ごと・顧客ごとに変わり、動的に組み立てざるを得ない場合。文法コンパイルのキャッシュが効かず、初回コストを毎回払い続けます。Bedrockでは初回のコンパイルに数分かかる場合があるため、この条件での不利はさらに大きくなります。素のJSONで受け、アプリ側の検証と再送で吸収するほうが安く済むでしょう。第3に、処理件数が1日数件で人手レビューが前提の場合。パースエラーを人が直すコストのほうが、スキーマの設計と保守より小さくなります。

型付きの下流・日次数百件・人手レビュー無し、この組み合わせなら採用する

逆に採用条件も言い切ります。出力を受け取るのが型付きの言語で書かれたプログラムで、処理件数が日次で数百を超え、人手レビューを挟まず業務データへ書き込む。この3つが揃うなら入れてください。パースエラーの発生率が低くても、無人で流れる経路では1件の失敗がジョブ全体の停止につながります。

AWSの中で処理が完結している案件なら、Bedrockの構造化出力を第一候補にしてください。バッチ推論でも追加設定なしで使えるため、夜間に数千件の帳票を抽出する構成と相性がよい。逆に引用機能で根拠の位置を返させることが要件の中心なら、構造化出力とは併用できないので、どちらを優先するかを先に決めます。

よくある誤りは、モデルの精度を上げる手段として構造化出力を検討することでしょう。これは精度の施策ではなく、出力を受け取る側のインターフェースを固定する施策です。抽出精度が足りないなら、スキーマではなくプロンプトと評価セットを見直してください。

外注する場合に要件定義へ書かせる4項目と、見積もり時の確認事項

外部に委託するなら、要件定義書に次の4項目が書かれているかを確認してください。第1にスキーマの版管理方法。第2に検証エラー時のリトライ回数と、打ち切り後の退避先。第3に形式エラー率とは別に測る、フィールド単位の内容一致率とその目標値。第4に、対象モデルを変更したときスキーマが通るかを確かめる回帰テストの有無です。Bedrockでモデルや推論プロファイルを切り替える計画があるなら、第4項目の対象にプロファイルも含めてください。

特に3番目が抜けた見積もりは危険で、「JSONが必ず返る」ことをもって完成とされる余地が残ります。抽出対象の文書種別と許容誤り率を発注側から先に提示しておけば、この曖昧さは消えるでしょう。スキーマ設計から評価セットの整備までを含めて相談したい場合は、生成AI導入支援で要件の切り分けから対応しています。

よくある質問

構造化出力の導入検討で実際に多い質問を、5つに絞って答えます。

構造化出力を使えばハルシネーションは無くなりますか?

無くなりません。制約デコーディングが縛るのは出力の形式だけで、値の内容は対象外です。存在しない取引先名がスキーマ通りの文字列フィールドに入って返ることは普通に起こります。減らせるのはパース失敗と、想定外のキー名・型による下流のエラーだけです。内容の誤りには、フィールド単位の一致率測定と値の存在確認を別工程で用意してください。

JSONモードと構造化出力はどちらを使うべきですか?

対象モデルが構造化出力に対応しているなら、構造化出力を選んでください。JSONモードが保証するのはJSONとして壊れていないことだけで、キー名・型・必須項目は保証されません。2026年10月時点では、JSONモードは後方互換のための旧方式です。JSONモード側の指定方法や、あえて残してよい条件はJSONモードとは?構文だけを保証する仕組みと構造化出力への移行判断にまとめています。新規実装でJSONモードを選ぶ理由は、対応していない旧モデルを使い続ける制約がある場合に限られるでしょう。

Amazon BedrockのClaudeで構造化出力を使うには何を指定しますか?

Converse APIなら outputConfig.textFormat に json_schema 型を指定し、スキーマを文字列にして渡します。InvokeModelやbedrock-mantleのMessages APIなら、Claude APIと同じ output_config.format にスキーマをオブジェクトのまま入れます。2026年10月20日以降はClaudeの全モデルが対象です。引用機能とは併用できず、数値や文字列長の制約を含むスキーマは400エラーになる点に注意してください。

構造化出力を使うと応答が遅くなりますか?

初回リクエストだけ遅くなります。スキーマをトークン生成用の文法へコンパイルする処理が入るためです。Claude APIではコンパイル結果が最終使用時点から24時間キャッシュされ、Bedrockでは初回アクセスから24時間キャッシュされます。Bedrockのコンパイルは最大で数分かかる場合があるので、デプロイ直後に1回呼んでおくと安心です。逆にリクエストごとにスキーマを組み立てる実装はキャッシュが効きません。スキーマは定数として持ち、可変部分は入力データ側へ寄せてください。

ローカルLLMやセルフホスト環境でも同じことができますか?

できます。vLLMは公式に構造化出力へ対応しており、JSON Schemaのほか正規表現・選択肢・文脈自由文法での制約も掛けられます。バックエンドは xgrammar・outlines・llguidance から選べ、既定は自動選択です。ただし旧来の guided_json 形式のフィールドは v0.12.0 で削除されている点に注意してください。

関連記事

お気に入りに入れた記事の一覧

一創の公式 SNS

X では毎朝の新着記事と IT ニュースの速報を、YouTube・TikTok・Instagram・LinkedIn・Facebook では記事の解説動画を配信しています。

この記事は以下の記事からリンクされています

ほか 16 件の記事からもリンクされています。

資料請求

今日のトレンド記事 直近 24 時間で、いつもより多く読まれている記事

  1. 2026.11.09 テックブログ エディオン不正アクセス第2報:カード番号の対象確認とログ・決済画面の改ざん対策
  2. 2025.04.30 テックブログ IMSIキャッチャー(偽基地局)とは?2Gフォールバックの手口と日本での対策
  3. 2026.11.10 テックブログ ニトリの情報漏洩:最大3,762万件の対象確認となりすまし連絡の見分け方
  4. 2026.11.10 テックブログ Claude Fable 5.2とは:料金・破壊的変更4点とFable 5.1からの移行手順【2026年11月】
  5. 2026.11.09 テックブログ LANSCOPE不正アクセス第2報:製品への影響と偽連絡の確認、停止中のライセンス認証の窓口

RELATED POSTS 関連記事

目次