「以程式呼叫工具」讓模型撰寫並執行 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"]:
function和custommcpapply_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相符,而它的status為completed或incomplete。
這些是 response.output 中各自獨立的頂層項目;caller 欄位會記錄它們之間的執行關係。
例如,當你的應用程式執行 get_inventory 和 get_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,不要修改。服務會使用該值繼續執行對應的程式。
在用戶端函式呼叫後繼續執行
程式執行到用戶端工具時可能會暫停,而且可能暫停多次。請持續執行,直到回應包含最終的助理訊息:
- 傳送請求,並在其中加入託管工具及允許以程式呼叫的函式。
- 執行每個傳回的用戶端函式呼叫。
- 傳回每個函式結果,並附上原始的
call_id和caller。 - 先處理不完整的回應,再繼續執行。
- 如果回應既沒有待處理的
function_call項目,也沒有最終的message項目,請從該回應繼續執行。使用store: false時,請重播其輸出項目;若是已儲存的回應,則使用previous_response_id。 - 當回應包含最終的
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 連線。