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 文書ではない。リクエスト単位でいちばんよくぶつかる三点は次のとおり。
propertiesに出したフィールドは、すべてrequired配列に入れる。- 入れ子を含むすべての
objectにadditionalProperties: falseを付ける。 - ルートオブジェクトを
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)
デバッグでリクエストが拒否されたら、まずエラーメッセージの欠けた制約を見る。モデルを落とすのはその後だ。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 フォールバックの有無を残す。
既存プロジェクトの移行チェックリスト
「動く」と「納品できる」を分けて検収する。旧バックエンドのスイッチは残し、独立環境で実トラフィックを再生する。
- モデル:新経路は
gpt-5.6(またはアカウントで開通済みの同等枠)を明示する。ゲートウェイの静かな旧スナップショットへのマップを許さない。 - 出力:
json_objectをjson_schema+strict: true、または Responses のtext.formatに替える。 - ツール:各 function に
requiredと入れ子のadditionalProperties: falseを足す。任意フィールドは null 許容ユニオンにする。 - パース:
parse()とrefusal分岐を入れる。ストリーミングでは増分 JSON と最終 parsed オブジェクトの一致を確認する。 - ツール面:十数個を超えたら
tool_searchを検討する。先に description を短くし、そのあと遅延ロードを考える。 - 対照:同じ固定タスクで旧 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 に縛らなくてよい。