← 技術ブログに戻る

OpenAI GPT 2026:Function Calling、Structured Outputs、JSON Schema の変化

OpenAI Function Calling と Structured Outputs の開発デスク

2026 年、OpenAI Agent を運用しているチームが最初に踏むのは「モデルが話せるか」ではない。古い実装がまだ json_object を構造化出力だと思い込んでいたり、Chat Completions で非 strict の Function Calling を続けていたりする点だ。新規プロジェクトでは公式が gpt-5.6 からの開始を推奨している。Function Calling と Structured Outputs はどちらも制約デコードだが、入口、既定の strict、JSON Schema のサブセットは別物である。

照合日は 2026 年 8 月 18 日。フィールドと挙動は OpenAI Function Calling ガイドStructured Outputs ガイドに従う。遅延・価格・成功率は捏造しない。公開ドキュメントで固定されていない箇所は「現行環境での再生確認が必要」と明示する。

OpenAI 互換バックエンドを別モデルへ切り替えるなら、構造化出力とツールループは単独で検収する。Base URL の差し替えだけでは足りない。サイト内の OpenAI APIからKimi K3への移行検収リスト と突き合わせるとよい。

先に結論:同時に変わった三層

多くのリポジトリはまだ 2024 年の頭の使い方のままだ。プロンプトに「JSON を返せ」と書き、コードフェンスを正規表現で削る。2026 年の本番経路では、Schema 逸脱、欠落フィールド、enum の幻覚 がパーサーをそのまま貫通する。

直すべきなのは三層であり、より大きなモデル名への付け替えではない。

納品契約
利用者や下流サービスへ渡す最終オブジェクト。Structured Outputs を使う(Responses では text.format、Chat Completions では response_format.json_schema)。
実行契約
モデルがツールを呼ぶとき、引数はそのツール自身の JSON Schema に沿う必要がある。これが Function Calling で、下層は Structured Outputs と同じ制約デコードである。
互換契約
旧来の JSON Mode(json_object)は「JSON らしく見えること」だけを保証し、フィールド・型・enum が Schema と一致することは保証しない。公式は Structured Outputs の前身と位置づけており、新規プロジェクトの主経路にしてはいけない。

見落としやすい製品側の変化もある。新規コードは Responses API を通す。Chat Completions は使えるが、strict の既定が違う。Responses は Schema をできるだけ厳密モードへ正規化し、失敗したときだけ緩める。Chat Completions の既定は非厳密のベストエフォートのままである。

モデルと API の主経路:gpt-5.6 + Responses

Structured Outputs は GPT-4o 世代から使える。公式が新規プロジェクトに勧めるのは gpt-5.6 だ。より古い gpt-4-turbo 以前のスナップショットでは、ドキュメントは依然 JSON Mode を指し、完全な json_schema 厳密出力ではない。

選定では入口を先に分ける

欲しい結果 使う入口 2026 年の注意
利用者/下流へ固定オブジェクトを渡す Responses:text.format、または Chat Completions:response_format: json_schema strict: true を付ける。SDK なら Pydantic / Zod + parse()
関数呼び出し、DB 参照、状態変更 tools の function tool 引数 Schema も strict。並列呼び出しと多ツールループは実行器を自前で書く
ツール面が広く、一度にコンテキストへ載せたくない tool_search の遅延ロード gpt-5.4 以降のみ。ツール定義は入力 token に計上される
引数が JSON ではなく自由テキストや特定文法 custom tools + 任意の CFG DSL やクエリ言語向き。function の JSON Schema に無理に載せない

SDK 側で身につけるべき習慣は、漏れやすい additionalProperties を手書きしないことだ。公式 helper で型から生成する。Python は client.responses.parse(..., text_format=YourModel)、JavaScript は zodTextFormat。手書き Schema で strict: true の制約を満たさないと、リクエストそのものが拒否される。「モデルが雑に出してリトライ」にはならない。

Gemini 路線と比べるとき、「OpenAI SDK 互換」を Schema 挙動まで同じだと読まないこと。Google 側の能力の伸び方は Gemini 3.5 Pro の新機能:知っておくべき AI 能力アップグレード 10 選 を参照する。同じ JSON Schema をベンダー横断でコピーすると、入れ子オブジェクトの additionalProperties が最初に壊れやすい。

JSON Mode、Structured Outputs、Function Calling

本番障害でいちばん多い混同は、ログが JSON だから Structured Outputs が効いていると思い込むことだ。公式の意味で分けると次のとおり。

能力 合法 JSON を保証 Schema 準拠を保証 典型的な有効化 対象モデル
JSON Mode はい いいえ text.format.type = json_object 一部の GPT-5 互換枠を含む。古いスナップショットでよく使う
Structured Outputs はい はい(サポートされた Schema サブセット) json_schema + strict: true gpt-4o-2024-08-06 / gpt-4o-mini 以降。新規は gpt-5.6
Function Calling + strict ツール引数は合法 JSON 引数が parameters Schema に沿う tools 内の strict: true tools 対応モデル。常時 strict を推奨

Function Calling を使わないとき

モデルがシステムに触れなくてよい場合——在庫照会も、チケット更新も、スクリプト実行も不要で、回答をカード・手順・スコアに分解するだけなら Structured Outputs でよい。逆に、出力が「この副作用を実行してほしい」なら tools 必須である。関数引数を最終回答 Schema に偽装してはいけない。

拒否は「壊れた JSON」ではない

安全上の拒否では、モデルは Schema へ無理に押し込まない。Responses / Chat Completions は独立した refusal フィールドを返す。パース層では拒否を第一級として扱う。先に refusal、そのあと output_parsed。空オブジェクトを成功とみなさない。

Strict JSON Schema の必須ルール

strict を付けると、OpenAI が受け付けるのは JSON Schema のサブセットであり、任意の Draft 2020-12 文書ではない。リクエスト単位でいちばんよくぶつかる三点は次のとおり。

  1. properties に出したフィールドは、すべて required 配列に入れる。
  2. 入れ子を含むすべての objectadditionalProperties: false を付ける。
  3. ルートオブジェクトを anyOf にしない。任意は「必須かつ null 可」で表す。例:["string", "null"]

つまり required から外して任意のふりをする という古い技は、strict では即 400 になる。正しい書き方はフィールドを required のままにし、型を null 許容のユニオンにする。アプリ層で null を「未指定」と解釈する。

次は本番でよくある「チケット抽出」オブジェクト。入れ子 object にも additionalProperties を書いている点に注意する。

from openai import OpenAI
from pydantic import BaseModel

client = OpenAI()

class Ticket(BaseModel):
    title: str
    priority: str
    assignee: str | None
    tags: list[str]

response = client.responses.parse(
    model="gpt-5.6",
    input=[
        {"role": "system", "content": "ユーザーの説明からチケット項目を抽出する。"},
        {"role": "user", "content": "ログイン画面が 500。Noah に割り当て、優先度は高、タグは auth と api。"},
    ],
    text_format=Ticket,
)
ticket = response.output_parsed
print(ticket.title, ticket.priority, ticket.assignee)
Schema 準拠は業務正しさではない
制約デコードが保証するのは型、必須キー、enum の値集合である。優先度が本当に high であるべきことや、社員番号の存在は保証しない。下流では権限、存在確認、冪等性の検証が残る。

デバッグでリクエストが拒否されたら、まずエラーメッセージの欠けた制約を見る。モデルを落とすのはその後だ。Playground が出す Schema は既定で strict 済みなので、リポジトリへそのままコピーした方が「古い json_object プロンプトの改造」より速いことが多い。

ベンダーをまたぐときはもう一度確認する。「すべての object で false」という同一 Schema が、一部の互換ゲートウェイや別モデルでは HTTP 400 になることがある。そのときはプロバイダ別の変換を置き、業務 Schema を三部持たない。

Function Calling 2026:strict、tool_search、custom tools

公式はいま Function Calling と tool calling を同一視している。JSON Schema で呼び出し可能な関数を記述し、アプリ側の実行器で副作用を走らせる。2026 年のドキュメントで追加・強調された項目は、Agent ループそのものを変える。

strict の既定は推測しない

  • 常に明示的に strict: true を付ける。
  • Responses:strict を省略すると、サーバが Schema の正規化を試みる。失敗すると非厳密へ戻り、応答の tool は strict: false になる。
  • Chat Completions:省略時の既定は非厳密。
  • ファインチューンモデルが同一ターンで複数関数を呼ぶ場合、ドキュメントはそのターンで strict が切れる可能性を明記している。

ツール定義はコンテキストに入り、入力 token として課金される。説明が長すぎる、一度に 40 個載せる、は請求とツール選択精度の両方を悪化させる。ツールが多いときは tool_search で低頻度ツールを遅延ロードする。gpt-5.4 以降のみ。ループでは先に tool_search_call / tool_search_output が出てから、本物の function_call に入ることがある。

custom tools:DSL を JSON オブジェクトに押し込まない

function tools は構造化引数向き。custom tools は自由テキストの入出力向きで、文脈自由文法(CFG)を付けられる。SQL 断片、社内クエリ言語、終端記号の排他が必要な書式は、「string フィールドにプロンプトを積み上げる」より CFG の方が安定する。CFG が unexpected tokens を出したら、まず終端の重複を疑い、モデルを責めない。

tools = [{
    "type": "function",
    "name": "get_order",
    "description": "注文番号でステータスを照会する。ユーザーが明確な注文番号を出したときだけ呼ぶ。",
    "strict": True,
    "parameters": {
        "type": "object",
        "properties": {
            "order_id": {"type": "string"},
            "locale": {"type": ["string", "null"]},
        },
        "required": ["order_id", "locale"],
        "additionalProperties": False,
    },
}]

実行ループ自体は変わらない。finish_reason / item type がツール呼び出しならローカル関数を走らせ、結果を tool ロールで返し、再リクエストする。変わったのは、引数を json.loads で運試ししなくてよくなった点だ。assistant メッセージ全体(tool_calls を含む)は保存必須。落とすと次ターンで呼び出し ID が失われる。

並列ツール呼び出しでは順序ではなく呼び出し ID で揃える

1 応答に複数の tool call が付くことがある。返却は call_id で対応づけ、配列添字の順を仮定しない。カナリーログには少なくともツール名、引数ハッシュ、所要時間、strict の有無、schema フォールバックの有無を残す。

既存プロジェクトの移行チェックリスト

「動く」と「納品できる」を分けて検収する。旧バックエンドのスイッチは残し、独立環境で実トラフィックを再生する。

  1. モデル:新経路は gpt-5.6(またはアカウントで開通済みの同等枠)を明示する。ゲートウェイの静かな旧スナップショットへのマップを許さない。
  2. 出力:json_objectjson_schema + strict: true、または Responses の text.format に替える。
  3. ツール:各 function に required と入れ子の additionalProperties: false を足す。任意フィールドは null 許容ユニオンにする。
  4. パース:parse()refusal 分岐を入れる。ストリーミングでは増分 JSON と最終 parsed オブジェクトの一致を確認する。
  5. ツール面:十数個を超えたら tool_search を検討する。先に description を短くし、そのあと遅延ロードを考える。
  6. 対照:同じ固定タスクで旧 JSON Mode と新 Schema 経路の再試行率、欠落フィールド率、人手やり直しを比べる。

合格は「200 が返る」ではない。パーサーに正規表現の逃げ道がないこと、ツール引数の型が安定していること、拒否が観測できること、切り戻しスイッチを演習済みであること。SDK、再生スクリプト、ブラウザセッションを長時間載せたままにするなら、ノート PC のスリープが対照実験を切る——そこが後述のクラウド Mac mini の出番である。


FAQ

JSON Mode と Structured Outputs は混在できるか

同一経路では混ぜない。JSON Mode は合法 JSON だけ、Structured Outputs が Schema を保証する。混ぜると監視が「パース失敗」をモデル問題か契約問題か切り分けられない。新規コードは json_schema / text.format だけにする。

新規プロジェクトでも Chat Completions を書くべきか

Responses が使えるなら Responses。公式サンプル、parse helper、strict 正規化はこちらが優先。既存の Chat Completions は継続できるが、strict を明示し、既定が非厳密である差を受け入れる。

strict を付けた瞬間に Schema が 400 になる理由

よくあるのは required 漏れ、入れ子 object に additionalProperties:false がない、ルートを anyOf にした、任意を「required に出さない」で表した、のいずれか。エラーメッセージの制約を埋めてから再送する。Schema 誤りを strict オフで隠さない。非厳密フォールバックを意図した場合だけ例外とする。

Function Calling は必ず strict か

公式は常時オンを勧める。オフだと引数はベストエフォートになり、実行器が欠落と型ドリフトを防がねばならない。Responses で省略するとサーバ側で書き換えられることもある。ログには最終の strict 値を残す。

tool_search を入れる時機

ツール定義がコンテキストを明らかに圧迫している、または大半のツールが単一タスクで使われないとき。gpt-5.4 以上が必要。本番前に「先にツール検索、そのあと呼び出し」の二段軌跡を再生する。旧実行器が function_call しか見ていないとそこで止まる。

Schema 保証のあと、業務値の検証はまだ必要か

必要。制約デコードは外部キー、権限、冪等を見ない。enum として合法でも、在庫にとって意味があるとは限らない。Schema 検証と業務検証はログを二層に分け、障害時に切り分けられるようにする。

gpt-5.6 とそれ以前の GPT-5.x の構造化出力の差

ドキュメントは gpt-5.6 を新規プロジェクトの既定としている。アカウント、リージョン、バッチ、ファインチューン経路で能力が揃うかは、現行のモデル一覧と最小の parse リクエストで確認する。ブログの別名でゲートウェイのマップを推測しない。

Claude / Grok と JSON Schema を一枚で共有できるか

契約の方言は Draft 2020-12 に近いが、サブセットは違う。OpenAI の strict はすべての object に additionalProperties:false を求める。入れ子層のそのフィールドを拒否するプロバイダもある。業務 Schema は一枚、プロバイダ変換層を別に置く。

関連記事

クラウド Mac mini なら、Schema 検収を 24/7 載せたままにできる

Function Calling と Structured Outputs の回帰は、長時間オンラインの対照実験である。二つの SDK、固定の再生セット、ツールサンドボックス、ストリーミングフロントエンド。ノート PC のフタを閉じたスリープを避けたい。Apple Silicon のユニファイドメモリはローカルプロキシとブラウザデバッグの同時実行向き。macOS では Homebrew、Docker、SSH がすぐ使える。M4 Mac mini の待機消費はおよそ 4W で、検収環境を一晩載せたままにしやすい。

家庭回線を奪わず SSH 常駐できる Mac で Agent 再生を回したいなら、Nuvcloud クラウド Mac mini M4 は「開発機」と「対照実験機」を分ける摩擦の少ない選択肢だ。プランを確認する。strict Schema のカナリーを自分のノート PC に縛らなくてよい。

期間限定 →