Funkcijska orodja

Funkcijska orodja vašim glasovnim agentom omogočajo klicanje zunanjih API-jev med telefonskimi klici. Z njimi lahko poiščete podatke o strankah, preverite razpoložljivost, rezervirate termine ali izvedete katero koli dejanje, ki ga podpira vaša zaledna infrastruktura.

Kako deluje

  1. Orodja določite s shemo (katere argumente orodje sprejema)
  2. Zagotovite konfiguracijo endpoint (kam ThunderPhone kliče vaš API) — ali jo izpustite, da klice orodij prejemate na spletni kljuki svoje organizacije
  3. Med klicem se UI na podlagi pogovora odloči, kdaj uporabiti orodje
  4. ThunderPhone pokliče vaš končni naslov z argumenti orodja
  5. Odgovor vašega API-ja se posreduje nazaj UI za nadaljevanje pogovora

Shema orodja

Vsako orodje sledi tej strukturi:

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

PoljeVrstaObveznoOpis
namenizDaEnolični identifikator orodja
descriptionnizDaUI pojasni, kdaj naj uporabi to orodje
parametersobjektDaShema JSON za argumente orodja

Konfiguracija končnega naslova

PoljeVrstaObveznoOpis
urlnizDaURL končnega naslova vašega API-ja
methodnizNeMetoda HTTP (privzeto: POST)
headersobjektNeGlave po meri, ki jih želite vključiti

Dve poti klicanja

Zahteva, ki jo prejme vaš strežnik, je odvisna od tega, ali ima orodje endpoint:

Orodje z endpointOrodje brez endpoint
Kam gre zahtevaNeposredno na endpoint.urlPodedovani URL spletne kljuke vaše organizacije
TeloSamo argumenti orodjaOvojnica telephony.tool / web.tool
GlaveVaše endpoint.headers + X-ThunderPhone-Call-ID + X-ThunderPhone-SignatureContent-Type + X-ThunderPhone-Signature
Ključ za podpisovanjeSkrivnost spletne kljuke organizacijeSkrivnost spletne kljuke organizacije

Obe poti sta blokirni — UI sredi stavka čaka na rezultat — s časovno omejitvijo 20 s. Obdelovalnike ohranite hitre. Kombinacija je možna: pri klicu, katerega organizacija ima URL spletne kljuke, se orodja z endpoint pokličejo neposredno, preostala pa se vrnejo na spletno kljuko.

Neposredni klici končne točke

Ko AI prikliče orodje, ki ima endpoint, ThunderPhone pošlje zahtevek na vaš URL:

Glave zahtevka

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

Glave po meri iz vašega endpoint.headers so vedno vključene dobesedno, skupaj z dvema glavama v imenskem prostoru ThunderPhone:

Content-Type: application/json je nastavljen, razen če ga vaš endpoint.headers preglasi — Content-Type po meri ima prednost.

Telo zahtevka

Za POST / PUT / PATCH telo vsebuje samo argumente orodja (brez ovoja), kanonično serializirane (urejeni ključi, strnjena ločila):

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

Za GET / DELETE so argumenti poslani kot parametri poizvedbe, telo pa je prazno — podpis se nato izračuna nad praznim bajtnim nizom. Glejte Preverjanje podpisov webhookov.

Odgovor

Vrnite odgovor JSON z rezultatom orodja:

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

Odgovor je oblikovan in posredovan AI-ju za nadaljevanje pogovora. Odgovori, ki niso JSON, so oviti kot {"data": "<text>"}; časovne prekoračitve in napake povezave so AI-ju sporočene kot napake, zato se lahko agent opraviči in nadaljuje, namesto da bi obstal.

Usmerjanje v načinu webhook

Orodja brez endpoint so poslana na podedovani URL webhooka vaše organizacije kot podpisan zahtevek telephony.tool (telefonski klici) ali web.tool (spletni klici). Za razliko od obvestil za revizijo, dostavljenih na končne točke webhookov po izvedbi, je ta zahtevek sam izvedba — vaš odgovor HTTP je rezultat orodja.

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

web.tool vsebuje origin_domain namesto from_number / to_number. Odgovorite z rezultatom orodja kot JSON — ista pogodba odgovora kot pri neposrednih klicih končne točke. Zahtevek je podpisan s skrivnostjo webhooka organizacije nad neobdelanim telesom, kot vsak drug webhook.


Preverjanje podpisa

Neposredni klici orodij so podpisani enako kot spletni kavlji:

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

Celotni recepti — vključno s primerom praznega telesa in opozorilom glede manjkajoče skrivnosti — so v razdelku Preverjanje podpisov spletnih kavljev.


Primer: celoten potek rezervacije

Tukaj je nabor orodij za celovit sistem rezervacije terminov:

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

Najboljše prakse

Napišite jasne opise

Polje description pomaga UI razumeti, kdaj naj uporabi orodje. Natančno opišite, kaj orodje počne in kdaj ga je primerno uporabiti.

Ustrezno obravnavajte napake

Vrnite sporočila o napakah, ki jih UI razume: {"error": "No slots available for that date"} namesto splošnih napak 500.

Odgovori naj bodo jedrnati

Vrnite le tisto, kar UI potrebuje za nadaljevanje pogovora. Veliki koristni tovori upočasnijo odzivni čas.

Polja, ki so obvezna, uporabljajte premišljeno

Polja označite kot required le, kadar je to res potrebno. UI bo uporabnika pred klicem orodja vprašal za zahtevane informacije.


Povezano