Alati funkcija

Funkcijski alati omogućuju vašim AI glasovnim agentima pozivanje vanjskih API-ja tijekom telefonskih poziva. Upotrijebite ih za dohvaćanje podataka o korisnicima, provjeru dostupnosti, rezerviranje termina ili izvršavanje bilo koje radnje koju podržava vaš pozadinski sustav.

Kako funkcionira

  1. Definirate alate sa shemom (koje argumente alat prihvaća)
  2. Navedete konfiguraciju endpoint (gdje ThunderPhone poziva vaš API) — ili je izostavite kako biste primali pozive alata na webhook svoje organizacije
  3. Tijekom poziva AI odlučuje kada upotrijebiti alat na temelju razgovora
  4. ThunderPhone poziva vašu krajnju točku s argumentima alata
  5. Odgovor vašeg API-ja vraća se AI-ju za nastavak razgovora

Shema alata

Svaki alat slijedi ovu 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"
    }
  }
}

Definicija funkcije

PoljeVrstaObaveznoOpis
namestringDaJedinstveni identifikator alata
descriptionstringDaObjašnjava AI-ju kada upotrijebiti ovaj alat
parametersobjectDaJSON shema za argumente alata

Konfiguracija krajnje točke

PoljeVrstaObaveznoOpis
urlstringDaURL krajnje točke vašeg API-ja
methodstringNeHTTP metoda (zadano: POST)
headersobjectNePrilagođena zaglavlja koja treba uključiti

Dva načina pozivanja

Zahtjev koji vaš poslužitelj prima ovisi o tome ima li alat endpoint:

Alat s endpointAlat bez endpoint
Kamo ide zahtjevIzravno na endpoint.urlNa URL naslijeđenog webhooka vaše organizacije
TijeloSamo argumenti alataOmotnica telephony.tool / web.tool
ZaglavljaVaša endpoint.headers + X-ThunderPhone-Call-ID + X-ThunderPhone-SignatureContent-Type + X-ThunderPhone-Signature
Ključ za potpisivanjeTajna webhooka organizacijeTajna webhooka organizacije

Oba načina su blokirajuća — AI usred rečenice čeka rezultat — uz vremensko ograničenje od 20 s. Obraditelji moraju biti brzi. Možete ih kombinirati: tijekom poziva čija organizacija ima URL webhooka alati s endpoint pozivaju se izravno, a ostali se vraćaju na webhook.

Izravni pozivi krajnje točke

Kada AI pozove alat koji ima endpoint, ThunderPhone šalje zahtjev na vaš URL:

Zaglavlja zahtjeva

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

Prilagođena zaglavlja iz vašeg endpoint.headers uvijek se uključuju doslovno, uz dva zaglavlja u imenskom prostoru ThunderPhonea:

Content-Type: application/json postavlja se osim ako ga vaš endpoint.headers ne nadjača — prilagođeni Content-Type ima prednost.

Tijelo zahtjeva

Za POST / PUT / PATCH, tijelo sadrži samo argumente alata (bez omotača), serijalizirane kanonski (sortirani ključevi, kompaktni razdjelnici):

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

Za GET / DELETE, argumenti se šalju kao parametri upita, a tijelo je prazno — potpis se tada izračunava nad praznim nizom bajtova. Pogledajte Provjerite potpise webhooka.

Odgovor

Vratite JSON odgovor s rezultatom alata:

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

Odgovor se formatira i pruža AI-ju za nastavak razgovora. Odgovori koji nisu JSON omataju se kao {"data": "<text>"}; vremenska ograničenja i pogreške povezivanja prijavljuju se AI-ju kao pogreške kako bi se agent mogao ispričati i nastaviti umjesto da zastane.

Distribucija u načinu rada webhooka

Alati bez endpoint šalju se na URL naslijeđenog webhooka vaše organizacije kao potpisani zahtjev telephony.tool (telefonski pozivi) ili web.tool (web-pozivi). Za razliku od obavijesti o reviziji dostavljenih krajnjim točkama webhooka nakon izvršavanja, ovaj zahtjev jest izvršavanje — vaš HTTP odgovor rezultat je alata.

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

web.tool sadrži origin_domain umjesto from_number / to_number. Odgovorite rezultatom alata kao JSON-om — isti ugovor odgovora kao za izravne pozive krajnje točke. Zahtjev je potpisan tajnim ključem webhooka organizacije nad neobrađenim tijelom, kao i svaki drugi webhook.


Provjera potpisa

Izravni pozivi alata potpisuju se na isti način kao webhookovi:

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 });
});

Potpuni primjeri — uključujući slučaj praznog tijela i napomenu o nedostatku tajne — nalaze se u odjeljku Provjera potpisa webhooka.


Primjer: cjeloviti tijek rezervacije

Evo skupa alata za cjelovit sustav rezervacije termina:

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

Najbolje prakse

Napišite jasne opise

Polje description pomaže AI-ju razumjeti kada upotrijebiti alat. Jasno navedite što alat radi i kada ga je prikladno koristiti.

Elegantno obradite pogreške

Vratite poruke o pogreškama koje AI može razumjeti: {"error": "No slots available for that date"} umjesto generičkih pogrešaka 500.

Neka odgovori budu sažeti

Vratite samo ono što AI treba za nastavak razgovora. Veliki korisni tereti usporavaju vrijeme odgovora.

Promišljeno koristite obavezna polja

Označite polja kao required samo kada je to doista potrebno. AI će od korisnika zatražiti obavezne informacije prije pozivanja alata.


Povezano