ThunderPhone 2.0 kini resmi hadir.Layanan mandiri, mulai dari 2¢/menit.Baca pengumumannya

Function Tools

Alat Fungsi

Berikan agen AI Anda alat fungsi yang memanggil API eksternal di tengah percakapan — mengambil data pelanggan, menjadwalkan janji temu, memperbarui catatan — dengan parameter bertipe.

Alat fungsi memungkinkan agen suara AI Anda memanggil API eksternal selama panggilan telepon. Gunakan untuk mencari data pelanggan, memeriksa ketersediaan, menjadwalkan janji temu, atau melakukan tindakan apa pun yang didukung backend Anda.

Cara Kerjanya

  1. Definisikan alat dengan skema (argumen yang diterima alat)
  2. Sediakan konfigurasi endpoint (tempat ThunderPhone memanggil API Anda) — atau kosongkan untuk menerima panggilan alat pada webhook organisasi Anda
  3. Selama panggilan, AI memutuskan kapan menggunakan alat berdasarkan percakapan
  4. ThunderPhone memanggil endpoint Anda dengan argumen alat
  5. Respons API Anda dikirim kembali ke AI untuk melanjutkan percakapan

Skema Alat

Setiap alat mengikuti struktur ini:

{
  "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
}

Konfigurasi Alat

KolomTipeWajibDeskripsi
timeoutangkaTidakWaktu eksekusi maksimum dalam detik (default: 20, maksimum: 180)

Definisi Fungsi

KolomTipeWajibDeskripsi
namestringYaPengidentifikasi unik untuk alat
descriptionstringYaMenjelaskan kepada AI kapan alat ini digunakan
parametersobjekYaJSON Schema untuk argumen alat

Konfigurasi Endpoint

KolomTipeWajibDeskripsi
urlstringYaURL endpoint API Anda
methodstringTidakMetode HTTP (default: POST)
headersobjekTidakHeader kustom yang akan disertakan

Dua jalur pemanggilan

Permintaan yang diterima server Anda bergantung pada apakah alat memiliki endpoint:

Alat dengan endpointAlat tanpa endpoint
Tujuan permintaanLangsung ke endpoint.urlURL webhook lama organisasi Anda
IsiArgumen alat tanpa pembungkusPembungkus telephony.tool / web.tool
Headerendpoint.headers Anda + X-ThunderPhone-Call-ID + X-ThunderPhone-SignatureContent-Type + X-ThunderPhone-Signature
Kunci penandatangananRahasia webhook organisasiRahasia webhook organisasi

Kedua jalur bersifat memblokir — AI menunggu hasil di tengah kalimat. Batas waktu default adalah 20 dtk; tetapkan timeout tingkat teratas alat untuk mengizinkan eksekusi yang lebih lama, hingga maksimum Platform 180 dtk. Pastikan handler tetap cepat. Kombinasi dapat digunakan: pada panggilan dengan organisasi yang memiliki URL webhook, alat dengan endpoint dipanggil langsung dan sisanya menggunakan webhook.

Panggilan endpoint langsung

Saat AI memanggil tool yang memiliki endpoint, ThunderPhone mengirimkan permintaan ke URL Anda:

Header Permintaan

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

Header kustom dari endpoint.headers Anda selalu disertakan secara verbatim, ditambah dua header dengan namespace ThunderPhone:

  • X-ThunderPhone-Signature — HMAC-SHA256 dari byte body permintaan yang persis sama, menggunakan secret webhook organisasi Anda sebagai kunci
  • X-ThunderPhone-Call-ID — ID panggilan saat ini

Content-Type: application/json ditetapkan kecuali endpoint.headers Anda menimpanya — Content-Type kustom diprioritaskan.

Body Permintaan

Untuk POST / PUT / PATCH, body hanya berisi argumen tool (tanpa wrapper), diserialisasi secara kanonis (kunci diurutkan, pemisah ringkas):

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

Untuk GET / DELETE, argumen dikirim sebagai parameter kueri dan body kosong — tanda tangan kemudian dihitung berdasarkan string byte kosong. Lihat Verifikasi tanda tangan webhook.

Respons

Kembalikan respons JSON dengan hasil tool:

{
  "available_slots": ["9:00 AM", "2:00 PM", "4:30 PM"],
  "timezone": "America/Los_Angeles"
}

Respons diformat dan diberikan kepada AI untuk melanjutkan percakapan. Respons non-JSON dibungkus sebagai {"data": "<text>"}; waktu habis dan kegagalan koneksi dilaporkan kepada AI sebagai error, sehingga agen dapat meminta maaf dan melanjutkan alih-alih terhenti.

Dispatch mode webhook

Tool tanpa endpoint dikirim ke URL webhook lama organisasi Anda sebagai permintaan telephony.tool (panggilan telepon) atau web.tool (panggilan web) yang ditandatangani. Berbeda dengan notifikasi audit yang dikirim ke endpoint webhook setelah eksekusi, permintaan ini adalah eksekusinya — respons HTTP Anda merupakan hasil tool.

{
  "type": "telephony.tool",
  "data": {
    "call_id": 987654321,
    "tool_name": "search_appointments",
    "arguments": { "date": "2026-04-21" },
    "from_number": "+14155550199",
    "to_number": "+15551234567"
  }
}

web.tool membawa origin_domain sebagai pengganti from_number / to_number. Respons dengan hasil tool sebagai JSON — kontrak responsnya sama seperti panggilan endpoint langsung. Permintaan ditandatangani menggunakan secret webhook organisasi pada body mentah, seperti setiap webhook lainnya.


Verifikasi Tanda Tangan

Panggilan alat langsung ditandatangani dengan cara yang sama seperti webhook:

  • HMAC-SHA256 pada byte isi permintaan yang persis sama (JSON kanonis — kunci diurutkan, tanpa spasi tambahan)
  • Dikunci dengan secret webhook organisasi Anda
  • Alat GET / DELETE menandatangani string byte kosong
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 });
});

Resep lengkap — termasuk kasus isi kosong dan peringatan tanpa secret — tersedia di Verifikasi tanda tangan webhook.


Contoh: Alur Pemesanan Lengkap

Berikut adalah serangkaian alat untuk sistem pemesanan janji temu lengkap:

{
  "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" }
      }
    }
  ]
}

Praktik Terbaik

Tulis deskripsi yang jelas

Kolom description membantu AI memahami kapan harus menggunakan alat tersebut. Jelaskan secara spesifik fungsinya dan kapan alat tersebut sesuai digunakan.

Tangani kesalahan dengan baik

Kembalikan pesan kesalahan yang dapat dipahami AI: {"error": "No slots available for that date"} alih-alih kesalahan 500 umum.

Jaga respons tetap ringkas

Kembalikan hanya hal yang diperlukan AI untuk melanjutkan percakapan. Payload besar memperlambat waktu respons.

Gunakan kolom wajib dengan bijak

Tandai kolom sebagai required hanya jika benar-benar diperlukan. AI akan meminta informasi yang diperlukan kepada pengguna sebelum memanggil alat tersebut.


Terkait