ThunderPhone 2.0 вече е тук.Започнете самостоятелно — от 2 цента/мин.Прочетете съобщението

Developer cookbook

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

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

Интеграцията на инструмент е крайна HTTP точка за многократна употреба, която агентът може да извиква по време на разговор. Предоставяте на ThunderPhone JSON Schema описание на инструмента плюс URL на крайна точка; агентът решава кога да го извика въз основа на разговора, а ThunderPhone изпраща изходящата HTTP заявка от своите сървъри и връща отговора на агента.

Това ръководство показва изграждането на инструмент за проверка на времето от край до край.

Анатомия на инструмент

Две части:

  1. Схемата — дефиниция на функция в стил OpenAI ({type: "function", function: {name, description, parameters}}), която указва на LLM какво прави инструментът и какви аргументи приема.
  2. Крайната точка — URL адресът, който сървърите на ThunderPhone извикват, когато LLM реши да използва инструмента. Заявката е JSON POST със избраните от LLM аргументи в тялото.

1. Изберете редактор

Табло

Отворете Връзки → API, създайте или редактирайте API връзката, превключете редактора на параметри на JSON и добавете формата там.

API за интеграции

Създайте спецификацията с POST /v1/integrations или я актуализирайте с PATCH /v1/integrations/{id}.

И двата подхода създават запазена интеграция. Прикачете тази интеграция към агента, след като я запазите. API за агенти няма поле tools за записване директно в него. Това ръководство използва подхода чрез API за интеграции.

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).

Декларирайте format: "email" за параметрите за адреси

Параметър, който получава имейл адрес, трябва да го указва в своята схема:

"email": { "type": "string", "format": "email", "description": "The caller's email address" }

format е повече от подсказка. При разпозната схема за имейл, преди да бъде извикана вашата крайна точка, ThunderPhone премахва водещите и завършващите интервали от стойността, преобразува домейна в малки букви, превръща самостоятелните английски думи at, dot, underscore, dash и hyphen в съответните им символи и премахва интервалите непосредствено около @, ., _ и -. Думите имат същото значение, независимо дали транскрипцията вече съдържа буквален @: "john dot smith at gmail dot com" става john.smith@gmail.com.

Всеки друг вътрешен интервал се отхвърля, вместо безшумно да бъде слят. Изговорените думи за разделители са само на английски; неанглийски или неразпознати форми с интервали се отхвърлят безопасно. Валидни интернационализирани домейни и локални части по SMTPUTF8 се приемат. Входът в Punycode остава в Punycode, а входът с Unicode домейн остава в Unicode след нормализиране от анализатора, така че вашият API получава конвенционалното представяне, предоставено от обаждащия се. Ако крайната стойност е невалидна, инструментът не се извиква. Агентът получава invalid_email_argument, което му указва да потвърди изписването с обаждащия се и да изпрати отново буквалния адрес.

Пропуснат незадължителен имейл остава непроменен. null, празен низ или низ само с интервали също остават непроменени, когато свойството е незадължително или допуска null; същите стойности се отхвърлят за задължителен имейл, който не допуска null.

Локални референции към схеми, като #/$defs/email и #/definitions/email, както и anyOf, oneOf и allOf, се проверяват с ограничения за цикли и дълбочина. Нелокален или неразрешим $ref е известно ограничение на проверката и се предава без промяна, както и извикване, чиято моментна снимка на инструмента няма използваема схема. Поддържайте схемите за имейл локални, когато е необходимо проверката да се прилага.

Параметрите без наложен формат за имейл се предават точно както моделът ги е създал.

Поддържаните формати са date-time, time, date, duration, email, hostname, ipv4, ipv6 и uuid; днес само email се нормализира и проверява.

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. Тествайте цикъла

Изпълнете mic сесия срещу агента и задайте въпроса, който вашият инструмент обработва („Какво е времето в 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 kB се съкращават в предварителния преглед на транскрипта. Връщайте само полетата, от които LLM се нуждае — не целия ви запис.

Изчаквания

Крайните точки на инструментите имат стандартно изчакване от 10 секунди. Ако ви трябва повече време, обработете заявката асинхронно: върнете {"status": "pending", "request_id": "..."} и предоставете резултата чрез отделно извикване на инструмент.

Версиониране

Всеки PATCH на интеграция създава нова редакция. Проверете GET /v1/integrations/{id}/versions, за да видите кой какво е променил. Ако нарушите схемата на инструмент, можете ръчно да върнете предишна версия, като приложите чрез PATCH по-старо моментно състояние.


Следващи стъпки