Jak zbudować agenta AI w Pythonie: Claude Agent SDK krok po kroku
Jak zbudować agenta AI, który sam czyta i poprawia kod? Instalujemy Claude Agent SDK, piszemy pierwszego agenta, dodajemy własne narzędzie i MCP. Krok po kroku.
Ten artykuł w innych językach:العربيةDeutschEnglishEspañolFrançaisItaliano日本語简体中文
W tym artykule
- Czym jest agent AI z punktu widzenia programisty?
- Krok 1: jak zainstalować Claude Agent SDK?
- Krok 2: jak ustawić klucz API?
- Krok 3: jak napisać pierwszego agenta AI?
- Krok 4: jak ustawić, co agent może robić sam?
- Krok 5: jak dodać agentowi własne narzędzie?
- Krok 6: jak podłączyć agenta do serwera MCP?
- Co dalej po pierwszym agencie?
- Na co zwrócić uwagę?
- FAQ
Jak zbudować agenta AI bez pisania całej pętli od zera? Najkrótsza droga, jaką znam, to Claude Agent SDK, czyli biblioteka dla Pythona i TypeScriptu, która daje nam te same narzędzia, pętlę agenta i zarządzanie kontekstem, na których działa Claude Code. Piszemy kilkanaście linijek kodu, a agent sam czyta pliki, poprawia błędy i uruchamia komendy.
W tym poradniku budujemy pierwszego agenta w Pythonie, ustawiamy mu uprawnienia, dodajemy własne narzędzie i serwer MCP. Wszystkie komendy i fragmenty kodu pochodzą z oficjalnego quickstartu Agent SDK i stron dokumentacji, do których linkuję po drodze.
Czym jest agent AI z punktu widzenia programisty?
Według dokumentacji agent to aplikacja, która wykonuje zadanie, sama planując kolejne kroki i wywołując narzędzia: czyta pliki, uruchamia komendy albo edytuje kod. Szerzej, bez kodu, opisałem to w poradniku Co to jest agent AI.
Z punktu widzenia programisty najważniejsza jest pętla: model myśli, wywołuje narzędzie, ogląda wynik i decyduje, co dalej. Agent SDK przejmuje tę pętlę, wykonywanie narzędzi, zarządzanie kontekstem i ponawianie zapytań, a my tylko czytamy strumień wiadomości.
Dokumentacja odróżnia przy tym cztery sposoby pracy z Claude:
- Agent SDK, czyli biblioteka, która uruchamia agenta Claude Code w naszej aplikacji (w procesie, którym sami zarządzamy),
- Claude Code CLI, czyli terminal do codziennej, interaktywnej pracy (o nim jest poradnik Claude Code),
- Client SDK, czyli bezpośredni dostęp do Claude API, gdzie pętlę narzędzi piszemy sami (albo zlecamy ją tzw. „tool runnerowi” w becie),
- Managed Agents, czyli agent hostowany przez Anthropic i konfigurowany przez API.
Ten poradnik dotyczy pierwszej opcji.
Krok 1: jak zainstalować Claude Agent SDK?
Potrzebujemy Pythona 3.10+ (albo Node.js 18.14+ dla TypeScriptu) i konta w Claude Console. Najpierw tworzymy folder projektu:
mkdir my-agent
cd my-agent
Agent ma domyślnie dostęp do plików w tym katalogu i jego podkatalogach. Dokumentacja poleca menedżer pakietów uv:
uv init
uv add claude-agent-sdk
Wersja ze zwykłym pip (macOS i Linux) wygląda tak:
python3 -m venv .venv
source .venv/bin/activate
pip install claude-agent-sdk
Co ciekawe, osobna instalacja Claude Code zwykle nie jest potrzebna: oba SDK mają w paczce natywny plik binarny Claude Code. Wyjątkiem są instalacje bez gotowej paczki dla danej platformy, np. na Windowsie ARM64 (wtedy instalujemy Claude Code ręcznie, a SDK znajdzie go w PATH).
Krok 2: jak ustawić klucz API?
Klucz tworzymy w Claude Console i ustawiamy jako zmienną środowiskową w terminalu, w którym uruchomimy agenta:
export ANTHROPIC_API_KEY=your-api-key
SDK nie wczytuje plików .env automatycznie, więc jeśli trzymamy klucz w .env, musimy go załadować sami (np. pakietem dotenv). Zamiast klucza Anthropic można też użyć Amazon Bedrock, Claude Platform on AWS, Google Cloud albo Microsoft Foundry, ustawiając odpowiednią zmienną, np. CLAUDE_CODE_USE_BEDROCK=1.
Jedno zastrzeżenie z dokumentacji: bez wcześniejszej zgody Anthropic nie pozwala, żeby produkty zbudowane na Agent SDK oferowały logowanie kontem claude.ai albo korzystały z limitów subskrypcji. Agent działa na kluczu API i płacimy za tokeny (jak je śledzić, pisałem przy okazji kosztów Claude API).
Krok 3: jak napisać pierwszego agenta AI?
Przykład z quickstartu to agent, który znajduje i naprawia błędy w kodzie. Najpierw tworzymy plik utils.py z dwoma celowymi błędami:
def calculate_average(numbers):
total = 0
for num in numbers:
total += num
return total / len(numbers)
def get_user_name(user):
return user["name"].upper()
calculate_average([]) wywali się na dzieleniu przez zero, a get_user_name(None) na TypeError. Teraz właściwy agent, czyli plik agent.py:
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage, ResultMessage
async def main():
# Agentic loop: streams messages as Claude works
async for message in query(
prompt="Review utils.py for bugs that would cause crashes. Fix any issues you find.",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Edit", "Glob"], # Auto-approve these tools
permission_mode="acceptEdits", # Auto-approve file edits
),
):
# Print human-readable output
if isinstance(message, AssistantMessage):
for block in message.content:
if hasattr(block, "text"):
print(block.text) # Claude's reasoning
elif hasattr(block, "name"):
print(f"Tool: {block.name}") # Tool being called
elif isinstance(message, ResultMessage):
print(f"Done: {message.subtype}") # Final result
asyncio.run(main())
Kod ma trzy części:
querytworzy pętlę agenta i zwraca asynchroniczny iterator, więc wiadomości czytamy na bieżąco przezasync for,promptto zadanie. Claude sam decyduje, których narzędzi użyć,optionsto konfiguracja: tuallowed_toolsz góry zatwierdzaRead,EditiGlob, apermission_mode="acceptEdits"automatycznie akceptuje zmiany w plikach.
Uruchamiamy:
uv run agent.py
(albo python agent.py w aktywnym środowisku venv). Agent wypisuje swoje rozumowanie i każde wywołane narzędzie, a na końcu Done: success. Po wszystkim w utils.py znajdziemy obsługę pustej listy i braku użytkownika. Agent sam przeczytał plik, znalazł przypadki brzegowe i poprawił kod, a my nie napisaliśmy ani jednej funkcji do obsługi narzędzi.
Jeśli zobaczymy błąd Not logged in albo Invalid API key, prawie na pewno zmienna ANTHROPIC_API_KEY nie jest ustawiona w tym terminalu.
Krok 4: jak ustawić, co agent może robić sam?
O tym, co agent potrafi, decydują narzędzia. Dokumentacja podaje trzy typowe zestawy:
Read,Glob,Grep, czyli tylko analiza, bez zmian w plikach,Read,Edit,Glob, czyli analiza i edycja kodu,Read,Edit,Bash,Glob,Grep, czyli pełna automatyzacja z komendami w terminalu.
Żeby agent mógł np. szukać w sieci albo uruchamiać testy, wystarczy dopisać narzędzie i zmienić prompt:
options = ClaudeAgentOptions(
allowed_tools=["Read", "Edit", "Glob", "Bash"], permission_mode="acceptEdits"
)
Z włączonym Bash quickstart proponuje zadanie „Write unit tests for utils.py, run them, and fix any failures”. Można też nadać agentowi rolę przez system_prompt, np. doświadczonego programisty Pythona, który pilnuje PEP 8.
Drugą dźwignią jest tryb uprawnień (permission_mode):
"default"przekazuje każde niezatwierdzone wywołanie do naszej funkcjicanUseTool, a bez niej odmawia,"acceptEdits"akceptuje edycje plików i proste komendy typumkdirczymvw katalogu roboczym,"plan"każe agentowi najpierw zbadać kod i przygotować plan,"dontAsk"nigdy nie pyta: działa tylko to, co zatwierdziliśmy z góry, reszta jest odrzucana (dobre dla agentów bez człowieka przy klawiaturze),"auto"przepuszcza akcje przez klasyfikator, który każdą przegląda i blokuje albo zezwala,"bypassPermissions"wykonuje wszystko bez pytania i według dokumentacji nadaje się tylko do odizolowanych środowisk, takich jak CI albo kontenery.
Złota zasada z dokumentacji: "acceptEdits" na komputerze deweloperskim, "bypassPermissions" tylko tam, gdzie agent nie może zaszkodzić niczemu ważnemu. Więcej o tym, dlaczego to ma znaczenie, w poradniku o bezpieczeństwie agentów AI.
Warto też od razu ustawić limity: max_turns ogranicza liczbę tur, a max_budget_usd zatrzymuje pętlę po przekroczeniu szacowanego kosztu. Bez nich agent działa, dopóki sam nie skończy, co przy otwartych zadaniach typu „ulepsz ten projekt” może potrwać ;)
Krok 5: jak dodać agentowi własne narzędzie?
Wbudowane narzędzia to dopiero początek. Własne narzędzie definiujemy dekoratorem @tool (nazwa, opis, schemat wejścia i funkcja), a potem pakujemy je w serwer MCP działający w tym samym procesie. Przykład z dokumentacji pobiera temperaturę z API Open-Meteo, więc najpierw dodajemy bibliotekę httpx:
uv add httpx
Definicja narzędzia:
from typing import Annotated, Any
import httpx
from claude_agent_sdk import tool, create_sdk_mcp_server
# Define a tool: name, description, input schema, handler
@tool(
"get_temperature",
"Get the current temperature at a location",
{
"latitude": Annotated[float, "Latitude coordinate"],
"longitude": Annotated[float, "Longitude coordinate"],
},
)
async def get_temperature(args: dict[str, Any]) -> dict[str, Any]:
async with httpx.AsyncClient() as client:
response = await client.get(
"https://api.open-meteo.com/v1/forecast",
params={
"latitude": args["latitude"],
"longitude": args["longitude"],
"current": "temperature_2m",
"temperature_unit": "fahrenheit",
},
)
data = response.json()
# Return a content array - Claude sees this as the tool result
return {
"content": [
{
"type": "text",
"text": f"Temperature: {data['current']['temperature_2m']}°F",
}
]
}
# Wrap the tool in an in-process MCP server
weather_server = create_sdk_mcp_server(
name="weather",
version="1.0.0",
tools=[get_temperature],
)
W tym samym pliku przekazujemy serwer do agenta. Pełna nazwa narzędzia ma format mcp__{serwer}__{narzędzie} i to ją wpisujemy do allowed_tools, żeby działało bez pytania o zgodę:
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
async def main():
options = ClaudeAgentOptions(
mcp_servers={"weather": weather_server},
allowed_tools=["mcp__weather__get_temperature"],
)
async for message in query(
prompt="What's the temperature in San Francisco?",
options=options,
):
# ResultMessage is the final message after all tool calls complete
if isinstance(message, ResultMessage) and message.subtype == "success":
print(message.result)
asyncio.run(main())
Agent wywołuje nasze narzędzie i na podstawie wyniku odpowiada. W miejsce pogody możemy podpiąć cokolwiek: naszą bazę danych, wewnętrzne API albo skrypt.
Krok 6: jak podłączyć agenta do serwera MCP?
Gotowe serwery MCP (o samym protokole pisałem w poradniku Co to jest MCP) podłączamy w opcji mcp_servers. Przykład z dokumentacji łączy agenta ze zdalnym serwerem dokumentacji Claude Code przez HTTP:
options = ClaudeAgentOptions(
mcp_servers={
"claude-code-docs": {
"type": "http",
"url": "https://code.claude.com/docs/mcp",
}
},
allowed_tools=["mcp__claude-code-docs__*"],
)
Gwiazdka w allowed_tools zatwierdza wszystkie narzędzia z danego serwera. Z promptem „Use the docs MCP server to explain what hooks are in Claude Code” agent przeszukuje dokumentację i zwraca odpowiedź.
Co dalej po pierwszym agencie?
Agent SDK ma też resztę funkcji Claude Code:
- hooki, czyli własny kod uruchamiany przed albo po wywołaniu narzędzia,
- subagenty do wydzielonych podzadań,
- sesje: identyfikator z
ResultMessage.session_idpozwala wznowić rozmowę z pełnym kontekstem albo ją rozgałęzić, - skille, komendy i pamięć wczytywane z katalogu
.claude/, tak jak w Claude Code.
Gotowe przykładowe aplikacje (m.in. asystent poczty i agent badawczy) są w repozytorium claude-agent-sdk-demos.
Na co zwrócić uwagę?
Po pierwsze, na koszty. Kontekst rośnie z każdą turą, a duży plik albo gadatliwa komenda potrafią zjeść tysiące tokenów naraz. Stałe części (prompt systemowy, definicje narzędzi) są automatycznie cache’owane, ale max_budget_usd i tak warto ustawić od pierwszego dnia (cap może zostać przekroczony o koszt jednej odpowiedzi, więc zostawmy zapas).
Po drugie, na uprawnienia. Agent z Bash i bypassPermissions na zwykłym laptopie to proszenie się o kłopoty, więc pełną automatyzację zostawmy dla kontenerów.
Po trzecie, na branding. Według dokumentacji produkt zbudowany na SDK może się nazywać np. „Claude Agent” albo „
FAQ
Jak zbudować agenta AI bez pisania pętli od zera?
Najprościej przez bibliotekę, która tę pętlę już ma, np. Claude Agent SDK. Instalujemy claude-agent-sdk, ustawiamy ANTHROPIC_API_KEY i wywołujemy query() z promptem oraz listą dozwolonych narzędzi. Resztę, czyli wywoływanie narzędzi i zarządzanie kontekstem, robi SDK.
Czy Claude Agent SDK jest darmowy?
Sama biblioteka nie kosztuje nic, ale agent korzysta z Claude API, więc płacimy za zużyte tokeny. Bez zgody Anthropic nie można go podpiąć pod subskrypcję claude.ai.
Czym różni się Agent SDK od Claude API?
W zwykłym Client SDK (Claude API) pętlę narzędzi piszemy sami albo korzystamy z tool runnera w becie. Agent SDK ma wbudowane narzędzia Claude Code (czytanie i edycję plików, komendy, wyszukiwanie w sieci), uprawnienia, sesje i hooki.
Czy agenta można napisać w TypeScripcie?
Tak. Pakiet to @anthropic-ai/claude-agent-sdk, wymaga Node.js 18.14+, a opcje w przykładach z dokumentacji nazywają się tak samo jak w Pythonie, tylko w camelCase (allowedTools, permissionMode).