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
- Definisikan alat dengan skema (argumen yang diterima alat)
- Sediakan konfigurasi
endpoint(tempat ThunderPhone memanggil API Anda) — atau kosongkan untuk menerima panggilan alat pada webhook organisasi Anda - Selama panggilan, AI memutuskan kapan menggunakan alat berdasarkan percakapan
- ThunderPhone memanggil endpoint Anda dengan argumen alat
- 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
| Kolom | Tipe | Wajib | Deskripsi |
|---|---|---|---|
timeout | angka | Tidak | Waktu eksekusi maksimum dalam detik (default: 20, maksimum: 180) |
Definisi Fungsi
| Kolom | Tipe | Wajib | Deskripsi |
|---|---|---|---|
name | string | Ya | Pengidentifikasi unik untuk alat |
description | string | Ya | Menjelaskan kepada AI kapan alat ini digunakan |
parameters | objek | Ya | JSON Schema untuk argumen alat |
Konfigurasi Endpoint
| Kolom | Tipe | Wajib | Deskripsi |
|---|---|---|---|
url | string | Ya | URL endpoint API Anda |
method | string | Tidak | Metode HTTP (default: POST) |
headers | objek | Tidak | Header kustom yang akan disertakan |
Dua jalur pemanggilan
Permintaan yang diterima server Anda bergantung pada apakah alat memiliki
endpoint:
Alat dengan endpoint | Alat tanpa endpoint | |
|---|---|---|
| Tujuan permintaan | Langsung ke endpoint.url | URL webhook lama organisasi Anda |
| Isi | Argumen alat tanpa pembungkus | Pembungkus telephony.tool / web.tool |
| Header | endpoint.headers Anda + X-ThunderPhone-Call-ID + X-ThunderPhone-Signature | Content-Type + X-ThunderPhone-Signature |
| Kunci penandatanganan | Rahasia webhook organisasi | Rahasia 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-keyHeader 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 kunciX-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/DELETEmenandatangani string byte kosong
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 });
});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
Alat yang dikelola Platform untuk HubSpot, Salesforce, Slack, Google Calendar, Google Sheets, dan Cal.com — tidak memerlukan endpoint.
Hubungkan server MCP dan biarkan agen memanggil alatnya.
Integrasi REST yang dapat digunakan kembali dan dapat Anda hubungkan ke agen.
Satu bantuan verifikasi untuk webhook dan panggilan alat.