AI活用

Programmatic Tool Callingの使い方|GPT-5.6にJavaScriptで複数ツールを実行させる方法

Programmatic Tool CallingでGPT-5.6にJavaScriptを書かせ、複数ツールを並列実行・集計する方法を解説。Node.jsの実装例と安全設計も紹介します。

この記事の目次
  1. 結論:予測できる複数ツール処理をJavaScriptへまとめる機能
  2. Programmatic Tool Callingとは?
  3. 通常のTool Calling・Function Callingとの違い
  4. Programmatic Tool Callingが向いている処理
  5. 直接のTool Callingを使うほうがよい処理
  6. JavaScriptが実行される環境の制約
  7. Programmatic Tool Callingを有効にする設定
  8. Programmatic Tool CallingのJavaScript実装例
  9. レスポンスに追加される主な項目
  10. 安全に実装するためのポイント
  11. Programmatic Tool Callingの効果を確認する方法
  12. よくある質問
  13. まとめ
  14. 参考リンク

Programmatic Tool Callingは、GPT-5.6がResponses API内でJavaScriptを書き、複数のツール呼び出しを並列実行したり、ループや条件分岐で処理したりできる仕組みです。

通常のTool Callingでは、モデルがツールを1つずつ選び、結果を読んで次の判断をします。Programmatic Tool Callingでは、処理手順が明確な部分をコードへまとめ、中間結果を絞り込んでからモデルへ返せます。

この記事では、通常のTool Callingとの違い、向いている処理、V8実行環境の制約、JavaScriptでの実装例、安全に使うための設計を解説します。

情報確認日:2026年7月11日(日本時間)

結論:予測できる複数ツール処理をJavaScriptへまとめる機能

この記事の結論

  • モデルが生成したJavaScriptをOpenAIの分離されたV8環境で実行する
  • 独立したツール呼び出しの並列化、ループ、条件分岐、集計に向いている
  • モデルに毎回意味判断をさせたい処理や、承認が必要な書き込みは直接呼び出しが向いている
  • programmatic_tool_callingと、各ツールのallowed_callersを設定する
  • ツールの戻り値はoutput_schemaで構造化し、引数と権限をアプリ側でも検証する

Programmatic Tool Callingとは?

Programmatic Tool Callingは、モデルがツールを呼び出すためのJavaScriptプログラムを生成し、そのプログラムをResponses API内のホスト環境で実行する機能です。

たとえば在庫と注文数を別々のツールから取得する場合、通常はモデルが在庫を取得し、結果を読み、次に注文数を取得して計算します。Programmatic Tool Callingでは、2つの取得をPromise.all()で並列に行い、差分だけを最終結果として返せます。

これにより、モデルのコンテキストへ大量の中間データをそのまま追加せず、コードでフィルター、結合、重複削除、集計、検証を行える場合があります。

通常のTool Calling・Function Callingとの違い

方式 処理の進め方 向いている場面
Function Calling モデルがアプリ側の関数を選び、引数を生成する 1つの関数実行や、小さなAPI連携
直接のTool Calling ツール結果をモデルが読み、次のツールや回答を判断する 結果ごとに意味判断が必要な検索や承認操作
Programmatic Tool Calling モデルがJavaScriptを生成し、複数ツールをコードで制御する 並列取得、集計、変換、検証、予測可能な依存処理

Tool Callingの基本を確認したい場合は、Tool Callingとは?AIに外部ツールを使わせる仕組みと、Function Callingの使い方から読むと整理しやすくなります。

Programmatic Tool Callingが向いている処理

  • 複数の独立したデータ取得を並列実行する
  • 大量の結果を条件で絞り込む
  • 複数の結果を結合し、重複を削除する
  • 数値を集計し、小さなJSONへまとめる
  • 後続ツールの引数を前の結果から機械的に作る
  • 明確な終了条件と再試行回数がある処理

直接のTool Callingを使うほうがよい処理

  • 1回の検索や1つの操作で終わる
  • 各結果を読んで、次の検索方針を意味的に変える
  • 送信、削除、購入、更新など、承認が必要な操作を行う
  • 引用やネイティブな成果物をそのまま維持する必要がある
  • ツールの戻り値の構造が事前に決められない

基本方針:1回の呼び出しなら直接、予測できる複数処理ならProgrammatic、結果ごとにモデルの判断が必要なら再び直接呼び出しを使います。

JavaScriptが実行される環境の制約

生成されたプログラムは、OpenAIが用意する新しい分離済みV8環境で実行されます。一般的なNode.jsサーバーではありません。

利用できるもの 利用できないもの
JavaScript、トップレベルのawait、許可されたツール、text()image()による出力 Node.js、npmパッケージ、直接のネットワーク通信、一般的なファイルシステム、サブプロセス、console、実行間で残る状態

外部システムへアクセスする場合は、プログラムが直接HTTP通信を行うのではなく、リクエストで許可されたFunction、MCP、Shellなどのツールを通します。

Programmatic Tool Callingを有効にする設定

基本設定は2つです。

  1. tools配列へ{ type: "programmatic_tool_calling" }を追加する
  2. プログラムから使わせるツールへallowed_callers: ["programmatic"]を設定する
allowed_callers 意味
省略または["direct"] モデルがツールを直接呼び出す
["programmatic"] 生成されたprogram内からだけ呼び出す
["direct", "programmatic"] 直接とprogram内の両方から呼び出せる

ツールの戻り値が決まっている場合は、output_schemaも定義します。生成されたJavaScriptが、説明文を解析せずにフィールドを利用できるためです。

Programmatic Tool CallingのJavaScript実装例

次の例では、在庫数と注文数を別のFunctionから取得し、不足数を計算します。モデルは2つのFunctionをprogram内で並列に呼び出せます。

import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});

const implementations = {
  get_stock: async ({ sku }) => ({ sku, available: 42 }),
  get_orders: async ({ sku }) => ({ sku, requested: 58 }),
};

const tools = [
  {
    type: "function",
    name: "get_stock",
    description: "Return the available stock for one SKU.",
    parameters: {
      type: "object",
      properties: { sku: { type: "string" } },
      required: ["sku"],
      additionalProperties: false,
    },
    output_schema: {
      type: "object",
      properties: {
        sku: { type: "string" },
        available: { type: "number" },
      },
      required: ["sku", "available"],
      additionalProperties: false,
    },
    allowed_callers: ["programmatic"],
  },
  {
    type: "function",
    name: "get_orders",
    description: "Return requested order units for one SKU.",
    parameters: {
      type: "object",
      properties: { sku: { type: "string" } },
      required: ["sku"],
      additionalProperties: false,
    },
    output_schema: {
      type: "object",
      properties: {
        sku: { type: "string" },
        requested: { type: "number" },
      },
      required: ["sku", "requested"],
      additionalProperties: false,
    },
    allowed_callers: ["programmatic"],
  },
  { type: "programmatic_tool_calling" },
];

const input = [
  {
    role: "developer",
    content:
      "Use Programmatic Tool Calling for the stock comparison. " +
      "Call independent tools in parallel, then return one JSON object " +
      "with sku, available, requested, and shortage. Do not change data.",
  },
  {
    role: "user",
    content: "Check whether sku_123 has enough stock.",
  },
];

while (true) {
  const response = await client.responses.create({
    model: "gpt-5.6-sol",
    store: false,
    input,
    tools,
    include: ["reasoning.encrypted_content"],
  });

  if (response.status !== "completed") {
    throw new Error(`Response ended with: ${response.status}`);
  }

  // program・reasoning・messageを含め、出力を順番どおり保持する
  input.push(...response.output);

  const calls = response.output.filter(
    (item) => item.type === "function_call",
  );

  if (calls.length === 0) {
    const message = response.output.find(
      (item) => item.type === "message",
    );

    if (message) {
      console.log(response.output_text);
      break;
    }

    continue;
  }

  const outputs = await Promise.all(
    calls.map(async (call) => {
      const run = implementations[call.name];
      if (!run) throw new Error(`Unknown tool: ${call.name}`);

      const result = await run(JSON.parse(call.arguments));

      return {
        type: "function_call_output",
        call_id: call.call_id,
        output: JSON.stringify(result),
        // どのprogramを再開するか判断するため、callerを維持する
        caller: call.caller,
      };
    }),
  );

  input.push(...outputs);
}

このコードでは、OpenAI側が生成したJavaScriptをアプリが直接実行するわけではありません。OpenAIの実行環境から返されたfunction_callだけをアプリが処理し、結果をfunction_call_outputとして戻します。

レスポンスに追加される主な項目

項目 内容
program モデルが生成したJavaScript、call_id、再開に使うfingerprint
function_call programから呼ばれたアプリ側のFunction。callerで親programを識別する
program_output programの最終結果とcompleted/incompleteの状態
message 利用者へ返す最終回答

programは複数回停止し、Functionの結果を待つ場合があります。最終的なmessageが返るまで、出力項目を順番どおり保持して処理を継続します。store: falseでは、program、reasoning、Function呼び出し、Function結果を含む履歴を再送します。

安全に実装するためのポイント

  • ツール名、引数、戻り値を具体的に定義する
  • 戻り値が決まっているツールにはoutput_schemaを付ける
  • アプリ側でも引数、権限、対象データを検証する
  • 再試行されても問題が起きにくい処理にする
  • 書き込みや高影響操作には、アプリ側の承認を必須にする
  • 終了条件、最大件数、再試行回数を指示する
  • 許可するツールを必要最小限にする

「効率よく使って」のような曖昧な指示だけでは、直接呼び出しとProgrammaticの境界が不明確になります。「この集計部分だけprogramで実行し、公開や更新は直接呼び出しで承認を取る」のように役割を分けます。

Programmatic Tool Callingの効果を確認する方法

すべての処理でProgrammatic Tool Callingが速く安くなるとは限りません。まず直接のTool Callingを基準にし、同じ入力データで比較します。

  • 最終結果の正確さ
  • 中間データを含む入力トークン量
  • 処理時間
  • ツール呼び出し回数と重複
  • 失敗時の再試行と復旧のしやすさ
  • 承認やログを追跡しやすいか

よくある質問

生成されたJavaScriptを自分のサーバーで実行しますか?

実行しません。JavaScriptはOpenAIの分離されたV8環境で動き、アプリは返されたクライアント所有Functionだけを実行します。

Node.jsのライブラリを使えますか?

Programmatic Tool Callingの実行環境ではNode.jsやnpmパッケージを利用できません。必要な外部処理は、許可したツールとして提供します。

すべてのツールをprogramから呼べますか?

対応するツールへallowed_callersを設定する必要があります。Function、Custom、MCP、Apply Patch、Shell、Code Interpreterなど、programからの呼び出しに対応したツールが対象です。

データ更新にも使えますか?

技術的に呼び出せる場合でも、書き込みや承認が必要な操作は直接のTool Callingを基本にし、アプリ側で明確な承認境界を設けるのが安全です。

まとめ

Programmatic Tool Callingは、GPT-5.6に複数ツールの制御用JavaScriptを生成させ、並列取得、条件分岐、ループ、集計などをResponses API内で実行する機能です。

  • 予測可能な複数処理をコードへまとめる
  • 意味判断や承認が必要な処理は直接呼び出しを使う
  • allowed_callersoutput_schemaを明確にする
  • アプリ側で引数、権限、承認を検証する
  • 直接のTool Callingを基準に、速度、料金、精度を比較する

最初は、2つの読み取り専用Functionを並列に呼び、結果を1つの小さなJSONへまとめる処理から試すと、通常のTool Callingとの違いを確認しやすくなります。

参考リンク