ThunderPhone 2.0 正式上線。全程自助,每分鐘 2 美分起查看公告

Function Tools

函式工具

為你的 AI 智慧體提供可在對話中呼叫外部 API 的函式工具——擷取客戶資料、預約行程、更新紀錄——並使用具型別的參數。

函式工具可讓你的 AI 語音智慧體在通話期間呼叫外部 API。你可以使用它們查詢客戶資料、檢查可用時段、預約安排,或執行後端支援的任何操作。

運作方式

  1. 使用結構描述定義工具(工具可接受哪些參數)
  2. 提供 endpoint 設定(ThunderPhone 在哪裡呼叫你的 API)——或省略它,以便在組織的網路掛鉤接收工具呼叫
  3. 通話期間,AI 會根據對話判斷何時使用工具
  4. ThunderPhone 會使用工具參數呼叫你的端點
  5. 你的 API 回應會回傳給 AI,以繼續對話

工具結構描述

每個工具皆遵循以下結構:

{
  "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字串向 AI 說明何時使用此工具
parameters物件工具參數的 JSON 結構描述

端點設定

欄位類型必填說明
url字串你的 API 端點 URL
method字串HTTP 方法(預設值:POST
headers物件要包含的自訂標頭

兩種呼叫路徑

伺服器收到哪一種請求,取決於工具是否具有 endpoint

使用 endpoint 的工具未使用 endpoint 的工具
請求傳送位置直接傳送至 endpoint.url組織的舊版網路掛鉤 URL
請求主體僅含工具參數telephony.tool / web.tool 封裝
標頭你的 endpoint.headers + X-ThunderPhone-Call-ID + X-ThunderPhone-SignatureContent-Type + X-ThunderPhone-Signature
簽署金鑰組織網路掛鉤密鑰組織網路掛鉤密鑰

兩種路徑皆為阻塞式——AI 會在句中等待 結果。預設逾時時間為 20 秒;設定工具頂層的 timeout 可允許更長的執行時間,最高可達180 秒的平台 上限。請讓處理常式快速完成。可以混合使用: 若通話所屬的組織設有網路掛鉤 URL,具有 endpoint 的工具會 直接呼叫,其餘工具則回退至網路掛鉤。

直接端點呼叫

當 AI 呼叫具有 endpoint 的工具時,ThunderPhone 會向你的 URL 傳送 請求:

請求標頭

POST /appointments/search HTTP/1.1
Host: api.example.com
Content-Type: application/json
X-ThunderPhone-Signature: abc123...
X-ThunderPhone-Call-ID: 987654321
X-Api-Key: your-api-key

系統一律會逐字包含 endpoint.headers 中的自訂標頭, 以及兩個以 ThunderPhone 為命名空間的標頭:

  • X-ThunderPhone-Signature —— 使用你的 組織 Webhook 密鑰作為金鑰,對精確的請求主體 位元組計算的 HMAC-SHA256
  • X-ThunderPhone-Call-ID —— 目前的通話 ID

除非你的 endpoint.headers 覆寫它,否則會設定 Content-Type: application/json —— 自訂的 Content-Type 優先。

請求主體

對於 POST / PUT / PATCH,主體僅包含工具 引數(沒有包裝層),並以標準化格式序列化(排序鍵名、緊湊 分隔符號):

{"date":"2025-01-02","service":"consultation"}

對於 GET / DELETE,引數會作為查詢參數 傳送,且主體為空 —— 此時簽章會根據空的 位元組字串計算。請參閱 驗證 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 相同:

  • 對精確的請求本文位元組計算 HMAC-SHA256(正規 JSON——排序金鑰、不含額外空白)
  • 使用你組織的 Webhook 密鑰作為金鑰
  • GETDELETE 工具會對空位元組字串進行簽署
Python
import hmac
import hashlib
 
def verify_tool_call(body: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)
 
@app.post("/appointments/search")
async def search_appointments(request: Request):
    body = await request.body()
    signature = request.headers.get("X-ThunderPhone-Signature", "")
 
    if not verify_tool_call(body, signature, WEBHOOK_SECRET):
        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}
Node.js
app.post('/appointments/search', express.raw({type: 'application/json'}), (req, res) => {
  const signature = req.headers['x-thunderphone-signature'] || '';
  const expected = crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(req.body)
    .digest('hex');
 
  if (!signature ||
      signature.length !== expected.length ||
      !crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))) {
    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 });
});

完整範例——包括空本文情況與未設定密鑰的注意事項——請參閱驗證 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 欄位可協助人工智慧理解何時該使用此工具。請明確說明工具的功能及適用時機。

妥善處理錯誤

回傳人工智慧可理解的錯誤訊息:{"error": "No slots available for that date"},而非籠統的 500 錯誤。

保持回應簡潔

僅回傳人工智慧繼續對話所需的資訊。大型酬載會拖慢回應時間。

審慎使用必填欄位

僅在確實必要時才將欄位標示為 required。人工智慧會在呼叫工具前向使用者詢問必填資訊。


相關內容