Żeby używać API OpenAI w Pythonie, instalujesz bibliotekę `openai`, ustawiasz klucz w zmiennej `OPENAI_API_KEY` i wywołujesz `client.chat.completions.create()` z listą wiadomości. Model nie liczy słów, tylko tokeny, a prompt i odpowiedź razem muszą zmieścić się w oknie kontekstu, więc tokeny liczysz biblioteką `tiktoken` przed wysyłką. Zużycie z `response.usage` pomnożone przez stawki z cennika daje koszt zapytania.
Pierwsze zapytanie do modelu językowego z poziomu Pythona zajmuje kilka linijek. Kłopoty zaczynają się dopiero wtedy, gdy wklejasz do promptu dłuższy dokument, dostajesz błąd o przekroczonej długości kontekstu, a na koniec miesiąca zastanawiasz się, skąd taki rachunek. Ten artykuł pokazuje, jak z tym wszystkim sobie poradzić: od pierwszego wywołania, przez tokeny, po koszty.
Jeśli znasz vibe coding, czyli programowanie z pomocą AI, zobaczysz tu, jak ten sam mechanizm działa od środka: ile kosztuje każda wiadomość i dlaczego model „zapomina” starszą część rozmowy. A jeśli dopiero uczysz się programować, zajrzyj też do artykułu o ChatGPT w nauce programowania.
To pierwsza część cyklu. W drugiej części napiszemy testy do takiego kodu, a w trzeciej złożymy z tego cały projekt.
Jak wywołać API OpenAI z Pythona?
Zainstaluj bibliotekę i ustaw klucz API w zmiennej środowiskowej. Klucza nie wpisuj w kodzie i nie commituj go do repozytorium.
pip install openai tiktoken
export OPENAI_API_KEY="twoj-klucz"
Samo wywołanie wygląda tak:
from openai import OpenAI
client = OpenAI() # klucz odczytany z OPENAI_API_KEY
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "Odpowiadasz po polsku, krótko i rzeczowo."},
{"role": "user", "content": "Czym jest token w modelu językowym?"},
],
)
print(response.choices[0].message.content)
Nazwę modelu sprawdź w dokumentacji OpenAI, bo lista modeli i ich ceny zmieniają się częściej niż sama biblioteka.
Czym jest prompt i jak podzielić go na role?
Prompt to wszystko, co wysyłasz do modelu. W API chat składa się z listy wiadomości, a każda ma rolę:
| Rola | Do czego służy |
|---|---|
system | Stałe instrukcje: jak model ma się zachowywać, w jakim języku i formie odpowiadać. |
user | Pytanie albo polecenie, czyli to, co wpisuje użytkownik, razem z wklejonym tekstem do przetworzenia. |
assistant | Wcześniejsze odpowiedzi modelu. Dodajesz je, jeśli chcesz prowadzić rozmowę. |
Ważna rzecz, o której początkujący często nie wiedzą: API nie pamięta poprzednich zapytań. Jeśli chcesz prowadzić rozmowę, przy każdym wywołaniu wysyłasz całą dotychczasową historię. To oznacza, że im dłuższa rozmowa, tym więcej tokenów kosztuje każde kolejne zapytanie.
Czym są tokeny i dlaczego nie są tym samym co słowa?
Model nie widzi słów ani liter. Tekst jest dzielony na tokeny, czyli kawałki: czasem całe słowa, częściej ich fragmenty. Za tokeny płacisz i to one wyznaczają limit długości.
W języku polskim wychodzi ich więcej niż w angielskim. Zmierzyliśmy to tokenizerem używanym przez gpt-4o-mini:
| Zdanie | Słów | Tokenów |
|---|---|---|
| Programista pisze testy jednostkowe dla swojego kodu. | 7 | 15 |
| The programmer writes unit tests for their code. | 8 | 9 |
Polskie znaki i odmiana sprawiają, że ten sam sens kosztuje więcej tokenów. Dlatego szacowanie „na oko” po liczbie słów zwykle się nie sprawdza.
Jak policzyć tokeny w tiktoken?
Biblioteka tiktoken używa tego samego tokenizera co modele OpenAI, więc możesz policzyć tokeny przed wysłaniem zapytania:
import tiktoken
def count_tokens(text: str, model: str = "gpt-4o-mini") -> int:
encoding = tiktoken.encoding_for_model(model)
return len(encoding.encode(text))
print(count_tokens("Programista pisze testy jednostkowe dla swojego kodu.")) # 15
Dlaczego tiktoken nie działa offline?
Przy pierwszym użyciu tiktoken pobiera plik ze słownikiem kodowania z internetu i zapisuje go w pamięci podręcznej. Na serwerze bez dostępu do sieci albo w kontenerze zbudowanym bez tego pliku dostaniesz błąd połączenia. Rozwiązanie: uruchom kod raz z dostępem do sieci, a potem wskaż stały katalog zmienną TIKTOKEN_CACHE_DIR i dołącz go do obrazu lub środowiska.
Co to jest okno kontekstu i skąd błąd „maximum context length”?
Okno kontekstu to maksymalna liczba tokenów, które model obsłuży w jednym zapytaniu. Mieszczą się w nim zarówno prompt (system, historia, wklejony tekst), jak i odpowiedź modelu. Jeśli suma jest za duża, API odrzuca zapytanie błędem 400, a biblioteka zgłasza BadRequestError z komunikatem o przekroczonej maksymalnej długości kontekstu. To samo dzieje się w narzędziach do vibe codingu: im dłuższa sesja, tym więcej historii trafia do kontekstu, aż starsze fragmenty przestają się mieścić.
Są trzy typowe sposoby, żeby się z tym uporać:
| Sposób | Kiedy się sprawdza |
|---|---|
| Policzyć tokeny przed wysłaniem i przerwać z czytelnym komunikatem | Zawsze, to najtańsza ochrona. |
| Podzielić dokument na fragmenty i streścić każdy osobno | Długie teksty. Pokazujemy to w projekcie z trzeciej części. |
| Skrócić historię rozmowy (usunąć lub streścić najstarsze wiadomości) | Czaty z długą rozmową. |
Przykład prostego zabezpieczenia:
CONTEXT_LIMIT = 128_000 # sprawdź limit swojego modelu w dokumentacji
RESERVED_FOR_ANSWER = 1_000
def check_prompt_fits(prompt: str) -> None:
tokens = count_tokens(prompt)
if tokens + RESERVED_FOR_ANSWER > CONTEXT_LIMIT:
raise ValueError(f"Prompt ma {tokens} tokenów, to za dużo.")
Jeśli temat dużych dokumentów interesuje Cię głębiej, zobacz też artykuł o bazach wektorowych i RAG w Pythonie, gdzie fragmenty dokumentu są wyszukiwane zamiast wysyłane w całości.
Ile kosztuje zapytanie do API i jak to policzyć?
Każda odpowiedź zawiera pole usage z faktycznym zużyciem:
usage = response.usage
print(usage.prompt_tokens) # tokeny wejściowe (Twój prompt)
print(usage.completion_tokens) # tokeny wyjściowe (odpowiedź modelu)
print(usage.total_tokens)
Tokeny wejściowe i wyjściowe mają różne stawki, zwykle tokeny wyjściowe są droższe. Koszt liczysz więc osobno dla obu:
PRICE_INPUT_PER_1M = 0.15 # USD za milion tokenów wejściowych (przykład, sprawdź cennik)
PRICE_OUTPUT_PER_1M = 0.60 # USD za milion tokenów wyjściowych (przykład, sprawdź cennik)
def cost_usd(usage) -> float:
return (
usage.prompt_tokens * PRICE_INPUT_PER_1M
+ usage.completion_tokens * PRICE_OUTPUT_PER_1M
) / 1_000_000
Stawki w kodzie to wartości przykładowe. Aktualny cennik jest na stronie OpenAI, a trzymanie stawek w stałych na górze pliku pozwala zmienić je w jednym miejscu.
Jak ograniczyć koszty w praktyce?
- Wybieraj najmniejszy model, który wystarcza do zadania. Streszczanie i klasyfikacja rzadko wymagają najdroższego.
- Skracaj prompt: stałe instrukcje trzymaj zwięzłe, a z dokumentu wycinaj to, co zbędne.
- Ogranicz długość odpowiedzi parametrem maksymalnej liczby tokenów wyjściowych.
- Nie wysyłaj całej historii rozmowy, jeśli wystarczy jej fragment.
- Loguj
usagez każdego wywołania. Bez tego nie wiesz, który fragment kodu generuje koszt.
Co dalej?
Masz już pierwsze wywołanie, liczenie tokenów i koszt. W kolejnej części dowiesz się, jak testować taki kod bez wysyłania prawdziwych zapytań, czyli bez kosztów i bez klucza API w testach. Jeśli chcesz rozwijać się w kierunku backendu w Pythonie, zobacz ścieżkę Python.


