結論から:Agents API はループをホストする。契約はホストしない。2026 年 9 月 10 日、OpenAI は Codex を駆動する Agent Harness を public beta として開発者に渡した。モデルのスケジューリング、コンテキスト圧縮、サブ Agent、サンドボックス寿命は、あなたのプロセスから beta.agents.sessions へ移った。手元に残るのはほぼすべて JSON:function ツールの JSON Schema、arguments、tool_result の文字列、MCP の inputSchema、session イベントストリーム。Harness が loop を回すことと、フィールドを検証してくれることとは別である。契約が緩ければ、ホストされたループは悪いパラメータをより頻繁に走らせるだけだ。
本稿は 2026 年 9 月 18 日時点。本サイトにはすでに Agent が JSON なしでは動かない理由、Tool Calling が JSON Schema に依存する理由、JSON Schema は標準 Contract になるか、MCP / Skills / Tools / Subagents、MCP とは何か がある。本稿が答えるのは次だけ:Agents API のあと、JSON がなぜより重要になるか——より不要になるかではない。
9 月 10 日に実際に出たもの
OpenAI の言い方はこうだ:Codex を駆動する同一の harness とインフラを、開発者向けのホストされたクラウド Agent として渡す。公開ドキュメントは beta.agents 名前空間に置き、リクエストには OpenAI-Beta: agents=v1 を付ける。Harness 自体に別料金はない。払うのはモデル token、ツール、サンドボックス時間だ。
session 作成で出すのは一つの JSON:モデル、指示、ツール一覧、環境、入力。公式サンプルは gpt-6-astra。ツールは MCP、カスタム function、組み込み検索でよい。環境は none、openai_hosted、あるいは Blaxel、Cloudflare、Daytona、E2B、Modal、Vercel といった持ち込み / 提携サンドボックス。マルチ Agent は multi_agent.enabled と max_concurrent_subagents で開く。
これはもう一つの「JSON を出力せよ」チャット口ではない。Responses API は残る。Agents SDK も残る。Agents API が取るのはループそのもの:次のホップを誰が決めるか、いつコンテキストを圧縮するか、いつサブ Agent を出すか。ベータ中はフィールド名が動き得る。層分けはすでに明確だ:OpenAI が harness を回し、あなたがツール契約と業務結果を出す。
三つの入口:Responses、Agents SDK、Agents API
2026 年 9 月、OpenAI は Agent を作る道を三つ並べている。混ぜる前に「ループはどこで回るか」を分けよ:
| 入口 | ループはどこで回るか | 状態はどこにあるか | あなたがまだ書くもの |
|---|---|---|---|
| Responses API | あなたのアプリ | 自分で組む history / Conversations | モデル呼び出し、ツール戻し、loop 全体 |
| Agents SDK | あなたのプロセス | SDK session + あなたの保存 | 承認、デプロイ、loop はまだ変えられる |
| Agents API | OpenAI ホストの Codex harness | サーバ側 session / turn / item | ツール定義、function 結果、環境選択;loop は変えられない |
単発の補完は Responses。承認と永続化を自分で握るなら SDK。「数日走る仕事、圧縮、サブ Agent、サンドボックス」を相手に渡すなら Agents API。三路ともツール引数は JSON Schema。違いは:前の二路は loop にパッチを当てられる;第三路のパッチは契約と戻しにしか置けない。
Agent Harness とは何か、何を署名しないか
Harness はモデルと副作用のあいだのランタイムである:イベントを読み、ツールを選び、結果を渡し、コンテキストを圧縮し、長い仕事で進捗を保つ。Codex 側はいまオープンソースで見える。Agents API は OpenAI が同じ論理を運用し、モデル版とともに上げる。発表で名指しされた能力は自動 compaction、Tool search、Programmatic Tool Calling、並列 subagents。
署名しないものはこれだ:
- ある
customer_idが存在するべきか、UUID であるべきか; - 関数が余分なキーを受けてよいか;
- MCP Server の
inputSchemaが緩いか硬いか; - モデルへ戻す
outputがオブジェクトか、文字列か、チャットの一段落か。
これらはなお JSON Schema と、あなた自身の二次検証である。ホストされた harness が上げるのは「ループがどれだけ長く、どれだけ並列に走れるか」であり、「このホップのパラメータが合法か」ではない。両者を同一視するのが、本稿がまず割る誤解である。
ホストしたあと JSON ホップが増える理由
自分で loop を書くとき、悪い JSON はたいていこちら側で死ぬ:parse が失敗し、フィールドが合わず、止まる。ループがホストされると、失敗は先送りされ、複製され、より多くのチャネルへ送られる:
| ホップ | ペイロード | 誰が生成するか | 誰が検証するか |
|---|---|---|---|
| session 作成 | agent / tools / environment JSON | あなたのアプリ | あなた:提出前 |
| function 定義 | JSON Schema(parameters) | あなたのアプリ | あなた:required / additionalProperties を締める |
| モデルが呼び出しを出す | arguments オブジェクト | ホストされた harness + モデル | あなた:実行前にもう一度検証 |
| 結果の戻し | tool_result.output 文字列 | あなたのアプリ | あなた:先に合法値を stringify |
| MCP | JSON-RPC + inputSchema | Server / harness | Server とあなたの許可リスト |
| イベントストリーム | agent.session.* JSON イベント | ホストされたサービス | あなた:type で分岐し、チャット本文として parse するな |
加えて Tool search が定義を必要時に載せ、Programmatic Tool Calling がコード内で直列・並列呼び出しをし、subagent がそれぞれコンテキストを持つ——一つのユーザタスクの JSON 往復は、「単発 Function Calling」より一段多い。ホストするとこれらのホップは見えなくなる。見えないことは、検証しなくてよいことではない。ホップごとのデータフローは Tool Calling から MCP へ を見よ。
Tool Calling:function ツールはなお JSON Schema
Agents API の function ツールは Responses API と同じ定義を使う。agent.tools に渡すのは自然言語ではない。名前、説明、JSON Schema 一通だ:
{
"type": "function",
"name": "get_customer",
"description": "Look up a customer by ID.",
"parameters": {
"type": "object",
"properties": { "customer_id": { "type": "string" } },
"required": ["customer_id"],
"additionalProperties": false
}
}
公式サンプルは required を埋め、additionalProperties を false にする。組版の癖ではない。Agent がキーを一つ余分に書いてよければ、そのキーはパス、SQL 断片、「ついでに削除」になり得る。Schema はモデルがデコード時に見る契約であり、実行前にあなたがもう一度走らせる契約でもある。厳格モード、ajv、二次検証のパイプラインは Tool Calling が JSON Schema に依存する理由 を見よ。
説明フィールドはなお役に立つ。モデルのツール選択を助ける。型、列挙、必須の代わりにはならない。Harness が賢いほど、山のツールから「だいたい近い」一つを選ぶ——だいたい近い呼び出しを止めるのは Schema だけだ。
requires_action と tool_result:戻しも JSON
モデルがあなたの関数を走らせるとき、session は agent.session.requires_action で止まる。待ちは required_actions にある。「履歴に function_call が一つある」では足りない。典型的な pending 呼び出しはこうだ:
{
"type": "function_call",
"turn_id": "turn_123",
"call_id": "call_123",
"name": "get_customer",
"arguments": { "customer_id": "123" }
}
ドキュメントは arguments をオブジェクトとして書く。チャット返信に包んで JSON.parse で掻き出すな——それは前稿 JSON.parse が失敗する理由 のチャネル誤りである。やることは:同じ Schema でこのオブジェクトを検証し、関数を実行し、session イベント口へ agent.session.input.tool_result を戻す。元の turn_id / call_id を付ける。
成功時は success: true、output は文字列または対応するコンテンツ配列。オブジェクトは先に JSON.stringify。失敗時は success: false、モデルが読める error を渡す。スタック、秘密、データベース行ごと戻すな。プロセスが実行後・戻し前に落ちたら、session / turn / call で冪等にせよ:再起動後は先に pending を読み、再実行するかを決める。
Function は常にあなたのアプリで走る。session にサンドボックスがあってもだ。Harness は get_customer を代わりに実行しない。あなたがオフラインなら、このホップは止まる。ホストされたループで、なお完全にあなたの同期点である数少ない箇所だ——JSON を正しくしなければならないホップでもある。
Tool search と Programmatic Tool Calling
ツールが増えると、全 Schema をコンテキストに詰めれば token を焼き、キャッシュを壊す。Agents API は既定で function を即時ロードする。使わないものは defer_loading: true にし、agent.tools に {"type": "tool_search"} を置く。モデルは先に関連定義を探し、それから呼ぶ。ここに「定義そのものも JSON」というホップが増える:検索で得た Schema は、実際に実装した関数と一致しなければならない。広い契約を広告し、狭い実装を走らせるな。
Programmatic Tool Calling は対応モデルに短いコードを書かせ、適格ツールを並列または直列で走らせ、フィルタ後の結果だけをコンテキストへ戻す。「毎ホップで窓を埋める」コストは下がる。「中間 JSON が合法でなければならない」要求は上がる。中間結果の型がずれると、後段のフィルタとマージは、見えない harness の中で黙って誤り続ける。SDK 側にはすでに「構造化エラーを JSON に符号化」する修正がある。この経路が食べるのは Schema であり、散文ではない。
MCP と Subagents:より多くの Schema、より多くの JSON
MCP Server を agent.tools に書けば、harness がツールを発見し、呼び出し、結果をモデルへ戻す。function と違う:これらの呼び出しはあなたのアプリを通らない。HTTP は既定で OpenAI から接続する。環境から繋ぐ指定も、サンドボックス内で stdio でプロセスを起こすこともできる。この層で握れるのは allowed_tools、初期化失敗で turn を落とすか(required: true)、Server 自身の inputSchema の締まり具合だ。
MCP の電文はなお JSON-RPC。Schema が緩ければ、ホストされた harness はモデルの代わりに、見えないリクエストをより多く打つ。「プロトコルが安全にしてくれた」ではない。「ループがより遠くへ行った」である。プロトコル層は MCP とは何か;Skills、Subagents との境界は 2026 の Agent スタック。
Subagents はそれぞれコンテキストを持ち、親 Agent がまとめる。並列は遅延を下げるが、arguments も並列に多く打つ。親が受け取るまとめがなお Schema なしの長文なら、「チャットをパースする」を最後のホップへ先送りしただけだ。プログラムへ入れる結論は、最終返答も Structured Output か、あなたが定義した結果 Schema にせよ。散文から掻き出すな。Structured Output とは何か を見よ。
いまもローカルで検証する四つのこと
Harness がホストされたあと、リストは短くならない。狭くなる:
- ツール Schema。
requiredを埋め、additionalProperties: false、列挙を締める。説明文で副作用を止めるな。 - 実行前の arguments。ベンダーが Schema を通しても、同じ文書をプロセス内でもう一度検証せよ。型違い、欠けたフィールド、余分なキーはここで止める。
- 戻す output。先に合法 JSON にしてから
stringify。エラーはsuccess: false。内部例外の原文をモデルへ渡すな。 - イベントとチャット本文を別チャネルに。
event.typeで分岐せよ。SSE 全体を一つの JSON 値にするな。ユーザへの構造化返答は Structured Output。assistant 文をJSON.parseするな。
セキュリティ側も忘れるな:arguments 内の文字列は注入であり得る。「型が合ったから実行」ではない。悪意ある JSON と Prompt Injection を見よ。JSON Schema がベンダー横断の契約になるかは 標準 Contract ——Agents API はこの判断を弱めていない。変えられる唯一の層へ押し出しただけだ。
ローカル JSON ツールで契約を見る
ホストされた session に渡す前に、ブラウザで三つのテキストを見よ:ツール Schema、サンプル arguments、戻す予定の output。
- JSONバリデーター — 文法が合法か;Schema があればフィールド、必須、余分なキーを合わせて見る。
- JSONフォーマッター — 一行に潰した
tool_resultを展開し、データベース行ごと直列化したかを見る。 - JSON Diff — 「モデルが送った arguments」と「Schema が許す最小オブジェクト」を比べる。
データはブラウザを出ない。失敗した required_actions、一つの parameters、stringify 後の結果を並べて見るのに向く。契約が安定してから、hosted harness に数日走らせよ。
FAQ
Agents API で JSON Schema を書かなくてよくなるのか?
逆である。ループがホストされたあと、Schema は手元に残る主契約だ。function の parameters、MCP の inputSchema、戻す output は、いずれも JSON のまま。
Agents API、Agents SDK、Responses API はどう選ぶか?
単発呼び出しは Responses。loop、承認、保存を自分で握るなら SDK。長い仕事、圧縮、サブ Agent、サンドボックスを OpenAI に渡すなら Agents API。三路ともツール引数は JSON Schema。
arguments はすでにオブジェクトだ。まだ JSON.parse するか?
周囲のチャットを再度 parse するな。ドキュメントどおりオブジェクトとして扱い、同じ JSON Schema で検証せよ。散文から arguments を掻き出すのは、チャネルを間違えている。
tool_result はなぜ stringify しなければならないのか?
ドキュメントは output を文字列または対応するコンテンツ配列とする。先に合法 JSON にしてから stringify せよ。「オブジェクトに見えるが実は文字列」との混用と、二重エンコードを避けるためだ。
MCP ツールは私のアプリを通るか?
既定では通らない。harness が Server に直結する。締めるのは Server 自身の inputSchema、allowed_tools、および Server 内の不可逆操作の承認だ。
ベータ中にフィールドは変わるか?
変わり得る。本稿は 2026 年 9 月 18 日の公開ドキュメントに従う。層分けは変わらない:harness がループを回し、あなたが JSON 契約を出す。フィールド名が変わっても、検証の責任はこちら側だ。
まとめ
Agents API が下げるのは「Agent を最後まで走らせる」工数であり、上げるのは「毎ホップの JSON が正しくなければならない」重みである。9 月 10 日に渡されたのは Codex harness:session、圧縮、ツール検索、プログラム的呼び出し、サブ Agent、サンドボックス。それは customer_id の形を見ず、tool_result を合法文字列にもしてくれない。
2026 年、Agent をプログラムへ繋ぐ順は変わっていない:ツールは JSON Schema、結果は Structured Output、チャット本文は API ではない。変わったのは、loop がホストされたあと、パッチを当てられる場所が契約だけになったことだ。先にローカル検証で Schema、arguments、戻し結果を見よ。それから hosted session に走らせよ。モデルは変わる。harness は版を上げる。フィールド契約は、それらと一緒に緩めてはならない。