Создайте интеграцию инструмента (API)
Позвольте вашему голосовому агенту вызывать ваши API прямо во время разговора — искать в базе данных, создавать тикеты, находить заказы.
Интеграция инструмента — это повторно используемая HTTP-конечная точка, которую агент может вызывать во время звонка. Вы предоставляете ThunderPhone описание инструмента в формате JSON-схемы и URL конечной точки; агент решает, когда вызвать его, на основе разговора, а ThunderPhone выполняет исходящий HTTP-запрос со своих серверов и возвращает ответ агенту.
В этом руководстве пошагово рассматривается создание инструмента для получения погоды.
Структура инструмента
Две части:
- Схема — определение функции в стиле OpenAI
(
{type: "function", function: {name, description, parameters}}), которое сообщает LLM, что делает инструмент и какие аргументы он принимает. - Конечная точка — URL, который серверы ThunderPhone вызывают, когда LLM решает использовать инструмент. Запрос представляет собой JSON POST, а тело содержит аргументы, выбранные LLM.
1. Выберите стратегию хранения
Добавьте разовый инструмент в массив tools агента. Это просто, но
не подходит для повторного использования.
Сохраните инструмент как повторно используемую интеграцию и привяжите его к нескольким агентам. Рекомендуется для всего, что используется более одного раза.
В этом руководстве используется путь с сохранённой интеграцией.
2. Создайте интеграцию
curl -X POST https://api.thunderphone.com/v1/integrations \
-H "Authorization: Bearer sk_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"display_name": "Weather API",
"spec": {
"type": "function",
"function": {
"name": "get_weather",
"description": "Return the current weather for a zip code.",
"parameters": {
"type": "object",
"properties": {
"zip": { "type": "string", "description": "5-digit US ZIP code" }
},
"required": ["zip"]
}
}
},
"endpoint_url": "https://api.example.com/weather",
"endpoint_method": "GET",
"headers": [
{ "key": "X-Api-Key", "value": "your-provider-key" }
]
}'Сохраните возвращённый id (UUID).
3. Протестируйте конечную точку в песочнице
Прежде чем привязывать интеграцию к агенту, отправьте подписанный запрос с серверов ThunderPhone, чтобы подтвердить подключение:
curl -X POST https://api.thunderphone.com/v1/integrations/test-request \
-H "Authorization: Bearer sk_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://api.example.com/weather?zip=94110",
"method": "GET",
"headers": { "X-Api-Key": "your-provider-key" }
}'{
"ok": true,
"status": 200,
"elapsed_ms": 187,
"response_headers": { "content-type": "application/json" },
"response_preview": "{\"temperature_f\": 64, ...}"
}Этот тест также усиливает SSRF-защиту ThunderPhone — запросы к localhost
или диапазонам частных IP-адресов возвращают 400 code=url_not_allowed.
4. Привяжите интеграцию к агенту
Добавьте integration_ids при создании или обновлении агента:
curl -X PATCH https://api.thunderphone.com/v1/agents/12 \
-H "Authorization: Bearer sk_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"integration_ids": ["f9b5a1a4-..."]
}'К одному агенту можно привязать несколько интеграций. В промпте агента
на них можно ссылаться по имени — «используй get_weather, когда звонящий спрашивает
о погодных условиях» — либо агент может неявно обнаружить их по
описаниям схем.
5. Реализуйте эндпоинт
Когда агент вызывает инструмент, ThunderPhone отправляет подписанный POST на
ваш endpoint_url:
POST /weather HTTP/1.1
Host: api.example.com
X-Api-Key: your-provider-key
X-ThunderPhone-Signature: <HMAC-SHA256 hex>
X-ThunderPhone-Call-ID: 987654321
Content-Type: application/json
{"zip": "94110"}
Ваш сервер отвечает JSON, который передаётся обратно в LLM:
{"temperature_f": 64, "condition": "Partly cloudy", "wind_mph": 8}LLM обрабатывает этот ответ и сообщает звонящему краткую информацию понятным языком.
6. Протестируйте цикл
Запустите сеанс с микрофоном для агента и задайте вопрос, который обрабатывает ваш инструмент («Какая погода в 94110?»). В расшифровке звонка отображается полный цикл:
{
"call_id": 987654321,
"transcripts": [
{ "role": "user",
"content": "What's the weather in 94110?" },
{ "role": "tool_call",
"content": "{\"tool_call\": \"get_weather\", \"arguments\": {\"zip\": \"94110\"}}" },
{ "role": "tool_response",
"content": "{\"tool_name\": \"get_weather\", \"response\": {\"temperature_f\": 64, \"condition\": \"Partly cloudy\"}}" },
{ "role": "agent",
"content": "It's 64 degrees and partly cloudy." }
]
}Получить её можно через
GET /v1/calls/{call_id}/transcript;
поток необработанных событий (со временем для каждой записи и смещениями аудио) доступен по адресу
GET /v1/calls/{call_id}/history.
Распространённые проблемы
Агент никогда не вызывает инструмент
LLM принимает решение на основе описания инструмента. Если вопрос звонящего
не соответствует описанию, модель не вызовет инструмент. Уточните описание
(добавьте распространённые синонимы и формулировки) или явно укажите это
в промпте агента («Когда звонящий спрашивает о погоде, используй get_weather.»).
Инструмент возвращает слишком много данных
Ответы размером более 6 кБ обрезаются в предпросмотре расшифровки. Возвращайте только поля, нужные LLM, а не всю запись.
Тайм-ауты
Для эндпоинтов инструментов по умолчанию установлен тайм-аут 10 секунд. Если нужно больше времени,
обрабатывайте запрос асинхронно: верните {"status": "pending", "request_id": "..."}
и передайте результат через отдельный вызов инструмента.
Версионирование
Каждый PATCH интеграции создаёт новую ревизию. Проверьте
GET /v1/integrations/{id}/versions,
чтобы узнать, кто и что изменил. Если вы нарушили схему инструмента, можно
вручную откатить изменения, передав через PATCH более ранний снимок.
Следующие шаги
CRUD, передача, история версий.
Полная грамматика схемы JSON и контракт подписанного эндпоинта.
Применяйте шаблон подписи вебхука к эндпоинтам инструментов.
Просматривайте полный цикл вызова инструмента.