ThunderPhone 2.0 уже доступен.Самостоятельное подключение — от 2 центов/мин.Читать анонс

Developer cookbook

Создайте интеграцию инструмента (API)

Позвольте вашему голосовому агенту вызывать ваши API прямо во время разговора — искать в базе данных, создавать тикеты, находить заказы.

Интеграция инструмента — это повторно используемая HTTP-конечная точка, которую агент может вызывать во время звонка. Вы предоставляете ThunderPhone описание инструмента в формате JSON-схемы и URL конечной точки; агент решает, когда вызвать его, на основе разговора, а ThunderPhone выполняет исходящий HTTP-запрос со своих серверов и возвращает ответ агенту.

В этом руководстве пошагово рассматривается создание инструмента для получения погоды.

Структура инструмента

Две части:

  1. Схема — определение функции в стиле OpenAI ({type: "function", function: {name, description, parameters}}), которое сообщает LLM, что делает инструмент и какие аргументы он принимает.
  2. Конечная точка — 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" }
  }'
Response
{
  "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 более ранний снимок.


Следующие шаги