For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
メインナビゲーション

非同期ツール呼び出し

アプリケーションがバックグラウンドでツールを実行している間も、処理を続けられます。

非同期ツール呼び出しを使うと、モデルはツールを呼び出した後、その結果を待たずに処理を続けられます。時間のかかる検索リクエストを早めに開始し、その結果に依存しない部分には先に回答し、アプリケーションが結果を取得した時点でモデルに渡すことができます。

非同期ツールの仕組み

通常の関数呼び出しでは、モデルのターンを一時停止してツールの応答を待ちます。関数ツールまたはカスタムツールの定義に async: true を設定すると、モデルはその呼び出しを行った後、アプリケーションが出力を返す前でも処理を続けられます。

ツールを実行するのは、引き続きアプリケーションです。非同期ツールによって実行先が OpenAI に移ることはなく、バックグラウンドジョブの管理も行われません。

これは、応答の生成を非同期で実行するバックグラウンドモードとは異なります。非同期ツール呼び出しでは、アプリケーションがツールを実行している間も、モデルが処理を続けられます。

ジョブが完了したら、その出力を後続の Responses リクエストに含めます。元の API の call_id を使って、結果をその呼び出しに対応付けます。

ツールの種類呼び出し項目出力項目
関数function_callfunction_call_output
カスタムcustom_tool_callcustom_tool_call_output

非同期ツールの呼び出し

ツールの定義に async: true を追加します。response.output 内の対応する呼び出し項目には、async: true が含まれます。

バックグラウンドで天気情報を取得
import json
from concurrent.futures import ThreadPoolExecutor

from openai import OpenAI
from openai.types.responses import FunctionToolParam


def get_weather(city):
    # Demo data. Replace this function with your weather service.
    weather = {
        "Paris": {
            "city": "Paris",
            "temperature_c": 22,
            "condition": "Clear",
            "source": "demo weather snapshot",
        }
    }
    return weather[city]


worker = ThreadPoolExecutor()


def main():
    client = OpenAI()
    model = "gpt-6-astra"
    tools: list[FunctionToolParam] = [
        {
            "type": "function",
            "name": "get_weather",
            "description": "Read the demo weather snapshot for a city.",
            "async": True,
            "strict": True,
            "parameters": {
                "type": "object",
                "properties": {"city": {"type": "string"}},
                "required": ["city"],
                "additionalProperties": False,
            },
        },
    ]

    instructions = (
        "Start the weather lookup and answer the independent packing "
        "question without waiting. Use the actual tool result when it "
        "arrives; never invent it. Identify the weather as demo data."
    )
    response = client.responses.create(
        model=model,
        tools=tools,
        instructions=instructions,
        input=(
            "Check the demo weather in Paris. Meanwhile, "
            "list three essentials for any city trip."
        ),
    )

    call = next(item for item in response.output if item.type == "function_call")
    arguments = json.loads(call.arguments)
    if call.name != "get_weather" or arguments != {"city": "Paris"}:
        raise ValueError("Expected a weather lookup for Paris")

    latest_response_id = response.id
    if call.async_:
        job = worker.submit(get_weather, **arguments)
        print(response.output_text)
        # Independent work or conversation turns can happen here.
        # Update latest_response_id after each continuation.
        result = job.result()
    else:
        result = get_weather(**arguments)

    response = client.responses.create(
        model=model,
        tools=tools,
        instructions=instructions,
        previous_response_id=latest_response_id,
        input=[
            {
                "type": "function_call_output",
                "call_id": call.call_id,
                "output": json.dumps(result),
            },
        ],
    )
    print(response.output_text)


if __name__ == "__main__":
    try:
        main()
    finally:
        worker.shutdown(wait=True)

レスポンスには、非同期呼び出しと回答の両方を含めることができます。ジョブが完了する前に会話の別のターンが発生した場合は、元のツールの call_id を保持したまま latest_response_id を更新し、最新のレスポンスから続行します。

ストリーミングでジョブをより早く開始するには、レスポンスの受信を続けながら、完全な呼び出し項目を受信した時点でそのジョブを開始します。

待機ツールの追加

待機ツールを使うと、まだ届いていない結果が必要になるタイミングをモデル自身が判断できます。たとえば、価格を取得するリクエストを 2 件開始し、その結果に依存しない処理を進めてから、価格を比較する段階になって初めて結果を待つことができます。

各非同期ツールに task_handle 引数を追加します。モデルは各呼び出しにハンドルを割り当て、アプリケーションはそのハンドルを元の API の call_id および実行中のジョブに対応付けます。完了済みのタスクや繰り返し行う検索リクエストも含め、会話全体でハンドルが一意になるようにしてください。

待機ツールは、通常の同期関数として定義します。async を省略するか、false に設定してください。スキーマと動作はアプリケーション側で定義します。wait_for_tasks は Responses の組み込みツールではありません。

リクエストの tools 配列で、次の定義を使用します。

[
  {
    "type": "function",
    "name": "lookup_price",
    "async": true,
    "description": "Look up a product price in the background. Choose a fresh task_handle unique within this conversation, including completed tasks.",
    "strict": true,
    "parameters": {
      "type": "object",
      "properties": {
        "sku": { "type": "string" },
        "task_handle": { "type": "string" }
      },
      "required": ["sku", "task_handle"],
      "additionalProperties": false
    }
  },
  {
    "type": "function",
    "name": "wait_for_tasks",
    "description": "Wait for selected tasks whose results you need. Pass a nonempty list of distinct task_handles from your earlier lookup_price calls. Results arrive on their original calls; this tool returns status only. Do not wait again for results that have already arrived.",
    "strict": true,
    "parameters": {
      "type": "object",
      "properties": {
        "task_handles": {
          "type": "array",
          "items": { "type": "string" }
        }
      },
      "required": ["task_handles"],
      "additionalProperties": false
    }
  }
]

各ジョブの登録

ジョブの完了を待つ呼び出しを処理する前に、各ジョブを登録して開始します。呼び出しは、同じレスポンスにまとめて含まれることも、複数のレスポンスに分かれて届くこともあります。次の出力項目の例は、2 件のジョブの開始と、その両方の完了を待つ呼び出しを示しています。

[
  {
    "type": "function_call",
    "name": "lookup_price",
    "async": true,
    "call_id": "call_widget",
    "arguments": "{\"sku\":\"WIDGET\",\"task_handle\":\"widget_price_1\"}"
  },
  {
    "type": "function_call",
    "name": "lookup_price",
    "async": true,
    "call_id": "call_gadget",
    "arguments": "{\"sku\":\"GADGET\",\"task_handle\":\"gadget_price_1\"}"
  },
  {
    "type": "function_call",
    "name": "wait_for_tasks",
    "call_id": "call_wait",
    "arguments": "{\"task_handles\":[\"widget_price_1\",\"gadget_price_1\"]}"
  }
]

アプリケーションのレジストリで、各ハンドルを元の呼び出しおよび実行中のジョブに対応付けます。

タスクハンドル元の呼び出し IDジョブ
widget_price_1call_widgetWIDGET の価格取得
gadget_price_1call_gadgetGADGET の価格取得

完了したタスクのハンドルが再利用されないように、会話が続く間はレジストリを保持してください。

待機ステータスより先に結果を返す順序

指定されたハンドルをレジストリで解決し、該当するジョブだけの完了を待ちます。新たに完了した各ジョブの結果を元の call_id で返してから、待機呼び出し自体の call_id でステータスを返します。この順序にすると、モデルが処理を再開する時点で結果を利用できます。

たとえば、次の出力項目を次回のリクエストの input 配列に含めて送信します。価格は例示用です。

[
  {
    "type": "function_call_output",
    "call_id": "call_widget",
    "output": "{\"task_handle\":\"widget_price_1\",\"price_cents\":1200,\"currency\":\"USD\"}"
  },
  {
    "type": "function_call_output",
    "call_id": "call_gadget",
    "output": "{\"task_handle\":\"gadget_price_1\",\"price_cents\":1500,\"currency\":\"USD\"}"
  },
  {
    "type": "function_call_output",
    "call_id": "call_wait",
    "output": "{\"status\":\"completed\",\"completed_task_handles\":[\"widget_price_1\",\"gadget_price_1\"]}"
  }
]

previous_response_id に最新のレスポンス ID を設定し、続行リクエストにツールと指示を含めます。アプリケーションは待機呼び出しを使わずに、結果が得られた時点でその都度渡すこともできます。待機ツールは、モデルの次の処理にまだ届いていない結果が必要な場合にのみ使用してください。

互換性

非同期ツール呼び出しは、GPT-6 Astra 以降のモデルでサポートされています。

非同期実行の対象は、アプリケーションが実行する関数ツールとカスタムツールです。ホスト型の組み込みツールには適用されません。ツールは直接呼び出してください。プログラムによるツール呼び出し用に非同期ツールを設定しないでください。

マルチエージェントモードでは、非同期ツールと並列ツール呼び出しを併用しないでください。