Pierwsze zapytanie do API AI w Pythonie krok po kroku
Od instalacji Pythona na Windowsie do działającego skryptu: środowisko wirtualne, pierwsze zapytanie z licznikiem kosztu, streaming, obsługa błędów i ponawianie z testowym serwerem 429. To samo w Node.js.

👁 114 przeczytań
- Pierwsze zapytanie do API AI w Pythonie to około 10 linijek kodu: instalacja biblioteki openai, podanie klucza i adresu, wysłanie listy wiadomości.
- Model openai/gpt-6-luna kosztuje 0,10/0,50 USD za milion tokenów, a wszystkie uruchomienia z artykułu pochłonęły łącznie około 0,005 USD.
- Gemini 3.8 Flash za dwa zdania odpowiedzi wygenerował 462 tokeny wyjścia, z czego 390 to tokeny myślenia, co dało koszt ponad 50 razy wyższy niż GPT-6 Luna.
Pierwsze zapytanie do modelu AI w Pythonie to dziesięć linijek kodu: instalujesz bibliotekę openai, wskazujesz adres i klucz, wysyłasz listę wiadomości i czytasz odpowiedź. Poniżej przechodzę przez wszystko od instalacji Pythona na Windowsie, przez środowisko wirtualne, po streaming, obsługę błędów i ponawianie zapytań. Każdy skrypt uruchomiłem 4 października 2026 na Windows 11 z Pythonem 3.13.15 przez OpenRouter i pokazuję prawdziwy wynik. To trzeci krok ścieżki API AI od zera.
Na czym testowałem (4 października 2026)
- Windows 11 Pro, Python 3.13.15, biblioteki: openai 3.24.0, python-dotenv 1.2.4, pydantic 2.13.5.
- Node.js 26.10 z biblioteką openai 7.27.0 (wersja JavaScript na końcu tekstu).
- Dostęp do modeli: OpenRouter, domyślny model
openai/gpt-6-luna(0,10 / 0,50 USD za milion tokenów). - Koszt wszystkich uruchomień z tego tekstu: około 0,005 USD.
Krok 1. Zainstaluj Pythona na Windowsie
- Wejdź na python.org/downloads i pobierz aktualny instalator dla Windows (Python 3.13 lub nowszy; biblioteka openai wymaga co najmniej 3.10).
- W pierwszym oknie instalatora zaznacz Add python.exe to PATH. Bez tego terminal nie znajdzie Pythona i to najczęstszy problem początkujących.
- Alternatywa dla lubiących terminal:
winget install Python.Python.3.13. - Otwórz nowy terminal (PowerShell albo Terminal Windows) i sprawdź:
python --version. Powinieneś zobaczyć numer wersji, a nie okno Microsoft Store.
Jeśli zamiast wersji otwiera się Microsoft Store, w Ustawieniach → Aplikacje → Zaawansowane ustawienia aplikacji → Aliasy wykonywania aplikacji wyłącz aliasy python.exe i python3.exe.
Krok 2. Środowisko wirtualne (venv)
venv to osobny „pokój” na biblioteki jednego projektu. Dzięki niemu instalacja czegoś do projektu A nie psuje projektu B. Tworzysz go raz na projekt:
mkdir moje-api
cd moje-api
python -m venv .venv
.venv\Scripts\Activate.ps1
pip install openai python-dotenvPo aktywacji na początku linii terminala zobaczysz (.venv). Gdy PowerShell odmówi uruchomienia skryptu aktywacji, raz wykonaj Set-ExecutionPolicy -Scope CurrentUser RemoteSigned. W Git Bash aktywujesz przez source .venv/Scripts/activate, na Linuksie i Macu przez source .venv/bin/activate.
Klucz zapisujesz w pliku .env w katalogu projektu (jedna linia: OPENROUTER_API_KEY=sk-or-v1-...). Skąd go wziąć i jak go zabezpieczyć, opisałem w tekście Klucz API: jak go zdobyć i jak go nie spalić.
Krok 3. Pierwsze zapytanie
Używam oficjalnej biblioteki OpenAI, ale z adresem OpenRouter. Format zapytań jest ten sam, więc z jednym kluczem masz dostęp do modeli OpenAI, Anthropic, Google, DeepSeek i setek innych. Zmiana modelu to zmiana jednego napisu.
"""Pierwsze zapytanie do modelu AI przez OpenRouter (SDK openai)."""
import os
from dotenv import load_dotenv
from openai import OpenAI
load_dotenv() # wczytuje zmienne z pliku .env w bieżącym katalogu
client = OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key=os.environ["OPENROUTER_API_KEY"],
)
odpowiedz = client.chat.completions.create(
model=os.getenv("MODEL", "openai/gpt-6-luna"),
messages=[
{"role": "system", "content": "Odpowiadasz po polsku, krótko i konkretnie."},
{"role": "user", "content": "Wyjaśnij w dwóch zdaniach, czym jest API."},
],
)
print(odpowiedz.choices[0].message.content)
print("---")
print("model:", odpowiedz.model)
print("tokeny wejścia:", odpowiedz.usage.prompt_tokens)
print("tokeny wyjścia:", odpowiedz.usage.completion_tokens)
szczegoly = odpowiedz.usage.completion_tokens_details
if szczegoly and szczegoly.reasoning_tokens:
print(" w tym tokeny myślenia:", szczegoly.reasoning_tokens)
koszt = getattr(odpowiedz.usage, "cost", None) # OpenRouter dokłada koszt w USD
if koszt is not None:
print(f"koszt: {koszt:.6f} USD")Co tu się dzieje, linijka po linijce:
load_dotenv()wczytuje klucz z pliku.envdo zmiennych środowiskowych;OpenAI(base_url=..., api_key=...)tworzy klienta - bezbase_urlłączyłby się z serwerami OpenAI;messagesto lista wiadomości:systemustala zasady,userto pytanie (więcej o rolach i parametrach w tekście System prompt, temperatura, okno kontekstowe);odpowiedz.choices[0].message.contentto wygenerowany tekst;usageto licznik tokenów, a OpenRouter dokłada polecostz kosztem w dolarach.
Wynik z mojego komputera dla domyślnego GPT-6 Luna:
API to zestaw reguł i narzędzi, dzięki którym różne programy mogą się ze sobą komunikować. Określa, jak wysyłać żądania i odbierać dane lub funkcje od innego systemu.
---
model: openai/gpt-6-luna
tokeny wejścia: 40
tokeny wyjścia: 58
koszt: 0.000033 USDI to samo pytanie wysłane do Gemini 3.8 Flash (zmieniłem tylko zmienną MODEL):
API (Interfejs Programowania Aplikacji) to zestaw reguł, który umożliwia różnym programom i systemom bezpieczną komunikację oraz wymianę danych między sobą. Działa jak pośrednik, pozwalając jednej aplikacji korzystać z funkcji lub zasobów innej bez konieczności znajomości jej wewnętrznej budowy.
---
model: google/gemini-3.8-flash
tokeny wejścia: 29
tokeny wyjścia: 462
w tym tokeny myślenia: 390
koszt: 0.001754 USDSpójrz na liczby: Gemini wygenerował 462 tokeny wyjścia na dwa zdania, bo 390 z nich to „myślenie” przed odpowiedzią. Płacisz za nie jak za zwykły tekst, dlatego to zapytanie kosztowało 0,00175 USD, ponad 50 razy więcej niż na Lunie. Gdy liczysz koszty, patrz na usage, nie na długość odpowiedzi. Więcej w tekście Tokeny AI: co to jest i ile kosztują.
Krok 4. Streaming: odpowiedź na żywo
Bez streamingu czekasz, aż model skończy, i dostajesz całość naraz. Ze streamingiem tekst przychodzi kawałek po kawałku, tak jak w ChatGPT. Przydaje się w czatach i wszędzie, gdzie człowiek patrzy na ekran.
"""Streaming: odpowiedź pojawia się kawałek po kawałku, jak w ChatGPT."""
import os
from dotenv import load_dotenv
from openai import OpenAI
load_dotenv()
client = OpenAI(base_url="https://openrouter.ai/api/v1", api_key=os.environ["OPENROUTER_API_KEY"])
strumien = client.chat.completions.create(
model=os.getenv("MODEL", "openai/gpt-6-luna"),
messages=[{"role": "user", "content": "Podaj 5 pomysłów na nazwę bloga o gotowaniu. Tylko lista."}],
stream=True,
stream_options={"include_usage": True}, # ostatni kawałek przyniesie licznik tokenów
)
for kawalek in strumien:
if kawalek.choices and kawalek.choices[0].delta.content:
print(kawalek.choices[0].delta.content, end="", flush=True)
if kawalek.usage: # przychodzi na samym końcu
print(f"\n--- tokeny: {kawalek.usage.prompt_tokens} wejścia, {kawalek.usage.completion_tokens} wyjścia")1. Prosto z Patelni
2. Szczypta Smaku
3. Gotuj z Głową
4. Widelcem po Talerzu
5. Kulinarna Przystań
--- tokeny: 20 wejścia, 439 wyjściaPrzy streamingu licznik tokenów nie przychodzi sam - trzeba poprosić o niego parametrem stream_options={"include_usage": True}, a dostaniesz go w ostatnim kawałku.
Krok 5. Obsługa błędów i ponawianie (retry)
W prawdziwym programie zapytania czasem się nie udają: zły klucz, literówka w nazwie modelu, przekroczony limit zapytań na minutę (429), chwilowa awaria dostawcy (5xx). Zasada jest prosta:
- błędy po Twojej stronie (400, 401, 403, 404) nie ponawiaj - powtórzenie da ten sam wynik, popraw kod;
- błędy przejściowe (429, 500, 502, 503, zerwane połączenie) ponawiaj z rosnącą przerwą: 2 s, 4 s, 8 s, z losowym dodatkiem, żeby wiele programów nie uderzało w serwer w tej samej sekundzie.
"""Obsługa błędów API: 401, 429, 5xx i ponawianie z rosnącą przerwą (exponential backoff)."""
import os, sys, time, random
from dotenv import load_dotenv
import openai
from openai import OpenAI
load_dotenv()
client = OpenAI(
# BASE_URL można podmienić na testowy serwer z pliku testy/serwer_429.py
base_url=os.getenv("BASE_URL", "https://openrouter.ai/api/v1"),
api_key=os.environ.get("OPENROUTER_API_KEY", ""),
max_retries=0, # wyłączam wbudowane ponawianie, żeby pokazać własne
timeout=60, # sekundy; bez tego zawieszone połączenie czeka bardzo długo
)
def zapytaj(pytanie, model, proby=4):
for proba in range(1, proby + 1):
try:
r = client.chat.completions.create(model=model, messages=[{"role": "user", "content": pytanie}])
return r.choices[0].message.content
except openai.AuthenticationError as e: # 401 - zły albo wyłączony klucz
sys.exit(f"401: sprawdź klucz API ({e.message})")
except openai.PermissionDeniedError as e: # 403 - brak dostępu (np. region, moderacja)
sys.exit(f"403: brak dostępu ({e.message})")
except openai.NotFoundError as e: # 404 - zła nazwa modelu albo adresu
sys.exit(f"404: nie ma takiego modelu lub adresu ({e.message})")
except openai.BadRequestError as e: # 400 - błąd w treści zapytania
sys.exit(f"400: popraw zapytanie ({e.message})")
except (openai.RateLimitError, openai.InternalServerError,
openai.APIConnectionError, openai.APITimeoutError) as e:
# 429 (za dużo zapytań / brak środków), 5xx (awaria po stronie serwera), zerwane połączenie
if proba == proby:
raise
przerwa = 2 ** proba + random.random() # 2, 4, 8 s + losowy ułamek
kod = getattr(e, "status_code", "sieć")
print(f"[próba {proba}] błąd {kod}, czekam {przerwa:.1f} s...")
time.sleep(przerwa)
except openai.APIStatusError as e: # inne kody, np. 402 (brak środków w OpenRouter)
sys.exit(f"{e.status_code}: {e.message}")
if __name__ == "__main__":
model = sys.argv[1] if len(sys.argv) > 1 else os.getenv("MODEL", "openai/gpt-6-luna")
print(zapytaj("Ile to jest 17 * 23? Podaj tylko wynik.", model))Sprawdziłem cztery scenariusze. Zwykłe zapytanie:
391Fałszywy klucz i nieistniejący model (zwróć uwagę, że OpenRouter na zły model odpowiada 400, nie 404):
401: sprawdź klucz API (Error code: 401 - {'error': {'message': 'User not found.', 'code': 401}})400: popraw zapytanie (Error code: 400 - {'error': {'message': 'openai/gpt-7-nie-istnieje is not a valid model ID', 'code': 400}})Najtrudniej przetestować 429, bo trzeba by naprawdę zalać serwer zapytaniami. Napisałem więc udawany serwer, który dwa pierwsze zapytania odrzuca kodem 429, a trzecie obsługuje. Skrypt nie wie, że to atrapa:
"""Udawany serwer API: dwa pierwsze zapytania dostają 429, trzecie poprawną odpowiedź.
Służy do sprawdzenia, czy ponawianie w 03_bledy_i_retry.py działa - bez wydawania pieniędzy.
Okno 1: python testy/serwer_429.py
Okno 2: set BASE_URL=http://127.0.0.1:8429/v1 (PowerShell: $env:BASE_URL="http://127.0.0.1:8429/v1")
python 03_bledy_i_retry.py
"""
import json
from http.server import BaseHTTPRequestHandler, HTTPServer
licznik = {"n": 0}
class Obsluga(BaseHTTPRequestHandler):
def do_POST(self):
self.rfile.read(int(self.headers.get("Content-Length", 0)))
licznik["n"] += 1
if licznik["n"] <= 2:
kod, tresc = 429, {"error": {"message": "Rate limit exceeded (test)", "code": 429}}
else:
kod, tresc = 200, {
"id": "test-1", "object": "chat.completion", "created": 0, "model": "testowy",
"choices": [{"index": 0, "finish_reason": "stop",
"message": {"role": "assistant", "content": "391"}}],
"usage": {"prompt_tokens": 10, "completion_tokens": 1, "total_tokens": 11},
}
body = json.dumps(tresc).encode()
self.send_response(kod)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
print(f"zapytanie {licznik['n']} -> {kod}")
HTTPServer(("127.0.0.1", 8429), Obsluga).serve_forever()[próba 1] błąd 429, czekam 2.8 s...
[próba 2] błąd 429, czekam 4.2 s...
391Ponawianie zadziałało: dwie odmowy, przerwy 2,8 s i 4,2 s, a za trzecim razem wynik. Biblioteka openai ma też wbudowane ponawianie (domyślnie 2 razy, parametr max_retries), które w skrypcie wyłączyłem, żeby pokazać mechanizm. W swoich programach zwykle zostawiam wbudowane i ustawiam max_retries=5.
Trzy dodatkowe rady z praktyki:
- Zawsze ustaw timeout. Domyślnie biblioteka czeka do 10 minut. Przy długich odpowiedziach modeli z myśleniem 60 s to czasem za mało, więc dobierz go do zadania.
- Loguj koszt każdego zapytania. Pole
usage.costzapisane do pliku po tygodniu powie więcej niż jakikolwiek kalkulator. - Odróżniaj 429 od braku środków. W OpenAI przekroczony limit wydatków też zwraca 429 (kod
project_spend_limit_exceeded), a ponawianie go nie naprawi.
To samo w JavaScript (Node.js)
Nie przepłacaj za te subskrypcje
Prowadzę sklep z rocznymi dostępami do narzędzi AI - te same konta, o których piszę wyżej, tylko taniej niż w cenniku producenta.
Biblioteka openai dla Node.js ma prawie identyczne nazwy. Zainstalowałem Node.js 26.10, w katalogu projektu wykonałem npm install openai dotenv (wersje 7.27.0 i 18.0.5), w package.json ustawiłem "type": "module". Skrypt robi trzy rzeczy: zwykłe zapytanie, streaming i złapanie błędu.
// Pierwsze zapytanie w Node.js przez OpenRouter: zwykła odpowiedź i streaming.
// Uruchom w katalogu js: npm install a potem node pierwsze_zapytanie.mjs
import "dotenv/config"; // wczytuje .env z bieżącego katalogu
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://openrouter.ai/api/v1",
apiKey: process.env.OPENROUTER_API_KEY,
});
const model = process.env.MODEL ?? "openai/gpt-6-luna";
// 1. Zwykłe zapytanie
const r = await client.chat.completions.create({
model,
messages: [
{ role: "system", content: "Odpowiadasz po polsku, krótko." },
{ role: "user", content: "Czym różni się JavaScript od Javy? Jedno zdanie." },
],
});
console.log(r.choices[0].message.content);
console.log(`--- ${r.usage.prompt_tokens} + ${r.usage.completion_tokens} tokenów, koszt ${r.usage.cost} USD\n`);
// 2. Streaming
const strumien = await client.chat.completions.create({
model,
messages: [{ role: "user", content: "Wymień 3 polskie rzeki. Tylko nazwy po przecinku." }],
stream: true,
});
for await (const kawalek of strumien) {
process.stdout.write(kawalek.choices[0]?.delta?.content ?? "");
}
console.log();
// 3. Obsługa błędów: zły model
try {
await client.chat.completions.create({ model: "nie/istnieje", messages: [{ role: "user", content: "test" }] });
} catch (e) {
if (e instanceof OpenAI.APIError) console.log(`Błąd ${e.status}: ${e.message}`);
else throw e;
}JavaScript to dynamiczny język używany głównie w przeglądarkach i aplikacjach webowych, a Java to osobny, statycznie typowany język kompilowany do uruchamiania na JVM.
--- 39 + 54 tokenów, koszt 0.0000309 USD
Wisła, Odra, Warta
Błąd 400: 400 nie/istnieje is not a valid model IDRóżnice wobec Pythona są kosmetyczne: baseURL zamiast base_url, await przed zapytaniem, for await przy streamingu. Klucz w Node.js też trzymasz w .env i nigdy w kodzie strony, który trafia do przeglądarki.
Gotowe skrypty do pobrania
Wszystkie skrypty z tego tekstu (i z pozostałych części ścieżki) są w paczce promptowy-api-starter z polskim README i plikiem .env.example. Wystarczy rozpakować, wpisać klucz i uruchomić python 01_pierwsze_zapytanie.py.
Co dalej
- Ustaw parametry modelu: System prompt, temperatura, okno kontekstowe, max tokens.
- Zmuś model do odpowiedzi w JSON: Structured output krok po kroku.
- Policz, ile to kosztuje: kalkulator kosztu API.
- Następny etap: automatyzacje i agenci - ścieżka Agenci AI od zera, a w kodzie: pierwszy agent w Pythonie.
Najczęstsze pytania
Czy do API OpenAI muszę używać OpenRouter?
Nie. Jeśli masz klucz OpenAI, usuń base_url i podaj model bez przedrostka (gpt-6-luna). Przykład bezpośredniego połączenia z OpenAI, Anthropic i Google jest w tekście o kluczach API.
Dostaję błąd ModuleNotFoundError: No module named 'openai’. Co robię źle?
Instalowałeś bibliotekę w innym środowisku, niż uruchamiasz skrypt. Aktywuj venv (.venv\Scripts\Activate.ps1) i zainstaluj ponownie, albo uruchom skrypt przez .venv\Scripts\python.
KeyError: 'OPENROUTER_API_KEY’ - dlaczego?
Skrypt nie znalazł klucza. Sprawdź, czy plik nazywa się dokładnie .env (Windows lubi dopisać .txt), czy leży w katalogu, z którego uruchamiasz skrypt, i czy w środku nie ma spacji wokół znaku równości.
Chat Completions czy Responses API?
OpenAI dla nowych projektów poleca Responses API, ale Chat Completions nadal działa i jest standardem rozumianym przez OpenRouter, DeepSeek, Mistrala i lokalne serwery jak Ollama. Do nauki wybrałem Chat Completions, bo ten sam kod działa wszędzie.
Ile kosztuje nauka API?
Grosze. Wszystkie uruchomienia z tego tekstu kosztowały mnie około pół centa. Darmowe modele w OpenRouter (z dopiskiem :free) i darmowy poziom Gemini pozwalają ćwiczyć za 0 zł.
Źródła i data sprawdzenia
- openai-python - biblioteka i dokumentacja
- openai-node - biblioteka dla JavaScript
- OpenRouter - Quickstart
- OpenRouter - kody błędów
- Python - dokumentacja venv
- python.org - Python dla Windows
Cały tydzień w AI, w jednym mailu
Wybrane premiery, narzędzia i analizy. Raz w tygodniu, prosto do skrzynki.
Zapisz się za darmo →
