ThunderPhone 2.0 je tady.Začnete bez obchodníka, od 2 ¢/min.Přečíst oznámení

Function Tools

Funkční nástroje

Poskytněte svým AI agentům funkční nástroje, které během hovoru volají externí API — načítají data zákazníků, rezervují schůzky, aktualizují záznamy — s typovanými parametry.

Funkční nástroje umožňují vašim AI agentům během telefonních hovorů volat externí API. Použijte je k vyhledávání údajů o zákaznících, kontrole dostupnosti, rezervaci schůzek nebo provedení jakékoli akce, kterou váš backend podporuje.

Jak to funguje

  1. Definujete nástroje pomocí schématu (jaké argumenty nástroj přijímá)
  2. Poskytnete konfiguraci endpoint (kam ThunderPhone volá vaše API) — nebo ji vynecháte, abyste přijímali volání nástrojů na webhooku své organizace
  3. Během hovoru AI podle konverzace rozhodne, kdy nástroj použít
  4. ThunderPhone zavolá váš endpoint s argumenty nástroje
  5. Odpověď vašeho API se předá zpět AI, aby mohla pokračovat v konverzaci

Schéma nástroje

Každý nástroj má tuto strukturu:

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

Konfigurace nástroje

PoleTypPovinnéPopis
timeoutčísloNeMaximální doba provádění v sekundách (výchozí: 20, maximum: 180)

Definice funkce

PoleTypPovinnéPopis
nameřetězecAnoJedinečný identifikátor nástroje
descriptionřetězecAnoVysvětluje AI, kdy má tento nástroj použít
parametersobjektAnoSchéma JSON pro argumenty nástroje

Konfigurace endpointu

PoleTypPovinnéPopis
urlřetězecAnoURL vašeho endpointu API
methodřetězecNeMetoda HTTP (výchozí: POST)
headersobjektNeVlastní hlavičky, které se mají zahrnout

Dvě cesty vyvolání

To, jaký požadavek váš server obdrží, závisí na tom, zda nástroj obsahuje endpoint:

Nástroj s endpointNástroj bez endpoint
Kam požadavek směřujePřímo na endpoint.urlNa starší URL webhooku vaší organizace
TěloPouhé argumenty nástrojeObálka telephony.tool / web.tool
HlavičkyVaše endpoint.headers + X-ThunderPhone-Call-ID + X-ThunderPhone-SignatureContent-Type + X-ThunderPhone-Signature
Podpisový klíčTajný klíč webhooku organizaceTajný klíč webhooku organizace

Obě cesty jsou blokující — AI uprostřed věty čeká na výsledek. Výchozí časový limit je 20 s; nastavte timeout na nejvyšší úrovni nástroje, pokud chcete povolit delší provádění, až do maxima platformy 180 s. Udržujte obslužné funkce rychlé. Kombinace je možná: při hovoru, jehož organizace má URL webhooku, jsou nástroje s endpoint volány přímo a ostatní se vrátí k webhooku.

Přímá volání endpointů

Když AI vyvolá nástroj, který má endpoint, ThunderPhone odešle požadavek na vaši adresu URL:

Hlavičky požadavku

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

Vlastní hlavičky z vašeho endpoint.headers jsou vždy zahrnuty doslovně spolu se dvěma hlavičkami ve jmenném prostoru ThunderPhone:

  • X-ThunderPhone-Signature — HMAC-SHA256 přes přesné bajty těla požadavku, s klíčem ve vašem tajemství webhooku organizace
  • X-ThunderPhone-Call-ID — ID aktuálního hovoru

Content-Type: application/json je nastaveno, pokud je nepřepíšou vaše endpoint.headers — vlastní Content-Type má přednost.

Tělo požadavku

Pro POST / PUT / PATCH tělo obsahuje pouze argumenty nástroje (bez obálky), serializované kanonicky (seřazené klíče, kompaktní oddělovače):

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

Pro GET / DELETE jsou argumenty odesílány jako parametry dotazu a tělo je prázdné — podpis se pak vypočítá přes prázdný bajtový řetězec. Viz Ověření podpisů webhooků.

Odpověď

Vraťte odpověď JSON s výsledkem nástroje:

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

Odpověď je naformátována a poskytnuta AI, aby mohla pokračovat v konverzaci. Odpovědi jiné než JSON jsou zabaleny jako {"data": "<text>"}; časové limity a selhání připojení jsou AI hlášeny jako chyby, takže se agent může omluvit a pokračovat, místo aby se zasekl.

Odesílání v režimu webhooku

Nástroje bez endpoint jsou odesílány na starší adresu URL webhooku vaší organizace jako podepsaný požadavek telephony.tool (telefonní hovory) nebo web.tool (webové hovory). Na rozdíl od oznámení auditu, která jsou doručena na endpointy webhooků po provedení, tento požadavek je provedením — vaše odpověď HTTP je výsledkem nástroje.

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

web.tool obsahuje origin_domain namísto from_number / to_number. Odpovězte výsledkem nástroje jako JSON — platí stejný kontrakt odpovědi jako pro přímá volání endpointů. Požadavek je podepsán tajemstvím webhooku organizace přes nezpracované tělo, stejně jako každý jiný webhook.


Ověření podpisu

Přímá volání nástrojů jsou podepisována stejným způsobem jako webhooky:

  • HMAC-SHA256 přes přesné bajty těla požadavku (kanonický JSON — seřazené klíče, bez nadbytečných mezer)
  • S použitím vašeho tajného klíče webhooku organizace
  • Nástroje GET / DELETE podepisují prázdný bajtový řetězec
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 });
});

Úplné postupy — včetně případu s prázdným tělem a upozornění pro případ bez tajného klíče — najdete v části Ověření podpisů webhooků.


Příklad: Kompletní tok rezervace

Zde je sada nástrojů pro kompletní systém rezervace schůzek:

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

Osvědčené postupy

Pište jasné popisy

Pole description pomáhá AI pochopit, kdy má nástroj použít. Jasně uveďte, co nástroj dělá a kdy je vhodné ho použít.

Chyby zpracovávejte vhodně

Vracíme chybové zprávy, kterým AI rozumí: {"error": "No slots available for that date"} namísto obecných chyb 500.

Odpovědi udržujte stručné

Vracejte pouze informace, které AI potřebuje k pokračování v konverzaci. Velké datové odpovědi zpomalují dobu odezvy.

Povinná pole používejte uvážlivě

Pole označujte jako required pouze tehdy, když je to skutečně nutné. AI si před voláním nástroje vyžádá od uživatele povinné informace.


Související