ThunderPhone 2.0 je tady.Spustíte sami, od 2 ¢/min.Přečíst oznámení

Function Tools

Nástroje funkcí

Poskytněte svým AI agentům nástroje funkcí, které během konverzace 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 provádění 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 a volání nástrojů budete přijímat na webhooku vaší 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
MožnostKde se spouštíNastavení
Vestavěné nástrojeThunderPhonePokyny v promptu; některé nástroje také vyžadují nastavení agenta
Připojení aplikacíThunderPhone a připojený poskytovatelPřipojte účet a přiřaďte schválené akce
Připojení API a funkční nástrojeVaše HTTP APIDefinujte endpoint a schéma nebo přijímejte volání funkcí přes webhook
Servery MCPVzdálený server MCPPřidejte server, zjistěte jeho nástroje a přiřaďte jej agentovi

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ězecAnoAdresa URL endpointu vašeho API
methodřetězecNeMetoda HTTP (výchozí: POST)
headersobjektNeVlastní hlavičky k zahrnutí

Dvě cesty volá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ěloVybraný formát požadavku (ve výchozím nastavení pouze argumenty)Obálka telephony.tool / web.tool
HlavičkyVaše endpoint.headers + X-ThunderPhone-Call-ID + X-ThunderPhone-Signature-V2 + X-ThunderPhone-SignatureContent-Type + X-ThunderPhone-Signature-V2 + 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, chcete-li povolit delší provádění, až do maximální hodnoty platformy 180 s. Udržujte obslužné rutiny rychlé. Kombinace je možná: při hovoru, jehož organizace má adresu URL webhooku, se nástroje s endpoint volají 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-V2: t=1767225600,v1=5f2c...
X-ThunderPhone-Signature: abc123...
X-ThunderPhone-Call-ID: 987654321
X-Api-Key: your-api-key

Vlastní hlavičky z endpoint.headers jsou vždy zahrnuty doslovně spolu s těmito hlavičkami v oboru názvů ThunderPhone:

  • X-ThunderPhone-Signature-V2 — HMAC-SHA256 s časovým razítkem pro metodu, cestu, dotaz a tělo, podepsaný vaším tajemstvím webhooku organizace. Ověřte jej a odmítněte požadavky starší než 5 minut; viz Ověření podpisů webhooků
  • X-ThunderPhone-Signature — starší HMAC-SHA256 přes přesné bajty těla požadavku, se stejným klíčem, stále odesílaný pro existující ověřovače
  • X-ThunderPhone-Call-ID — ID aktuálního hovoru

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

Formát požadavku

Každé připojení API má nastavení request_format. Zvolte vapi nebo retell, pokud má importovaný nástroj nadále volat endpoint vytvořený pro danou platformu. Nová i stávající připojení ve výchozím nastavení používají standard.

Pro POST / PUT / PATCH ThunderPhone serializuje vybranou obálku kanonicky (seřazené klíče, kompaktní oddělovače). Oba podpisy pokrývají tyto přesné bajty.

Standard

standard odesílá pouze argumenty nástroje bez obálky. Toto je výchozí nastavení a zachovává původní tělo požadavku ThunderPhone bajt po bajtu:

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

Vapi

vapi odesílá serverovou zprávu tool-calls platformy Vapi ve formátu dokumentovaném platformou Vapi. call.id je ID hovoru ThunderPhone. ID volání nástroje id je pro dané vyvolání jedinečné a znovu se používá ke spárování výsledku endpointu. Volání se zobrazí v toolCallList i toolWithToolCallList, přičemž function.arguments je objekt 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" }
          }
        }
      }
    ]
  }
}

Pole určená pouze pro Vapi, například assistant, artifact a celý objekt call, se neodesílají.

Vraťte obálku odpovědi Vapi s odpovídajícím ID volání nástroje:

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

ThunderPhone poskytne AI rozbalený řetězec result. Z důvodu kompatibility také přijímá hodnotu JSON z endpointů, které ji již vracejí. Položka error místo result je AI vrácena jako chyba nástroje. Pokud endpoint vrátí neplatnou nebo neshodující se obálku Vapi, ThunderPhone zaznamená varování a místo selhání hovoru použije standardní zpracování odpovědi.

Retell

retell odesílá požadavek dokumentovaný pro vlastní funkci Retell:

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

Objekt call obsahuje pouze call_id. ThunderPhone nezahrnuje specifická pole Retell, která při odeslání nemůže poctivě poskytnout, například agent_id, transcript, transcript_object, metadata nebo dynamické proměnné. Retell přijímá jakékoli tělo odpovědi; ThunderPhone jej předá pomocí standardního zpracování odpovědi.

Pro GET / DELETE se argumenty odesílají jako parametry dotazu a tělo je prázdné bez ohledu na request_format. Podpis V2 pokrývá řetězec dotazu v odeslané podobě; starší podpis se vypočítává z prázdného bajtového řetězce. 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 nahlášeny jako chyby, takže se agent může omluvit a pokračovat místo toho, aby se zasekl.

Odesílání v režimu webhooku

Nástroje bez endpoint jsou odesílány na adresu staršího 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čována 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 ve formátu JSON — se stejným kontraktem odpovědi jako při přímých voláních endpointu. Požadavek je podepsán tajným klíčem webhooku organizace a obsahuje obě hlavičky podpisu, stejně jako každý jiný webhook.


Ověření podpisu

Přímá volání nástrojů jsou podepisována stejným způsobem jako webhooky, pomocí tajného klíče webhooku vaší organizace:

  • X-ThunderPhone-Signature-V2 podepisuje časové razítko, metodu, cestu a dotaz tak, jak byly odeslány, a přesné bajty těla. Odmítněte požadavky, jejichž časové razítko se od vašeho času liší o více než 5 minut.
  • X-ThunderPhone-Signature (starší verze) podepisuje pouze bajty těla, pro GET / DELETE prázdný bajtový řetězec. Stále se odesílá beze změny.

Pomocné funkce SDK ověřují hlavičku V2 včetně 5minutového okna:

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

Úplné postupy — podepisovaný řetězec, praktický příklad, kód bez SDK, případ GET / DELETE a upozornění pro případ chybějícího tajného klíče — naleznete v části Ověření podpisů webhooků.


Příklad: Kompletní proces rezervace

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

{
  "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 nástroj použít. Konkrétně popište, co dělá a kdy je vhodné jej použít.

Zpracovávejte chyby správně

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

Udržujte odpovědi stručné

Vracejte pouze to, co AI potřebuje k pokračování v konverzaci. Velké datové objemy zpomalují dobu odezvy.

Používejte povinná pole uvážlivě

Označte pole jako required pouze tehdy, když je to skutečně nutné. AI před voláním nástroje požádá uživatele o povinné informace.


Související