ThunderPhone 2.0 kini resmi hadir.Gunakan langsung secara mandiri, mulai 2¢/menit.Baca pengumumannya

Function Tools

Alat Fungsi

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

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

Cara Kerjanya

  1. Tentukan alat dengan skema (argumen yang diterima alat)
  2. Sediakan konfigurasi endpoint (tempat ThunderPhone memanggil API Anda) — atau biarkan kosong 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
KemampuanTempat dijalankanPenyiapan
Alat bawaanThunderPhoneInstruksi Prompt; beberapa alat juga memerlukan pengaturan agen
Koneksi aplikasiThunderPhone dan penyedia yang terhubungHubungkan akun dan lampirkan tindakan yang disetujui
Koneksi API dan alat fungsiAPI HTTP AndaTentukan endpoint dan skema, atau terima panggilan fungsi melalui webhook
Server MCPServer MCP jarak jauhTambahkan server, temukan alatnya, lalu lampirkan ke agen

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
timeoutnumberTidakWaktu eksekusi maksimum dalam detik (default: 20, maksimum: 180)

Definisi Fungsi

KolomTipeWajibDeskripsi
namestringYaPengenal unik untuk alat
descriptionstringYaMenjelaskan kepada AI kapan alat ini digunakan
parametersobjectYaSkema JSON untuk argumen alat

Konfigurasi Endpoint

KolomTipeWajibDeskripsi
urlstringYaURL endpoint API Anda
methodstringTidakMetode HTTP (default: POST)
headersobjectTidakHeader khusus yang akan disertakan

Dua jalur pemanggilan

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

Tool dengan endpointTool tanpa endpoint
Tujuan permintaanLangsung ke endpoint.urlURL webhook lama organisasi Anda
IsiFormat permintaan yang dipilih (argumen tanpa pembungkus secara default)Pembungkus telephony.tool / web.tool
Headerendpoint.headers Anda + X-ThunderPhone-Call-ID + X-ThunderPhone-Signature-V2 + X-ThunderPhone-SignatureContent-Type + X-ThunderPhone-Signature-V2 + X-ThunderPhone-Signature
Kunci penandatangananRahasia webhook organisasiRahasia webhook organisasi

Kedua jalur bersifat memblokir — AI menunggu hasilnya di tengah kalimat. Batas waktu default adalah 20 d; atur timeout tingkat atas pada alat untuk mengizinkan eksekusi yang lebih lama, hingga batas maksimum Platform 180 d. Pastikan handler tetap cepat. Kombinasi keduanya dapat digunakan: pada panggilan yang organisasinya memiliki URL webhook, alat dengan endpoint dipanggil secara langsung dan sisanya dialihkan ke webhook.

Panggilan endpoint langsung

Saat AI memanggil alat yang memiliki endpoint, ThunderPhone mengirim permintaan ke URL Anda:

Header Permintaan

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

Header kustom dari endpoint.headers Anda selalu disertakan apa adanya, ditambah header dengan namespace ThunderPhone berikut:

  • X-ThunderPhone-Signature-V2 — HMAC-SHA256 bertanda waktu atas metode, path, kueri, dan body, yang menggunakan secret webhook organisasi Anda. Verifikasi header ini dan tolak permintaan yang berusia lebih dari 5 menit; lihat Verifikasi signature webhook
  • X-ThunderPhone-Signature — HMAC-SHA256 lama dari byte body permintaan yang persis sama, dengan kunci yang sama, masih dikirim untuk verifier yang ada
  • X-ThunderPhone-Call-ID — ID panggilan saat ini

Content-Type: application/json ditetapkan kecuali endpoint.headers Anda menggantinya — Content-Type kustom akan digunakan.

Format permintaan

Setiap koneksi API memiliki pengaturan request_format. Pilih vapi atau retell ketika tool yang diimpor harus tetap memanggil endpoint yang dibuat untuk platform tersebut. Koneksi baru dan yang sudah ada secara default menggunakan standard.

Untuk POST / PUT / PATCH, ThunderPhone membuat serialisasi envelope yang dipilih secara kanonis (kunci diurutkan, pemisah ringkas). Kedua tanda tangan mencakup byte yang tepat ini.

Standard

standard hanya mengirim argumen alat, tanpa wrapper. Ini adalah default dan mempertahankan isi permintaan asli ThunderPhone byte demi byte:

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

Vapi

vapi mengirim pesan server tool-calls Vapi dalam bentuk yang didokumentasikan Vapi. call.id adalah ID panggilan ThunderPhone. id tool-call bersifat unik untuk pemanggilan tersebut dan digunakan kembali untuk mencocokkan hasil endpoint. Panggilan muncul di toolCallList dan toolWithToolCallList, dengan function.arguments sebagai objek 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" }
          }
        }
      }
    ]
  }
}

Kolom khusus Vapi seperti assistant, artifact, dan objek call lengkap tidak dikirim.

Kembalikan envelope respons Vapi dengan ID tool-call yang sesuai:

{
  "results": [
    {
      "toolCallId": "call_00112233445566778899aabbccddeeff",
      "result": "{\"available_slots\":[\"9:00 AM\",\"2:00 PM\"]}"
    }
  ]
}

ThunderPhone memberikan string result tanpa pembungkus kepada AI. ThunderPhone juga menerima nilai JSON untuk kompatibilitas dengan endpoint yang sudah mengembalikannya. error sebagai pengganti result dikembalikan kepada AI sebagai error tool. Jika endpoint mengembalikan envelope Vapi yang tidak valid atau tidak cocok, ThunderPhone mencatat peringatan dan beralih ke parsing respons standarnya alih-alih menggagalkan panggilan.

Retell

retell mengirim permintaan yang didokumentasikan untuk fungsi kustom Retell:

{
  "name": "search_appointments",
  "call": { "call_id": "987654321" },
  "args": { "date": "2025-01-02", "service": "consultation" }
}

Objek call hanya menyertakan call_id. ThunderPhone tidak menyertakan kolom khusus Retell yang tidak dapat disediakannya secara akurat saat pengiriman, seperti agent_id, transcript, transcript_object, metadata, atau variabel dinamis. Retell menerima isi respons apa pun; ThunderPhone meneruskannya menggunakan penanganan respons standar.

Untuk GET / DELETE, argumen dikirim sebagai parameter kueri dan isi permintaan kosong terlepas dari request_format. Tanda tangan V2 mencakup string kueri sebagaimana dikirim; tanda tangan lama dihitung berdasarkan string byte kosong. Lihat Verifikasi tanda tangan webhook.

Respons

Kembalikan respons JSON dengan hasil alat:

{
  "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 kesalahan, sehingga agen dapat meminta maaf dan melanjutkan alih-alih terhenti.

Pengiriman mode webhook

Alat 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 dikirimkan ke endpoint webhook setelah eksekusi, permintaan ini adalah eksekusinya — respons HTTP Anda adalah hasil alat.

{
  "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 alih-alih from_number / to_number. Tanggapi dengan hasil tool sebagai JSON — kontrak respons yang sama seperti panggilan endpoint langsung. Permintaan ditandatangani dengan rahasia webhook organisasi, menggunakan kedua header tanda tangan, seperti setiap webhook lainnya.


Verifikasi Tanda Tangan

Panggilan tool langsung ditandatangani dengan cara yang sama seperti webhook, menggunakan rahasia webhook organisasi Anda:

  • X-ThunderPhone-Signature-V2 menandatangani stempel waktu, metode, path, dan query sebagaimana dikirim, serta byte body yang tepat. Tolak permintaan yang stempel waktunya berjarak lebih dari 5 menit dari jam Anda.
  • X-ThunderPhone-Signature (legacy) hanya menandatangani byte body, yaitu string byte kosong untuk GET / DELETE. Header ini tetap dikirim, tanpa perubahan.

Helper SDK memeriksa header V2, termasuk jangka waktu 5 menit:

Python
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}
Node.js
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 });
});

Panduan lengkap — string yang ditandatangani, contoh yang dikerjakan, kode tanpa SDK, kasus GET / DELETE, dan catatan tanpa rahasia — 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 apa fungsinya dan kapan alat tersebut sesuai digunakan.

Tangani error dengan baik

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

Jaga respons tetap ringkas

Kembalikan hanya informasi 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 wajib dari pengguna sebelum memanggil alat.


Terkait