Алатке функција
Функцијски алати омогућавају вашим AI агентима да позивају спољне API-је током телефонских позива. Користите их за проналажење података о клијентима, проверу доступности, заказивање термина или обављање било које радње коју ваш позадински систем подржава.
Како функционише
- Дефинишете алате помоћу шеме (које аргументе алат прихвата)
- Наводите конфигурацију
endpoint(где ThunderPhone позива ваш API) — или је изоставите да бисте примали позиве алата на webhook-у ваше организације - Током позива, AI одлучује када ће користити алат на основу разговора
- ThunderPhone позива ваш крајњи приступ са аргументима алата
- Одговор вашег API-ја враћа се AI-ју ради наставка разговора
Шема алата
Сваки алат прати ову структуру:
{
"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"
}
}
}
Дефиниција функције
| Поље | Тип | Обавезно | Опис |
|---|---|---|---|
name | ниска | Да | Јединствени идентификатор алата |
description | ниска | Да | Објашњава AI-ју када да користи овај алат |
parameters | објекат | Да | JSON Schema за аргументе алата |
Конфигурација крајњег приступа
| Поље | Тип | Обавезно | Опис |
|---|---|---|---|
url | ниска | Да | URL крајњег приступа вашег API-ја |
method | ниска | Не | HTTP метод (подразумевано: POST) |
headers | објекат | Не | Прилагођена заглавља која треба укључити |
Два пута позивања
Захтев који ваш сервер прима зависи од тога да ли алат има
endpoint:
Алат са endpoint | Алат без endpoint | |
|---|---|---|
| Куда захтев иде | Директно на endpoint.url | На застарели URL webhook-а ваше организације |
| Тело | Само аргументи алата | Омотач telephony.tool / web.tool |
| Заглавља | Ваш endpoint.headers + X-ThunderPhone-Call-ID + X-ThunderPhone-Signature | Content-Type + X-ThunderPhone-Signature |
| Кључ за потписивање | Тајна webhook-а организације | Тајна webhook-а организације |
Оба пута су блокирајућа — AI чека резултат усред реченице — са
временским ограничењем од 20 s. Обрађиваче одржавајте брзим. Можете користити
комбинацију: у позиву чија организација има URL webhook-а, алати са endpoint се
позивају директно, а остали се враћају на webhook.
Директни позиви крајње тачке
Када AI позове алатку која има endpoint, ThunderPhone шаље
захтев на Ваш URL:
Заглавља захтева
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
Прилагођена заглавља из Вашег endpoint.headers увек су укључена
дословно, уз два заглавља у ThunderPhone простору имена:
X-ThunderPhone-Signature— HMAC-SHA256 тачних бајтова тела захтева, са Вашом тајном за вебхук организације као кључемX-ThunderPhone-Call-ID— ID тренутног позива
Content-Type: application/json се поставља осим ако га Ваш
endpoint.headers не замени — прилагођени Content-Type има предност.
Тело захтева
За POST / PUT / PATCH, тело садржи само аргументе алатке
(без омотача), канонски серијализоване (сортирани кључеви, компактни
раздвајачи):
{"date":"2025-01-02","service":"consultation"}
За GET / DELETE, аргументи се шаљу као параметри упита
а тело је празно — потпис се тада израчунава над празним низом
бајтова. Погледајте
Верификација потписа вебхука.
Одговор
Вратите JSON одговор са резултатом алатке:
{
"available_slots": ["9:00 AM", "2:00 PM", "4:30 PM"],
"timezone": "America/Los_Angeles"
}
Одговор се форматира и прослеђује AI-ју да настави
разговор. Одговори који нису JSON умотавају се као {"data": "<text>"};
истеци времена и неуспешне везе пријављују се AI-ју као грешке, тако да
агент може да се извини и настави уместо да застане.
Отпремање у режиму вебхука
Алатке без endpoint отпремају се на застарели URL вебхука Ваше
организације као потписани захтев telephony.tool (телефонски позиви) или web.tool
(веб позиви). За разлику од обавештења за ревизију
која се достављају крајњим тачкама вебхука након извршавања, овај захтев јесте
извршавање — Ваш HTTP одговор је резултат алатке.
{
"type": "telephony.tool",
"data": {
"call_id": 987654321,
"tool_name": "search_appointments",
"arguments": { "date": "2026-04-21" },
"from_number": "+14155550199",
"to_number": "+15551234567"
}
}
web.tool носи origin_domain уместо from_number /
to_number. Одговорите са резултатом алатке као JSON — исти уговор о
одговору као за директне позиве крајње тачке. Захтев је потписан тајном
за вебхук организације над сировим телом, као и сваки други вебхук.
Верификација потписа
Директни позиви алата потписују се на исти начин као webhook-ови:
- HMAC-SHA256 преко тачних бајтова тела захтева (канонски JSON — сортирани кључеви, без додатних размака)
- Са тајном webhook-а ваше организације као кључем
- Алати
GET/DELETEпотписују празан низ бајтова
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}
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 });
});
Комплетни примери — укључујући случај празног тела и напомену о одсуству тајне — налазе се у одељку Верификујте webhook потписе.
Пример: Комплетан ток заказивања
Ево скупа алата за комплетан систем заказивања термина:
{
"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" }
}
}
]
}
Најбоље праксе
Пишите јасне описе
Поље description помаже AI-ју да разуме када треба да користи алат. Прецизно наведите шта алат ради и када је прикладно да се користи.
Елегантно обрађујте грешке
Вратите поруке о грешкама које AI може да разуме: {"error": "No slots available for that date"} уместо општих грешака 500.
Нека одговори буду сажети
Вратите само оно што је AI-ју потребно да настави разговор. Велики пакети података успоравају време одговора.
Промишљено користите обавезна поља
Означите поља као required само када је то заиста неопходно. AI ће затражити од корисника обавезне информације пре позивања алата.
Повезано
Алатке којима управља платформа за HubSpot, Salesforce, Slack, Google Calendar, Google Sheets и Cal.com — крајња тачка није потребна.
Повежите MCP сервер и омогућите агенту да позива његове алатке.
REST интеграције за вишекратну употребу које можете повезати са агентима.
Један помоћник за верификацију веб-хукова и позива алатки.