Open in
Narzędzia funkcji
Wyposaż swoich agentów AI w narzędzia funkcji, które wywołują zewnętrzne interfejsy API w trakcie rozmowy — pobierają dane klientów, umawiają wizyty, aktualizują rekordy — z parametrami o określonych typach.
Narzędzia funkcji umożliwiają agentom AI wywoływanie zewnętrznych interfejsów API podczas rozmów telefonicznych. Używaj ich do wyszukiwania danych klientów, sprawdzania dostępności, umawiania wizyt lub wykonywania dowolnych działań obsługiwanych przez Twój backend.
Jak to działa
- Zdefiniuj narzędzia za pomocą schematu (jakie argumenty akceptuje narzędzie)
- Podaj konfigurację
endpoint(gdzie ThunderPhone wywołuje Twój interfejs API) — lub ją pomiń, aby otrzymywać wywołania narzędzi na webhooku organizacji - Podczas rozmowy AI decyduje, kiedy użyć narzędzia, na podstawie konwersacji
- ThunderPhone wywołuje Twój endpoint z argumentami narzędzia
- Odpowiedź Twojego API jest przekazywana z powrotem do AI, aby kontynuować konwersację
| Możliwość | Gdzie działa | Konfiguracja |
|---|---|---|
| Wbudowane narzędzia | ThunderPhone | Instrukcje w prompcie; niektóre narzędzia wymagają także ustawienia agenta |
| Połączenia z aplikacjami | ThunderPhone i połączony dostawca | Połącz konto i przypisz zatwierdzone działania |
| Połączenia API i narzędzia funkcji | Twój interfejs HTTP API | Zdefiniuj endpoint i schemat lub odbieraj wywołania funkcji przez webhook |
| Serwery MCP | Zdalny serwer MCP | Dodaj serwer, wykryj jego narzędzia i przypisz go do agenta |
Schemat narzędzia
Każde narzędzie ma następującą 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
}Konfiguracja narzędzia
| Pole | Typ | Wymagane | Opis |
|---|---|---|---|
timeout | liczba | Nie | Maksymalny czas wykonania w sekundach (domyślnie: 20, maksymalnie: 180) |
Definicja funkcji
| Pole | Typ | Wymagane | Opis |
|---|---|---|---|
name | ciąg znaków | Tak | Unikalny identyfikator narzędzia |
description | ciąg znaków | Tak | Wyjaśnia AI, kiedy użyć tego narzędzia |
parameters | obiekt | Tak | Schemat JSON argumentów narzędzia |
Konfiguracja endpointu
| Pole | Typ | Wymagane | Opis |
|---|---|---|---|
url | ciąg znaków | Tak | Adres URL endpointu Twojego API |
method | ciąg znaków | Nie | Metoda HTTP (domyślnie: POST) |
headers | obiekt | Nie | Niestandardowe nagłówki do uwzględnienia |
Dwie ścieżki wywołania
To, jakie żądanie otrzyma Twój serwer, zależy od tego, czy narzędzie ma
endpoint:
Narzędzie z endpoint | Narzędzie bez endpoint | |
|---|---|---|
| Dokąd trafia żądanie | Bezpośrednio do endpoint.url | Starszy adres URL webhooka organizacji |
| Treść | Wybrany format żądania (domyślnie same argumenty) | Otoczka telephony.tool / web.tool |
| Nagłówki | endpoint.headers + X-ThunderPhone-Call-ID + X-ThunderPhone-Signature-V2 + X-ThunderPhone-Signature | Content-Type + X-ThunderPhone-Signature-V2 + X-ThunderPhone-Signature |
| Klucz podpisywania | Sekret webhooka organizacji | Sekret webhooka organizacji |
Obie ścieżki są blokujące — AI czeka w środku zdania na
wynik. Domyślny limit czasu wynosi 20 s; ustaw timeout
na najwyższym poziomie narzędzia, aby zezwolić na dłuższe wykonanie, do
maksymalnej wartości platformy wynoszącej 180 s. Utrzymuj szybką obsługę handlerów. Możesz używać obu ścieżek:
w rozmowie, której organizacja ma adres URL webhooka, narzędzia z endpoint są
wywoływane bezpośrednio, a pozostałe korzystają z webhooka.
Bezpośrednie wywołania punktów końcowych
Gdy AI wywołuje narzędzie z endpoint, ThunderPhone wysyła
żądanie na Twój adres URL:
Nagłówki żądania
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-keyNiestandardowe nagłówki z endpoint.headers są zawsze dołączane
dosłownie, wraz z tymi nagłówkami z przestrzeni nazw ThunderPhone:
X-ThunderPhone-Signature-V2— HMAC-SHA256 ze znacznikiem czasu obejmujący metodę, ścieżkę, parametry zapytania i treść, z kluczem w postaci sekretu webhooka organizacji. Zweryfikuj ten nagłówek i odrzucaj żądania starsze niż 5 minut; zobacz Weryfikowanie podpisów webhookówX-ThunderPhone-Signature— starszy HMAC-SHA256 dokładnych bajtów treści żądania, z tym samym kluczem, nadal wysyłany dla istniejących weryfikatorówX-ThunderPhone-Call-ID— identyfikator bieżącego połączenia
Content-Type: application/json jest ustawiany, chyba że
endpoint.headers go zastępuje — niestandardowy Content-Type ma pierwszeństwo.
Format żądania
Każde połączenie API ma ustawienie request_format. Wybierz vapi lub
retell, gdy zaimportowane narzędzie powinno nadal wywoływać punkt końcowy utworzony dla
tej platformy. Nowe i istniejące połączenia domyślnie używają standard.
Dla POST / PUT / PATCH ThunderPhone serializuje wybraną
kopertę kanonicznie (posortowane klucze, zwarte separatory). Oba podpisy
obejmują dokładnie te bajty.
Standard
standard wysyła tylko argumenty narzędzia, bez opakowania. To ustawienie
domyślne zachowuje oryginalne ciało żądania ThunderPhone bajt po bajcie:
{"date":"2025-01-02","service":"consultation"}Vapi
vapi wysyła komunikat serwera tool-calls Vapi
w formacie udokumentowanym przez Vapi. call.id to identyfikator połączenia ThunderPhone. Identyfikator
wywołania narzędzia id jest unikalny dla wywołania i jest ponownie używany do dopasowania
wyniku punktu końcowego. Połączenie pojawia się zarówno w toolCallList, jak i
toolWithToolCallList, z function.arguments jako obiektem 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" }
}
}
}
]
}
}Pola dostępne wyłącznie w Vapi, takie jak assistant, artifact i pełny obiekt call,
nie są wysyłane.
Zwróć kopertę odpowiedzi Vapi z pasującym identyfikatorem wywołania narzędzia:
{
"results": [
{
"toolCallId": "call_00112233445566778899aabbccddeeff",
"result": "{\"available_slots\":[\"9:00 AM\",\"2:00 PM\"]}"
}
]
}ThunderPhone przekazuje AI rozpakowany ciąg result. Akceptuje również
wartość JSON dla zgodności z punktami końcowymi, które już ją zwracają. error
zamiast result jest zwracany do AI jako błąd narzędzia. Jeśli punkt końcowy zwróci
nieprawidłową lub niedopasowaną kopertę Vapi, ThunderPhone zapisuje
ostrzeżenie i przechodzi do standardowego przetwarzania odpowiedzi zamiast przerywać
połączenie.
Retell
retell wysyła żądanie udokumentowane dla funkcji niestandardowej Retell:
{
"name": "search_appointments",
"call": { "call_id": "987654321" },
"args": { "date": "2025-01-02", "service": "consultation" }
}Obiekt call zawiera tylko call_id. ThunderPhone nie uwzględnia
pól specyficznych dla Retell, których nie może rzetelnie dostarczyć podczas wysyłki, takich jak
agent_id, transcript, transcript_object, metadata ani zmienne dynamiczne.
Retell akceptuje dowolną treść odpowiedzi; ThunderPhone przekazuje ją dalej,
stosując standardowe przetwarzanie odpowiedzi.
Dla GET / DELETE argumenty są wysyłane jako parametry zapytania
a treść jest pusta niezależnie od request_format. Podpis V2
obejmuje ciąg zapytania w wysłanej postaci; starszy podpis jest obliczany dla
pustego ciągu bajtów. Zobacz
Weryfikowanie podpisów webhooków.
Odpowiedź
Zwróć odpowiedź JSON z wynikiem narzędzia:
{
"available_slots": ["9:00 AM", "2:00 PM", "4:30 PM"],
"timezone": "America/Los_Angeles"
}Odpowiedź jest formatowana i przekazywana AI, aby mogła kontynuować
rozmowę. Odpowiedzi inne niż JSON są opakowywane jako {"data": "<text>"};
przekroczenia limitu czasu i błędy połączenia są zgłaszane AI jako błędy, dzięki czemu
agent może przeprosić i kontynuować zamiast się zatrzymać.
Przekazywanie w trybie webhooka
Narzędzia bez endpoint są przekazywane na starszy adres URL
webhooka Twojej organizacji jako podpisane żądanie telephony.tool (połączenia
telefoniczne) lub web.tool (połączenia internetowe). W przeciwieństwie do powiadomień
audytowych dostarczanych do punktów końcowych webhooków po wykonaniu,
to żądanie jest wykonaniem — Twoja odpowiedź HTTP jest wynikiem narzędzia.
{
"type": "telephony.tool",
"data": {
"call_id": 987654321,
"tool_name": "search_appointments",
"arguments": { "date": "2026-04-21" },
"from_number": "+14155550199",
"to_number": "+15551234567"
}
}web.tool zawiera origin_domain zamiast from_number /
to_number. Odpowiedz wynikiem narzędzia w formacie JSON — obowiązuje ten sam kontrakt odpowiedzi co w przypadku bezpośrednich wywołań punktów końcowych. Żądanie jest podpisane sekretem webhooka organizacji, z użyciem obu nagłówków podpisu, tak jak każdy inny webhook.
Weryfikacja podpisu
Bezpośrednie wywołania narzędzi są podpisywane tak samo jak webhooki, przy użyciu sekretu webhooka organizacji:
X-ThunderPhone-Signature-V2podpisuje znacznik czasu, metodę, ścieżkę i parametry zapytania w przesłanej postaci oraz dokładne bajty treści. Odrzucaj żądania, których znacznik czasu różni się od czasu systemowego o więcej niż 5 minut.X-ThunderPhone-Signature(starsza wersja) podpisuje tylko bajty treści, pusty ciąg bajtów dlaGET/DELETE. Nadal jest wysyłany bez zmian.
Pomocnicze funkcje SDK sprawdzają nagłówek V2, w tym 5-minutowe okno:
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 });
});Pełne instrukcje — podpisywany ciąg, szczegółowy przykład, kod bez
SDK, przypadek GET / DELETE oraz zastrzeżenie dotyczące braku sekretu — znajdziesz w sekcji Weryfikowanie podpisów webhooków.
Przykład: kompletny proces rezerwacji
Oto zestaw narzędzi dla kompletnego systemu Umawiania wizyt:
{
"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" }
}
}
]
}Najlepsze praktyki
Pisz jasne opisy
Pole description pomaga AI zrozumieć, kiedy użyć narzędzia. Precyzyjnie opisz, co robi i kiedy należy go użyć.
Prawidłowo obsługuj błędy
Zwracaj komunikaty o błędach zrozumiałe dla AI: {"error": "No slots available for that date"} zamiast ogólnych błędów 500.
Zachowaj zwięzłość odpowiedzi
Zwracaj tylko to, czego AI potrzebuje, aby kontynuować rozmowę. Duże ładunki danych spowalniają czas odpowiedzi.
Rozważnie używaj pól wymaganych
Oznaczaj pola jako required tylko wtedy, gdy jest to naprawdę konieczne. AI poprosi użytkownika o wymagane informacje przed wywołaniem narzędzia.
Powiązane
Uruchamiaj zarządzane przez platformę działania połączeń bez definiowania punktu końcowego.
Narzędzia zarządzane przez platformę dla HubSpot, Salesforce, Slack, Google Calendar, Google Sheets i Cal.com — nie wymagają punktu końcowego.
Podłącz serwer MCP i pozwól agentowi wywoływać jego narzędzia.
Integracje REST wielokrotnego użytku, które możesz podłączać do agentów.
Jeden pomocnik weryfikacyjny dla webhooków i wywołań narzędzi.