AI 開発

OpenAI Agents API の JSON データ構造:Agent、Tool Call、Tool Result、Handoff はどうつながるか(2026)

約 16 分

公開ベータ後に濁るのは「ツールを呼べるか」ではない。四つの対象が一本の鎖にどう留まるかだ。公式に handoff という item はない。留めるのは ID:session_id、turn_id、call_id、agent_id。この稿はその JSON 鎖だけを解く。

読む前の一覧

対象 公式の形 留め具
Agent モデル、ツール表、multi_agent session 作成時に書く
Tool Call required_actions 内の function_call turn_id + call_id
Tool Result agent.session.input.tool_result 同じ対を書き戻す
Handoff create / send / wait / interrupt items agent_id / subagent_id

履歴の function_call は、結果待ちを意味しない。待ちは required_actions を見る。

四つの対象は ID でつながる。自然文ではない

Agents API では、Agent は session 作成時に書いた設定。Tool Call は停止時の required_actions にある function_call。Tool Result はイベント流へ返す agent.session.input.tool_result。ここでの Handoff は協調 item の組であり、SDK の handoff オブジェクトではない。

  • 同じ turn_id / call_id の対:呼び出しと結果が揃わねば harness は続かない。
  • 履歴だけでは足りない:items の function_call は「呼んだ」ことだけ。required_actions を読む。
  • Handoff は type ではない:create_subagent_call と subagent_id を見る。handoff という欄を探さない。

ツールの呼び方は OpenAI Agents API 完全解説。長い仕事の続きは 長時間の Agents API。ループを預けるかは Agents API vs Responses API。Agent と Function Calling がまだ一つの語なら AI Agent 完全ガイド。

Agent:設定オブジェクトであり、返答ではない

作成時にモデル、指示、ツール、multi_agent を一度書く。後続 item の主語になる。公式は POST /v1/agents/sessions、ヘッダは OpenAI-Beta: agents=v1:

{
  "agent": {
    "model": "gpt-6-astra",
    "instructions": "Look up orders. Confirm before any refund.",
    "tools": [
      {
        "type": "function",
        "name": "lookup_order",
        "parameters": {
          "type": "object",
          "properties": {
            "order_id": { "type": "string", "pattern": "^[A-Z]-\\d{4}$" }
          },
          "required": ["order_id"],
          "additionalProperties": false
        }
      }
    ],
    "multi_agent": { "enabled": true, "max_concurrent_subagents": 3 }
  },
  "environment": { "type": "openai_hosted" },
  "input": [{ "role": "user", "content": [{ "type": "input_text", "text": "Look up A-1042." }] }]
}

Agent 設定は session に残る。モデルや推論強度の変更はこの session の設定を更新する。保存済みテンプレートは新しい session にだけ効く。環境は別資源:openai_hosted または自前のサンドボックス。session を消しても sandbox は残る。

Tool Call:required_actions だけを信じる

関数結果が必要になると session は agent.session.requires_action を出す。待ちは required_actions にあり、形は turn_id / call_id 付きの function_call:

{
  "type": "function_call",
  "turn_id": "turn_2",
  "call_id": "call_3c91",
  "name": "lookup_order",
  "arguments": { "order_id": "A-1042" }
}

引数は Schema を通す。広い object は門ではない。口径は AI に JSON Schema が必要な理由。履歴にも function_call は出る。公式は、履歴だけでは待ちと判断できないと書く。

Tool Result:同じ対をイベント流へ戻す

関数を実行したら、session の events 端点へ agent.session.input.tool_result を送る。turn_id と call_id は待ち動作から写す。成功は success: true と文字列 output。失敗は success: false と error:

{
  "type": "agent.session.input.tool_result",
  "turn_id": "turn_2",
  "call_id": "call_3c91",
  "success": true,
  "output": "{\"order_id\":\"A-1042\",\"status\":\"paid\"}"
}

オブジェクトは先に文字列化する。切断前に実行済みなら、同じ対で保存結果を再提出する。新しい session で「再試行」しない。harness は必要な結果が揃ってから turn を続ける。

Handoff:協調 item であり、欄名ではない

multi_agent.enabled を付けると、harness が作成、伝言、待機、中断を用意する。これらのツールを宣言しない。items に協調動作が出る:

{
  "data": [
    {
      "type": "create_subagent_call",
      "agent_id": "agent_main",
      "task": "Compare A-1042 packing notes with the invoice."
    },
    {
      "type": "send_subagent_input_call",
      "subagent_id": "sub_7a12",
      "input": "Focus on line items only."
    },
    {
      "type": "agent_message",
      "from": "sub_7a12",
      "text": "Invoice lines match packing notes for A-1042."
    }
  ]
}
  • create_subagent_call:派遣。agent_id は誰が頼んだか。完了は下位作業の終了ではない。
  • send / wait / interrupt:伝言、待機、中断。agent_message は見える対内テキストを持ちうる。流れは全文ではない。
  • SDK の handoff オブジェクト:それはプロセス内の runner。これらの item とは別資源。

次の主語へ渡すものは監査できる JSON であるべきだ。注文番号、意図、根拠。Schema への収め方は JSON Schema と Agent ワークフロー。

留め具が揃って鎖が立つ

四つの対象を、手元で再建できる鎖に折る。架空の注文。実鍵は貼らない:

{
  "session_id": "sess_8f21",
  "links": [
    { "object": "agent", "id": "agent_main" },
    { "object": "turn", "id": "turn_2" },
    { "object": "function_call", "call_id": "call_3c91" },
    { "object": "tool_result", "call_id": "call_3c91" },
    { "object": "subagent", "id": "sub_7a12", "via": "create_subagent_call" }
  ]
}
対象 見える type 何に留めるか よくあるずれ
Agent session.agent session_id 新しい session を再試行にする
Tool Call function_call turn_id + call_id items 履歴だけを見る
Tool Result input.tool_result 同じ対 output がオブジェクトのまま
Handoff create_subagent_call agent_id / subagent_id handoff という欄を探す
Turn turn.completed / failed turn_id;根の subagent_id は空 アイドルを成功と読む

MCP の行は別のツール表。第二の ID 体系は作らない。境界は MCP Tool Schema vs Function Calling。

この鎖を見直すなら、二つの JSON を広げる

揃わない多くは、留め具が漂ったことだ。モデルが愚かになったことではない。

  • required_actions と書き戻しを 整形 し、call_id が一字違わぬか見る。
  • JSONPath 抽出 で turn_id、call_id、subagent_id を抜く。
  • 同じ注文の呼び出しと結果を JSON Diff。漂ったら ID を先に見る。
  • 主 Agent の items とある subagent の items は分けて列挙する。一頁に混ぜると協調が別人に付く。
  • 注文、session、社内 MCP を公開フォーマッタに貼らない。JSONSort はブラウザ内で動く。

二つの軌跡が ID で再建できて初めて、構造を読んでいる。そうでなければ標語を読んでいる。

よくある落とし穴

  • items の function_call を待ちだと見る。待ちは required_actions。
  • 書き戻しで対を取り替える。harness は合わせられず、turn は止まる。
  • output にオブジェクトをそのまま渡す。公式は文字列か対応する content 配列を求める。
  • payload に type: handoff を探す。Agents API は create / send / wait / interrupt。
  • subagent に function を走らせる。下位エージェントは function ツールを持たない。照会は主 Agent に残す。
  • SDK の handoff と session items を同一資源だと思う。一つを消しても他は残る。

FAQ

Tool Call と Tool Result は必ず対か?

待ちの呼び出しは書き戻す。すでに終わった履歴の function_call に再提出は不要。判断は required_actions であり、items の長さではない。

Agents API に handoff という JSON 欄はあるか?

一等の item type としてはない。協調は create_subagent_call、send_subagent_input_call、wait_for_subagents_call、interrupt_subagent_call。SDK の handoff は別物。

call_id と item_id の違いは?

call_id は関数呼び出しとその結果を留める。item_id は保存された item の名。流れは item_id で増分を同じ部分へ付ける。二つの留め具。混ぜない。

turn が完了なのにツールが失敗することがあるか?

公式は、completed は全ツール成功を意味しないと書く。tool_result の success とその turn の items も見る。

アプリ内で独自の handoff JSON を持ってよいか?

よいし、持つべきだ。それは業務オブジェクト:注文番号、意図、根拠。公式 item に金額を覚えさせない。Schema にして session items とは別に置く。

結論

Agent、Tool Call、Tool Result、Handoff は四つの散文ではない。一本の JSON 鎖の上の四つの対象であり、留め具は ID。公式の書き戻しはイベント、公式の受け渡しは協調 item。

call_id だけで呼び出しと結果を合わせられるかを先に書く。できるなら構造はつながっている。モデルは変わる。留め具を先に安定させる。

続きを読む

更新記録: 初回公開