Powrót do bloga

API i SDKPrzewodnik

Function calling w Pythonie z API zgodnym z OpenAI

Wysyłaj narzędzia, czytaj tool_calls i zwracaj wynik z rolą tool: dwuetapowa pętla function calling w Pythonie z MiniMax-M2.7.

Autor: CheapTokens TeamOpublikowano Zaktualizowano 5 min czytania

Diagram dwuetapowej pętli wywołań narzędzi: wyślij narzędzia, odczytaj tool_calls, zwróć wynik jako wiadomość narzędzia
Na tej stronie
  1. Jak działa function calling
  2. Skonfiguruj klienta
  3. Zadeklaruj funkcję i wyślij pierwsze żądanie
  4. Co powinieneś zobaczyć
  5. Kilka wywołań i dłuższe pętle
  6. Dlaczego MiniMax-M2.7 pasuje do pętli narzędzi
  7. Jeśli to nie działa
  8. Następne kroki

Function calling (wywoływanie narzędzi) pozwala modelowi poprosić Twój kod o uruchomienie funkcji. Wysyłasz listę tools wraz z żądaniem, model odpowiada tool_calls zamiast tekstu, sam uruchamiasz funkcję i odsyłasz jej wynik w wiadomości z role: tool. Następnie model pisze ostateczną odpowiedź. Ten przewodnik pokazuje całą pętlę w Pythonie na endpointcie zgodnym z OpenAI https://api.cheaptokens.dev/v1/chat/completions z MiniMax-M2.7 (id MiniMaxAI/MiniMax-M2.7, kontekst 180K, do 8 192 tokenów wyjściowych na odpowiedź).

Wywoływanie narzędzi jest wymienione jako obsługiwane dla każdego modelu w katalogu (dokumentacja CheapTokens docs, sprawdzono 22 października 2026). Potrzebujesz klucza API; jeśli nie wysłałeś jeszcze żądania, zacznij od pierwszego żądania API.

Jak działa function calling#

Model nigdy niczego nie uruchamia. Tworzy jedynie ustrukturyzowane żądanie: „wywołaj get_weather z {\"city\": \"Paris\"}”. Twój program wykonuje rzeczywistą pracę i raportuje z powrotem. To tworzy pętlę dwóch żądań:

  1. Żądanie 1. Wysyłasz wiadomość użytkownika oraz listę tools. Model albo odpowiada tekstem, albo zwraca jedno lub więcej tool_calls.
  2. Twój kod. Parsujesz każde wywołanie, uruchamiasz pasującą funkcję i zbierasz wynik.
  3. Żądanie 2. Wysyłasz ponownie całą rozmowę: oryginalne wiadomości, wiadomość asystenta z tool_calls oraz po jednej wiadomości role: tool na każde wywołanie. Model używa wyników do napisania ostatecznej odpowiedzi.

Każde żądanie odsyła całą historię, więc pętle narzędzi zużywają więcej tokenów wejściowych niż pojedyncze pytanie. Jeśli to dla Ciebie nowość, przeczytaj czym jest token.

Skonfiguruj klienta#

Zainstaluj SDK OpenAI (pip install openai) i umieść klucz w zmiennej środowiskowej zamiast w kodzie źródłowym:

bash
export CHEAPTOKENS_API_KEY="your-key-here"

Bazowy URL to https://api.cheaptokens.dev/v1. Identyfikator modelu weź z dokumentacji CheapTokens: różni dostawcy nazywają ten sam model inaczej. Ten przewodnik używa MiniMaxAI/MiniMax-M2.7.

Zadeklaruj funkcję i wyślij pierwsze żądanie#

Funkcja jest opisana w tablicy tools. Każdy wpis ma type: function oraz obiekt function z name, description i parameters zapisanym jako JSON Schema. Opis to treść, którą model czyta, aby zdecydować, kiedy wywołać funkcję, więc napisz go jako krótkie, konkretne zdanie.

Poniżej znajduje się kompletny skrypt. Funkcja pogody to zaślepka z fałszywymi danymi, więc przykład nie wymaga dodatkowych usług:

python
import json
import os

from openai import OpenAI

client = OpenAI(
    base_url='https://api.cheaptokens.dev/v1',
    api_key=os.environ['CHEAPTOKENS_API_KEY'],
)
MODEL = 'MiniMaxAI/MiniMax-M2.7'


def get_weather(city: str) -> dict:
    # Stub with fake data: replace with a real lookup
    fake = {'Paris': 14, 'Tokyo': 19}
    return {'city': city, 'temp_c': fake.get(city, 10)}


FUNCTIONS = {'get_weather': get_weather}

tools = [
    {
        'type': 'function',
        'function': {
            'name': 'get_weather',
            'description': 'Get the current temperature in Celsius for a city.',
            'parameters': {
                'type': 'object',
                'properties': {
                    'city': {'type': 'string', 'description': 'City name, for example Paris'},
                },
                'required': ['city'],
            },
        },
    }
]

messages = [{'role': 'user', 'content': 'What is the weather in Paris right now?'}]

# Step 1: the model decides whether to call a function
first = client.chat.completions.create(model=MODEL, messages=messages, tools=tools)
message = first.choices[0].message

if not message.tool_calls:
    print(message.content)
    raise SystemExit

# Step 2: run every requested call and send the results back
messages.append(message)
for call in message.tool_calls:
    args = json.loads(call.function.arguments)
    result = FUNCTIONS[call.function.name](**args)
    messages.append({
        'role': 'tool',
        'tool_call_id': call.id,
        'content': json.dumps(result),
    })

final = client.chat.completions.create(model=MODEL, messages=messages, tools=tools)
print(final.choices[0].message.content)

Trzy szczegóły decydują o tym, czy pętla działa:

  • call.function.arguments to ciąg JSON, a nie słownik. Parsuj go za pomocą json.loads.
  • Każda wiadomość role: tool musi zawierać tool_call_id wywołania, na które odpowiada, czyli call.id.
  • content wiadomości narzędzia to ciąg znaków. Użyj json.dumps dla wyników strukturalnych.

Co powinieneś zobaczyć#

Jeśli wypiszesz pola po pierwszym żądaniu, wyglądają tak (id wywołania różni się przy każdym uruchomieniu):

text
finish_reason: tool_calls
call.id: call_abc123
call.function.name: get_weather
call.function.arguments: {"city": "Paris"}

Następnie skrypt wypisuje ostateczną odpowiedź, zwykłe zdanie w stylu „It is currently 14 °C in Paris.” Sformułowanie zmienia się przy każdym uruchomieniu; liczba pochodzi z Twojej funkcji.

Kilka wywołań i dłuższe pętle#

Model może zwrócić więcej niż jedno wywołanie w jednej odpowiedzi, na przykład gdy pytasz o pogodę w dwóch miastach. Dlatego przykład iteruje po message.tool_calls i odpowiada na każde wywołanie po jego własnym id. Przewodnik OpenAI dotyczący function calling opisuje to samo zachowanie: przy domyślnym tool_choice równym auto model może wywołać zero, jedną lub kilka funkcji (dokumentacja OpenAI, sprawdzono 22 października 2026; strona nie ma daty ostatniej aktualizacji i opisuje nowszy kształt Responses API, podczas gdy ten przewodnik używa kształtu Chat Completions endpointu /v1/chat/completions).

Agenci powtarzają te dwa kroki, aż model przestanie prosić o narzędzia. Otocz żądania pętlą i zawsze ustaw limit kroków:

python
for _ in range(5):  # safety limit against endless loops
    response = client.chat.completions.create(model=MODEL, messages=messages, tools=tools)
    message = response.choices[0].message
    if not message.tool_calls:
        print(message.content)
        break
    messages.append(message)
    for call in message.tool_calls:
        args = json.loads(call.function.arguments)
        result = FUNCTIONS[call.function.name](**args)
        messages.append({'role': 'tool', 'tool_call_id': call.id, 'content': json.dumps(result)})

Jeśli chcesz, aby odpowiedź pojawiała się token po tokenie, połącz to ze streamingiem w Pythonie.

Dlaczego MiniMax-M2.7 pasuje do pętli narzędzi#

Pętla narzędzi wysyła wiele żądań z rosnącą historią. Dla tego wzorca CheapTokens oferuje MiniMax-M2.7: kontekst 180K, do 8 192 tokenów wyjściowych na odpowiedź, jedna cena o dowolnej porze dnia bez godzin szczytu i jedno saldo dla wszystkich modeli. Licząc wejście i wyjście razem, jest taniej niż cena referencyjna OpenRouter (porównanie cen CheapTokens, sprawdzono 31 października 2026).

Aktualne ceny za 1M tokenów: wejście $0.05, wyjście $0.15. Jako przykładowe obciążenie (nie pomiar), opisana powyżej dwuetapowa wymiana z około 2 700 tokenami wejściowymi i 350 wyjściowymi łącznie kosztuje $0.00019. Pełna lista cen znajduje się na stronie cen.

Aby wypróbować inny model, zmień tylko id; lista identyfikatorów znajduje się na stronie modeli.

Jeśli to nie działa#

  • message.tool_calls to None. Model odpowiedział tekstem. Uczyń opis funkcji description bardziej konkretnym i upewnij się, że pytanie rzeczywiście wymaga tej funkcji.
  • json.JSONDecodeError na arguments. Model wygenerował nieprawidłowy JSON. Otocz json.loads w try/except i odeślij tekst błędu jako wynik narzędzia, aby model mógł ponowić próbę z poprawionymi argumentami.
  • Drugie żądanie kończy się niepowodzeniem lub model ignoruje wynik. Sprawdź, czy każde wywołanie ma dokładnie jedną wiadomość role: tool z pasującym tool_call_id oraz czy wiadomość asystenta z tool_calls znajduje się w historii przed nimi.
  • KeyError w FUNCTIONS[...]. Model wskazał funkcję, której nie zarejestrowałeś. Zwróć krótki ciąg błędu jako wynik narzędzia zamiast się wywalać.
  • Odpowiedź jest ucięta. Sprawdź finish_reason: wartość length oznacza, że osiągnięto limit tokenów wyjściowych. Zobacz dlaczego odpowiedź AI urywa się w połowie zdania.
  • 401 lub błędy uwierzytelniania. Sprawdź, czy klucz jest w CHEAPTOKENS_API_KEY i czy bazowy URL kończy się na /v1.

Następne kroki#

Zastąp zaślepkę prawdziwą funkcją: zapytaniem do bazy danych, wywołaniem wyszukiwania lub kalkulatorem. Dodaj więcej wpisów do tools i do FUNCTIONS, a każdy wynik funkcji trzymaj krótki, ponieważ wraca on do historii przy każdym kolejnym żądaniu. Aby uzyskać klucz i wykonać pierwsze wywołanie, otwórz dokumentację CheapTokens.