Z poprzedniej lekcji wiesz już, czym jest LLM, token i okno kontekstu. Kłopot w tym, że taki model nie mieszka na Twoim laptopie - stoi na serwerze dostawcy. Żeby go użyć z Pythona, trzeba wysłać zapytanie HTTP, podpisać je kluczem i rozpakować odpowiedź. Ręcznie to godzina dłubaniny, z oficjalną biblioteką - cztery linie.
Ta lekcja jest właśnie o tych czterech krokach: instalacji, imporcie, wywołaniu i odczycie wyniku. Tropienie modelu przez sieć niewiele różni się od tropienia zwierzyny: liczy się to, czy idziesz właściwą ścieżką, a nie jak szybko biegniesz.
Biblioteki Pythona instalujesz menedżerem pip. To pierwsza pułapka, bo w sieci krąży mnóstwo przykładów w JavaScripcie, gdzie ten sam pakiet instaluje się przez
npm install openai. npm to menedżer pakietów Node.js - w Pythonie nie zainstaluje niczego, w najlepszym razie powie, że nie zna takiej komendy.Druga pułapka to nazwa pakietu. Firma nazywa się OpenAI, produkt ChatGPT, a rodzina modeli GPT - ale w repozytorium PyPI pakiet nazywa się po prostu
openai. Polecenia pip install chatgpt oraz pip install gpt4 nie zainstalują oficjalnej biblioteki, bo takich pakietów OpenAI nie wydaje. Analogicznie pakiet Anthropic nazywa się anthropic, a nie claude.1pip install openai
2pip install anthropicPo tych dwóch poleceniach masz w środowisku dwa niezależne pakiety. Żaden nie wysłał jeszcze ani jednego zapytania i żaden nie zna Twojego klucza API - klucz podasz dopiero przy tworzeniu klienta.
Kolejność w linii importu jest zawsze taka sama:
from → openai → import → OpenAI. Najpierw from wskazuje pakiet, z którego bierzemy, a dopiero potem import wskazuje nazwę, którą chcemy z niego wyciągnąć. Zwróć uwagę na wielkość liter: małymi zapisany jest pakiet (openai), wielkimi klasa klienta (OpenAI). Zamiana ich miejscami to najczęstszy błąd w tej jednej linii.1from openai import OpenAI
2
3client = OpenAI(api_key="your-api-key")
4
5response = client.chat.completions.create(
6 model="gpt-4",
7 messages=[
8 {"role": "system", "content": "Jestes przewodnikiem safari o imieniu Darwin."},
9 {"role": "user", "content": "Ktore zwierze sawanny jest najszybsze?"}
10 ],
11 temperature=0.7,
12 max_tokens=500
13)Samo wywołanie czyta się jak ścieżkę:
client → .chat → .completions → .create(. Klient grupuje rodziny API, chat to rodzina rozmów, completions to zasób wewnątrz tej rodziny, a create to akcja, którą na nim wykonujesz. Kolejność nie jest umowna - zapis client.completions.chat nie istnieje, bo completions mieszka w środku chat, nie odwrotnie. Rozbita na pojedyncze elementy ta sama ścieżka wygląda tak: client, ., chat, ., completions, ., create.Nazwa modelu to zwykły napis. Tutaj podaliśmy
"gpt-4", ale równie dobrze może tam stać "gpt-5" - biblioteka niczego nie sprawdza u siebie, tylko przekazuje nazwę dalej. Literówka skończy się błędem z serwera i akurat to jest dobra wiadomość.Gorzej z parametrem
max_tokens. Ogranicza on długość odpowiedzi, a nie długość pytania, i kiedy limit się wyczerpie, model po prostu przestaje pisać - w połowie zdania, bez żadnego wyjątku. Kod działa, odpowiedź jest, tylko urwana. Jeśli Twoje wyniki regularnie kończą się w pół myśli, @name, to zwykle nie wina modelu, lecz za niskiego max_tokens. Parametr temperature steruje z kolei losowością: 0 to odpowiedzi możliwie powtarzalne, 1 - bardziej zróżnicowane.W zmiennej
response nie ma tekstu. Jest obiekt z metadanymi, a właściwa treść leży cztery kroki głębiej.1answer = response.choices[0].message.content
2print(answer)Ścieżka to
response → .choices[0] → .message → .content, dokładnie w tej kolejności. choices jest listą, bo API potrafi zwrócić kilka wariantów odpowiedzi naraz, dlatego [0] wybiera pierwszy z nich. message to obiekt wiadomości, który ma między innymi rolę i treść, a content to dopiero czysty tekst. Pominięcie [0] da listę zamiast wiadomości, a zatrzymanie się na .message da obiekt, którego wydruk jest nieczytelnym zrzutem pól - bez błędu, po prostu nie to, o co chodziło.Z modelem Claude wygląda to bardzo podobnie, tylko nazwy są inne. Import ma tę samą kolejność:
from → anthropic → import → Anthropic. Znów pakiet małą literą, klasa wielką. Spotkasz też wariant import anthropic, w którym klienta tworzy się przez anthropic.Anthropic(...) - działa tak samo, ale polecam wersję z from, bo raz wyciągnięta nazwa klasy jest potem krótsza w użyciu.1from anthropic import Anthropic
2
3client = Anthropic(api_key="your-api-key")
4
5message = client.messages.create(
6 model="claude-sonnet-4-6",
7 max_tokens=1024,
8 system="Jestes ekspertem od jezyka Python.",
9 messages=[
10 {"role": "user", "content": "Jak napisac funkcje sortujaca?"}
11 ]
12)
13
14print(message.content[0].text)Trzy różnice warto zapamiętać. Ścieżka wywołania jest krótsza -
client.messages.create(, bez chat i bez completions. Instrukcja systemowa to osobny parametr system, a nie wpis w messages, więc wrzucenie tam roli "system" skończy się błędem z API. I wreszcie max_tokens jest tu obowiązkowy: bez niego zapytanie w ogóle nie przejdzie. Odpowiedź czytasz przez message.content[0].text, a nie przez choices - to rozgraniczenie łatwo pomylić, gdy w jednym projekcie korzystasz z obu dostawców.Domyślnie czekasz na całą odpowiedź i dopiero wtedy cokolwiek widzisz. Przy dłuższym tekście to kilkanaście sekund ciszy. Parametr
stream=True zmienia jedno: odpowiedź dociera kawałkami, token po tokenie, i możesz ją wypisywać na bieżąco.1stream = client.chat.completions.create(
2 model="gpt-4",
3 messages=[{"role": "user", "content": "Opowiedz historie o sawannie"}],
4 stream=True
5)
6
7for chunk in stream:
8 content = chunk.choices[0].delta.content
9 if content:
10 print(content, end="", flush=True)Zamiast jednego obiektu dostajesz strumień fragmentów, po których przechodzisz pętlą. W trybie strumieniowym nie ma
.message - fragment niesie .delta, czyli przyrost treści. Pierwszy i ostatni fragment mają delta.content równe None i właśnie dlatego stoi tam if content:. Bez tego sprawdzenia Python wypisze w środku tekstu słowo "None" i nie zgłosi żadnego błędu.Warto też wiedzieć, czego
stream=True nie robi. Nie szyfruje komunikacji - za szyfrowanie odpowiada HTTPS i działa ono identycznie w obu trybach. Nie kompresuje danych - kompresja jest sprawą transportu HTTP i biblioteka załatwia ją niezależnie od tego parametru. Nie zapisuje też odpowiedzi do pliku - jeśli chcesz mieć zapis, musisz sam otworzyć plik i dopisywać do niego kolejne fragmenty. Liczba zużytych tokenów i koszt pozostają takie same jak bez strumienia. Zmienia się wyłącznie moment, w którym tekst pojawia się na ekranie.pip install openai. Zapis npm install openai należy do świata Node.js i w Pythonie nie zadziała.pip install gpt4 i pip install chatgpt nie instalują oficjalnej biblioteki - nazwa pakietu na PyPI to openai.from → openai → import → OpenAI, czyli pakiet małą literą, klasa wielką.from → anthropic → import → Anthropic, według tego samego wzorca.client → .chat → .completions → .create(, znak po znaku client . chat . completions . create.response → .choices[0] → .message → .content.client.messages.create(...), max_tokens jest obowiązkowy, instrukcja idzie w parametrze system, a tekst odczytujesz z message.content[0].text.stream=True służy do otrzymywania odpowiedzi w czasie rzeczywistym, token po tokenie. Nie szyfruje, nie kompresuje i nie zapisuje niczego do pliku."gpt-4", "gpt-5" albo "claude-sonnet-4-6".W następnej lekcji zajmiemy się treścią samych wiadomości - prompt engineering pokaże, jak formułować polecenia, żeby model trafiał za pierwszym razem. Na razie zapamiętaj jedno: całe API sprowadza się do czterech ruchów - zainstaluj pakiet, zaimportuj klasę klienta, zawołaj
create i wyłuskaj tekst z końca ścieżki.