ThunderPhone 2.0 er lansert.Kom i gang selv – fra 2¢/min.Les mer om lanseringen

Function Tools

Funksjonsverktøy

Gi AI-agentene dine funksjonsverktøy som kaller eksterne API-er midt i samtalen – hent kundedata, bestill avtaler, oppdater oppføringer – med typede parametere.

Funksjonsverktøy lar stemmeagentene dine kalle eksterne API-er under telefonsamtaler. Bruk dem til å slå opp kundedata, sjekke tilgjengelighet, bestille avtaler eller utføre enhver handling backend-en din støtter.

Slik fungerer det

  1. Du definerer verktøy med et skjema (hvilke argumenter verktøyet godtar)
  2. Du oppgir en endpoint-konfigurasjon (der ThunderPhone kaller API-et ditt) — eller utelater den for å motta verktøykall på organisasjonens webhook
  3. Under en samtale avgjør AI-en når den skal bruke et verktøy basert på samtalen
  4. ThunderPhone kaller endepunktet ditt med verktøyargumentene
  5. API-svaret ditt mates tilbake til AI-en for å fortsette samtalen
MulighetHvor det kjørerOppsett
Innebygde verktøyThunderPhonePromptinstruksjoner; enkelte verktøy trenger også en agentinnstilling
AppkoblingerThunderPhone og den tilkoblede leverandørenKoble til kontoen og legg til godkjente handlinger
API-koblinger og funksjonsverktøyHTTP API-et dittDefiner endepunktet og skjemaet, eller motta funksjonskall via en webhook
MCP-servereEn ekstern MCP-serverLegg til serveren, oppdag verktøyene og legg den til agenten

Verktøyskjema

Hvert verktøy følger denne strukturen:

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

Verktøykonfigurasjon

FeltTypePåkrevdBeskrivelse
timeouttallNeiMaksimal kjøretid i sekunder (standard: 20, maksimum: 180)

Funksjonsdefinisjon

FeltTypePåkrevdBeskrivelse
namestrengJaUnik identifikator for verktøyet
descriptionstrengJaForklarer AI-en når dette verktøyet skal brukes
parametersobjektJaJSON Schema for verktøyargumenter

Endepunktkonfigurasjon

FeltTypePåkrevdBeskrivelse
urlstrengJaURL-en til API-endepunktet ditt
methodstrengNeiHTTP-metode (standard: POST)
headersobjektNeiEgendefinerte headere som skal inkluderes

To kallbaner

Hvilken forespørsel serveren din mottar, avhenger av om verktøyet har et endpoint:

Verktøy med endpointVerktøy uten endpoint
Hvor forespørselen sendesDirekte til endpoint.urlOrganisasjonens eldre webhook-URL
BrødtekstValgt forespørselsformat (rene argumenter som standard)telephony.tool / web.tool-omslag
HeadereDine endpoint.headers + X-ThunderPhone-Call-ID + X-ThunderPhone-Signature-V2 + X-ThunderPhone-SignatureContent-Type + X-ThunderPhone-Signature-V2 + X-ThunderPhone-Signature
SigneringsnøkkelOrganisasjonens webhook-hemmelighetOrganisasjonens webhook-hemmelighet

Begge banene er blokkerende — AI-en venter midt i en setning på resultatet. Standard tidsavbrudd er 20 s; angi verktøyets øverste timeout for å tillate lengre kjøretid, opptil plattformens maksimum på 180 s. Hold behandlere raske. En blanding fungerer fint: I en samtale der organisasjonen har en webhook-URL, kalles verktøy med et endpoint direkte, mens resten faller tilbake til webhooken.

Direkte endepunktkall

Når stemmeagenten kaller et verktøy som har et endpoint, sender ThunderPhone en forespørsel til URL-en din:

Forespørselsoverskrifter

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

Egendefinerte headere fra endpoint.headers inkluderes alltid ordrett, i tillegg til disse ThunderPhone-navngitte headerne:

  • X-ThunderPhone-Signature-V2 — tidsstemplet HMAC-SHA256 over metode, sti, spørring og brødtekst, med din organisasjons webhook-hemmelighet som nøkkel. Verifiser denne og avvis forespørsler som er eldre enn 5 minutter. Se Verifiser webhook-signaturer
  • X-ThunderPhone-Signature — eldre HMAC-SHA256 av de nøyaktige bytene i forespørselsbrødteksten, med samme nøkkel, fortsatt sendt for eksisterende verifikatorer
  • X-ThunderPhone-Call-ID — ID-en for gjeldende samtale

Content-Type: application/json angis med mindre endpoint.headers overstyrer den — en egendefinert Content-Type har forrang.

Forespørselsformat

Hver API-tilkobling har en request_format-innstilling. Velg vapi eller retell når et importert verktøy skal fortsette å kalle et endepunkt som er bygget for den plattformen. Nye og eksisterende tilkoblinger bruker standard som standard.

For POST / PUT / PATCH serialiserer ThunderPhone den valgte konvolutten kanonisk (sorterte nøkler, kompakte skilletegn). Begge signaturene dekker nøyaktig disse bytene.

Standard

standard sender bare verktøyargumentene, uten innpakning. Dette er standardinnstillingen og bevarer ThunderPhone sin opprinnelige forespørselskropp byte for byte:

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

Vapi

vapi sender Vapis tool-calls-servermelding i formen Vapi dokumenterer. call.id er ThunderPhone-anrops-ID-en. Verktøykallets id er unik for påkallingen og brukes på nytt til å matche endepunktets resultat. Kallet vises i både toolCallList og toolWithToolCallList, med function.arguments som et JSON-objekt:

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

Vapi-spesifikke felt som assistant, artifact og det fullstendige call-objektet sendes ikke.

Returner Vapis svarkonvolutt med samsvarende verktøykall-ID:

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

ThunderPhone gir AI-en den utpakkede result-strengen. Den godtar også en JSON-verdi for kompatibilitet med endepunkter som allerede returnerer en. En error i stedet for result returneres til AI-en som en verktøyfeil. Hvis endepunktet returnerer en feilformatert eller ikke-samsvarende Vapi-konvolutt, logger ThunderPhone en advarsel og faller tilbake til standard svarbehandling i stedet for å avbryte anropet.

Retell

retell sender forespørselen som er dokumentert for en egendefinert Retell- funksjon:

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

call-objektet inkluderer bare call_id. ThunderPhone inkluderer ikke Retell-spesifikke felt den ikke kan oppgi korrekt ved utsending, for eksempel agent_id, transcript, transcript_object, metadata eller dynamiske variabler. Retell godtar enhver svartekst; ThunderPhone sender den videre med standard svarbehandling.

For GET / DELETE sendes argumentene som spørringsparametere og brødteksten er tom uavhengig av request_format. V2-signaturen dekker spørringsstrengen slik den sendes; den eldre signaturen beregnes over den tomme bytestrengen. Se Verifiser webhook-signaturer.

Svar

Returner et JSON-svar med verktøyresultatet:

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

Svaret formateres og gis til stemmeagenten for å fortsette samtalen. Svar som ikke er JSON, pakkes inn som {"data": "<text>"}; tidsavbrudd og tilkoblingsfeil rapporteres til stemmeagenten som feil, slik at agenten kan beklage og gå videre i stedet for å stoppe opp.

Ruting i webhook-modus

Verktøy uten et endpoint rutes til organisasjonens eldre webhook-URL som en signert telephony.tool-forespørsel (telefonanrop) eller web.tool-forespørsel (nettanrop). I motsetning til revisjonsvarslene som leveres til webhook-endepunkter etter utførelse, er denne forespørselen selve utførelsen — HTTP-svaret ditt er verktøyresultatet.

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

web.tool inneholder origin_domain i stedet for from_number / to_number. Svar med verktøyresultatet som JSON — samme svarkontrakt som ved direkte endepunktkall. Forespørselen er signert med organisasjonens webhook-hemmelighet, med begge signaturheaderne, som alle andre webhooks.


Signaturverifisering

Direkte verktøykall signeres på samme måte som webhooks, med organisasjonens webhook-hemmelighet som nøkkel:

  • X-ThunderPhone-Signature-V2 signerer tidsstempelet, metoden, banen og spørringen slik de sendes, samt de nøyaktige byteverdiene i brødteksten. Avvis forespørsler der tidsstempelet avviker med mer enn 5 minutter fra klokken din.
  • X-ThunderPhone-Signature (eldre) signerer bare byteverdiene i brødteksten, den tomme bytestrengen for GET / DELETE. Den sendes fortsatt, uendret.

SDK-hjelpefunksjonene kontrollerer V2-headeren, inkludert 5-minuttersvinduet:

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

Fullstendige oppskrifter — den signerte strengen, et gjennomarbeidet eksempel, kode uten SDK-et, tilfellet GET / DELETE og forbeholdet om ingen hemmelighet — finner du i Verifiser webhook-signaturer.


Eksempel: Fullstendig bestillingsflyt

Her er et sett med verktøy for et komplett system for timebestilling:

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

Beste praksis

Skriv tydelige beskrivelser

Feltet description hjelper AI-en med å forstå når verktøyet skal brukes. Vær spesifikk om hva det gjør, og når det passer å bruke det.

Håndter feil på en god måte

Returner feilmeldinger AI-en kan forstå: {"error": "No slots available for that date"} i stedet for generiske 500-feil.

Hold svarene korte

Returner bare det AI-en trenger for å fortsette samtalen. Store nyttelaster gir tregere responstider.

Bruk obligatoriske felt med omtanke

Merk felt som required bare når det er helt nødvendig. AI-en vil be brukeren om obligatorisk informasjon før den kaller verktøyet.


Relatert