✨ Świeża dostawa•nowe kody na kinetyka.pl: Gemini Pro 18 mies. 170 zł•Cursor, ElevenLabs, Lovable i więcej, roczne plany AI w ułamku ceny Zobacz →
Przejdź do treści
Artykuły

Function calling (tool use) po polsku: jak AI wywołuje Twoje funkcje

Jak model prosi o wywołanie funkcji, a Twój kod ją wykonuje. Działający przykład w Pythonie z trzema narzędziami i prawdziwymi przebiegami.

11 min czytania
Logo OpenAI - function calling po polsku z działającym przykładem

👁 116 przeczytań

// w skrócie
  • Function calling to mechanizm, w którym model językowy nie wykonuje kodu, lecz zwraca ustrukturyzowaną prośbę - np. pogoda(miasto='Gdańsk') - a Twój program wywołuje funkcję i odsyła wynik.
  • Mechanizm obsługują wszystkie duże API: OpenAI, Anthropic (Claude), Google (Gemini), Mistral, DeepSeek i Qwen, a format opisu funkcji oparty jest na JSON Schema.
  • Przykład z trzema funkcjami (pogoda, kalkulator, Wikipedia) uruchomiony na modelu openai/gpt-5.6-luna przez OpenRouter kosztował 0,001 USD łącznie za trzy testowe pytania.

Function calling (w Claude nazywa się to tool use) to mechanizm, w którym model językowy nie wykonuje kodu sam, tylko odpisuje: „wywołaj funkcję X z takimi argumentami”. Twój program wykonuje funkcję, odsyła wynik, a model składa z niego odpowiedź. Poniżej pokazuję cały obieg na działającym przykładzie w Pythonie (pogoda, kalkulator, Wikipedia), z prawdziwymi przebiegami z 4 października 2026. To drugi krok ścieżki Agenci AI od zera.

Stan na 4 października 2026

  • Function calling obsługują wszystkie duże API: OpenAI, Anthropic (Claude), Google (Gemini), Mistral, DeepSeek, Qwen. Format jest prawie taki sam: opis funkcji w JSON Schema.
  • Przykład uruchomiłem na Windows 11, Python 3.13, biblioteka openai 3.24.0, model openai/gpt-5.6-luna przez OpenRouter.
  • Koszt trzech testowych pytań: 0,001 USD łącznie.
  • Kod jest w paczce promptowy-agenci-starter (plik 01_function_calling.py).

Co to jest function calling, prostymi słowami

Model językowy umie tylko jedno: przyjąć tekst i oddać tekst. Nie ma internetu, zegarka ani kalkulatora. Function calling to umowa: w zapytaniu do API dokładasz listę funkcji, które masz u siebie, z opisem i listą parametrów. Model, zamiast zgadywać, może odpowiedzieć ustrukturyzowaną prośbą: „chcę pogoda(miasto="Gdańsk")”.

Najważniejsza rzecz, którą warto zrozumieć na starcie: model niczego nie uruchamia. To Twój kod czyta tę prośbę, woła prawdziwą funkcję, a wynik dokleja do rozmowy. Dzięki temu Ty decydujesz, co model może zrobić. Jeśli nie dasz mu funkcji „usuń plik”, nie ma jak czegoś usunąć.

Jeśli nie wiesz jeszcze, czym jest zapytanie do API i token, zacznij od przewodnika po API modeli AI i tekstu o tokenach.

Cały obieg w 5 krokach

  1. Opisujesz funkcje. Nazwa, opis po ludzku i parametry w JSON Schema. Opis jest dla modelu instrukcją, kiedy ma po funkcję sięgnąć.
  2. Wysyłasz pytanie razem z listą funkcji (parametr tools).
  3. Model odpowiada prośbą o wywołanie (tool_calls) albo zwykłym tekstem, jeśli funkcje nie są potrzebne.
  4. Twój kod wykonuje funkcję i dokleja wynik do rozmowy jako wiadomość z rolą tool, z tym samym tool_call_id.
  5. Wysyłasz rozmowę jeszcze raz. Model albo prosi o kolejne funkcje, albo daje odpowiedź końcową.

Kroki 3-5 powtarzają się w pętli. Jeśli tę pętlę oddasz modelowi i pozwolisz mu samemu decydować, ile razy i po co sięga po narzędzia, masz już agenta. O tym jest tekst Jak zbudować agenta AI w Pythonie.

Jak wygląda prośba modelu o wywołanie funkcji

Zapytałem „Ile to 15% z 2340 zł?”, dając modelowi kalkulator. Oto surowa odpowiedź API, bez żadnej obróbki:

# surowa wiadomość modelu (message) na pytanie „Ile to 15% z 2340 zł?”
{
  "role": "assistant",
  "tool_calls": [
    {
      "id": "call_m25uxE3pxeXOqgLd33CWNInn",
      "function": {
        "arguments": "{\"wyrazenie\":\"2340*0.15\"}",
        "name": "kalkulator"
      },
      "type": "function",
      "index": 0
    }
  ]
}
finish_reason: tool_calls koszt 6.58e-05

Zwróć uwagę na trzy rzeczy:

  • pole content jest puste: model nic nie napisał, tylko poprosił o funkcję;
  • arguments to tekst z JSON-em, nie gotowy obiekt. Trzeba go sparsować (json.loads), a w razie błędu odesłać modelowi komunikat;
  • finish_reason ma wartość tool_calls. Po tym poznajesz, że rozmowa się nie skończyła.

Działający przykład: pogoda, kalkulator i Wikipedia

Napisałem trzy zwykłe funkcje w Pythonie. Żadna nie wymaga klucza API: pogodę daje darmowe Open-Meteo, wyszukiwanie daje API polskiej Wikipedii, a kalkulator liczy lokalnie. Kalkulator celowo nie używa eval(), tylko rozbiera wyrażenie przez moduł ast. Gdyby model (albo ktoś, kto mu podsunie złośliwy tekst) wpisał tam polecenie systemowe, eval by je wykonał.

"""01 - Function calling (tool use): model prosi o wywołanie Twojej funkcji, Ty ją wykonujesz.
Uruchom: python 01_function_calling.py "Jaka jest pogoda w Gdańsku i ile to 15% z 2340 zł?"
"""
import ast, json, operator, os, sys
import requests
from dotenv import load_dotenv
from openai import OpenAI

load_dotenv()
MODEL = os.getenv("MODEL", "openai/gpt-5.6-luna")
client = OpenAI(base_url="https://openrouter.ai/api/v1", api_key=os.environ["OPENROUTER_API_KEY"])
UA = {"User-Agent": "promptowy-agenci-starter/1.0"}

# --- 1. Zwykłe funkcje w Pythonie ---------------------------------------------
def pogoda(miasto: str) -> dict:
    geo = requests.get("https://geocoding-api.open-meteo.com/v1/search",
                       params={"name": miasto, "count": 1, "language": "pl"}, headers=UA, timeout=15).json()
    if not geo.get("results"):
        return {"blad": f"nie znam miasta {miasto}"}
    m = geo["results"][0]
    w = requests.get("https://api.open-meteo.com/v1/forecast", params={
        "latitude": m["latitude"], "longitude": m["longitude"],
        "current": "temperature_2m,wind_speed_10m,precipitation", "timezone": "Europe/Warsaw"},
        headers=UA, timeout=15).json()
    return {"miasto": m["name"], **w["current"]}

OPS = {ast.Add: operator.add, ast.Sub: operator.sub, ast.Mult: operator.mul,
       ast.Div: operator.truediv, ast.Pow: operator.pow, ast.USub: operator.neg}
def kalkulator(wyrazenie: str) -> dict:
    def licz(n):  # bezpieczne liczenie: tylko liczby i + - * / **
        if isinstance(n, ast.Constant) and isinstance(n.value, (int, float)): return n.value
        if isinstance(n, ast.BinOp): return OPS[type(n.op)](licz(n.left), licz(n.right))
        if isinstance(n, ast.UnaryOp): return OPS[type(n.op)](licz(n.operand))
        raise ValueError("niedozwolone wyrażenie")
    return {"wyrazenie": wyrazenie, "wynik": licz(ast.parse(wyrazenie, mode="eval").body)}

def szukaj_wikipedia(fraza: str) -> dict:
    r = requests.get("https://pl.wikipedia.org/w/api.php", params={
        "action": "query", "list": "search", "srsearch": fraza, "srlimit": 3, "format": "json"},
        headers=UA, timeout=15).json()
    return {"wyniki": [{"tytul": h["title"], "fragment": h["snippet"].replace('<span class="searchmatch">', "").replace("</span>", "")}
                       for h in r["query"]["search"]]}

FUNKCJE = {"pogoda": pogoda, "kalkulator": kalkulator, "szukaj_wikipedia": szukaj_wikipedia}

# --- 2. Opis funkcji dla modelu (JSON Schema) ----------------------------------
def narzedzie(nazwa, opis, param, opis_param):
    return {"type": "function", "function": {"name": nazwa, "description": opis, "parameters": {
        "type": "object", "properties": {param: {"type": "string", "description": opis_param}}, "required": [param]}}}

TOOLS = [
    narzedzie("pogoda", "Aktualna pogoda w podanym mieście (temperatura, wiatr, opad).", "miasto", "nazwa miasta, np. Kraków"),
    narzedzie("kalkulator", "Liczy wyrażenie arytmetyczne. Używaj zamiast liczenia w pamięci.", "wyrazenie", "np. 2340*0.15"),
    narzedzie("szukaj_wikipedia", "Szuka w polskiej Wikipedii, zwraca 3 tytuły z fragmentami.", "fraza", "czego szukać"),
]

# --- 3. Rozmowa: model -> wywołania funkcji -> wyniki -> odpowiedź --------------
pytanie = sys.argv[1] if len(sys.argv) > 1 else "Jaka jest teraz pogoda w Gdańsku i ile to 15% z 2340 zł?"
messages = [{"role": "system", "content": "Odpowiadaj po polsku, krótko. Do faktów i liczenia używaj narzędzi."},
            {"role": "user", "content": pytanie}]
koszt = 0.0
for runda in range(1, 6):
    r = client.chat.completions.create(model=MODEL, messages=messages, tools=TOOLS)
    koszt += getattr(r.usage, "cost", 0) or 0
    msg = r.choices[0].message
    if not msg.tool_calls:  # model nie chce już narzędzi = gotowa odpowiedź
        print(f"\n[runda {runda}] ODPOWIEDŹ:\n{msg.content}")
        break
    messages.append(msg.model_dump(exclude_none=True))
    for call in msg.tool_calls:
        args = json.loads(call.function.arguments)
        print(f"[runda {runda}] model prosi: {call.function.name}({json.dumps(args, ensure_ascii=False)})")
        try:
            wynik = FUNKCJE[call.function.name](**args)
        except Exception as e:  # błąd też oddajemy modelowi, niech sam zdecyduje
            wynik = {"blad": str(e)}
        print(f"           wynik: {json.dumps(wynik, ensure_ascii=False)[:300]}")
        messages.append({"role": "tool", "tool_call_id": call.id, "content": json.dumps(wynik, ensure_ascii=False)})
print(f"\nmodel: {MODEL}, rund: {runda}, koszt: {koszt:.6f} USD")

Instalacja to pip install openai requests python-dotenv i plik .env z kluczem OPENROUTER_API_KEY. Przez OpenRouter ten sam kod działa z modelami OpenAI, Google, Anthropic czy DeepSeek: zmieniasz tylko nazwę modelu w zmiennej MODEL.

Przebieg 1: dwie funkcje naraz

> python 01_function_calling.py "Jaka jest teraz pogoda w Gdańsku i ile to 15% z 2340 zł?"
[runda 1] model prosi: pogoda({"miasto": "Gdańsk"})
           wynik: {"miasto": "Gdańsk", "time": "2026-10-04T13:45", "interval": 900, "temperature_2m": 19.0, "wind_speed_10m": 14.0, "precipitation": 0.0}
[runda 1] model prosi: kalkulator({"wyrazenie": "2340*0.15"})
           wynik: {"wyrazenie": "2340*0.15", "wynik": 351.0}

[runda 2] ODPOWIEDŹ:
W Gdańsku jest teraz **19°C**, wiatr **14 km/h**, bez opadów.  
**15% z 2340 zł = 351 zł.**

model: openai/gpt-5.6-luna, rund: 2, koszt: 0.000260 USD

Model w pierwszej rundzie poprosił o dwie funkcje jednocześnie (to się nazywa parallel tool calls). Mój kod wykonał obie, odesłał wyniki i w drugiej rundzie dostałem gotową odpowiedź. Temperatura 19 stopni to faktyczny odczyt z Open-Meteo z 13:45, a nie zgadywanie modelu.

Przebieg 2: narzędzie zwraca śmieci

Mam to spisane w całości

Zebrałem te rzeczy w ebookach, które możesz pobrać za darmo - bez zapisu na listę, bez haczyka.

Pobierz ebooki

Ten przebieg jest ciekawszy, bo pokazuje typowy problem:

> python 01_function_calling.py "Kto zbudował Pałac Kultury i Nauki i ile lat ma ten budynek w 2026 roku?"
[runda 1] model prosi: szukaj_wikipedia({"fraza": "Pałac Kultury i Nauki kto zbudował ukończony 1955"})
           wynik: {"wyniki": [{"tytul": "Siedem Sióstr (Moskwa)", "fragment": "2019-09-05]  (ros.). Jarosław Zieliński: Pałac Kultury i Nauki, Księży Młyn 2012, s.16. Pałac Kultury i Nauki w Warszawie [online], www.pkin.pl [dostęp"}, {"tytul": "Drezno", "fragment": " kościół Krzyża (do 1955), Zwinger (do 1963), kated
[runda 2] model prosi: kalkulator({"wyrazenie": "2026-1955"})
           wynik: {"wyrazenie": "2026-1955", "wynik": 71}

[runda 3] ODPOWIEDŹ:
Pałac Kultury i Nauki zbudował **Związek Radziecki** jako dar dla Polski. Projekt opracował **Lew Rudniew**, a budowę prowadzili radzieccy robotnicy.

Oddano go do użytku **22 lipca 1955 roku**, więc w 2026 roku będzie miał **71 lat** - dokładnie od 22 lipca; wcześniej w tym roku będzie miał jeszcze 70 lat.

model: openai/gpt-5.6-luna, rund: 3, koszt: 0.000662 USD

Model wpisał do wyszukiwarki zbyt długie zapytanie („Pałac Kultury i Nauki kto zbudował ukończony 1955”) i Wikipedia zwróciła artykuły o moskiewskich wieżowcach i o Dreźnie. Model tego nie zauważył głośno, tylko odpowiedział z własnej wiedzy. Tym razem fakty się zgadzają (oddanie do użytku 22 lipca 1955, projekt Lwa Rudniewa), ale gdyby chodziło o świeże dane, mielibyśmy halucynację z pozorem źródła. Wnioski, które z tego wyciągnąłem:

  • w opisie funkcji wyszukiwania dopisz: „używaj krótkich zapytań, 2-4 słowa”;
  • w poleceniu systemowym każ modelowi mówić, kiedy narzędzie nie dało odpowiedzi;
  • loguj wszystkie wywołania i wyniki. Bez logu nie zauważyłbym, że odpowiedź nie pochodzi z Wikipedii.

Przebieg 3: model wie, kiedy funkcje są zbędne

> python 01_function_calling.py "Napisz jedno zdanie zachęty do nauki programowania."

[runda 1] ODPOWIEDŹ:
Zacznij naukę programowania już dziś i twórz własne pomysły, aplikacje oraz nowe możliwości kariery!

model: openai/gpt-5.6-luna, rund: 1, koszt: 0.000080 USD

Prośba o zdanie zachęty nie wymagała żadnej funkcji, więc model odpowiedział od razu, w jednej rundzie, za 0,00008 USD. Nie musisz sam decydować, kiedy dać modelowi narzędzia, a kiedy nie. Dajesz zawsze, a model wybiera.

Jak pisać opisy funkcji, żeby model ich dobrze używał

  • Opis to instrukcja. „Liczy wyrażenie arytmetyczne. Używaj zamiast liczenia w pamięci” działa lepiej niż „kalkulator”.
  • Parametry z przykładami. "np. 2340*0.15" w opisie parametru ucina większość błędów formatu.
  • Mało funkcji naraz. 3-10 dobrze opisanych funkcji to bezpieczny zakres. Przy kilkudziesięciu model zaczyna mylić podobne narzędzia.
  • Wynik w JSON, krótki. Każdy znak wyniku wraca do modelu jako tokeny wejściowe i kosztuje. Przycinaj długie odpowiedzi.
  • Błąd też jest wynikiem. Zamiast przerywać program, odeślij {"blad": "nie znam miasta"}. Model zwykle sam poprawi argument.

Function calling w OpenAI, Claude i Gemini: różnice

APINazwaGdzie opis funkcjiJak przychodzi prośbaJak odsyłasz wynik
OpenAI (Chat Completions, też OpenRouter)function calling / toolstools=[{"type":"function","function":{...}}]message.tool_callswiadomość role: "tool" z tool_call_id
Anthropic (Claude)tool usetools=[{"name","description","input_schema"}]blok tool_use w treści, stop_reason: "tool_use"blok tool_result w wiadomości user
Google (Gemini)function callingfunction_declarationsfunctionCall w odpowiedzifunctionResponse

Pod spodem to ten sam pomysł. Dlatego biblioteki takie jak LangGraph czy OpenAI Agents SDK potrafią przełączać się między dostawcami, a protokół MCP pozwala opisać narzędzia raz dla wszystkich aplikacji.

Bezpieczeństwo: o czym pamiętać

  • Model może wywołać funkcję z argumentami, których się nie spodziewasz. Waliduj je w kodzie (zakresy, ścieżki, typy).
  • Funkcje, które coś zmieniają (wysyłają maila, płacą, kasują), powinny prosić człowieka o potwierdzenie.
  • Tekst ze stron WWW i dokumentów, który trafia do modelu przez narzędzie, może zawierać ukryte polecenia (prompt injection). Traktuj go jako dane, nie jako rozkazy.

Najczęstsze pytania

Czym się różni function calling od tool use?

Niczym istotnym. OpenAI i Google mówią „function calling”, Anthropic „tool use”. W obu przypadkach model zwraca nazwę narzędzia i argumenty, a kod je wykonuje.

Czy function calling działa po polsku?

Tak. Opisy funkcji i parametrów pisałem po polsku, model rozumiał je bez problemu i sam wpisywał polskie nazwy miast. Nazwy funkcji lepiej trzymać bez polskich znaków (szukaj_wikipedia), bo niektóre API dopuszczają w nazwach tylko litery łacińskie, cyfry i podkreślenia.

Czy każdy model obsługuje function calling?

Nie. Duże modele komercyjne tak. Lokalne modele w Ollamie obsługują narzędzia, jeśli mają to w szablonie (np. Llama 3.1, Qwen, Mistral), ale mniejsze częściej mylą argumenty. Na OpenRouterze lista modeli ma filtr „tools”.

Ile kosztuje function calling?

Tyle, co zwykłe tokeny, ale każda runda to osobne zapytanie, a opisy funkcji doliczają się do wejścia przy każdym zapytaniu. U mnie pytanie z dwiema funkcjami kosztowało 0,00026 USD, a z trzema rundami 0,00066 USD.

Czy model może sam uruchomić kod na moim komputerze?

Nie. Model tylko prosi. Uruchamia Twój program i tylko te funkcje, które sam podłączysz.

Function calling a agent AI: czym się różnią?

Function calling to mechanizm: jedno zapytanie, jedna prośba o funkcję. Agent to pętla, w której model wiele razy wybiera narzędzia, ogląda wyniki i decyduje, co dalej, aż skończy zadanie. Przykłady agentów są w tekście Agent AI: przykłady.

Google · Twoje źródłaPromptowy wyżej w Twoim Google - jednym kliknięciemDodaj do preferowanych źródeł →

Źródła i data sprawdzenia

// Newsletter

Cały tydzień w AI, w jednym mailu

Wybrane premiery, narzędzia i analizy. Raz w tygodniu, prosto do skrzynki.

Zapisz się za darmo →
Za darmo. Wypisujesz się jednym kliknięciem.
// czytaj też

Podobne tematy na Promptowym

Piotr Olszewski

Piotr Olszewski

AUTOR I WYDAWCA

Piotr Olszewski - twórca i autor Promptowego, polskiego serwisu o sztucznej inteligencji. Codziennie śledzi premiery modeli, narzędzia i regulacje AI, i tłumaczy je prostym, konkretnym językiem.

// mapa strony

🛒 Sklep Kinetyka Google AI Gemini Pro 170 zł CapCut Pro 460 zł/rok Lovable Pro 400 zł/rok Zobacz wszystko →
promptowy w liczbach 0tekstów w archiwum0newsów z ostatnich 7 dni0modeli wideo w obserwatorium0zagadek w grach
× ‹ powiększenie ›