---
title: "Funkcijų įrankiai"
description: "Suteikite savo DI agentams funkcijų įrankius, kurie pokalbio metu iškviečia išorines API, gauna klientų duomenis, rezervuoja susitikimus ir atnaujina įrašus naudodami tipizuotus parametrus."
---

Funkcijų įrankiai leidžia jūsų balso agentams skambučių metu iškviesti išorines API. Naudokite juos klientų duomenims rasti, prieinamumui patikrinti, susitikimams rezervuoti arba bet kuriam veiksmui, kurį palaiko jūsų vidinė sistema, atlikti.

## Kaip tai veikia

1. Apibrėžiate įrankius naudodami schemą (kokius argumentus priima įrankis)
2. Pateikiate `endpoint` konfigūraciją (kur ThunderPhone iškviečia jūsų API) arba jos nenurodote, kad įrankio iškvietimus gautumėte organizacijos žiniatinklio kablio adresu
3. Skambučio metu DI nusprendžia, kada naudoti įrankį, pagal pokalbį
4. ThunderPhone iškviečia jūsų galinį tašką su įrankio argumentais
5. Jūsų API atsakymas perduodamas atgal DI, kad pokalbis tęstųsi

| Galimybė | Kur vykdoma | Nustatymas |
| --- | --- | --- |
| [Integruoti įrankiai](/lt/guides/built-in-tools) | ThunderPhone | Raginimo instrukcijos; kai kuriems įrankiams taip pat reikia agento nustatymo |
| [Programų jungtys](/lt/guides/connect-apps) | ThunderPhone ir prijungtas paslaugų teikėjas | Prijunkite paskyrą ir pridėkite patvirtintus veiksmus |
| [API jungtys](/lt/guides/api-connections) ir funkcijų įrankiai | Jūsų HTTP API | Apibrėžkite galinį tašką ir schemą arba gaukite funkcijų iškvietimus per žiniatinklio kablį |
| [MCP serveriai](/lt/guides/mcp-servers) | Nuotolinis MCP serveris | Pridėkite serverį, aptikite jo įrankius ir prijunkite jį prie agento |

---

## Įrankio schema

Kiekvienas įrankis turi tokią struktūrą:

```json
{
  "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
}
```

### Įrankio konfigūracija

| Laukas | Tipas | Būtinas | Aprašymas |
|-------|------|----------|-------------|
| `timeout` | skaičius | Ne | Maksimalus vykdymo laikas sekundėmis (numatytoji reikšmė: `20`, didžiausia: `180`) |

### Funkcijos apibrėžimas

| Laukas | Tipas | Būtinas | Aprašymas |
|-------|------|----------|-------------|
| `name` | eilutė | Taip | Unikalus įrankio identifikatorius |
| `description` | eilutė | Taip | Paaiškina DI, kada naudoti šį įrankį |
| `parameters` | objektas | Taip | JSON Schema įrankio argumentams |

### Galinio taško konfigūracija

| Laukas | Tipas | Būtinas | Aprašymas |
|-------|------|----------|-------------|
| `url` | eilutė | Taip | Jūsų API galinio taško URL |
| `method` | eilutė | Ne | HTTP metodas (numatytoji reikšmė: `POST`) |
| `headers` | objektas | Ne | Įtraukiamos pasirinktinės antraštės |

<Note>
  `endpoint` konfigūracija **nėra** siunčiama DI modeliui — ją ThunderPhone naudoja tik įrankio iškvietimui vykdyti.
</Note>

---

## Du iškvietimo keliai

Kokią užklausą gauna jūsų serveris, priklauso nuo to, ar įrankis turi
`endpoint`:

| | Įrankis **su** `endpoint` | Įrankis **be** `endpoint` |
|---|---|---|
| Kur siunčiama užklausa | Tiesiogiai į `endpoint.url` | Jūsų organizacijos [ankstesnis žiniatinklio kablio URL](/api-reference/organizations#legacy-single-url-webhook) |
| Turinys | **Vien tik įrankio argumentai** | `telephony.tool` / `web.tool` apvalkalas |
| Antraštės | Jūsų `endpoint.headers` + `X-ThunderPhone-Call-ID` + `X-ThunderPhone-Signature` | `Content-Type` + `X-ThunderPhone-Signature` |
| Pasirašymo raktas | Organizacijos žiniatinklio kablio paslaptis | Organizacijos žiniatinklio kablio paslaptis |

Abu keliai yra **blokuojantys** — DI sakinio viduryje laukia
rezultato. Numatytasis laiko limitas yra **20 s**; nustatykite įrankio aukščiausio lygio
`timeout`, kad leistumėte ilgesnį vykdymą, iki platformos **180 s**
maksimumo. Užtikrinkite, kad tvarkytuvės veiktų greitai. Galima naudoti mišrų variantą:
skambučio, kurio organizacija turi žiniatinklio kablio URL, metu įrankiai su `endpoint` yra
iškviečiami tiesiogiai, o kiti grįžta prie žiniatinklio kablio.

## Tiesioginiai galinio taško iškvietimai

Kai AI iškviečia įrankį, turintį `endpoint`, ThunderPhone siunčia
užklausą į jūsų URL:

### Užklausos antraštės

```http
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
```

Pasirinktinės antraštės iš jūsų `endpoint.headers` visada įtraukiamos
nepakeistos, kartu su dviem ThunderPhone vardų srities antraštėmis:

- `X-ThunderPhone-Signature` — tikslių užklausos turinio baitų HMAC-SHA256,
  kuriam naudojama jūsų **organizacijos webhook paslaptis**
- `X-ThunderPhone-Call-ID` — dabartinio skambučio ID

`Content-Type: application/json` nustatoma, nebent jūsų `endpoint.headers`
ją pakeičia — pasirinktinė `Content-Type` turi pirmenybę.

<Warning>
  Parašui naudojama organizacijos lygio webhook paslaptis iš
  [`GET /v1/webhook`](/api-reference/organizations#legacy-single-url-webhook).
  Jei jūsų organizacija niekada nekonfigūravo senojo webhook, paslapties nėra,
  o įrankių iškvietimuose pateikiama **tik** `X-ThunderPhone-Call-ID` — juos
  atmes apdorojimo priemonė, kuri nutraukia vykdymą, jei trūksta parašo.
  Arba sukonfigūruokite senąjį webhook, kad gautumėte paslaptį, arba įtraukite
  savo bendrą paslaptį į `endpoint.headers`.
</Warning>

### Užklausos turinys

Naudojant `POST` / `PUT` / `PATCH`, turinyje pateikiami **tik** įrankio
argumentai (be apvalkalo), kanoniškai serializuoti (surikiuoti raktai,
glausti skirtukai):

```json
{"date":"2025-01-02","service":"consultation"}
```

Naudojant `GET` / `DELETE`, argumentai siunčiami kaip **užklausos parametrai**,
o turinys yra tuščias — tuomet parašas apskaičiuojamas pagal tuščią
baitų eilutę. Žr.
[Webhook parašų tikrinimas](/lt/guides/verify-webhook-signatures).

### Atsakymas

Grąžinkite JSON atsakymą su įrankio rezultatu:

```json
{
  "available_slots": ["9:00 AM", "2:00 PM", "4:30 PM"],
  "timezone": "America/Los_Angeles"
}
```

Atsakymas suformatuojamas ir pateikiamas AI, kad šis galėtų tęsti
pokalbį. Ne JSON atsakymai apgaubiami kaip `{"data": "<text>"}`;
laiko limitų viršijimai ir ryšio klaidos AI pateikiamos kaip klaidos,
todėl agentas gali atsiprašyti ir tęsti, užuot užstrigęs.

## Išsiuntimas webhook režimu

Įrankiai **be** `endpoint` siunčiami į jūsų organizacijos senojo
webhook URL kaip pasirašyta `telephony.tool` (telefono skambučiai) arba `web.tool`
(žiniatinklio iškvietimai) užklausa. Kitaip nei [audito pranešimai](/lt/webhooks/events),
kurie pateikiami webhook galiniams taškams po vykdymo, ši užklausa **yra**
vykdymas — jūsų HTTP atsakymas yra įrankio rezultatas.

```json
{
  "type": "telephony.tool",
  "data": {
    "call_id": 987654321,
    "tool_name": "search_appointments",
    "arguments": { "date": "2026-04-21" },
    "from_number": "+14155550199",
    "to_number": "+15551234567"
  }
}
```

`web.tool` vietoj `from_number` /
`to_number` pateikia `origin_domain`. Atsakykite įrankio rezultatu JSON formatu —
taikoma ta pati atsakymo sutartis kaip ir tiesioginiams galinio taško iškvietimams.
Užklausa pasirašoma organizacijos webhook paslaptimi pagal neapdorotą turinį,
kaip ir kiekvienas kitas webhook.

<Note>
  Prenumeruojami [webhook galiniai taškai](/lt/webhooks/endpoints) papildomai
  gauna neužblokuojantį `telephony.tool` / `web.tool` **pranešimą
  po** kiekvieno įrankio vykdymo (nepriklausomai nuo jį vykdžiusio kelio),
  įskaitant įrankio atsakymą — tai naudinga audito sekai. Žr.
  [įvykių katalogą](/lt/webhooks/events).
</Note>

---

## Parašo patvirtinimas

Tiesioginiai įrankių iškvietimai pasirašomi taip pat kaip ir žiniatinklio kabliukai:

- HMAC-SHA256 pagal tikslius užklausos teksto baitus (kanoninis JSON — surikiuoti raktai, be papildomų tarpų)
- Naudojant jūsų organizacijos žiniatinklio kabliuko slaptąjį raktą
- `GET` / `DELETE` įrankiai pasirašo tuščią baitų eilutę

<CodeGroup>
```python Python
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}
```

```javascript Node.js
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 });
});
```
</CodeGroup>

Visi pavyzdžiai, įskaitant tuščio teksto atvejį ir pastabą dėl slaptojo rakto nebuvimo, pateikti skyriuje [Žiniatinklio kabliukų parašų tikrinimas](/lt/guides/verify-webhook-signatures).

---

## Pavyzdys: visas rezervavimo procesas

Štai įrankių rinkinys visai vizitų rezervavimo sistemai:

```json
{
  "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" }
      }
    }
  ]
}
```

---

## Geriausios praktikos

<AccordionGroup>
  <Accordion title="Rašykite aiškius aprašus">
    Laukas `description` padeda DI suprasti, **kada** naudoti įrankį. Tiksliai nurodykite, ką jis daro ir kada jį tinka naudoti.
  </Accordion>

  <Accordion title="Tinkamai tvarkykite klaidas">
    Pateikite DI suprantamus klaidų pranešimus: `{"error": "No slots available for that date"}`, o ne bendrines 500 klaidas.
  </Accordion>

  <Accordion title="Išlaikykite atsakymus glaustus">
    Grąžinkite tik tai, ko DI reikia pokalbiui tęsti. Dideli duomenų paketai lėtina atsako laiką.
  </Accordion>

  <Accordion title="Apgalvotai naudokite privalomus laukus">
    Žymėkite laukus kaip `required` tik tada, kai tai tikrai būtina. Prieš iškviesdamas įrankį, DI paprašys naudotojo pateikti privalomą informaciją.
  </Accordion>
</AccordionGroup>

---

## Susiję

<CardGroup cols={2}>
  <Card title="Integruoti įrankiai" icon="wrench" href="/lt/guides/built-in-tools">
    Inicijuokite platformos valdomus skambučių veiksmus neapibrėždami galinio taško.
  </Card>
  <Card title="Programų jungtys" icon="plug" href="/lt/guides/connect-apps">
    Platformos valdomi įrankiai, skirti HubSpot, Salesforce, Slack, Google
    Calendar, Google Sheets ir Cal.com — galinis taškas nereikalingas.
  </Card>
  <Card title="MCP serveriai" icon="server" href="/lt/guides/mcp-servers">
    Prijunkite MCP serverį ir leiskite agentui iškviesti jo įrankius.
  </Card>
  <Card title="API jungtys" icon="code" href="/lt/guides/api-connections">
    Pakartotinai naudojamos REST integracijos, kurias galite prijungti prie agentų.
  </Card>
  <Card title="Tikrinkite webhook parašus" icon="shield-check" href="/lt/guides/verify-webhook-signatures">
    Viena tikrinimo pagalbinė priemonė webhook ir įrankių iškvietimams.
  </Card>
</CardGroup>
