For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
主要導覽

以程式呼叫工具

讓模型編寫並執行 JavaScript,協調工具呼叫。

「以程式呼叫工具」讓模型撰寫並執行 JavaScript,協調工具的使用。程式可以平行呼叫工具、使用迴圈與條件判斷,並將中間結果保留在託管執行環境中。當任務需要一連串相關的工具呼叫,或需要先處理大量工具輸出再傳回結果時,這項功能就很實用。

在 Responses API 中,你的應用程式決定是否開放「以程式呼叫工具」,以及模型可以直接呼叫哪些符合條件的工具、透過程式呼叫哪些工具,或對哪些工具同時開放兩種呼叫方式。應用程式仍負責執行所有由用戶端負責的工具呼叫。Agents API 預設啟用「以程式呼叫工具」,並為你管理智慧體的執行迴圈。

啟用「以程式呼叫工具」前,請先查看模型頁面

瞭解執行環境

OpenAI 會在全新且隔離的 V8 執行環境中執行每個生成的程式。這個環境支援使用頂層 await 的 JavaScript,但不提供 Node.js、套件安裝、直接網路存取、通用檔案系統、子程序執行或主控台,也不會在不同次程式執行之間保留 JavaScript 狀態。程式只能透過請求中已啟用的工具與外部系統互動,並可使用 text(...)image(...) 產生輸出。

對於 Responses API 請求,「以程式呼叫工具」支援零資料保留(ZDR)工作流程,無須使用持續存在的程式碼執行容器。你必須為組織或專案啟用 ZDR;設定 store: false 可啟用無狀態接續執行,但這項設定本身不會啟用 ZDR。是否符合適用資格以及資料保留方式,取決於完整請求,包括使用的模型、工具與第三方服務;請參閱資料控制

選擇何時使用「以程式呼叫工具」

當某個階段的控制流程可預測,且程式碼能傳回較精簡的結構化結果時,請使用「以程式呼叫工具」。如果一次呼叫就足夠、每個結果都需要模型重新判斷,或工作需要核准、保留引用來源或原生產物,請直接呼叫工具。

任務類型建議模式
單次查詢或動作直接呼叫工具。
多筆可由程式碼篩選、聯結、排序、去除重複、彙總或驗證的結果當程式能傳回較精簡的結構化結果時,請使用「以程式呼叫工具」。
具有相依關係且資料流程可預測的呼叫當程式碼能推導後續呼叫的引數,且限制與失敗時的行為已明確定義時,請使用「以程式呼叫工具」。
適應性搜尋或語意評估當每個結果都應影響模型的下一步決策時,請直接呼叫工具。
寫入操作或需謹慎處理核准的動作預設直接呼叫工具,以維持明確的授權界線。
最終引用來源或原生產物的驗證除非程式會保留原生輸出並驗證每個必要項目,否則請直接呼叫工具。

設定「以程式呼叫工具」

使用 Responses API 時,請將 programmatic_tool_calling 託管工具加入請求,接著為程式可呼叫的每個符合條件的工具設定 allowed_callers

啟用「以程式呼叫工具」
[
  {
    "type": "function",
    "name": "get_inventory",
    "description": "Return an object with sku (string) and available_units (number).",
    "parameters": {
      "type": "object",
      "properties": {
        "sku": { "type": "string" }
      },
      "required": ["sku"],
      "additionalProperties": false
    },
    "output_schema": {
      "type": "object",
      "properties": {
        "sku": { "type": "string" },
        "available_units": { "type": "number" }
      },
      "required": ["sku", "available_units"],
      "additionalProperties": false
    },
    "allowed_callers": ["programmatic"]
  },
  {
    "type": "programmatic_tool_calling"
  }
]

allowed_callers 控制模型可以如何呼叫工具:

行為
省略或設為 ["direct"]模型可以直接呼叫工具。
["programmatic"]只有 program 項目中的程式碼可以呼叫工具。
["direct", "programmatic"]模型可以直接呼叫工具,也可以透過程式呼叫。

parameters 描述函式的引數。當函式傳回可預測的結構化資料時,output_schema 描述其 function_call_output.output 字串中編碼的 JSON 物件。請同時定義兩者,讓生成的 JavaScript 能可靠地使用傳回的欄位。

支援的工具

下列工具類型支援 allowed_callers: ["programmatic"]

  • functioncustom
  • mcp
  • apply_patch
  • 本機與託管的 shell
  • code_interpreter

對於 MCP 工具,工具的 require_approval 政策可以暫停程式,直到你核准該呼叫。

對於 OpenAI 託管的工具,在程式中啟用前,請先審閱該工具的資料保留與安全性指引。

工具搜尋是以頂層 Responses API 工具的形式執行,而非在生成的 JavaScript 內執行。設定為 defer_loading: true 的函式工具、自訂工具和 MCP 工具,起初無法供程式使用。模型載入符合條件的工具後,只要該工具的 allowed_callers 包含 "programmatic",後續程式就能透過 tools.* 呼叫它。已在執行中的程式無法呼叫工具搜尋,因此模型必須先載入延後載入的工具,再啟動需要這些工具的程式。

兩種模式皆可用時,指引模型選擇呼叫方式

如果你的應用程式允許模型直接或透過程式呼叫函式,請為每種呼叫方式指定適用的工作流程階段。「有效率地使用『以程式呼叫工具』」這類籠統指示,無法明確指出預期的使用界線。例如:

<tool_orchestration>
Use Programmatic Tool Calling for [bounded stage] using only [eligible tools].
Run independent calls concurrently when safe. Use only documented tool input
and output fields.

Process and reduce the intermediate results, then emit exactly [program result shape],
including the evidence needed for the final answer.

Stop when [condition] is met. Retry transient failures at most [R] times.
Do not repeat completed calls or perform side-effecting actions. If a required
result is still missing, return a clear structured failure.

Use direct tool calls for [semantic judgment, approval, or final validation].
</tool_orchestration>

以下範例示範如何使用這個範本:

<tool_orchestration>
Use Programmatic Tool Calling to compare inventory with demand for sku_123
using only get_inventory and get_demand. Run both calls concurrently. Use
only documented tool input and output fields.

Process and reduce the intermediate results, then emit exactly one JSON object
with sku, available_units, requested_units, and shortage_units, where
shortage_units is max(requested_units - available_units, 0). Include
available_units and requested_units as evidence for the calculation.

Stop when both tool results contain the required fields. Retry transient
failures at most 1 time. Do not repeat completed calls or perform
side-effecting actions. If a required result is still missing, return a clear
structured failure.

Use direct tool calls only for approval before any inventory-changing action.
</tool_orchestration>

對於需要兩種模式的工作流程,請定義一個交接點,避免來回切換呼叫方式或重複工作。如果有安全的備援方式,請統一定義一次,並限制其重試次數。

瞭解程式回應項目

每次 API 呼叫仍會傳回標準的 Responses API 物件。「以程式呼叫工具」不會引入另一種回應外層結構。模型使用「以程式呼叫工具」時,回應的 output 陣列可以包含:

  • 一個 program 項目,其中包含生成的 JavaScript、call_id,以及用於繼續執行或重播程式的不透明值 fingerprint
  • 程式產生的 function_call 項目。它有自己的 call_id,你的應用程式會用這個值傳回函式結果。它的 caller.caller_id 與程式的 call_id 相符。
  • 一個 program_output 項目,其中包含程式的最終結果與狀態。它的 call_id 與程式的 call_id 相符,而它的 statuscompletedincomplete

這些是 response.output 中各自獨立的頂層項目;caller 欄位會記錄它們之間的執行關係。

例如,當你的應用程式執行 get_inventoryget_demand 時,程式可以暫停:

程式與巢狀函式呼叫
[
  {
    "type": "program",
    "id": "prog_123",
    "call_id": "call_prog_123",
    "code": "const [stock, demand] = await Promise.all([tools.get_inventory({ sku: 'sku_123' }), tools.get_demand({ sku: 'sku_123' })]); text(JSON.stringify({ sku: stock.sku, available_units: stock.available_units, requested_units: demand.requested_units, shortage_units: Math.max(demand.requested_units - stock.available_units, 0) }));",
    "fingerprint": "opaque_replay_state"
  },
  {
    "type": "function_call",
    "id": "fc_123",
    "call_id": "call_inventory_123",
    "name": "get_inventory",
    "arguments": "{\"sku\":\"sku_123\"}",
    "caller": {
      "type": "program",
      "caller_id": "call_prog_123"
    }
  },
  {
    "type": "function_call",
    "id": "fc_456",
    "call_id": "call_demand_123",
    "name": "get_demand",
    "arguments": "{\"sku\":\"sku_123\"}",
    "caller": {
      "type": "program",
      "caller_id": "call_prog_123"
    }
  }
]

這些範例只顯示 response.output 中的相關項目,省略了外層的標準 Responses 物件。當你的應用程式傳回巢狀函式的結果後,後續回應中就可以包含完整的 program_output 項目:

程式輸出
{
  "type": "program_output",
  "id": "prog_out_123",
  "call_id": "call_prog_123",
  "result": "{\"sku\":\"sku_123\",\"available_units\":42,\"requested_units\":31,\"shortage_units\":0}",
  "status": "completed"
}

program_output.result 中的 JSON 字串遵循你在指示中定義的程式結果結構。外層的 program_output 項目則遵循上述 API 契約。這是兩套不同的契約。最終的 message 可能隨程式輸出一起傳回,也可能出現在後續回應中,因此請持續執行,直到收到該訊息。

OpenAI 會在託管執行環境中執行模型生成的 JavaScript。你的應用程式負責執行傳回的用戶端函式呼叫,不會執行生成的 JavaScript。

function_call_output 傳回函式結果。從函式呼叫中原樣複製 caller,不要修改。服務會使用該值繼續執行對應的程式。

在用戶端函式呼叫後繼續執行

程式執行到用戶端工具時可能會暫停,而且可能暫停多次。請持續執行,直到回應包含最終的助理訊息:

  1. 傳送請求,並在其中加入託管工具及允許以程式呼叫的函式。
  2. 執行每個傳回的用戶端函式呼叫。
  3. 傳回每個函式結果,並附上原始的 call_idcaller
  4. 先處理不完整的回應,再繼續執行。
  5. 如果回應既沒有待處理的 function_call 項目,也沒有最終的 message 項目,請從該回應繼續執行。使用 store: false 時,請重播其輸出項目;若是已儲存的回應,則使用 previous_response_id
  6. 當回應包含最終的 message 項目時,停止執行。讀取 response.output_text 或訊息中的拒絕內容。

以下範例使用 store: false,保留每個回應項目,並將每個函式結果傳回程式:

執行以程式呼叫工具的迴圈
import json

from openai import OpenAI

client = OpenAI()
model = "gpt-6-astra"


def get_inventory(sku):
    return {"sku": sku, "available_units": 42}


def get_demand(sku):
    return {"sku": sku, "requested_units": 31}


implementations = {
    "get_inventory": get_inventory,
    "get_demand": get_demand,
}

tools = [
    {
        "type": "function",
        "name": "get_inventory",
        "description": "Return an object with sku (string) and available_units (number).",
        "parameters": {
            "type": "object",
            "properties": {"sku": {"type": "string"}},
            "required": ["sku"],
            "additionalProperties": False,
        },
        "output_schema": {
            "type": "object",
            "properties": {
                "sku": {"type": "string"},
                "available_units": {"type": "number"},
            },
            "required": ["sku", "available_units"],
            "additionalProperties": False,
        },
        "allowed_callers": ["programmatic"],
    },
    {
        "type": "function",
        "name": "get_demand",
        "description": "Return an object with sku (string) and requested_units (number).",
        "parameters": {
            "type": "object",
            "properties": {"sku": {"type": "string"}},
            "required": ["sku"],
            "additionalProperties": False,
        },
        "output_schema": {
            "type": "object",
            "properties": {
                "sku": {"type": "string"},
                "requested_units": {"type": "number"},
            },
            "required": ["sku", "requested_units"],
            "additionalProperties": False,
        },
        "allowed_callers": ["programmatic"],
    },
    {"type": "programmatic_tool_calling"},
]

input_items = [
    {
        "role": "user",
        "content": "Compare inventory with demand for sku_123.",
    }
]

while True:
    response = client.responses.create(
        model=model,
        store=False,
        input=input_items,
        tools=tools,
    )

    if response.status != "completed":
        raise RuntimeError(f"Response ended with status {response.status}")

    # Preserve every output item, including program and reasoning items.
    input_items.extend(item.model_dump(exclude_none=True) for item in response.output)

    calls = [item for item in response.output if item.type == "function_call"]
    if not calls:
        message = next(
            (item for item in response.output if item.type == "message"), None
        )
        if message:
            refusal = next(
                (part.refusal for part in message.content if part.type == "refusal"),
                "",
            )
            print(response.output_text or refusal)
            break
        continue

    for call in calls:
        run = implementations.get(call.name)
        if run is None:
            raise ValueError(f"Unknown tool: {call.name}")

        result = run(**json.loads(call.arguments))
        input_items.append(
            {
                "type": "function_call_output",
                "call_id": call.call_id,
                "output": json.dumps(result),
                # Preserve caller so the runtime can resume the correct program.
                "caller": call.caller.model_dump() if call.caller else None,
            }
        )

儲存回應後,你可以透過 previous_response_id 繼續執行,無須重新傳送先前所有的回應項目。將新的 function_call_output 項目作為下一次輸入傳送。使用 store: false 時,請依序重播完整序列,包括每個 program、推理、函式呼叫、函式呼叫輸出及 program_output 項目。

對於無狀態的推理模型請求,請重播每個傳回的推理項目。每個項目預設都包含 encrypted_content。如需瞭解一般的無狀態處理模式,請參閱對話狀態

設計供程式使用的工具

  • 傳回精簡的結構化資料,讓 JavaScript 無須解析自然語言文字即可檢查。
  • 使用 output_schema 定義每個工具預期傳回的欄位與型別,並在文件中說明其錯誤處理行為。如果無法事先確定傳回的結構,請維持直接呼叫工具的方式,讓模型能夠檢查結果。
  • 明確定義程式結果的結構及所需的佐證。當程式無法產生有效結果時,請傳回清楚的結構化失敗資訊。
  • 盡可能讓函式呼叫具備冪等性。重試或重播不應重複觸發不安全的副作用。
  • 在應用程式中檢查每次呼叫的引數與權限,即使呼叫來自託管程式也不例外。
  • 為工具提供明確的名稱與描述,讓模型能正確組合使用。
  • 無論呼叫者是誰,在執行影響重大的動作之前,都必須取得應用程式層級的核准。

評估以程式呼叫工具

以程式呼叫工具可以減少加入模型上下文的中間工具輸出量,但實際效果取決於任務與工具回應。先以直接呼叫工具作為基準,再使用具代表性的任務比較這兩種方法。

衡量效率之前,請先定義最終答案的品質標準與所需的佐證。評估 Token 用量與工具呼叫時,也要一併評估正確性、完整性與佐證涵蓋範圍,並明確說明任何可接受的品質取捨。

衡量下列項目:

  • 最終答案的正確性、完整性與佐證涵蓋範圍。
  • 輸入 Token 數與 Token 總數、端對端延遲及成本。
  • 模型回合數、工具呼叫次數、重試次數與復原行為。
  • 安全性結果,尤其是副作用與核准要求方面的結果。
  • 實際執行的呼叫路徑是否符合預定的工作流程階段。

Agents API

Agents API 中,「以程式呼叫工具」預設為啟用,並在 OpenAI 管理的智慧體任務執行框架中執行。這個框架會為智慧體提供 exec 工具,並讓生成的 JavaScript 可以使用智慧體現有的工具。你無須將這些工具包裝成指令列程式,也無須將它們安裝到沙盒中。

若要停用「以程式呼叫工具」,請在 agent.tools 中加入以下項目:

{
  "type": "programmatic_tool_calling",
  "enabled": false
}

若省略此項目或其中的 enabled 欄位,「以程式呼叫工具」仍會保持啟用。僅指定類型的項目 { "type": "programmatic_tool_calling" } 也會讓這項功能保持啟用。上述 allowed_callers 組態與 Responses 接續執行迴圈,說明的是 Responses API 的整合方式。

在僅供對話、將 environment.type 設為 none 的工作階段中,也能使用「以程式呼叫工具」。Bash、執行器 MCP 及其他在沙盒中執行的工具,仍然需要執行環境

透過 JavaScript 協調工具呼叫,不會改變工具的執行位置。Shell 呼叫會在沙盒中執行指令;JavaScript 執行環境本身不會啟動系統程序。執行器 MCP 仍會使用沙盒,函式工具也仍會呼叫你的應用程式伺服器。智慧體會先處理這些工具的結果,再決定將哪些內容納入模型的上下文。

請依照上述呼叫路徑選擇指引,決定哪些工作流程階段應使用程式碼。如需設定 Agents API 及處理呼叫,請參閱函式MCP 連線

  • 使用函式呼叫定義由用戶端管理的函式。
  • 使用工具搜尋,將大型工具定義延後到模型需要時才提供。
  • 使用對話狀態,延續已儲存或無狀態的 Responses API 請求。
  • 選擇儲存模式之前,請先閱讀資料控制