Response
工具呼叫
將模型提出的工具請求交由應用程式執行,再回傳結果以繼續對話。
POST /v1/responses
自訂函式由您的應用程式執行。模型提供函式名稱和參數,應用程式負責查詢資料並回傳結果。
請求與驗證
http
POST https://api.tokatlas.ai/v1/responses
Authorization: Bearer YOUR_API_KEY
Content-Type: application/jsonjson
{
"model": "gpt-5",
"tools": [
{
"type": "function",
"name": "lookup_stock",
"description": "Look up available inventory for a product SKU.",
"parameters": {
"type": "object",
"properties": {
"sku": {
"type": "string",
"description": "Product SKU, for example DEMO-001"
}
},
"required": [
"sku"
],
"additionalProperties": false
},
"strict": true
}
],
"input": "Check stock for DEMO-001."
}工具呼叫格式
以下為呼叫項目示意;ID 與參數應取自實際回應。
json
{
"type": "function_call",
"id": "fc_example",
"name": "lookup_stock",
"arguments": "{\"sku\": \"DEMO-001\"}",
"call_id": "call_example"
}檢查全部
output項目。function_call.arguments是 JSON 字串;回傳function_call_output時須使用call_id,而非項目的id。範例使用
store: false並回傳包含推理項目的完整輸出。也可使用已儲存的previous_response_id,只送入新的工具結果;仍須重新傳送工具定義。tool_choice支援"auto"、"required"、"none"或{"type":"function","name":"lookup_stock"}。嚴格結構須將所有屬性列入required,並設定additionalProperties: false。串流時,依輸出項目合併
response.function_call_arguments.delta,等參數完整後再執行。
多語言首輪請求
這組範例會取得模型的工具呼叫要求,尚未執行工具。讀取下方完整流程,以真實呼叫 ID 回傳工具結果並繼續對話。
執行方式見多語言範例說明。先設定 API_KEY,並替換模型、檔案網址及 ID 占位值;四種方式會顯示相同請求的原始回應。
bash
curl --fail-with-body --silent --show-error --max-time 180 \
--request POST \
--url "https://api.tokatlas.ai/v1/responses" \
--header "Authorization: Bearer $API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "gpt-5",
"tools": [
{
"type": "function",
"name": "lookup_stock",
"description": "Look up available inventory for a product SKU.",
"parameters": {
"type": "object",
"properties": {
"sku": {
"type": "string",
"description": "Product SKU, for example DEMO-001"
}
},
"required": [
"sku"
],
"additionalProperties": false
},
"strict": true
}
],
"stream": false,
"input": "Check stock for DEMO-001.",
"store": false
}'python
import os
import requests
headers = {
'Authorization': 'Bearer ' + os.environ["API_KEY"],
'Content-Type': 'application/json',
}
payload = {'model': 'gpt-5',
'tools': [{'type': 'function',
'name': 'lookup_stock',
'description': 'Look up available inventory for a product SKU.',
'parameters': {'type': 'object',
'properties': {'sku': {'type': 'string',
'description': 'Product SKU, for '
'example DEMO-001'}},
'required': ['sku'],
'additionalProperties': False},
'strict': True}],
'stream': False,
'input': 'Check stock for DEMO-001.',
'store': False}
response = requests.request(
'POST', 'https://api.tokatlas.ai/v1/responses', headers=headers,
json=payload,
timeout=180,
)
response.raise_for_status()
print(response.text)js
if (!process.env.API_KEY) throw new Error("Set API_KEY first.");
const response = await fetch("https://api.tokatlas.ai/v1/responses", {
method: "POST",
headers: {
"Authorization": "Bearer " + process.env.API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
"model": "gpt-5",
"tools": [
{
"type": "function",
"name": "lookup_stock",
"description": "Look up available inventory for a product SKU.",
"parameters": {
"type": "object",
"properties": {
"sku": {
"type": "string",
"description": "Product SKU, for example DEMO-001"
}
},
"required": [
"sku"
],
"additionalProperties": false
},
"strict": true
}
],
"stream": false,
"input": "Check stock for DEMO-001.",
"store": false
}),
signal: AbortSignal.timeout(180_000),
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}
console.log(await response.text());java
import java.net.URI;
import java.net.http.*;
import java.time.Duration;
public class Example {
public static void main(String[] args) throws Exception {
String apiKey = System.getenv("API_KEY");
if (apiKey == null || apiKey.isBlank()) {
throw new IllegalArgumentException("Set API_KEY first.");
}
String payload = String.join("\n",
"{",
" \"model\": \"gpt-5\",",
" \"tools\": [",
" {",
" \"type\": \"function\",",
" \"name\": \"lookup_stock\",",
" \"description\": \"Look up available inventory for a product SKU.\",",
" \"parameters\": {",
" \"type\": \"object\",",
" \"properties\": {",
" \"sku\": {",
" \"type\": \"string\",",
" \"description\": \"Product SKU, for example DEMO-001\"",
" }",
" },",
" \"required\": [",
" \"sku\"",
" ],",
" \"additionalProperties\": false",
" },",
" \"strict\": true",
" }",
" ],",
" \"stream\": false,",
" \"input\": \"Check stock for DEMO-001.\",",
" \"store\": false",
"}"
);
HttpClient client = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(30)).build();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.tokatlas.ai/v1/responses"))
.timeout(Duration.ofSeconds(180))
.header("Authorization", "Bearer " + apiKey)
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString(payload))
.build();
HttpResponse<String> response = client.send(
request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() < 200 || response.statusCode() >= 300) {
throw new IllegalStateException("HTTP " + response.statusCode() + ": "
+ response.body());
}
System.out.println(response.body());
}
}完整 Python 範例
安裝 requests(pip install requests),並設定 API_KEY 環境變數。庫存結果為示範資料;請將 execute 替換為業務服務,並選用帳戶已開通的模型。
python
import json
import os
import requests
URL = "https://api.tokatlas.ai/v1/responses"
HEADERS = {'Authorization': "Bearer " + os.environ["API_KEY"], 'Content-Type': 'application/json'}
TOOLS = [{'type': 'function',
'name': 'lookup_stock',
'description': 'Look up available inventory for a product SKU.',
'parameters': {'type': 'object',
'properties': {'sku': {'type': 'string',
'description': 'Product SKU, for example '
'DEMO-001'}},
'required': ['sku'],
'additionalProperties': False},
'strict': True}]
def post(payload):
response = requests.post(URL, headers=HEADERS, json=payload, timeout=60)
response.raise_for_status()
body = response.json()
# Accept the documented gateway envelope or a direct protocol response.
data = body.get("data", body)
if not isinstance(data, dict):
raise RuntimeError("Unexpected API response")
if data.get("error"):
raise RuntimeError(data["error"])
return data
def execute(name, args):
if name != "lookup_stock":
return {"error": "Unknown tool"}
if not isinstance(args, dict) or set(args) != {"sku"}:
return {"error": "Expected exactly one sku argument"}
if not isinstance(args["sku"], str) or not args["sku"].strip():
return {"error": "sku must be a non-empty string"}
# Demo fixture only; replace with your inventory service.
stock = {"DEMO-001": 18}
if args["sku"] not in stock:
return {"error": "SKU not found"}
return {"sku": args["sku"], "available": stock[args["sku"]]}
history = [{"role": "user", "content": "Check stock for DEMO-001."}]
for _ in range(6):
reply = post({"model": "gpt-5", "store": False,
"tools": TOOLS, "input": history})
if reply.get("status") != "completed":
raise RuntimeError("Response did not complete")
output = reply["output"]
calls = [item for item in output if item["type"] == "function_call"]
if not calls:
for item in output:
if item["type"] == "message":
for block in item["content"]:
if block["type"] == "output_text":
print(block["text"])
break
history.extend(output) # Preserve reasoning items as well as calls.
for call in calls:
try:
args = json.loads(call["arguments"])
result = execute(call["name"], args)
except (TypeError, ValueError):
result = {"error": "Invalid JSON arguments"}
history.append({"type": "function_call_output", "call_id": call["call_id"],
"output": json.dumps(result)})
else:
raise RuntimeError("Tool round limit reached")常見問題
| 狀況 | 檢查方式 |
|---|---|
| 缺少工具結果 | 每個呼叫都須回傳結果,保留原始 ID。 |
| 重複呼叫 | 避免每輪強制使用工具,並限制循環次數。 |
| 參數無效 | 執行前驗證函式名稱與參數。 |
| 工具執行失敗 | 回傳結構化錯誤,勿編造資料。 |
| 選項不支援 | 檢查模型與閘道路由的能力。 |
