ThunderPhone 2.0 är här.Kom igång själv, från 2 cent/minut.Läs lanseringsnyheten

Function Tools

Funktionsverktyg

Ge dina AI-agenter funktionsverktyg som anropar externa API:er mitt i samtalet — hämta kunddata, boka tider, uppdatera poster — med typade parametrar.

Funktionsverktyg gör det möjligt för dina AI-agenter att anropa externa API:er under telefonsamtal. Använd dem för att slå upp kunddata, kontrollera tillgänglighet, boka möten eller utföra valfri åtgärd som din backend stöder.

Så fungerar det

  1. Du definierar verktyg med ett schema (vilka argument verktyget accepterar)
  2. Du anger en endpoint-konfiguration (där ThunderPhone anropar ditt API) — eller utelämnar den för att ta emot verktygsanrop på din organisations webhook
  3. Under ett samtal avgör AI:n när ett verktyg ska användas baserat på konversationen
  4. ThunderPhone anropar din endpoint med verktygsargumenten
  5. Ditt API-svar skickas tillbaka till AI:n för att fortsätta konversationen

Verktygsschema

Varje verktyg följer denna struktur:

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

Verktygskonfiguration

FältTypKrävsBeskrivning
timeoutnumberNejMaximal körningstid i sekunder (standard: 20, maximalt: 180)

Funktionsdefinition

FältTypKrävsBeskrivning
namestringJaUnik identifierare för verktyget
descriptionstringJaFörklarar för AI:n när verktyget ska användas
parametersobjectJaJSON Schema för verktygsargument

Endpoint-konfiguration

FältTypKrävsBeskrivning
urlstringJaURL:en för din API-endpoint
methodstringNejHTTP-metod (standard: POST)
headersobjectNejAnpassade headers att inkludera

Två anropsvägar

Vilken begäran din server tar emot beror på om verktyget har en endpoint:

Verktyg med endpointVerktyg utan endpoint
Vart begäran skickasDirekt till endpoint.urlDin organisations äldre webhook-URL
InnehållEndast verktygsargumenttelephony.tool / web.tool-omslag
HTTP-huvudenDina endpoint.headers + X-ThunderPhone-Call-ID + X-ThunderPhone-SignatureContent-Type + X-ThunderPhone-Signature
SigneringsnyckelOrganisationens webhook-hemlighetOrganisationens webhook-hemlighet

Båda vägarna är blockerande — AI:n väntar mitt i en mening på resultatet. Standardtimeouten är 20 s; ange verktygets timeout på toppnivå för att tillåta en längre körningstid, upp till plattformens maxgräns på 180 s. Håll hanterare snabba. Du kan blanda dem: i ett samtal där organisationen har en webhook-URL anropas verktyg med en endpoint direkt, medan övriga faller tillbaka till webhooken.

Direkta endpointanrop

När AI:n anropar ett verktyg som har ett endpoint skickar ThunderPhone en begäran till din URL:

Begärandehuvuden

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

Anpassade huvuden från ditt endpoint.headers inkluderas alltid ordagrant, tillsammans med två ThunderPhone-namnområdesindelade huvuden:

  • X-ThunderPhone-Signature — HMAC-SHA256 av de exakta bytevärdena i begärandetexten, med din organisations webhookhemlighet som nyckel
  • X-ThunderPhone-Call-ID — ID:t för det aktuella samtalet

Content-Type: application/json anges om det inte åsidosätts av ditt endpoint.headers — en anpassad Content-Type har företräde.

Begärandetext

För POST / PUT / PATCH innehåller texten endast verktygsargumenten (inget omslag), serialiserade kanoniskt (sorterade nycklar, kompakta avgränsare):

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

För GET / DELETE skickas argumenten som frågeparametrar och texten är tom — signaturen beräknas då över den tomma bytesträngen. Se Verifiera webhooksignaturer.

Svar

Returnera ett JSON-svar med verktygsresultatet:

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

Svaret formateras och skickas till AI:n för att fortsätta konversationen. Icke-JSON-svar omsluts som {"data": "<text>"}; tidsgränser och anslutningsfel rapporteras till AI:n som fel, så att agenten kan be om ursäkt och gå vidare i stället för att fastna.

Utskick i webhookläge

Verktyg utan ett endpoint skickas till organisationens äldre webhook-URL som en signerad telephony.tool-begäran (telefonsamtal) eller web.tool-begäran (webbsamtal). Till skillnad från granskningsnotiserna som levereras till webhook-endpoints efter körning, är denna begäran körningen — ditt HTTP-svar är verktygsresultatet.

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

web.tool innehåller origin_domain i stället för from_number / to_number. Svara med verktygsresultatet som JSON — samma svarskontrakt som för direkta endpointanrop. Begäran signeras med organisationens webhookhemlighet över den råa texten, precis som alla andra webhookar.


Signaturverifiering

Direkta verktygsanrop signeras på samma sätt som webhooks:

  • HMAC-SHA256 över de exakta bytevärdena i förfrågningstexten (det kanoniska JSON-formatet — sorterade nycklar, inga extra blanksteg)
  • Signeras med din organisations webhook-hemlighet
  • Verktyg med GET / DELETE signerar den tomma bytesträngen
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 });
});

Kompletta exempel — inklusive fallet med tom förfrågningstext och information om när ingen hemlighet har angetts — finns i Verifiera webhook-signaturer.


Exempel: Komplett bokningsflöde

Här är en uppsättning verktyg för ett komplett system för tidsbokning:

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

Bästa praxis

Skriv tydliga beskrivningar

Fältet description hjälper AI:n att förstå när verktyget ska användas. Var specifik om vad det gör och när det är lämpligt.

Hantera fel smidigt

Returnera felmeddelanden som AI:n kan förstå: {"error": "No slots available for that date"} i stället för generiska 500-fel.

Håll svaren kortfattade

Returnera endast det AI:n behöver för att fortsätta samtalet. Stora nyttolaster förlänger svarstiderna.

Använd obligatoriska fält med omdöme

Markera fält som required endast när det verkligen behövs. AI:n ber användaren om obligatorisk information innan verktyget anropas.


Relaterat