---
title: "Narzędzia funkcji"
description: "Wyposaż swoich agentów AI w narzędzia funkcji, które wywołują zewnętrzne interfejsy API w trakcie rozmowy — pobierają dane klientów, umawiają wizyty, aktualizują rekordy — z parametrami o określonych typach."
---

Narzędzia funkcji umożliwiają agentom AI wywoływanie zewnętrznych interfejsów API podczas rozmów telefonicznych. Używaj ich do wyszukiwania danych klientów, sprawdzania dostępności, umawiania wizyt lub wykonywania dowolnych działań obsługiwanych przez Twój backend.

## Jak to działa

1. Zdefiniuj narzędzia za pomocą schematu (jakie argumenty akceptuje narzędzie)
2. Podaj konfigurację `endpoint` (gdzie ThunderPhone wywołuje Twój interfejs API) — lub ją pomiń, aby otrzymywać wywołania narzędzi na webhooku organizacji
3. Podczas rozmowy AI decyduje, kiedy użyć narzędzia, na podstawie konwersacji
4. ThunderPhone wywołuje Twój endpoint z argumentami narzędzia
5. Odpowiedź Twojego API jest przekazywana z powrotem do AI, aby kontynuować konwersację

| Możliwość | Gdzie działa | Konfiguracja |
| --- | --- | --- |
| [Wbudowane narzędzia](/pl/guides/built-in-tools) | ThunderPhone | Instrukcje w prompcie; niektóre narzędzia wymagają także ustawienia agenta |
| [Połączenia z aplikacjami](/pl/guides/connect-apps) | ThunderPhone i połączony dostawca | Połącz konto i przypisz zatwierdzone działania |
| [Połączenia API](/pl/guides/api-connections) i narzędzia funkcji | Twój interfejs HTTP API | Zdefiniuj endpoint i schemat lub odbieraj wywołania funkcji przez webhook |
| [Serwery MCP](/pl/guides/mcp-servers) | Zdalny serwer MCP | Dodaj serwer, wykryj jego narzędzia i przypisz go do agenta |

---

## Schemat narzędzia

Każde narzędzie ma następującą strukturę:

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

### Konfiguracja narzędzia

| Pole | Typ | Wymagane | Opis |
|-------|------|----------|-------------|
| `timeout` | liczba | Nie | Maksymalny czas wykonania w sekundach (domyślnie: `20`, maksymalnie: `180`) |

### Definicja funkcji

| Pole | Typ | Wymagane | Opis |
|-------|------|----------|-------------|
| `name` | ciąg znaków | Tak | Unikalny identyfikator narzędzia |
| `description` | ciąg znaków | Tak | Wyjaśnia AI, kiedy użyć tego narzędzia |
| `parameters` | obiekt | Tak | Schemat JSON argumentów narzędzia |

### Konfiguracja endpointu

| Pole | Typ | Wymagane | Opis |
|-------|------|----------|-------------|
| `url` | ciąg znaków | Tak | Adres URL endpointu Twojego API |
| `method` | ciąg znaków | Nie | Metoda HTTP (domyślnie: `POST`) |
| `headers` | obiekt | Nie | Niestandardowe nagłówki do uwzględnienia |

<Note>
  Konfiguracja `endpoint` **nie** jest wysyłana do modelu AI — ThunderPhone używa jej wyłącznie do wykonania wywołania narzędzia.
</Note>

---

## Dwie ścieżki wywołania

To, jakie żądanie otrzyma Twój serwer, zależy od tego, czy narzędzie ma
`endpoint`:

| | Narzędzie **z** `endpoint` | Narzędzie **bez** `endpoint` |
|---|---|---|
| Dokąd trafia żądanie | Bezpośrednio do `endpoint.url` | Starszy [adres URL webhooka organizacji](/api-reference/organizations#legacy-single-url-webhook) |
| Treść | Wybrany format żądania (domyślnie same argumenty) | Otoczka `telephony.tool` / `web.tool` |
| Nagłówki | `endpoint.headers` + `X-ThunderPhone-Call-ID` + `X-ThunderPhone-Signature-V2` + `X-ThunderPhone-Signature` | `Content-Type` + `X-ThunderPhone-Signature-V2` + `X-ThunderPhone-Signature` |
| Klucz podpisywania | Sekret webhooka organizacji | Sekret webhooka organizacji |

Obie ścieżki są **blokujące** — AI czeka w środku zdania na
wynik. Domyślny limit czasu wynosi **20 s**; ustaw `timeout`
na najwyższym poziomie narzędzia, aby zezwolić na dłuższe wykonanie, do
maksymalnej wartości platformy wynoszącej **180 s**. Utrzymuj szybką obsługę handlerów. Możesz używać obu ścieżek:
w rozmowie, której organizacja ma adres URL webhooka, narzędzia z `endpoint` są
wywoływane bezpośrednio, a pozostałe korzystają z webhooka.

## Bezpośrednie wywołania punktów końcowych

Gdy AI wywołuje narzędzie z `endpoint`, ThunderPhone wysyła
żądanie na Twój adres URL:

### Nagłówki żądania

```http
POST /appointments/search HTTP/1.1
Host: api.example.com
Content-Type: application/json
X-ThunderPhone-Signature-V2: t=1767225600,v1=5f2c...
X-ThunderPhone-Signature: abc123...
X-ThunderPhone-Call-ID: 987654321
X-Api-Key: your-api-key
```

Niestandardowe nagłówki z `endpoint.headers` są zawsze dołączane
dosłownie, wraz z tymi nagłówkami z przestrzeni nazw ThunderPhone:

- `X-ThunderPhone-Signature-V2` — HMAC-SHA256 ze znacznikiem czasu obejmujący
  metodę, ścieżkę, parametry zapytania i treść, z kluczem w postaci **sekretu webhooka organizacji**.
  Zweryfikuj ten nagłówek i odrzucaj żądania starsze niż 5 minut; zobacz
  [Weryfikowanie podpisów webhooków](/pl/guides/verify-webhook-signatures)
- `X-ThunderPhone-Signature` — starszy HMAC-SHA256 dokładnych bajtów
  treści żądania, z tym samym kluczem, nadal wysyłany dla istniejących weryfikatorów
- `X-ThunderPhone-Call-ID` — identyfikator bieżącego połączenia

`Content-Type: application/json` jest ustawiany, chyba że
`endpoint.headers` go zastępuje — niestandardowy `Content-Type` ma pierwszeństwo.

<Warning>
  Podpis jest oparty na sekrecie webhooka na poziomie organizacji z
  [`GET /v1/webhook`](/api-reference/organizations#legacy-single-url-webhook).
  Jeśli Twoja organizacja nigdy nie skonfigurowała starszego webhooka,
  nie ma sekretu, a wywołania narzędzi zawierają **tylko**
  `X-ThunderPhone-Call-ID` — procedura obsługi, która kończy działanie
  z błędem przy braku podpisu, odrzuciłaby je.
  Skonfiguruj starszy webhook, aby uzyskać sekret, lub umieść własny
  współdzielony sekret w `endpoint.headers`.
</Warning>

### Format żądania

Każde połączenie API ma ustawienie `request_format`. Wybierz `vapi` lub
`retell`, gdy zaimportowane narzędzie powinno nadal wywoływać punkt końcowy utworzony dla
tej platformy. Nowe i istniejące połączenia domyślnie używają `standard`.

Dla `POST` / `PUT` / `PATCH` ThunderPhone serializuje wybraną
kopertę kanonicznie (posortowane klucze, zwarte separatory). Oba podpisy
obejmują dokładnie te bajty.

#### Standard

`standard` wysyła tylko argumenty narzędzia, bez opakowania. To ustawienie
domyślne zachowuje oryginalne ciało żądania ThunderPhone bajt po bajcie:

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

#### Vapi

`vapi` wysyła [komunikat serwera `tool-calls` Vapi](https://docs.vapi.ai/tools/custom-tools)
w formacie udokumentowanym przez Vapi. `call.id` to identyfikator połączenia ThunderPhone. Identyfikator
wywołania narzędzia `id` jest unikalny dla wywołania i jest ponownie używany do dopasowania
wyniku punktu końcowego. Połączenie pojawia się zarówno w `toolCallList`, jak i
`toolWithToolCallList`, z `function.arguments` jako obiektem JSON:

```json
{
  "message": {
    "type": "tool-calls",
    "timestamp": 1725000000123,
    "call": { "id": "987654321" },
    "toolCallList": [
      {
        "id": "call_00112233445566778899aabbccddeeff",
        "type": "function",
        "function": {
          "name": "search_appointments",
          "arguments": { "date": "2025-01-02", "service": "consultation" }
        }
      }
    ],
    "toolWithToolCallList": [
      {
        "type": "function",
        "function": { "name": "search_appointments" },
        "toolCall": {
          "id": "call_00112233445566778899aabbccddeeff",
          "type": "function",
          "function": {
            "name": "search_appointments",
            "arguments": { "date": "2025-01-02", "service": "consultation" }
          }
        }
      }
    ]
  }
}
```

Pola dostępne wyłącznie w Vapi, takie jak `assistant`, `artifact` i pełny obiekt `call`,
nie są wysyłane.

Zwróć kopertę odpowiedzi Vapi z pasującym identyfikatorem wywołania narzędzia:

```json
{
  "results": [
    {
      "toolCallId": "call_00112233445566778899aabbccddeeff",
      "result": "{\"available_slots\":[\"9:00 AM\",\"2:00 PM\"]}"
    }
  ]
}
```

ThunderPhone przekazuje AI rozpakowany ciąg `result`. Akceptuje również
wartość JSON dla zgodności z punktami końcowymi, które już ją zwracają. `error`
zamiast `result` jest zwracany do AI jako błąd narzędzia. Jeśli punkt końcowy zwróci
nieprawidłową lub niedopasowaną kopertę Vapi, ThunderPhone zapisuje
ostrzeżenie i przechodzi do standardowego przetwarzania odpowiedzi zamiast przerywać
połączenie.

#### Retell

`retell` wysyła żądanie udokumentowane dla [funkcji niestandardowej Retell](https://docs.retellai.com/build/single-multi-prompt/custom-function):

```json
{
  "name": "search_appointments",
  "call": { "call_id": "987654321" },
  "args": { "date": "2025-01-02", "service": "consultation" }
}
```

Obiekt `call` zawiera tylko `call_id`. ThunderPhone nie uwzględnia
pól specyficznych dla Retell, których nie może rzetelnie dostarczyć podczas wysyłki, takich jak
`agent_id`, `transcript`, `transcript_object`, `metadata` ani zmienne dynamiczne.
Retell akceptuje dowolną treść odpowiedzi; ThunderPhone przekazuje ją dalej,
stosując standardowe przetwarzanie odpowiedzi.

Dla `GET` / `DELETE` argumenty są wysyłane jako **parametry zapytania**
a treść jest pusta niezależnie od `request_format`. Podpis V2
obejmuje ciąg zapytania w wysłanej postaci; starszy podpis jest obliczany dla
pustego ciągu bajtów. Zobacz
[Weryfikowanie podpisów webhooków](/pl/guides/verify-webhook-signatures).

### Odpowiedź

Zwróć odpowiedź JSON z wynikiem narzędzia:

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

Odpowiedź jest formatowana i przekazywana AI, aby mogła kontynuować
rozmowę. Odpowiedzi inne niż JSON są opakowywane jako `{"data": "<text>"}`;
przekroczenia limitu czasu i błędy połączenia są zgłaszane AI jako błędy, dzięki czemu
agent może przeprosić i kontynuować zamiast się zatrzymać.

## Przekazywanie w trybie webhooka

Narzędzia **bez** `endpoint` są przekazywane na starszy adres URL
webhooka Twojej organizacji jako podpisane żądanie `telephony.tool` (połączenia
telefoniczne) lub `web.tool` (połączenia internetowe). W przeciwieństwie do [powiadomień
audytowych](/pl/webhooks/events) dostarczanych do punktów końcowych webhooków po wykonaniu,
to żądanie **jest** wykonaniem — Twoja odpowiedź HTTP jest wynikiem narzędzia.

```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` zawiera `origin_domain` zamiast `from_number` /
`to_number`. Odpowiedz wynikiem narzędzia w formacie JSON — obowiązuje ten sam kontrakt odpowiedzi co w przypadku bezpośrednich wywołań punktów końcowych. Żądanie jest podpisane sekretem webhooka organizacji, z użyciem obu nagłówków podpisu, tak jak każdy inny webhook.

<Note>
  Subskrybowane [punkty końcowe webhooków](/pl/webhooks/endpoints) dodatkowo
  otrzymują nieblokujące **powiadomienie `telephony.tool` / `web.tool`
  po** każdym wykonaniu narzędzia (niezależnie od ścieżki, która je uruchomiła),
  wraz z odpowiedzią narzędzia — przydatne do celów audytowych. Zobacz
  [katalog zdarzeń](/pl/webhooks/events).
</Note>

---

## Weryfikacja podpisu

Bezpośrednie wywołania narzędzi są podpisywane tak samo jak webhooki, przy użyciu sekretu webhooka organizacji:

- `X-ThunderPhone-Signature-V2` podpisuje znacznik czasu, metodę, ścieżkę i
  parametry zapytania w przesłanej postaci oraz dokładne bajty treści. Odrzucaj żądania, których
  znacznik czasu różni się od czasu systemowego o więcej niż 5 minut.
- `X-ThunderPhone-Signature` (starsza wersja) podpisuje tylko bajty treści,
  pusty ciąg bajtów dla `GET` / `DELETE`. Nadal jest wysyłany bez zmian.

Pomocnicze funkcje SDK sprawdzają nagłówek V2, w tym 5-minutowe okno:

<CodeGroup>
```python Python
import json

from fastapi import FastAPI, HTTPException, Request
from thunderphone import verify_signature

app = FastAPI()

@app.post("/appointments/search")
async def search_appointments(request: Request):
    body = await request.body()
    query = request.scope.get("query_string", b"").decode("latin-1")
    path = request.url.path + (f"?{query}" if query else "")

    if not verify_signature(
        request.headers.get("X-ThunderPhone-Signature-V2"),
        secret=WEBHOOK_SECRET,
        method=request.method,
        path=path,
        body=body,
    ):
        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
import express from "express";
import { verifySignature } from "@thunderphone/sdk";

app.post('/appointments/search', express.raw({type: 'application/json'}), (req, res) => {
  const ok = verifySignature({
    header: req.header('X-ThunderPhone-Signature-V2'),
    secret: WEBHOOK_SECRET,
    method: req.method,
    path: req.originalUrl,
    body: req.body,
  });
  if (!ok) 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>

Pełne instrukcje — podpisywany ciąg, szczegółowy przykład, kod bez
SDK, przypadek `GET` / `DELETE` oraz zastrzeżenie dotyczące braku sekretu — znajdziesz w sekcji [Weryfikowanie podpisów webhooków](/pl/guides/verify-webhook-signatures).

---

## Przykład: kompletny proces rezerwacji

Oto zestaw narzędzi dla kompletnego systemu Umawiania wizyt:

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

---

## Najlepsze praktyki

<AccordionGroup>
  <Accordion title="Pisz jasne opisy">
    Pole `description` pomaga AI zrozumieć, **kiedy** użyć narzędzia. Precyzyjnie opisz, co robi i kiedy należy go użyć.
  </Accordion>

  <Accordion title="Prawidłowo obsługuj błędy">
    Zwracaj komunikaty o błędach zrozumiałe dla AI: `{"error": "No slots available for that date"}` zamiast ogólnych błędów 500.
  </Accordion>

  <Accordion title="Zachowaj zwięzłość odpowiedzi">
    Zwracaj tylko to, czego AI potrzebuje, aby kontynuować rozmowę. Duże ładunki danych spowalniają czas odpowiedzi.
  </Accordion>

  <Accordion title="Rozważnie używaj pól wymaganych">
    Oznaczaj pola jako `required` tylko wtedy, gdy jest to naprawdę konieczne. AI poprosi użytkownika o wymagane informacje przed wywołaniem narzędzia.
  </Accordion>
</AccordionGroup>

---

## Powiązane

<CardGroup cols={2}>
  <Card title="Wbudowane narzędzia" icon="wrench" href="/pl/guides/built-in-tools">
    Uruchamiaj zarządzane przez platformę działania połączeń bez definiowania punktu końcowego.
  </Card>
  <Card title="Połączenia z aplikacjami" icon="plug" href="/pl/guides/connect-apps">
    Narzędzia zarządzane przez platformę dla HubSpot, Salesforce, Slack, Google
    Calendar, Google Sheets i Cal.com — nie wymagają punktu końcowego.
  </Card>
  <Card title="Serwery MCP" icon="server" href="/pl/guides/mcp-servers">
    Podłącz serwer MCP i pozwól agentowi wywoływać jego narzędzia.
  </Card>
  <Card title="Połączenia API" icon="code" href="/pl/guides/api-connections">
    Integracje REST wielokrotnego użytku, które możesz podłączać do agentów.
  </Card>
  <Card title="Weryfikuj podpisy webhooków" icon="shield-check" href="/pl/guides/verify-webhook-signatures">
    Jeden pomocnik weryfikacyjny dla webhooków i wywołań narzędzi.
  </Card>
</CardGroup>
