Function calling 2026-ban: OpenAI, Claude és Gemini tool use gyakorlati összehasonlítása

Gyakorlati összehasonlítás: hogyan definiálsz, hívsz és evaluálsz function callingot OpenAI, Anthropic Claude és Google Gemini API-val 2026-ban, futtatható Python példákkal és production mintákkal.

Function calling 2026: OpenAI vs Claude vs Gemini

Frissítve: 2026. szeptember 1.

A function calling (más néven tool use) az a mechanizmus, amellyel egy nagy nyelvi modell strukturált JSON-hívást ad vissza egy általad definiált függvényre, ahelyett hogy csak szabad szöveget generálna. Te futtatod le a függvényt, visszaadod az eredményt a modellnek, és a beszélgetés folytatódik. 2026-ban az OpenAI, Anthropic és Gemini mindegyike támogatja, de a részletek (schema validáció, párhuzamos hívások, streaming, forced tool choice) vendorokként másképp működnek. Ebben a cikkben mindhármat összehasonlítom futtatható példákkal, és megmutatom, milyen mintákat használok az éles rendszereimben.

  • Mindhárom vendor JSON Schema alapú paraméter-definíciót vár, de csak az OpenAI strict: true és a Gemini responseSchema ad kemény schema-kényszerítést a modell szintjén.
  • Az Anthropic Claude a legmegbízhatóbb párhuzamos tool call-ok esetén (több tool egy asszisztens fordulóban); az OpenAI ugyanezt támogatja, a Gemini 2.5 pedig 2026 elején zárkózott fel.
  • A tool_choice paraméterrel kényszerítheted a modellt, hogy egy adott toolt hívjon. Hibakeresésnél és determinisztikus workflow-nál nélkülözhetetlen.
  • Az agentic loop (modell hív, te végrehajtasz, visszaadod, modell folytatja) minden vendornál ugyanaz a séma, csak a message formátum különbözik.
  • Az eval réteg (schema-validitás, tool-call precision/recall, argumentum-egyezés) fontosabb, mint a modell választása. Enélkül nem tudod, mit rontasz el.
  • A tool schema tokeneket fogyaszt minden hívásnál. 10+ tool esetén érdemes tool routing vagy MCP szerver mögé rejteni őket.

Mi az a function calling és miben különbözik a tool use-tól?

A function calling és a tool use ugyanaz a mechanizmus, csak más néven fut az egyes vendoroknál. Az OpenAI eredetileg „function calling"-nak nevezte 2023-ban, majd 2024-ben átnevezte „tools"-ra (a régi functions paraméter deprecated lett). Az Anthropic mindig „tool use"-nak hívta. A Gemini a „function calling" nevet használja hivatalosan, de a request JSON-ban tools és functionDeclarations szerepel.

A folyamat mindenütt ugyanaz: (1) tool schemát adsz a modellnek a paraméterek JSON Schema leírásával, (2) a modell egy speciális tool call üzenetet küld vissza, ami nem szabad szöveg, hanem egy strukturált objektum a függvény nevével és argumentumaival, (3) te futtatod a függvényt, (4) az eredményt tool result üzenetként visszaküldöd, (5) a modell folytatja a beszélgetést vagy újabb toolt hív.

Fontos, hogy a modell nem hívja meg a függvényt. Csak jelzi, hogy szerinte melyiket kellene, és milyen argumentumokkal. A végrehajtás mindig a te kódodban történik, ami biztonsági szempontból is előny: te validálhatod a paramétereket, rate-limitelheted a hívásokat, és tetszőleges autentikációt tehetsz elé. Az MCP protokoll ezt a mintát általánosítja: a tool implementációk külön szerverekbe kerülhetnek, és a kliens csak beköti őket a modellhez. Erről részletesen írtam a Model Context Protocol (MCP) 2026-os gyakorlati útmutatóban.

Vendor-összehasonlító táblázat

Az alábbi táblázat a 2026 augusztusi API-verziók alapján készült (OpenAI Responses API, Anthropic Messages API 2023-06-01, Gemini API v1beta). A részletek gyorsan változnak, úgyhogy mielőtt production-be teszed, ellenőrizd a hivatalos changelogokat.

FunkcióOpenAI (GPT-4.1/5)Anthropic (Claude 4/4.5)Google (Gemini 2.5)
Tool definíció mezőjetools[].functiontools[] (input_schema)tools[].functionDeclarations
Paraméter formátumJSON SchemaJSON SchemaOpenAPI 3.0 részhalmaza
Strict schema kényszerítésIgen (strict: true)Nem (soft, prompt-alapú)Igen (responseSchema)
Párhuzamos tool call-okIgen (alapból)Igen (disable_parallel_tool_use kapcsoló)Igen (2.5-től stabil)
Tool choice kényszerítéseauto / required / {"type":"function","name":"x"}auto / any / {"type":"tool","name":"x"}AUTO / ANY / NONE
Streaming tool call chunkokDelta-alapú (function argumentumok karakterenként)Content block delta-k (input_json_delta)Chunkonként teljes függvényhívás
Tool result formátumrole: "tool" üzenetrole: "user" + tool_result blockrole: "function" part
Beépített tool-ok (web search, code)Igen (Responses API-ban)Igen (server tools: web_search, computer_use)Igen (Google Search grounding, code execution)

A táblázatból már látszik a fő tanulság: a mechanizmus koncepcionálisan azonos, de a mezőnevek és a message rétegződés eltér. Ezért egy vendor-agnosztikus wrapper (LangChain, LiteLLM, saját absztrakció) hasznos, ha több modell mögé akarod ugyanazt a tool-készletet betenni.

OpenAI function calling gyakorlatban

Az OpenAI Responses API 2025-ben váltotta le a Chat Completions-t az új funkciók elsődleges felületeként. A Chat Completions továbbra is működik, de az új képességek (built-in tools, reasoning summary) csak a Responses API-ban élnek. A tool schema mindkét felületen ugyanaz: JSON Schema a paraméterekhez, és opcionális strict: true, ami garantálja, hogy a modell csak schema-konform argumentumokat ad vissza.

Az alábbi példa egy időjárás-toolt definiál és futtat egy teljes agentic loopban. A strict mód azt jelenti, hogy a modell hallucinált mezőket vagy hibás típust nem tud visszaadni. Production-ben ez óriási különbség, mert a json.loads() utáni Pydantic-validálás szinte sosem bukik el.

from openai import OpenAI
import json

client = OpenAI()

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Aktuális időjárás egy adott városra. Csak ha a felhasználó időjárást kér.",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {"type": "string", "description": "Város neve, pl. 'Budapest'"},
                "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
            },
            "required": ["city", "unit"],
            "additionalProperties": False
        },
        "strict": True
    }
}]

def get_weather(city: str, unit: str) -> dict:
    # Éles kódban itt egy valódi API hívás lenne.
    return {"city": city, "temp": 22, "unit": unit, "conditions": "napos"}

messages = [{"role": "user", "content": "Milyen az idő Budapesten Celsiusban?"}]

while True:
    resp = client.chat.completions.create(
        model="gpt-4.1",
        messages=messages,
        tools=tools,
        tool_choice="auto",
    )
    msg = resp.choices[0].message
    messages.append(msg)

    if not msg.tool_calls:
        print(msg.content)
        break

    for call in msg.tool_calls:
        args = json.loads(call.function.arguments)
        if call.function.name == "get_weather":
            result = get_weather(**args)
        else:
            result = {"error": f"unknown tool {call.function.name}"}
        messages.append({
            "role": "tool",
            "tool_call_id": call.id,
            "content": json.dumps(result)
        })

Két buktató, amit sokan elkövetnek. Először: a strict: true-hoz kötelező az additionalProperties: false, és minden mezőnek szerepelnie kell a required tömbben. Opcionális mezőt ["string", "null"] union típussal kell kifejezned. Másodszor: a tool_call_id-t pontosan vissza kell adnod a tool response üzenetben, különben a modell összekeveri több párhuzamos hívás eredményét. Ezt a bugot én is elszenvedtem egy éles projektben, és órákba került, mire rájöttem. A pontos szabályok a hivatalos function calling dokumentációban vannak leírva.

Anthropic Claude tool use gyakorlatban

A Claude API tool use-a filozófiában közel áll az OpenAI-hoz, de két lényeges eltérés van. Először: a Claude message-formátuma content blockokból áll, és egy asszisztens üzenet több blokkot tartalmazhat, pl. egy text blokk (a modell magyarázata) és egy vagy több tool_use blokk (a hívások). Másodszor: nincs kemény strict mód. Az Anthropic a promptra és a rendszer belső finomhangolására támaszkodik, hogy a modell schema-konform outputot adjon. Éles rendszerben ez azt jelenti, hogy Pydantic-validálást mindig teszek a tool call argumentumaira, függetlenül attól, mennyire tiszta a schema.

import anthropic
import json

client = anthropic.Anthropic()

tools = [{
    "name": "get_weather",
    "description": "Aktuális időjárás egy adott városra.",
    "input_schema": {
        "type": "object",
        "properties": {
            "city": {"type": "string"},
            "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
        },
        "required": ["city", "unit"]
    }
}]

def get_weather(city, unit):
    return {"city": city, "temp": 22, "unit": unit, "conditions": "napos"}

messages = [{"role": "user", "content": "Milyen az idő Budapesten Celsiusban?"}]

while True:
    resp = client.messages.create(
        model="claude-sonnet-4-5",
        max_tokens=1024,
        tools=tools,
        messages=messages,
    )
    messages.append({"role": "assistant", "content": resp.content})

    if resp.stop_reason != "tool_use":
        print(next(b.text for b in resp.content if b.type == "text"))
        break

    tool_results = []
    for block in resp.content:
        if block.type != "tool_use":
            continue
        if block.name == "get_weather":
            result = get_weather(**block.input)
        else:
            result = {"error": f"unknown tool {block.name}"}
        tool_results.append({
            "type": "tool_result",
            "tool_use_id": block.id,
            "content": json.dumps(result)
        })
    messages.append({"role": "user", "content": tool_results})

Figyeld meg, hogy a tool eredmény role: "user" üzenetként megy vissza (nem "tool"-ként, mint az OpenAI-nál), és a content egy lista tool_result blokkokkal. A tool_use_id-t itt is pontosan párosítani kell. Ha egy tool hibát dob, tedd bele az is_error: True mezőt a tool_result-ba. A modell ezt hasznos jelként használja retry vagy user-facing hibaüzenet generálásához.

Gemini function calling gyakorlatban

A Gemini function calling formátuma az OpenAPI 3.0 spec egy szűkített részhalmazát használja. Ez nem teljesen JSON Schema, ezért néhány kulcsszó (pl. $ref, oneOf) nem támogatott. A Gemini 2.5 óta a párhuzamos function calling stabilan működik, és a toolConfig.functionCallingConfig.mode mezővel finoman szabályozható, hogy a modell mikor hívhat toolt.

from google import genai
from google.genai import types

client = genai.Client()

weather_tool = types.Tool(function_declarations=[
    types.FunctionDeclaration(
        name="get_weather",
        description="Aktuális időjárás egy adott városra.",
        parameters={
            "type": "OBJECT",
            "properties": {
                "city": {"type": "STRING"},
                "unit": {"type": "STRING", "enum": ["celsius", "fahrenheit"]}
            },
            "required": ["city", "unit"]
        }
    )
])

def get_weather(city, unit):
    return {"city": city, "temp": 22, "unit": unit, "conditions": "napos"}

contents = [types.Content(role="user", parts=[
    types.Part(text="Milyen az idő Budapesten Celsiusban?")
])]

while True:
    resp = client.models.generate_content(
        model="gemini-2.5-pro",
        contents=contents,
        config=types.GenerateContentConfig(tools=[weather_tool])
    )
    part = resp.candidates[0].content.parts[0]
    contents.append(resp.candidates[0].content)

    if not part.function_call:
        print(part.text)
        break

    fc = part.function_call
    result = get_weather(**dict(fc.args)) if fc.name == "get_weather" else {"error": "unknown"}
    contents.append(types.Content(role="user", parts=[
        types.Part(function_response=types.FunctionResponse(name=fc.name, response=result))
    ]))

A Gemininek van egy kellemetlen sajátossága: a type mezőket nagybetűvel kéri ("OBJECT", "STRING"), nem kisbetűvel, mint a JSON Schema. Ha copy-paste-elsz OpenAI vagy Anthropic schemát, ez lesz az első hibád. A Google Gemini function calling dokumentációja részletezi a támogatott OpenAPI részhalmazt.

Párhuzamos tool call-ok és agentic loop

A párhuzamos tool calling azt jelenti, hogy egy modell-forduló több tool_use blokkot ad vissza, pl. „nézd meg az időjárást Budapesten és Bécsben". Ha ezt szekvenciálisan futtatnád, két teljes körutat kellene tenni. Párhuzamosan az összes tool egy körben lefut, és az eredmények egy tool result batchben mennek vissza.

Mindhárom vendor támogatja, de van egy csapda. Ha a tooljaid nem valóban függetlenek (pl. az egyik írja, a másik olvassa ugyanazt az erőforrást), akkor a modell által kezdeményezett párhuzamosság inkonzisztens állapotot okozhat. Erre a Claude-nál a disable_parallel_tool_use: true a legtisztább megoldás, az OpenAI-nál a parallel_tool_calls: False. A Gemininél a system promptban kell szabályozni.

Az agentic loop szerkezete mindenütt ugyanaz:

  1. Küldd el a user üzenetet és a tool schemákat.
  2. Ha a modell tool callt ad vissza, futtasd le mindet (párhuzamosan, ha lehet).
  3. Küldd vissza az összes tool resultot egy üzenetben.
  4. Ismételd, amíg a modell szöveggel válaszol (stop_reason nem tool_use).
  5. Legyen egy max_iterations limit (én 10-et használok), különben egy hallucináló modell végtelen ciklusba tud kerülni.

Tool choice kényszerítése és streaming

Alapból mindhárom modell maga dönti el, hogy hívjon-e toolt (tool_choice: "auto"). Van három másik üzemmód, amit érdemes ismerni:

  • Kényszerített bármely tool. OpenAI: tool_choice: "required", Claude: tool_choice: {"type": "any"}, Gemini: mode: "ANY". A modell muszáj hív valamelyik toolt. Hasznos strukturált output kikényszerítéséhez, ha nem használsz külön Structured Outputs API-t.
  • Kényszerített konkrét tool. Mindhárom támogatja tool név megadásával. Ilyenkor a modell csak azt a toolt hívhatja, adott argumentumokkal. Determinisztikus tesztelésnél és ETL-jellegű pipeline-oknál használom.
  • Tool tiltás. OpenAI: tool_choice: "none", Gemini: mode: "NONE". A modell szabad szöveget ad, még ha toolok vannak is a requestben. Ez akkor jó, ha ugyanazt a rendszerpromptot futtatod tool-mentes módban is (pl. végső összefoglaló generáláshoz).

Streaming esetén mindhárom modell inkrementálisan küldi a tool call argumentumokat is. Az OpenAI karakterenként streameli a JSON stringet, ami azt jelenti, hogy a chunkok koncatenációja után kell json.loads()-ot hívni. Soha ne próbálj részleges JSON-t parse-olni. Az Anthropic input_json_delta eventekben küldi ugyanezt. A Gemini SDK a legkényelmesebb: minden chunk egy teljes, parse-olt function call objektumot ad. A Claude tool use dokumentáció jó példákat mutat streaming tool call feldolgozásra.

Schema-tervezési minták és gyakori hibák

Őszintén szólva a schema minősége sokkal jobban meghatározza a tool calling success ratet, mint a modell választása. Az alábbi minták növelik a helyes hívások arányát, függetlenül a vendortól. Ha mélyebben érdekel a strukturált output oldala, olvasd el a strukturált LLM kimenetek 2026-os útmutatót.

Leíró tool és paraméter description mezők

A description nem díszítés. A modell ezt olvassa, és ez alapján dönt. Egy jó tool description tartalmazza: mit csinál a tool, mikor érdemes használni, mit ne várjon tőle, és milyen a visszatérési érték. Pl. „Aktuális időjárás egy városra. Használd, ha a felhasználó jelenlegi vagy mai időjárást kér. Ne használd történelmi adatokhoz, arra a get_weather_history tool való. Visszaadja: hőmérséklet, csapadék, szélsebesség."

Kis, fókuszált toolok

Egy 15 paraméteres uber-tool sokkal kevésbé megbízható, mint 3 db 5 paraméteres tool. A modellek jól teljesítenek 5-10 tool alatt; 20 felett drámaian romlik a hit rate. Ha 20+ toolod van, gondolkodj tool routingon: egy meta-toolt hívsz először, ami eldönti, melyik alcsoportba tartozik a kérés, aztán csak azt a részhalmazt adod át a modellnek. Az MCP szerverek pontosan ezt teszik lehetővé skálázhatóan.

Enumek és korlátozott értékek

Ahol lehet, használj enum-ot. „Adj vissza egy prioritást (high/medium/low)" sokkal megbízhatóbb enumként, mint szabad szövegként. Ugyanígy minimum, maximum, pattern: minél több constraint, annál kevesebb hallucináció.

Idempotens és biztonságos defaultok

Feltételezd, hogy a modell időnként rossz argumentumokkal hív. Egy DELETE-jellegű toolnak legyen kétfázisú confirmation flow-ja: első hívás egy dry_run, ami visszaadja mit fog törölni, második hívás a confirm_token-nel a tényleges művelet.

Function calling evaluáció: amit tényleg mérni kell

Ha egyetlen dolgot kiemelnék ebből a cikkből, ez az: a function calling evaluáció nélkül vak repülés. Sokan csak azt mérik, hogy „jött-e helyes szöveges válasz a végén", ami elrejti a tool szintű hibákat. A minimum, amit én minden production tool-készletre bevezetek:

  1. Tool selection accuracy. A helyes toolt hívta-e a modell? (per-tool precision/recall)
  2. Argument correctness. A mezők megegyeznek-e az elvárt referenciával? (kulcsonkénti egzakt vagy szemantikus match)
  3. Schema validity rate. Hány százaléka a hívásoknak megy át Pydantic-validáláson? Éles rendszerben ez legyen 99%+.
  4. Latency per tool call. A tool schema tokenizálása is időt vesz igénybe. Nagy schema-készletnél mérd külön.
  5. Loop length distribution. Hány agentic körben ér el a modell a végállapotig? Ha nő, valami rosszul van (tool description, argument formátum, vagy hallucinál).

Ehhez ma Promptfoo-t vagy DeepEvalt használok golden settel; részletes összehasonlítás a DeepEval, Promptfoo és Ragas cikkben. A lényeg, hogy CI-be kösd be, és minden schema-módosítás után futtasd le. A tool description egyetlen szavának megváltoztatása is drasztikusan tudja mozgatni a hit ratet.

Gyakran Ismételt Kérdések

Miért nem hívja meg a modell a definiált függvényemet?

Három leggyakoribb ok: (1) a tool description-ja túl vague vagy nem említi meg, mikor kell használni; (2) a user prompt nem elég egyértelműen jelzi a szükségességet, próbáld ki tool_choice: "required" vagy specifikus tool erőltetéssel, hogy kiderüljön a schema vagy a prompt a hibás; (3) alacsony hőmérséklet mellett a modell konzervatívabb, próbáld temperature=0.2 körül, ne 0-n.

Használhatok ugyanazt a schemát OpenAI-hoz, Claude-hoz és Geminihez?

Kis módosítással igen. Az OpenAI és Claude ugyanazt a JSON Schema szintaxist várja (kisbetűs type-okkal). A Gemini nagybetűs type-okat kér, és nem támogat $ref-et vagy oneOf-ot. Egy közös belső schemából generátorral konvertálj vendor-specifikus formátumra, ne kézzel duplikáld.

Mennyi tool az optimális egy modell számára?

Tapasztalatom szerint 5-10 tool alatt minden modell megbízhatóan teljesít. 10-20 között romlik a selection accuracy, 20 fölött látványosan. Nagyobb tool-készletnél használj tool routingot vagy MCP szervert, ami subseteket ad át a modellnek a felhasználói kérés kontextusa alapján.

Hogyan kezeljem, ha a tool hibát dob futásidőben?

A hibaüzenetet strukturált JSON-ként add vissza a tool resultban ({"error": "...", "code": "..."}), Claude-nál állítsd az is_error: true flaget. A modell így képes user-friendly hibaüzenetet generálni vagy retry-t kezdeményezni. Soha ne dobj kivételt az agentic loopból, mindig térj vissza a modellhez a hibával, hogy értelmes választ tudjon adni a felhasználónak.

Számít a tool sorrendje a tools tömbben?

Kis mértékben igen. Mindhárom modellnek van enyhe „recency biasa" a tömb végén lévő toolok felé. Nagy különbséget nem tesz, de A/B tesztelésnél tartsd fix sorrendben, hogy összehasonlítható legyen a metrikád. Ne rendezd dinamikusan futásidőben; a stabil sorrend a cachingnek is jót tesz.

Daichi Watanabe
A Szerzőről Daichi Watanabe

LLM integration specialist with a strong opinion about function calling and an even stronger one about evaluations.