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

非同期ツール呼び出し

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

非同期ツール呼び出しを使うと、モデルはツールを呼び出した後、その結果を待たずに作業を続けられます。時間のかかる照会を早めに開始し、結果を待つ間に、依頼のうちその結果に依存しない部分に回答できます。アプリケーションは結果が得られた時点でモデルに返します。

非同期ツールの仕組み

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

非同期でも、ツールを実行するのはアプリケーションです。実行が OpenAI 側に移ることはなく、バックグラウンドジョブの管理もアプリケーションが担います。

バックグラウンドモードでは、レスポンスの生成自体を非同期で実行します。一方、非同期ツール呼び出しでは、アプリケーションがツールを実行している間もモデルが作業を続けられます。

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

ツールの種類 呼び出し項目 出力項目
関数 function_call function_call_output
カスタム custom_tool_call custom_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)

レスポンスには、非同期の呼び出しとモデルの回答の両方が含まれる場合があります。ジョブの完了前に会話が進んだ場合は、latest_response_id を更新して最新のレスポンスから会話を続けます。その際、元のツール呼び出しの call_id は保持してください。

ストリーミングを使ってジョブを早めに開始するには、呼び出し項目の全体を受信した時点でジョブを開始し、レスポンスの残りを引き続き受信します。

待機ツールの追加

待機ツールを使うと、モデルはまだ届いていない結果をいつ待つか判断できます。たとえば、2 件の価格照会を開始した後、価格に依存しない作業を進め、価格を比較する段階で初めて結果を待つことができます。

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

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

リクエストの 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 async tool 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_1 call_widget WIDGET の価格照会
gadget_price_1 call_gadget GADGET の価格照会

完了済みタスクのハンドルを再利用しないよう、会話が終わるまでレジストリを保持してください。

待機ステータスに先立つ結果の返却

指定されたハンドルに対応するジョブをレジストリから取得し、それらのジョブだけを待ちます。新たに完了した各ジョブの結果を元の呼び出しの 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 を設定し、会話を続けるためのリクエストにツールと指示を含めます。アプリケーションは、待機呼び出しがなくても、結果が得られた時点で返すことができます。待機ツールは、モデルが次の処理に進むために、まだ届いていない結果が必要な場合にのみ使ってください。

ユーザーに入力を求めるツールの追加

非同期ツールを使うと、モデルはユーザーに質問した後も、回答に依存しない作業を続けられます。たとえば、レポートの読者をユーザーに尋ね、回答を待つ間に情報を集め、回答が届いたら読者に合わせてレポートを作成できます。

不足している情報やユーザーの希望を尋ねるには、async: true を指定して関数を定義します。アプリケーションが質問を表示し、ユーザーの回答を受け取ってツールの結果として返します。スキーマと動作はアプリケーション側で定義します。request_user_input_async は Responses API の組み込みツールではありません。

リクエストの tools 配列に、wait_for_tasks とともに次の定義を追加します。

{
  "type": "function",
  "name": "request_user_input_async",
  "async": true,
  "description": "Ask the user for missing information or a preference. Choose a fresh task_handle unique within this conversation, including completed tasks. Continue independent work while the answer is pending. Use wait_for_tasks when your next step depends on the answer.",
  "strict": true,
  "parameters": {
    "type": "object",
    "properties": {
      "question": { "type": "string" },
      "task_handle": { "type": "string" }
    },
    "required": ["question", "task_handle"],
    "additionalProperties": false
  }
}

質問の表示

呼び出し項目の全体を受信したら、質問の task_handle と元の call_id を登録し、ユーザーに質問を表示します。次の出力項目は、レポートの読者を尋ねる例です。

{
  "type": "function_call",
  "name": "request_user_input_async",
  "async": true,
  "call_id": "call_audience",
  "arguments": "{\"question\":\"Who is the report for: executives or engineers?\",\"task_handle\":\"report_audience_1\"}"
}

待機ツールが使うレジストリで、質問を回答待ちの状態にしておきます。ユーザーが回答する間も、モデルのレスポンスを引き続き受信してください。質問を表示したという通知を返してツール呼び出しを完了させないでください。この呼び出しの結果は、ユーザーの回答です。

ユーザーの回答の返却

ユーザーから回答が届いたら、質問の元の call_id で回答を送信します。たとえば、次のリクエストの input 配列に以下の出力項目を含めます。

[
  {
    "type": "function_call_output",
    "call_id": "call_audience",
    "output": "{\"task_handle\":\"report_audience_1\",\"answer\":\"Executives\"}"
  }
]

previous_response_id に最新のレスポンス ID を設定し、会話を続けるためのリクエストにツールと指示を含めます。モデルが wait_for_tasks を呼び出して report_audience_1 の結果を待っている場合は、待機ステータスを返す前に回答を返してください。具体的な順序は待機ツールの例を参照してください。

非同期で実行しても、ユーザーが回答するまでレスポンスが開いたままになるわけではありません。回答に依存しない作業は続け、回答が必要な処理に進む前に待機するようモデルに指示してください。アプリケーションで質問を閉じたり回答期限を設定したりできる場合は、回答がなかったことを結果として明示的に返し、モデルが次の対応を判断できるようにします。

互換性

GPT-6 Astra 以降のモデルは、非同期ツール呼び出しに対応しています。

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

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