✨ Świeża dostawa•nowe kody na kinetyka.pl: Gemini Pro 18 mies. 170 zł•Cursor, ElevenLabs, Lovable i więcej, roczne plany AI w ułamku ceny Zobacz →
Przejdź do treści
Artykuły

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.

11 min czytania
Logo Pythona i napis Pierwsze zapytanie - API AI w Pythonie krok po kroku

👁 112 przeczytań

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

  1. Wejdź na python.org/downloads i pobierz aktualny instalator dla Windows (Python 3.13 lub nowszy; biblioteka openai wymaga co najmniej 3.10).
  2. W pierwszym oknie instalatora zaznacz Add python.exe to PATH. Bez tego terminal nie znajdzie Pythona i to najczęstszy problem początkujących.
  3. Alternatywa dla lubiących terminal: winget install Python.Python.3.13.
  4. 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-dotenv

Po 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 .env do zmiennych środowiskowych;
  • OpenAI(base_url=..., api_key=...) tworzy klienta - bez base_url łączyłby się z serwerami OpenAI;
  • messages to lista wiadomości: system ustala zasady, user to pytanie (więcej o rolach i parametrach w tekście System prompt, temperatura, okno kontekstowe);
  • odpowiedz.choices[0].message.content to wygenerowany tekst;
  • usage to licznik tokenów, a OpenRouter dokłada pole cost z 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 USD

I 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 USD

Spó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ścia

Przy 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:

391

Fał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...
391

Ponawianie 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.cost zapisane 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.

Zobacz, co jest dostępne

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 ID

Róż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

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ł.

Google · Twoje źródłaPromptowy wyżej w Twoim Google - jednym kliknięciemDodaj do preferowanych źródeł →

Źródła i data sprawdzenia

// Newsletter

Cały tydzień w AI, w jednym mailu

Wybrane premiery, narzędzia i analizy. Raz w tygodniu, prosto do skrzynki.

Zapisz się za darmo →
Za darmo. Wypisujesz się jednym kliknięciem.
// czytaj też

Podobne tematy na Promptowym

Piotr Olszewski

Piotr Olszewski

AUTOR I WYDAWCA

Piotr Olszewski - twórca i autor Promptowego, polskiego serwisu o sztucznej inteligencji. Codziennie śledzi premiery modeli, narzędzia i regulacje AI, i tłumaczy je prostym, konkretnym językiem.

// mapa strony

🛒 Sklep Kinetyka Google AI Gemini Pro 170 zł CapCut Pro 460 zł/rok Lovable Pro 400 zł/rok Zobacz wszystko →
promptowy w liczbach 0tekstów w archiwum0newsów z ostatnich 7 dni0modeli wideo w obserwatorium0zagadek w grach
× ‹ powiększenie ›