Claude API - jak integrować w aplikacjach Python i TypeScript
Seria Claude Code · JSystemsChcesz zbudować własną aplikację z AI? Zaczynasz od Claude API. Ten artykuł to Twój punkt startu - od pierwszego wywołania do produkcyjnej obsługi błędów, bez zakładania że wiesz wszystko od początku.
Claude API (Anthropic API) daje programistyczny dostęp do modeli Claude. Możesz go użyć do zbudowania chatbota, systemu analizy dokumentów, agenta kodującego, pipeline'u przetwarzania tekstu - i tysięcy innych zastosowań. Każdy przykład kodu w tym artykule jest opatrzony wyjaśnieniem co robi i dlaczego.
Czego się nauczysz z tego artykułu:
Zanim zaczniesz - kluczowe pojęcia
Jeśli dopiero zaczynasz z API, przeczytaj najpierw wyjaśnienia poniżej. Jeśli już wiesz co to API i tokeny - przejdź do sekcji "Krok 1 - Instalacja".
Czym jest API i dlaczego jest to ważne dla programisty?
API (Application Programming Interface) to interfejs programistyczny - zestaw reguł i adresów przez które jeden program może rozmawiać z innym.
Analogia: API jak kelner w restauracji
Wyobraź sobie restaurację. Ty (Twój kod) siedzisz przy stoliku i chcesz zamówić jedzenie. Kuchnia (serwer Claude) robi jedzenie. Nie chodzisz sam do kuchni - rozmawiasz z kelnerem (API). Kelner przyjmuje Twoje zamówienie w ustalonym formacie ("chcę burger z frytkami"), przekazuje do kuchni, i przynosi wynik. Claude API działa tak samo: Twój kod wysyła zapytanie w ustalonym formacie, Claude przetwarza je i zwraca odpowiedź.
Dlaczego to ważne dla Ciebie jako programisty? Zamiast budować własny model AI (co wymaga miesięcy pracy i milionów w sprzęcie), przez API płacisz za każde zapytanie do gotowego, inteligentnego modelu. To jak wynajem zamiast budowania własnego domu - elastyczne i tanie na start.
Czym są tokeny? (To podstawa rozliczenia)
Modele AI nie pracują na słowach - pracują na tokenach. Token to kawałek tekstu, zazwyczaj 3-4 znaki lub jedno krótkie słowo. Płacisz za każdy token wejściowy (Twoje zapytanie) i wyjściowy (odpowiedź Claude).
Jak szacować tokeny?
- 1 token ~ 4 znaki angielskie (lub 3 polskie - polskie znaki to czasem 2 tokeny)
- 100 słów ~ 130 tokenów
- Typowa konwersacja = kilkaset do kilku tysięcy tokenów
| Model | Tokeny wejściowe / 1M | Tokeny wyjściowe / 1M | ||
|---|---|---|---|---|
| USD | PLN | USD | PLN | |
| Claude Haiku 4.5 | $1 | 3,66 zł | $5 | 18,28 zł |
| Claude Sonnet 4.6 | $3 | 10,97 zł | $15 | 54,83 zł |
| Claude Opus 4.8 | $5 | 18,28 zł | $25 | 91,38 zł |
Kurs USD/PLN (NBP, 03.06.2026): 3,66 zł. Dla 1 000 zapytań × 100 słów (same tokeny wejściowe): Haiku ~$0.13 (0,48 zł), Sonnet ~$0.39 (1,43 zł), Opus ~$0.65 (2,38 zł).
Przy każdym wywołaniu API podajesz parametr max_tokens - określa maksymalną liczbę tokenów w odpowiedzi modelu. Dla porównania: max_tokens=512 to ok. 380 słów, max_tokens=2048 to kilkustronicowy tekst. Płacisz tylko za faktycznie wygenerowane tokeny, ale zbyt mała wartość przetnie odpowiedź w połowie zdania - ustaw z zapasem.
Krok 1 - Instalacja i konfiguracja
Zanim wywołasz API, musisz zainstalować pakiet SDK i ustawić klucz API. Klucz to Twoje "hasło" do Anthropic - generujesz go raz i przechowujesz jako zmienną środowiskową (nigdy w kodzie!).
Python
Poniższy kod instaluje pakiet anthropic przez pip i tworzy obiekt klienta który będziesz używać do wszystkich wywołań API:
# Instalacja pakietu przez pip (menedżer paczek Pythona)
pip install anthropic
import anthropic
import os
# Tworzymy klienta API - "klient" to obiekt który zarządza połączeniem
client = anthropic.Anthropic(
# os.environ.get() czyta zmienną środowiskową - token nie jest w kodzie!
api_key=os.environ.get("ANTHROPIC_API_KEY")
)
# Lub po prostu: client = anthropic.Anthropic()
# SDK automatycznie czyta ANTHROPIC_API_KEY z env - czyta zmienną środowiskową o tej nazwie
Po wykonaniu tego kodu masz gotowy obiekt client który używasz do wywołań API. Jeśli klucz jest pusty (zmienna środowiskowa nie ustawiona), SDK zgłosi błąd przy pierwszym wywołaniu - nie przy tworzeniu klienta.
Skąd wziąć API key? Zarejestruj się na console.anthropic.com --> API Keys --> Create Key. To jednorazowe hasło do API - traktuj jak hasło do konta bankowego. Ustaw jako zmienną środowiskową: na Windows: setx ANTHROPIC_API_KEY "sk-ant-...", na Linux/Mac: export ANTHROPIC_API_KEY="sk-ant-..."
TypeScript / Node.js
W TypeScript używamy pakietu @anthropic-ai/sdk. Instalacja przez npm i inicjalizacja klienta wyglądają tak:
# Instalacja przez npm (Node Package Manager)
npm install @anthropic-ai/sdk
import Anthropic from "@anthropic-ai/sdk";
// Tworzymy klienta - process.env to obiekt ze zmiennymi środowiskowymi w Node.js
const client = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY,
});
Wolisz nauczyć się tego z doświadczonym trenerem w formie warsztatowej? Szkolenie AI dla programistów z terminem gwarantowanym -->
Krok 2 - Pierwsze wywołanie Messages API
API Claude opiera się na konwersacji - wysyłasz listę wiadomości z rolami ("user" lub "assistant") i dostajesz odpowiedź. To odwzorowuje strukturę normalnego czatu. Każda wiadomość ma rolę i treść - zupełnie jak w rozmowie między dwoma osobami.
user = Ty lub Twój użytkownik, assistant = Claude. W historii wieloturowej konwersacji przeplatasz user/assistant żeby Claude wiedział kto mówił kiedy. Pierwsze wywołanie zawsze zaczyna się od "user".
Python
Poniższy kod wysyła jedno zapytanie do Claude i wyświetla odpowiedź. To najprostszy możliwy przykład - dobry punkt startowy zanim dodasz bardziej zaawansowane funkcje:
# client.messages.create() wysyła żądanie do API i czeka na pełną odpowiedź
message = client.messages.create(
model="claude-sonnet-4-6", # Który model Claude używać
max_tokens=1024, # Maksymalna długość odpowiedzi (w tokenach)
messages=[
# Lista wiadomości - każda ma "role" (kto mówi) i "content" (co mówi)
# "user" to Ty/Twój użytkownik, "assistant" to Claude
{"role": "user", "content": "Wyjaśnij jak działa quicksort w Pythonie"}
]
)
# message.content to lista bloków - zazwyczaj jeden blok tekstowy
# .text wyciąga sam tekst odpowiedzi
print(message.content[0].text)
Po uruchomieniu skrypt wyśle zapytanie, poczeka na odpowiedź (zazwyczaj 1-5 sekund) i wydrukuje pełny tekst odpowiedzi Claude. Zmienna message zawiera też metadane - model, liczbę tokenów, powód zatrzymania.
TypeScript
Identyczna logika w TypeScript - używamy await bo wywołanie API jest asynchroniczne (musi czekać na odpowiedź z serwera):
// "await" czeka na zakończenie wywołania asynchronicznego (bez blokowania wątku)
const message = await client.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 1024,
messages: [
{ role: "user", content: "Wyjaśnij jak działa quicksort w TypeScript" }
],
});
console.log(message.content[0].text);
Krok 3 - System Prompt: nadaj Claude "osobowość" i kontekst
System prompt to instrukcja dla Claude, która definiuje jego rolę, styl i ograniczenia - nie widzi jej użytkownik końcowy, ale wpływa na wszystkie odpowiedzi w całej sesji.
Poniższy kod pokazuje jak dodać system prompt do wywołania. Zauważ że jest osobnym parametrem - nie częścią listy messages:
# Parametr "system" to osobny parametr - nie jest częścią listy messages
message = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
# System prompt definiuje "kim jest" Claude w tej aplikacji
system="""Jesteś ekspertem od PostgreSQL z 15-letnim doświadczeniem.
Odpowiadaj konkretnie, podawaj przykłady SQL.
Zawsze ostrzegaj o potencjalnych problemach z wydajnością.""",
messages=[
# Dopiero tutaj zaczyna się rzeczywista konwersacja z użytkownikiem
{"role": "user", "content": "Jak zindeksować kolumnę JSONB?"}
]
)
Claude użyje systemu prompt przy każdej odpowiedzi w tej sesji - nie musisz go powtarzać w każdej wiadomości użytkownika. To klucz do spójnego zachowania w całej aplikacji.
Krok 4 - Streaming: odpowiedź wyświetlana na bieżąco
Streaming to technika gdzie zamiast czekać na całą odpowiedź, odbierasz ją kawałek po kawałku, na bieżąco. Dla aplikacji z interfejsem użytkownika to ogromna różnica w odczuciu szybkości.
Analogia: streaming jak oglądanie serialu
Bez streamingu: czekasz aż cały odcinek (5GB) pobierze się na dysk, a dopiero potem go oglądasz. Ze streamingiem: zaczynasz oglądać natychmiast, a film ładuje się w tle. Claude bez streamingu: czekasz 5 sekund na całą odpowiedź. Claude ze streamingiem: pierwsze słowa pojawiają się już po 0.5 sekundy, a reszta spływa na bieżąco. Różnica w UX jest ogromna.
Poniższy kod w Pythonie używa client.messages.stream() zamiast client.messages.create() - to jedyna zmiana potrzebna do włączenia streamingu:
# Python - streaming
# Używamy "with" - context manager, który automatycznie sprząta po zakończeniu
with client.messages.stream(
model="claude-sonnet-4-6",
max_tokens=1024,
messages=[
{"role": "user", "content": "Podaj 5 zasad pisania czystego kodu w Pythonie. Kazda w jednej linii."}
]
) as stream:
# stream.text_stream to generator - zwraca kolejne kawałki tekstu
# Każda iteracja to nowy fragment odpowiedzi (zwykle kilka słów)
for text in stream.text_stream:
print(text, end="", flush=True) # end="" nie dodaje nowej linii po każdym fragmencie
# flush=True wymusza natychmiastowe wyświetlenie
print() # nowa linia na końcu - bo end="" ją eliminował
Efekt: tekst pojawia się w terminalu słowo po słowie w czasie rzeczywistym, dokładnie jak na interfejsie Claude.ai. W aplikacji webowej wystarczy przekazać każdy fragment przez WebSocket lub Server-Sent Events do przeglądarki.
// TypeScript - streaming
// stream() zwraca asynchroniczny iterator - można po nim iterować przez "for await"
const stream = client.messages.stream({
model: "claude-sonnet-4-6",
max_tokens: 1024,
messages: [{ role: "user", content: "Podaj 5 zasad pisania czystego kodu w TypeScript. Kazda w jednej linii." }],
});
// "for await" iteruje asynchronicznie - czeka na każde zdarzenie ze streamu
for await (const event of stream) {
// Sprawdzamy typ zdarzenia - interesuje nas "content_block_delta" z tekstem
if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
process.stdout.write(event.delta.text); - // Wypisuje bez nowej linii
}
}
Krok 5 - Tool Use: Claude wywołuje Twoje funkcje
Tool use (zwany też function calling) to mechanizm gdzie opisujesz Claude jakie funkcje ma do dyspozycji, a Claude sam decyduje kiedy i jak je wywołać, by odpowiedzieć na pytanie.
Poniższy kod definiuje jedno narzędzie (zapytanie SQL) i obsługuje pętlę: zapytanie --> Claude decyduje czy użyć narzędzia --> Twój kod je wykonuje --> wynik trafia z powrotem do Claude:
# Definiujemy "narzędzia" - funkcje które Claude może wołać
tools = [
{
"name": "query_database",
"description": "Wykonuje zapytanie SQL na bazie produkcyjnej (tylko SELECT)",
# input_schema = jak dokumentacja funkcji - Claude czyta to i wie jak jej użyć
"input_schema": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Zapytanie SQL"},
},
"required": ["query"]
}
}
]
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
tools=tools, # Przekazujemy listę dostępnych narzędzi
messages=[{"role": "user", "content": "Ile mamy aktywnych użytkowników z ostatniego tygodnia?"}]
)
# Claude może odpowiedzieć bezpośrednio LUB zażądać użycia narzędzia
# stop_reason == "tool_use" oznacza: "Potrzebuję narzędzia, zanim odpowiem"
if response.stop_reason == "tool_use":
# Wyciągamy blok z żądaniem narzędzia z listy content
tool_use = next(b for b in response.content if b.type == "tool_use")
# Wywołujemy naszą funkcję z parametrami które Claude wybrał
result = execute_query(tool_use.input["query"])
# Kontynuujemy konwersację - dodajemy wynik narzędzia do historii
final = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
tools=tools,
messages=[
# Cała poprzednia historia konwersacji
{"role": "user", "content": "Ile mamy aktywnych użytkowników..."},
{"role": "assistant", "content": response.content}, # Odpowiedź Claude z żądaniem narzędzia
# Wynik narzędzia - identyfikujemy przez tool_use_id żeby Claude wiedział do czego to pasuje
{"role": "user", "content": [{"type": "tool_result", "tool_use_id": tool_use.id, "content": str(result)}]}
]
)
Claude sam napisze poprawne zapytanie SQL, Twój kod je wykona, a Claude sformułuje odpowiedź w naturalnym języku - bez pisania ani jednej linii parsowania.
Prompt Caching - 90% taniej dla stałych promptów
Prompt caching to mechanizm gdzie Anthropic "zapamiętuje" fragment Twojego promptu (np. długi system prompt) i nie przetwarza go od nowa przy każdym wywołaniu. Płacisz 10× mniej za kolejne użycia.
Wystarczy dodać cache_control do fragmentu który chcesz cachować. System prompt zamienia się z prostego stringa w listę obiektów:
# Prompt caching - system prompt cachowany po pierwszym użyciu
# System jest teraz listą obiektów, nie prostym stringiem
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
system=[
{
"type": "text",
"text": "Długi system prompt (min. 1024 tokeny żeby opłacało się cachować)...",
# cache_control: {"type": "ephemeral"} = oznacz ten fragment do cachowania
# "ephemeral" = cache przez ~5 minut (wystarczy dla typowych scenariuszy)
"cache_control": {"type": "ephemeral"}
}
],
messages=[{"role": "user", "content": zapytanie}]
)
# Sprawdź oszczędności w response.usage
print(response.usage)
# cache_creation_input_tokens: 1500 (tylko przy PIERWSZYM wywołaniu - tu piszemy do cache)
# cache_read_input_tokens: 1500 (przy KOLEJNYCH wywołaniach - czytamy z cache, 90% taniej!)
Obsługa błędów - co może pójść nie tak
Każde API może zwrócić błąd. Dobrze napisana aplikacja obsługuje je gracefully zamiast "crashować". Najczęstsze błędy Claude API:
- RateLimitError (429) - za dużo zapytań na minutę. Rozwiązanie: czekaj i spróbuj ponownie
- APIConnectionError - problem z siecią lub serwer niedostępny. Rozwiązanie: retry z backoff
- APIStatusError (4xx) - błędne zapytanie (np. zły klucz API). Rozwiązanie: nie próbuj ponownie, napraw kod
2 ** attempt daje sekwencję: 1, 2, 4, 8, 16 sekund.
Poniższy kod opakowuje wywołanie API w funkcję z automatycznym retry - obsługuje każdy typ błędu inaczej i nie ponawia prób gdy błąd jest po stronie kodu (a nie serwera):
import anthropic
# Importujemy konkretne typy błędów - każdy obsługujemy inaczej
from anthropic import APIStatusError, APIConnectionError, RateLimitError
import time
def safe_claude_call(messages, retries=3):
for attempt in range(retries): # Próbuj maksymalnie 3 razy
try:
return client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
messages=messages
)
except RateLimitError:
# Za dużo zapytań - czekamy coraz dłużej (exponential backoff)
wait = 2 ** attempt # 1s, 2s, 4s...
print(f"Rate limit, czekam {wait}s...")
time.sleep(wait)
except APIConnectionError as e:
# Problem z siecią - możemy spróbować ponownie
print(f"Problem z połączeniem: {e}")
if attempt == retries - 1: # Jeśli to ostatnia próba
raise # Rzuć wyjątek - nie ma sensu dalej czekać
except APIStatusError as e:
# Błąd 4xx (np. zły klucz) - retry nie pomoże, trzeba naprawić kod
print(f"API error {e.status_code}: {e.message}")
raise # nie retry na błędy 4xx
raise Exception("Max retries exceeded")
Ta funkcja jest dobrym punktem startowym dla każdej aplikacji produkcyjnej. Warto dodać do niej logowanie do pliku i alerty gdy retry wyczerpią się po raz trzeci.
Częste błędy przy pierwszej integracji z Claude API
- Błąd 1: API key w kodzie zamiast w zmiennej środowiskowej
Najczęstszy błąd początkujących. Wklejaszapi_key="sk-ant-..."bezpośrednio w pliku Python lub TypeScript. Gdy wrzucisz kod na GitHub - klucz jest widoczny dla całego świata, Anthropic go dezaktywuje automatycznie. Zawsze używajos.environ.get(). - Błąd 2: Za mały max_tokens
Ustawiaszmax_tokens=100żeby "nie płacić za dużo". Claude zaczyna generować kod, dochodzi do granicy i... urwa odpowiedź w środku bloku kodu lub zdania. Dla generowania kodu ustaw minimum 1 024-4 096 tokenów. Płacisz za faktycznie wygenerowane tokeny, nie za limit. - Błąd 3: Brak obsługi błędów
Pierwsza wersja działa, aplikacja idzie na produkcję bez try/catch. Gdy Anthropic ma chwilową przerwę (zdarza się), aplikacja crashuje z nieobsługiwanym wyjątkiem. Zawsze owijaj wywołania API w obsługę błędów - nawet minimalnetry/except Exception as e.
Modele i ich ID w 2026
Wybór modelu to balans między inteligencją, szybkością i ceną. Reguła ogólna: zacznij od Sonnet, użyj Haiku gdy szybkość ważniejsza niż jakość, Opus gdy jakość ważniejsza niż cena.
| Model | ID w API | Zastosowanie |
|---|---|---|
| Claude Haiku | claude-haiku-4-5 | Szybkie, tanie zadania: klasyfikacja tekstu, proste podsumowania, analiza logów |
| Claude Sonnet | claude-sonnet-4-5 | Złoty środek (rekomendowany na start): code review, chatbot, pisanie kodu |
| Claude Opus 4.7 | claude-opus-4-7 | Najtrudniejsze zadania: architektura, złożone rozumowanie, research |
Gdy opanujesz Claude API, masz w rękach silnik do budowania aplikacji które robią rzeczy niemożliwe rok temu. Chatbot który rozumie kontekst całej konwersacji, system analizy dokumentów który czyta setki PDF-ów w minutę, agent który sam pisze i testuje kod. To nie są prototypy - to produkcyjne możliwości dostępne przez kilka linii kodu.
5 rzeczy, które wdrożysz w pierwszej integracji z API
Pierwsze wywołanie API masz już w lekcji. Te pięć rzeczy ustaw od razu, żeby było tanio i bezpiecznie:
- Klucz w zmiennej środowiskowej. trzymaj go w
ANTHROPIC_API_KEY, nigdy w kodzie ani w repozytorium. - Prompt caching na stały kontekst. oznacz niezmienny system prompt parametrem
cache_control- do 90% taniej i szybciej przy powtarzalnych wywołaniach. max_tokensświadomie. to limit ODPOWIEDZI, nie wejścia - za mała wartość utnie wynik w połowie zdania.- Streaming dla UX. włącz
stream=True- tekst pojawia się na bieżąco, zamiast zamrażać aplikację na kilka sekund. - Wymuś format prefillem. dodaj wiadomość roli
assistantzaczynającą się np. od{- Claude dokończy w tym formacie i dostaniesz czysty JSON bez gadania dookoła.
Newsletter bloga JSystems
Otrzymuj każdą nową lekcję prosto na swoją skrzynkę
Nowe lekcje pojawiają się co poniedziałek i czwartek. Zapisz się do newslettera bloga JSystems - dostaniesz powiadomienie zaraz po publikacji każdej lekcji.
Szkolenie AI dla programistów - Claude API, agenci, RAG, MCP
5 dni warsztatów gdzie budujesz kompletną aplikację AI z Claude API. Tool use, streaming, prompt caching, agenci, deployment. Termin gwarantowany.
Komentarze (0)
Brak komentarzy...