功能工具

功能工具讓你的 AI 智能體可在通話期間呼叫外部 API。你可用於查詢客戶資料、檢查可用時段、預約服務,或執行任何後端支援的操作。

運作方式

  1. 以綱要定義工具(工具可接受的引數)
  2. 提供 endpoint 設定(ThunderPhone 呼叫你的 API 的位置)——或不設定,讓你的組織 webhook 接收工具呼叫
  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"
    }
  }
}

功能定義

欄位類型必填說明
name字串工具的唯一識別碼
description字串向 AI 說明何時使用此工具
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-SignatureContent-Type + X-ThunderPhone-Signature
簽署金鑰組織 webhook 密鑰組織 webhook 密鑰

兩種路徑均會阻塞——AI 會在句子中途等候結果——逾時時間為 20 秒。請保持處理程式迅速。混合使用亦可: 如通話所屬組織設有 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: abc123...
X-ThunderPhone-Call-ID: 987654321
X-Api-Key: your-api-key

來自 endpoint.headers 的自訂標頭一律會原樣包含, 另加兩個 ThunderPhone 命名空間標頭:

除非 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 相同的方式簽署:

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}
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 欄位可協助 AI 理解何時使用工具。請清楚說明工具的功能及適用時機。

妥善處理錯誤

傳回 AI 可理解的錯誤訊息:例如 {"error": "No slots available for that date"},而非通用的 500 錯誤。

保持回應精簡

僅傳回 AI 繼續對話所需的資訊。大型資料載荷會拖慢回應時間。

審慎使用必填欄位

只有在確實必要時才將欄位標示為 required。AI 會在呼叫工具前向用戶詢問所需資料。


相關內容