Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie
CodeWorlds

Function Calling - AI, które sięga po narzędzia

Model językowy sam z siebie nie zna dzisiejszej pogody w Serengeti ani aktualnej populacji lwów - potrafi tylko układać słowa. Function calling daje mu narzędzia: Twoje funkcje Pythona, po które może sięgnąć, gdy pytanie wykracza poza to, co wie.

Najważniejsze: model nie wykonuje funkcji

Zanim napiszesz linijkę kodu, zrozum jedno - to źródło wszystkich nieporozumień z function calling. Model nigdy sam nie uruchamia Twojej funkcji. On tylko mówi: "chcę wywołać

get_weather
z argumentem
Serengeti
". Wykonanie należy do Ciebie. To rozmowa w turach:

  1. Dajesz modelowi pytanie i listę dostępnych narzędzi.
  2. Model odpowiada nie tekstem, lecz prośbą: "wywołaj tę funkcję z tymi argumentami".
  3. Ty uruchamiasz funkcję w Pythonie i dostajesz wynik.
  4. Oddajesz wynik modelowi.
  5. Model układa z niego ludzką odpowiedź.

Przejdziemy przez te tury po kolei. Zaczynamy od tego, jak opisać modelowi narzędzie - bo model nie widzi Twojego kodu, tylko jego opis.

1from openai import OpenAI
2import json
3
4client = OpenAI()
5
6tools = [
7    {
8        "type": "function",
9        "function": {
10            "name": "get_weather",
11            "description": "Pobiera pogodę dla lokalizacji Safari",
12            "parameters": {
13                "type": "object",
14                "properties": {
15                    "location": {
16                        "type": "string",
17                        "description": "Nazwa lokalizacji, np. 'Serengeti'"
18                    }
19                },
20                "required": ["location"]
21            }
22        }
23    }
24]

Zwróć uwagę: to jest sam opis narzędzia, nie jego działanie. Pola

description
są tu najważniejsze - to po nich model decyduje, kiedy sięgnąć po funkcję i co wpisać w argument. Im lepszy opis, tym trafniej model wybiera narzędzie. Sekcja
required
mówi, które argumenty są obowiązkowe.

Tura druga: model prosi o wywołanie

Teraz wysyłamy pytanie razem z listą narzędzi. Uważnie przeczytaj, co model zwraca - to nie odpowiedź dla użytkownika.

1response = client.chat.completions.create(
2    model="gpt-5",
3    messages=[{"role": "user", "content": "Jaka jest pogoda w Serengeti?"}],
4    tools=tools,
5    tool_choice="auto"
6)
7
8message = response.choices[0].message
9if message.tool_calls:
10    for tool_call in message.tool_calls:
11        function_name = tool_call.function.name
12        arguments = json.loads(tool_call.function.arguments)
13        print(f"Model chce wywołać: {function_name}({arguments})")

Zamiast gotowej odpowiedzi model zwrócił

tool_calls
- listę próśb o wywołanie. Argumenty przychodzą jako tekst JSON, dlatego
json.loads
zamienia je na słownik Pythona. Na tym etapie nic się jeszcze nie wydarzyło - model tylko powiedział, czego chce. Wykonanie jest naszym kolejnym krokiem.

Tura trzecia: to Ty wykonujesz funkcję

Model zna nazwę funkcji tylko jako napis. Musimy więc mieć jej prawdziwą implementację i sposób, by z nazwy trafić do właściwego kodu.

1def get_weather(location: str) -> dict:
2    # W prawdziwej aplikacji - wywołanie API pogodowego
3    return {"location": location, "temperature": 28, "conditions": "Słonecznie"}
4
5available_functions = {
6    "get_weather": get_weather
7}

Słownik

available_functions
to most między światem modelu a Twoim kodem: model podaje napis
"get_weather"
, a Ty po tym napisie wyciągasz prawdziwą funkcję. To Ty decydujesz, co naprawdę się wykona - model nie ma dostępu do niczego, czego mu tu nie udostępnisz. Zauważ, że to naturalne miejsce na kontrolę bezpieczeństwa.

Wszystkie tury razem

Zobacz teraz pełną rozmowę: pytanie, prośba modelu, wykonanie, oddanie wyniku i finalna odpowiedź. Prześledź, jak lista

messages
rośnie o kolejne tury.

1def chat_with_tools(user_message: str):
2    messages = [{"role": "user", "content": user_message}]
3
4    response = client.chat.completions.create(
5        model="gpt-5", messages=messages, tools=tools
6    )
7    message = response.choices[0].message
8
9    if message.tool_calls:
10        messages.append(message)  # zapisz prośbę modelu
11
12        for tool_call in message.tool_calls:
13            name = tool_call.function.name
14            args = json.loads(tool_call.function.arguments)
15            result = available_functions[name](**args)  # Ty wykonujesz
16
17            messages.append({
18                "role": "tool",
19                "tool_call_id": tool_call.id,
20                "content": json.dumps(result)  # oddaj wynik modelowi
21            })
22
23        final = client.chat.completions.create(model="gpt-5", messages=messages)
24        return final.choices[0].message.content
25
26    return message.content

Kluczowe są dwa wywołania

create
: pierwsze, w którym model prosi o narzędzie, i drugie - po dopisaniu wyniku - w którym model układa odpowiedź dla człowieka. Rola
"tool"
i
tool_call_id
to sposób, w jaki mówisz modelowi "oto wynik dokładnie tej funkcji, o którą prosiłeś". Bez tej drugiej tury użytkownik dostałby surowy JSON zamiast zdania.

LangChain - ta sama idea, mniej kodu

Ręczne prowadzenie tur bywa żmudne. LangChain pakuje całą tę pętlę w agenta - Ty tylko oznaczasz funkcje jako narzędzia, a on sam prowadzi rozmowę.

1from langchain.tools import tool
2from langchain.agents import create_tool_calling_agent, AgentExecutor
3from langchain_openai import ChatOpenAI
4from langchain_core.prompts import ChatPromptTemplate
5
6@tool
7def calculate_distance(from_loc: str, to_loc: str) -> str:
8    """Oblicza odległość między lokalizacjami Safari."""
9    return f"Odległość z {from_loc} do {to_loc}: 150 km"
10
11llm = ChatOpenAI(model="gpt-5")
12prompt = ChatPromptTemplate.from_messages([
13    ("system", "Jesteś pomocnym asystentem Safari."),
14    ("human", "{input}"),
15    ("placeholder", "{agent_scratchpad}")
16])
17
18agent = create_tool_calling_agent(llm, [calculate_distance], prompt)
19executor = AgentExecutor(agent=agent, tools=[calculate_distance], verbose=True)
20executor.invoke({"input": "Jak daleko jest z Nairobi do Serengeti?"})

Dekorator

@tool
robi to, co wcześniej pisaliśmy ręcznie: z docstringa buduje opis dla modelu, a z sygnatury - listę argumentów.
AgentExecutor
prowadzi za Ciebie wszystkie tury z poprzedniego przykładu, w kółko, aż model uzna, że ma komplet informacji.

Pamiętaj z tej lekcji jedno zdanie: function calling to nie "AI uruchamia kod", tylko model prosi, a Ty wykonujesz i oddajesz wynik. Cała reszta - OpenAI czy LangChain - to tylko wygodniejszy zapis tej samej rozmowy w turach.

Przejdź do CodeWorlds