Open in
Funktionsværktøjer
Giv dine AI-agenter funktionsværktøjer, der kalder eksterne API
Funktionsværktøjer giver dine AI-agenter mulighed for at kalde eksterne API'er under opkald. Brug dem til at slå kundedata op, kontrollere tilgængelighed, booke aftaler eller udføre enhver handling, som din backend understøtter.
Sådan fungerer det
- Du definerer værktøjer med et skema (hvilke argumenter værktøjet accepterer)
- Du angiver en
endpoint-konfiguration (hvor ThunderPhone kalder dit API) — eller udelader den for at modtage værktøjskald på din organisations webhook - Under et opkald beslutter AI'en, hvornår et værktøj skal bruges, baseret på samtalen
- ThunderPhone kalder dit endpoint med værktøjsargumenterne
- Dit API-svar sendes tilbage til AI'en for at fortsætte samtalen
| Funktionalitet | Hvor den kører | Opsætning |
|---|---|---|
| Indbyggede værktøjer | ThunderPhone | Promptinstruktioner; nogle værktøjer kræver også en agentindstilling |
| Appforbindelser | ThunderPhone og den tilsluttede udbyder | Forbind kontoen, og tilknyt godkendte handlinger |
| API-forbindelser og funktionsværktøjer | Dit HTTP API | Definer endpointet og skemaet, eller modtag funktionskald via en webhook |
| MCP-servere | En fjern MCP-server | Tilføj serveren, find dens værktøjer, og tilknyt den til agenten |
Værktøjsskema
Hvert værktøj følger denne 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
}Værktøjskonfiguration
| Felt | Type | Påkrævet | Beskrivelse |
|---|---|---|---|
timeout | tal | Nej | Maksimal udførelsestid i sekunder (standard: 20, maksimum: 180) |
Funktionsdefinition
| Felt | Type | Påkrævet | Beskrivelse |
|---|---|---|---|
name | streng | Ja | Unik identifikator for værktøjet |
description | streng | Ja | Forklarer AI'en, hvornår dette værktøj skal bruges |
parameters | objekt | Ja | JSON-skema for værktøjsargumenter |
Endpointkonfiguration
| Felt | Type | Påkrævet | Beskrivelse |
|---|---|---|---|
url | streng | Ja | URL'en til dit API-endpoint |
method | streng | Nej | HTTP-metode (standard: POST) |
headers | objekt | Nej | Tilpassede headere, der skal inkluderes |
To kaldestier
Hvilken anmodning din server modtager, afhænger af, om værktøjet har et
endpoint:
Værktøj med endpoint | Værktøj uden endpoint | |
|---|---|---|
| Hvor anmodningen sendes hen | Direkte til endpoint.url | Din organisations ældre webhook-URL |
| Brødtekst | Valgt anmodningsformat (rene argumenter som standard) | telephony.tool / web.tool-indpakning |
| Headere | Dine endpoint.headers + X-ThunderPhone-Call-ID + X-ThunderPhone-Signature-V2 + X-ThunderPhone-Signature | Content-Type + X-ThunderPhone-Signature-V2 + X-ThunderPhone-Signature |
| Signeringsnøgle | Organisationens webhook-hemmelighed | Organisationens webhook-hemmelighed |
Begge stier er blokerende — AI'en venter midt i en sætning på
resultatet. Standardtimeouttet er 20 s; angiv værktøjets timeout
på øverste niveau for at tillade en længere udførelse, op til platformens
maksimum på 180 s. Hold handlere hurtige. En blanding er helt fint:
Ved et opkald, hvis organisation har en webhook-URL, kaldes værktøjer med et
endpoint direkte, og resten falder tilbage til webhooken.
Direkte endpointkald
Når AI'en kalder et værktøj, der har et endpoint, sender ThunderPhone
en anmodning til din URL:
Anmodningsheadere
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-keyBrugerdefinerede headere fra dine endpoint.headers medtages altid
uændret sammen med disse ThunderPhone-navnerumsheadere:
X-ThunderPhone-Signature-V2— tidsstemplet HMAC-SHA256 over metoden, stien, forespørgslen og brødteksten, med din organisations-webhookhemmelighed som nøgle. Verificer denne, og afvis forespørgsler, der er mere end 5 minutter gamle; se Verificer webhooksignaturerX-ThunderPhone-Signature— ældre HMAC-SHA256 af de nøjagtige byte i forespørgselsbrødteksten, med samme nøgle, sendes stadig til eksisterende verifikatorerX-ThunderPhone-Call-ID— Det aktuelle opkalds-ID
Content-Type: application/json angives, medmindre dit endpoint.headers
overskriver det — en brugerdefineret Content-Type har forrang.
Anmodningsformat
Hver API-forbindelse har en indstilling for request_format. Vælg vapi eller
retell, når et importeret værktøj fortsat skal kalde et endpoint, der er bygget til
den pågældende platform. Nye og eksisterende forbindelser bruger som standard standard.
For POST / PUT / PATCH serialiserer ThunderPhone den valgte
indpakning kanonisk (sorterede nøgler, kompakte skilletegn). Begge signaturer
dækker disse nøjagtige bytes.
Standard
standard sender kun værktøjsargumenterne uden wrapper. Dette er
standarden og bevarer ThunderPhone's oprindelige anmodningsbrødtekst byte for byte:
{"date":"2025-01-02","service":"consultation"}Vapi
vapi sender Vapis tool-calls-servermeddelelse
i det format, Vapi dokumenterer. call.id er ThunderPhone-opkalds-ID'et. Værktøjskaldets
id er unikt for påkaldelsen og genbruges til at matche endpointets
resultat. Opkaldet vises både i 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-specifikke felter som assistant, artifact og det fulde call-objekt
sendes ikke.
Returner Vapis svarindpakning med det matchende værktøjskalds-ID:
{
"results": [
{
"toolCallId": "call_00112233445566778899aabbccddeeff",
"result": "{\"available_slots\":[\"9:00 AM\",\"2:00 PM\"]}"
}
]
}ThunderPhone giver AI'en den udpakkede result-streng. Den accepterer også en
JSON-værdi for kompatibilitet med endpoints, der allerede returnerer en. En
error i stedet for result returneres til AI'en som en værktøjsfejl. Hvis
endpointet returnerer en forkert formateret eller ikke-matchende Vapi-indpakning, logger ThunderPhone
en advarsel og falder tilbage til sin standardfortolkning af svar i stedet for at afbryde
opkaldet.
Retell
retell sender anmodningen, der er dokumenteret for en Retell-tilpasset
funktion:
{
"name": "search_appointments",
"call": { "call_id": "987654321" },
"args": { "date": "2025-01-02", "service": "consultation" }
}call-objektet indeholder kun call_id. ThunderPhone inkluderer ikke
Retell-specifikke felter, som den ikke reelt kan levere ved afsendelse, såsom
agent_id, transcript, transcript_object, metadata eller dynamiske
variabler. Retell accepterer enhver svartekst; ThunderPhone videresender den
ved hjælp af standardhåndteringen af svar.
For GET / DELETE sendes argumenterne som queryparametre
og brødteksten er tom uanset request_format. V2-signaturen
dækker querystrengen, som den sendes; den ældre signatur beregnes over
den tomme bytestreng. Se
Verificer webhook-signaturer.
Svar
Returner et JSON-svar med værktøjsresultatet:
{
"available_slots": ["9:00 AM", "2:00 PM", "4:30 PM"],
"timezone": "America/Los_Angeles"
}Svaret formateres og gives til AI'en, så den kan fortsætte
samtalen. Ikke-JSON-svar indpakkes som {"data": "<text>"};
timeouts og forbindelsesfejl rapporteres til AI'en som fejl, så
agenten kan undskylde og fortsætte i stedet for at gå i stå.
Afsendelse i webhooktilstand
Værktøjer uden et endpoint sendes til din organisations ældre
webhook-URL som en signeret telephony.tool-anmodning (telefonopkald) eller
web.tool-anmodning (webopkald). I modsætning til
revisionsnotifikationerne, der leveres til webhookendpoints efter
udførelse, er denne anmodning udførelsen — dit HTTP-svar er
værktøjsresultatet.
{
"type": "telephony.tool",
"data": {
"call_id": 987654321,
"tool_name": "search_appointments",
"arguments": { "date": "2026-04-21" },
"from_number": "+14155550199",
"to_number": "+15551234567"
}
}web.tool indeholder origin_domain i stedet for from_number /
to_number. Svar med værktøjsresultatet som JSON — samme svarformat
som ved direkte endpointkald. Anmodningen er signeret med organisationens
webhook-hemmelighed og begge signaturheadere, ligesom alle andre webhooks.
Signaturverificering
Direkte værktøjskald signeres på samme måde som webhooks med din organisations webhook-hemmelighed:
X-ThunderPhone-Signature-V2signerer tidsstemplet, metoden, stien og forespørgselsstrengen som sendt samt de nøjagtige bytes i brødteksten. Afvis anmodninger, hvis deres tidsstempel afviger mere end 5 minutter fra dit ur.X-ThunderPhone-Signature(forældet) signerer kun bytes i brødteksten og den tomme bytestreng forGET/DELETE. Den sendes stadig uændret.
SDK-hjælpefunktionerne kontrollerer V2-headeren, herunder 5-minuttersvinduet:
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}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 });
});Fuldstændige opskrifter — den signerede streng, et gennemarbejdet eksempel, kode uden
SDK'et, tilfældet med GET / DELETE og forbeholdet om ingen hemmelighed — findes i Bekræft webhook-signaturer.
Eksempel: Komplet bookingflow
Her er et sæt værktøjer til et komplet system til tidsbestilling:
{
"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" }
}
}
]
}Bedste praksis
Skriv klare beskrivelser
Feltet description hjælper AI'en med at forstå, hvornår værktøjet skal bruges. Vær specifik om, hvad det gør, og hvornår det er relevant.
Håndter fejl elegant
Returnér fejlmeddelelser, som AI'en kan forstå: {"error": "No slots available for that date"} frem for generiske 500-fejl.
Hold svar korte
Returnér kun det, AI'en har brug for, for at fortsætte samtalen. Store payloads gør svartiderne langsommere.
Brug obligatoriske felter med omtanke
Markér kun felter som required, når det er absolut nødvendigt. AI'en vil bede brugeren om obligatoriske oplysninger, før værktøjet kaldes.
Relateret
Anmod om platformadministrerede opkaldshandlinger uden at definere et endpoint.
Platformadministrerede værktøjer til HubSpot, Salesforce, Slack, Google Kalender, Google Sheets og Cal.com — intet endpoint påkrævet.
Tilknyt en MCP-server, og lad agenten kalde dens værktøjer.
Genanvendelige REST-integrationer, som du kan tilknytte agenter.
Én bekræftelseshjælper til webhooks og værktøjskald.