Open in
函式工具
為你的 AI 智慧體提供函式工具,可在對話進行中呼叫外部 API——擷取客戶資料、預約、更新紀錄——並使用具型別的參數。
函式工具可讓你的語音智慧體在通話期間呼叫外部 API。使用它們查詢客戶資料、確認可用時段、預約,或執行你的後端支援的任何動作。
運作方式
- 使用結構描述定義工具(工具接受哪些參數)
- 提供
endpoint設定(ThunderPhone 在何處呼叫你的 API)——或省略它,以便在你的組織 webhook 上接收工具呼叫 - 通話期間,人工智慧會根據對話決定何時使用工具
- ThunderPhone 使用工具參數呼叫你的端點
- 你的 API 回應會回傳給人工智慧,以繼續對話
| 功能 | 執行位置 | 設定方式 |
|---|---|---|
| 內建工具 | ThunderPhone | 提示指令;部分工具也需要設定智慧體 |
| 應用程式連線 | ThunderPhone 與已連線的服務供應商 | 連接帳號並附加已核准的動作 |
| API 連線與函式工具 | 你的 HTTP API | 定義端點與結構描述,或透過 webhook 接收函式呼叫 |
| MCP 伺服器 | 遠端 MCP 伺服器 | 新增伺服器、探索其工具,並將其附加至智慧體 |
工具結構描述
每個工具都遵循以下結構:
{
"type": "function",
"function": {
"name": "search_appointments",
"description": "Find available appointment slots for a given date",
"parameters": {
"type": "object",
"properties": {
"date": {
"type": "string",
"description": "Date in YYYY-MM-DD format"
},
"service": {
"type": "string",
"description": "Type of service (e.g., 'consultation', 'follow-up')"
}
},
"required": ["date"]
}
},
"endpoint": {
"url": "https://api.example.com/appointments/search",
"method": "POST",
"headers": {
"X-Api-Key": "your-api-key"
}
},
"timeout": 120
}工具設定
| 欄位 | 類型 | 必填 | 說明 |
|---|---|---|---|
timeout | 數字 | 否 | 最長執行時間(秒)(預設值:20,最大值:180) |
函式定義
| 欄位 | 類型 | 必填 | 說明 |
|---|---|---|---|
name | 字串 | 是 | 工具的唯一識別碼 |
description | 字串 | 是 | 向人工智慧說明何時使用此工具 |
parameters | 物件 | 是 | 工具參數的 JSON Schema |
端點設定
| 欄位 | 類型 | 必填 | 說明 |
|---|---|---|---|
url | 字串 | 是 | 你的 API 端點 URL |
method | 字串 | 否 | HTTP 方法(預設值:POST) |
headers | 物件 | 否 | 要包含的自訂標頭 |
兩種呼叫路徑
你的伺服器收到哪種請求,取決於工具是否具有
endpoint:
含有 endpoint 的工具 | 不含 endpoint 的工具 | |
|---|---|---|
| 請求傳送位置 | 直接傳送至 endpoint.url | 你組織的舊版 Webhook URL |
| 內文 | 所選的請求格式(預設為純引數) | telephony.tool / web.tool 封裝 |
| 標頭 | 你的 endpoint.headers + X-ThunderPhone-Call-ID + X-ThunderPhone-Signature-V2 + X-ThunderPhone-Signature | Content-Type + X-ThunderPhone-Signature-V2 + X-ThunderPhone-Signature |
| 簽署金鑰 | 組織 Webhook 密鑰 | 組織 Webhook 密鑰 |
兩種路徑都是阻塞式——人工智慧會在句子中途等待
結果。預設逾時時間為20 秒;請設定工具頂層的
timeout 以允許更長的執行時間,最長可達平台的180 秒
上限。請讓處理常式保持快速。混用沒有問題:
在組織具有 webhook URL 的通話中,具有 endpoint 的工具會
直接呼叫,其餘工具則會改由 webhook 處理。
直接端點呼叫
當 AI 呼叫具有 endpoint 的工具時,ThunderPhone 會向你的 URL 傳送
請求:
請求標頭
POST /appointments/search HTTP/1.1
Host: api.example.com
Content-Type: application/json
X-ThunderPhone-Signature-V2: t=1767225600,v1=5f2c...
X-ThunderPhone-Signature: abc123...
X-ThunderPhone-Call-ID: 987654321
X-Api-Key: your-api-key你在 endpoint.headers 中設定的自訂標頭一律會原樣包含,
此外還會加入以下 ThunderPhone 命名空間標頭:
X-ThunderPhone-Signature-V2——涵蓋方法、路徑、查詢參數與 內文的時間戳記 HMAC-SHA256,並以你的組織 webhook 密鑰作為金鑰。 請驗證此簽章並拒絕超過 5 分鐘的請求;請參閱 驗證 webhook 簽章X-ThunderPhone-Signature——針對完整請求內文位元組的舊版 HMAC-SHA256, 使用相同金鑰,仍會傳送給既有的驗證工具X-ThunderPhone-Call-ID——目前的通話 ID
除非你的 endpoint.headers 覆寫它,否則會設定
Content-Type: application/json —— 自訂 Content-Type 優先。
請求格式
每個 API 連線都有 request_format 設定。當匯入的工具應持續呼叫為該平台建立的端點時,請選擇 vapi 或
retell。新的和既有的連線預設為 standard。
對於 POST / PUT / PATCH,ThunderPhone 會以標準形式序列化所選的
封裝格式(排序鍵值、精簡分隔符)。兩種簽章都涵蓋這些完全相同的位元組。
Standard
standard 僅傳送工具引數,不含任何包裝。這是預設行為,並會逐位元組保留 ThunderPhone 原始的請求主體:
{"date":"2025-01-02","service":"consultation"}Vapi
vapi 會以 Vapi 文件記載的格式傳送 Vapi 的 tool-calls 伺服器訊息。
call.id 是 ThunderPhone 的通話 ID。工具呼叫 id 對每次叫用皆為唯一,並會重複使用以比對端點的結果。該呼叫會同時出現在 toolCallList 和
toolWithToolCallList 中,其中 function.arguments 為 JSON 物件:
{
"message": {
"type": "tool-calls",
"timestamp": 1725000000123,
"call": { "id": "987654321" },
"toolCallList": [
{
"id": "call_00112233445566778899aabbccddeeff",
"type": "function",
"function": {
"name": "search_appointments",
"arguments": { "date": "2025-01-02", "service": "consultation" }
}
}
],
"toolWithToolCallList": [
{
"type": "function",
"function": { "name": "search_appointments" },
"toolCall": {
"id": "call_00112233445566778899aabbccddeeff",
"type": "function",
"function": {
"name": "search_appointments",
"arguments": { "date": "2025-01-02", "service": "consultation" }
}
}
}
]
}
}不會傳送僅限 Vapi 的欄位,例如 assistant、artifact 和完整的 call 物件。
請傳回包含相符工具呼叫 ID 的 Vapi 回應封裝:
{
"results": [
{
"toolCallId": "call_00112233445566778899aabbccddeeff",
"result": "{\"available_slots\":[\"9:00 AM\",\"2:00 PM\"]}"
}
]
}ThunderPhone 會將未封裝的 result 字串提供給 AI。為了相容於已經傳回 JSON 值的端點,也接受 JSON 值。以 error 取代 result 時,會以工具錯誤的形式傳回給 AI。如果端點傳回格式錯誤或不相符的 Vapi 封裝,ThunderPhone 會記錄警告,並改用其標準回應剖析,而不會使通話失敗。
Retell
retell 會傳送 Retell 自訂函式文件中記載的請求:
{
"name": "search_appointments",
"call": { "call_id": "987654321" },
"args": { "date": "2025-01-02", "service": "consultation" }
}call 物件僅包含 call_id。ThunderPhone 不會包含在派送時無法如實提供的 Retell 專用欄位,例如
agent_id、transcript、transcript_object、metadata 或動態變數。Retell 接受任何回應主體;ThunderPhone 會使用標準回應處理將其直接傳遞。
對於 GET / DELETE,引數會作為查詢參數傳送,
且無論 request_format 為何,主體皆為空。V2 簽章涵蓋傳送的查詢字串;舊版簽章則根據空位元組字串計算。請參閱
驗證 webhook 簽章。
回應
傳回包含工具結果的 JSON 回應:
{
"available_slots": ["9:00 AM", "2:00 PM", "4:30 PM"],
"timezone": "America/Los_Angeles"
}系統會格式化回應並提供給 AI,以繼續進行
對話。非 JSON 回應會包裝為 {"data": "<text>"};
逾時與連線失敗會以錯誤形式回報給 AI,讓
智慧體可以致歉並繼續處理,而不會停滯。
Webhook 模式分派
沒有 endpoint 的工具會作為已簽名的 telephony.tool(電話通話)或 web.tool
(網頁通話)請求,分派至你的組織舊版 Webhook URL。不同於在執行後
傳送至 Webhook 端點的稽核通知,此請求就是
執行本身 —— 你的 HTTP 回應即為工具結果。
{
"type": "telephony.tool",
"data": {
"call_id": 987654321,
"tool_name": "search_appointments",
"arguments": { "date": "2026-04-21" },
"from_number": "+14155550199",
"to_number": "+15551234567"
}
}web.tool 會帶有 origin_domain,而非 from_number /
to_number。請以 JSON 回傳工具結果——其回應契約與直接呼叫端點時相同。此請求會使用組織的 webhook 密鑰簽署,並包含兩個簽章標頭,如同其他所有 webhook。
簽章驗證
直接工具呼叫的簽署方式與 Webhook 相同,使用你組織的 Webhook 密鑰:
X-ThunderPhone-Signature-V2會簽署傳送時的時間戳記、方法、路徑和查詢字串,以及完全相同的請求主體位元組。若請求的時間戳記與你的時鐘相差超過 5 分鐘,請拒絕該請求。X-ThunderPhone-Signature(舊版)僅簽署請求主體位元組;對於GET/DELETE,則簽署空白位元組字串。此標頭仍會照原樣傳送。
SDK 輔助函式會驗證 V2 標頭,包括 5 分鐘的有效時間範圍:
import json
from fastapi import FastAPI, HTTPException, Request
from thunderphone import verify_signature
app = FastAPI()
@app.post("/appointments/search")
async def search_appointments(request: Request):
body = await request.body()
query = request.scope.get("query_string", b"").decode("latin-1")
path = request.url.path + (f"?{query}" if query else "")
if not verify_signature(
request.headers.get("X-ThunderPhone-Signature-V2"),
secret=WEBHOOK_SECRET,
method=request.method,
path=path,
body=body,
):
raise HTTPException(status_code=401)
data = json.loads(body)
date = data["date"]
# Look up availability
slots = await get_available_slots(date)
return {"available_slots": slots}import express from "express";
import { verifySignature } from "@thunderphone/sdk";
app.post('/appointments/search', express.raw({type: 'application/json'}), (req, res) => {
const ok = verifySignature({
header: req.header('X-ThunderPhone-Signature-V2'),
secret: WEBHOOK_SECRET,
method: req.method,
path: req.originalUrl,
body: req.body,
});
if (!ok) return res.status(401).send('Invalid signature');
const { date, service } = JSON.parse(req.body);
// Look up availability
const slots = getAvailableSlots(date, service);
res.json({ available_slots: slots });
});完整指南——簽署字串、實作範例、不使用 SDK 的程式碼、GET / DELETE 情境,以及未設定密鑰時的注意事項——請參閱驗證 Webhook 簽章。
範例:完整預約流程
以下是一組可用於完整預約系統的工具:
{
"tools": [
{
"type": "function",
"function": {
"name": "search_appointments",
"description": "Find available appointment slots",
"parameters": {
"type": "object",
"properties": {
"date": { "type": "string", "description": "YYYY-MM-DD" },
"service": { "type": "string" }
},
"required": ["date"]
}
},
"endpoint": {
"url": "https://api.example.com/appointments/search",
"method": "POST",
"headers": { "X-Api-Key": "key" }
}
},
{
"type": "function",
"function": {
"name": "book_appointment",
"description": "Book an appointment at a specific time",
"parameters": {
"type": "object",
"properties": {
"date": { "type": "string", "description": "YYYY-MM-DD" },
"time": { "type": "string", "description": "HH:MM format" },
"customer_name": { "type": "string" },
"customer_phone": { "type": "string" }
},
"required": ["date", "time", "customer_name"]
}
},
"endpoint": {
"url": "https://api.example.com/appointments/book",
"method": "POST",
"headers": { "X-Api-Key": "key" }
}
},
{
"type": "function",
"function": {
"name": "cancel_appointment",
"description": "Cancel an existing appointment",
"parameters": {
"type": "object",
"properties": {
"confirmation_number": { "type": "string" }
},
"required": ["confirmation_number"]
}
},
"endpoint": {
"url": "https://api.example.com/appointments/cancel",
"method": "POST",
"headers": { "X-Api-Key": "key" }
}
}
]
}最佳實務
撰寫清楚的說明
description 欄位可協助 AI 理解何時使用工具。請明確說明工具的功能及適用時機。
妥善處理錯誤
回傳 AI 能理解的錯誤訊息:{"error": "No slots available for that date"},而非通用的 500 錯誤。
保持回應精簡
僅回傳 AI 繼續對話所需的資訊。大型承載資料會拖慢回應時間。
審慎使用必填欄位
僅在確實必要時才將欄位標記為 required。AI 會在呼叫工具前向使用者詢問必填資訊。