このページの目次

プロンプトエンジニアリングと構造化出力

サンプリングパラメータが削除された後、「創造性/決定性の調整」ノブは2つに置き換わりました: prompt (意図を明確にする) と effort (十分な計算リソースを提供する)。そして、出力をプログラムが消費可能にするのは、「JSONを返してください」ではなく、スキーマ制約です。

概要

トークンとサンプリング で紹介した分岐: Claude のマネージド API は Opus 4.7 から temperature/top_p/top_k を削除し、送信すると即座に 400 エラーになります。旧時代の「温度で創造性を制御し、温度0で決定性を得る」という手触りは失われました。Anthropic は制御権を、より高レベルで制御可能な2つのノブに移動しました:

  • プロンプティング⁠——決定性が必要なら指示を固定し、発散が必要ならプロンプト内で明確に多様性を要求する;
  • effort——どの程度深く推論するか、どのくらいのトークンを使うかを制御する (推論と思考 参照)。

このページでは、この2つのノブの使い込み方(前半: プロンプトエンジニアリング)と、出力をダウンストリームのプログラムに渡す際に、⁠構造化出力を使って「自由テキスト」を「確実に解析可能な JSON」に制約する方法(後半)について解説します。これら2つはよくセットで現れます: プロンプトが振る舞いを定め、スキーマが形状を定めます。

前半: プロンプトエンジニアリング

モデルが一度に見るのは、結合された1つのテキスト

コンテキストエンジニアリング でレンダリング順序 tools → system → messages は説明済みです。プロンプトエンジニアリングとは、このテキストに何を書き、どのように配置するかを決定することです:

  • system: 安定したロール、ルール、出力規約——これを凍結し、タイムスタンプを挿入しない(キャッシュを維持するため)。
  • user: 今回の具体的なタスク + 必要な動的コンテキスト(検索スニペット、状態)。
  • few-shot 例⁠: 数個の入力→出力の例は、長い抽象的なルールよりも、フォーマットやスタイルを「教える」のに効果的です。system と user の間に配置します。

触れると実感できる4つの原則

  • 「〜しなければならない」と積み重ねるのではなく、「いつ/境界」を明確にする。 最近の Opus (4.7/4.8) は指示遵守が非常に強く、旧時代のモデルを「圧迫」するために使っていた CRITICAL: YOU MUST過剰にトリガーされる可能性があります。「CRITICAL: 検索ツールを使わなければならない」を、「答えが会話に含まれていない情報に依存する場合、まず検索してから回答する」といった条件文に緩和してください。
  • 重要な指示は注意力の強い位置に配置する。 重要な制約は、先頭の system または末尾の user に配置し、XML タグや区切り文字で囲む(<rules>...</rules>)。中間に埋め込まない(lost in the middle に対抗するため)。
  • 正例は反例より優れている。 「こう書いて: …」は「こう書いてはいけない」よりも安定しています。簡潔さを求めるなら、1つの簡潔な例を与える方が、「冗長にするな」という10のルールを列挙するよりも効果的です。
  • 意図を与える。 指示だけでなく、「これは誰のために、何に使うものか」を説明すると、モデルは合理的な詳細を自ら補完できます——特に長期的なタスクで顕著です。

移行レシピ: temperature → prompt + effort

旧コードのサンプリングパラメータは、意図に応じて変換します:

旧書き方 (意図)新書き方
temperature=0 (決定性追求)effort:"low" + 指示を固定し、出力フォーマットを指定
temperature=高 (発散追求)プロンプト内で明確に「N個の異なる方向を提示」; フロントエンドでモデルに「まず4つの異なる方向を提示してから実装する」ようなシナリオを設計
temperature で長さを制御プロンプト内で長さ/詳しさの要件を直接記載(モデルはタスクの複雑さに応じて自動調整するため、必要なら固定する)

古い誤解へのヒント: temperature=0 は旧モデルでも決してバイト単位の再現を保証しません(浮動小数点の累積順序、バッチ処理、MoE ルーティングが変動するため。詳細は トークンとサンプリング を参照)。「決定性」はパラメータの保証ではなく、エンジニアリングの目標(プロンプトの固定 + 低 effort + 微小なドリフトの許容)です。

後半: 構造化出力

モデルの出力をプログラムに渡す(データベースへの保存、ダウンストリーム API の呼び出し、アサーションの実行)場合、「JSONを返してください」では不十分です——モデルは前言を追加したり、フィールドを漏らしたり、フォーマットがぶれたりする可能性があります。⁠構造化出力は、スキーマを使って API レベルで出力を制約し、確実に有効な形状にします。2つのレベルがあります:

1. JSON 出力: 応答全体を制約

messages.createoutput_config.format を送信(注意: 従来のトップレベルの output_format パラメータは廃止済み):

response = client.messages.create(
    model="claude-opus-4-8",
    max_tokens=16000,
    messages=[{"role": "user", "content": "Extract: John (john@co.com), Enterprise plan"}],
    output_config={"format": {
        "type": "json_schema",
        "schema": {
            "type": "object",
            "properties": {
                "name":  {"type": "string"},
                "email": {"type": "string"},
                "plan":  {"type": "string"},
            },
            "required": ["name", "email", "plan"],
            "additionalProperties": False,   # 必須
        },
    }},
)
# 最初の text block が有効な JSON となる

SDK には client.messages.parse() + Pydantic/Zod も用意されており、手動解析なしで検証済みのオブジェクトを直接取得できます。

2. 厳格なツール呼び出し: ツール引数を制約

モデルがツールを呼び出す際、引数もスキーマに従って厳密に検証されるようにする——ツール定義に strict: true を追加する(tool_choice ではなく、ツール自体に設定)。スキーマには additionalProperties: falserequired を含める必要がある:

tools=[{
    "name": "book_flight",
    "strict": True,
    "input_schema": {
        "type": "object",
        "properties": {
            "destination": {"type": "string"},
            "passengers":  {"type": "integer", "enum": [1,2,3,4]},
        },
        "required": ["destination", "passengers"],
        "additionalProperties": False,
    },
}]

これにより tool_use.input がスキーマに厳密に一致することが保証されます——分類タスクでは、モデルに「ラベル単語を出力」させて解析するよりも、enum を持つツールや構造化出力を使う方がはるかに安定しています。

スキーマの能力限界(知っておかないと静かにハマる)

構造化出力は対応⁠: 基本型、enum/const/anyOf/$ref、文字列フォーマット(date-time/email/uri/uuid...)、additionalProperties: false(各オブジェクトに記述が必要)。⁠非対応⁠: 再帰スキーマ、数値制約(minimum/maximum)、文字列長(minLength/maxLength)、複雑な配列制約。Python/TS SDK は非対応の制約を自動的に除去し、クライアント側での検証にフォールバックします。

実務上の2点:⁠新しいスキーマを初めて使用する場合、一度限りのコンパイルオーバーヘッドがあり、その後24時間はキャッシュがヒットします。⁠構造化出力と引用(citations)は排他⁠(両方を有効にすると 400 エラー。詳細は RAG 参照)。

構造化出力 × 評価: 検証をプログラム可能にする

これが構造化出力で最も過小評価されている価値です。評価と観測 で述べたように、「コードで判定できるスコアリングはモデルに任せない」のが原則です。構造化出力により、多くの検証が「LLM-as-judge」から「コードアサーション」に格下げされます: スキーマに適合しているか、列挙値が有効か、必須フィールドが揃っているか——すべて assert で処理可能。決定性があり、コストゼロ、バイアスなし。⁠まずスキーマを使って出力をアサート可能な形状に固定し、その上で LLM 判定器を使うかどうかを検討する。

ベストプラクティス

  • サンプリングパラメータはすべて削除し、意図を prompt + effort に変換。 temperature=0effort:"low" + 指示の固定; 発散を求む→プロンプトで明確に「N個の方向を提示」。
  • 指示は「いつ/境界」を記述し、「〜しなければならない」を積み重ねない。 新しい Opus は指示遵守が強く、過激な表現は過剰にトリガーされる; 重要な制約は強い位置に配置し、XML で囲む。
  • few-shot 正例 > 抽象的なルールの山。 例を与えてフォーマットやスタイルを教える。簡潔さを求めるなら簡潔な例を与える。
  • 出力をプログラムに渡す場合はスキーマを使用。 output_config.format で全体を制約、strict:true でツール引数を制約; 「JSONを返してください」に依存しない。
  • 各オブジェクトに additionalProperties:falserequired を記述。 さもないと厳格モードが有効にならない。
  • スキーマを使って検証をコードアサーションに格下げ。 assert できる場合は判定器を呼ばない; 構造化出力は評価のプログラム可能性の前提条件。
  • スキーマの限界と排他性を記憶。 再帰/数値/長さ制約は非対応; 引用とは排他なので、どちらか一方を選択。

トレードオフと失敗パターン

  • 新モデルでも temperature/top_p/top_k を送信⁠: 400 エラー → 削除し、prompt + effort に移行。
  • 旧式の CRITICAL: YOU MUST 攻撃⁠: ツール/スキルが過剰にトリガー → 「いつ使うか」の条件文に緩和。
  • 「JSONを返してください」に依存⁠: 偶発的な前言/フィールド漏れ/フォーマット崩れ → output_config.format で厳格に制約。
  • stricttool_choice に設定⁠: 無効 → ツール定義に設定し、additionalProperties:false を付与。
  • スキーマに minLength/minimum を記述⁠: 静かに除去され、制約が効かない → これらの範囲検証はクライアントコードで行う。
  • 構造化出力と同時に citations を有効⁠: 400 エラー → どちらか一方を選択; 出典追跡が必要ならプレーンテキスト + 引用、解析可能ならスキーマを使用。
  • 思考無効化時に冗長になる⁠: thinking:disabled で推論が本文に漏れる → adaptive を残すか、「最終回答のみを出力」を追加(推論と思考 参照)。

参考

キーワード: プロンプトエンジニアリング、system プロンプト、few-shot、XML タグ、指示配置、temperature 移行、effort、構造化出力、structured outputs、output_config.format、json_schema、厳格なツール使用、additionalProperties、required、messages.parse、Pydantic、Zod、enum、スキーマコンパイルキャッシュ、citations 排他、プログラム可能検証、決定性