gdamian.pl
← Wszystkie wpisy
11 min

OpenAI Agents SDK 2026: pierwszy agent krok po kroku (Python, tracing, MCP, handoffy) 

Damian GębalaAutor

OpenAI Agents SDK to oficjalna biblioteka OpenAI w Pythonie, która zamienia model językowy w agenta: model dostaje instrukcje, korzysta z narzędzi, może przekazać zadanie innemu agentowi i sam zapisuje dziennik tego, co zrobił. Pierwszego agenta uruchomisz na kilkunastu linijkach kodu po instalacji jednego pakietu. Poniżej konfiguracja krok po kroku, razem z miejscami, w których dokumentacja milczy, a kod się wywala.

Czym jest OpenAI Agents SDK i kiedy warto po niego sięgnąć

Oficjalna dokumentacja definiuje to jednym zdaniem: „The OpenAI Agents SDK enables you to build agentic AI apps in a lightweight, easy-to-use package with very few abstractions. It's a production-ready upgrade of our previous experimentation for agents, Swarm.” Kluczowe są te „very few abstractions” - to mało pojęć do nauki, a nie osobny panel do klikania. Pakiet jest na licencji MIT, więc wchodzi do zamkniętej aplikacji bez pytania nikogo o zgodę.

SDK to biblioteka, nie usługa. Nie logujesz się do panelu - piszesz kod i uruchamiasz go u siebie. Dokumentacja podaje przy tym kryterium wyboru, które jest najuczciwszą rzeczą w całym pierwszym akapicie. Z Responses API korzystaj bezpośrednio, gdy sam chcesz zarządzać pętlą, wywołaniami narzędzi i stanem. Z Agents SDK - gdy runtime ma przejąć tury, wykonanie narzędzi, guardraile, handoffy i sesje, czyli gdy agent ma wyprodukować rezultat w kilku krokach, a nie tylko odpowiedzieć. Autorzy dopisują, że nie musisz wybierać jednego globalnie.

Jedno trzeba powiedzieć wprost, bo tu jest największe rozczarowanie w tym temacie: to narzędzie dla inżynierów. Humanloop opisał to wprost - architektura SDK jest projektowana pod programistów, co stawia barierę przy osobach nietechnicznych, które chciałyby edytować prompt, narzędzia albo guardraile, i wypycha inżyniera w rolę pośrednika. Jeśli w firmie nie ma nikogo, kto pisze kod, ten artykuł jest dla Ciebie wartościowy jako mapa rozmowy z wykonawcą, a nie jako instrukcja do samodzielnego wdrożenia.

Co musisz mieć, żeby uruchomić pierwszego agenta

  • Python 3.10 albo nowszy. Repozytorium podaje to wprost: „To get started, set up your Python environment (Python 3.10 or newer required)”.
  • Pakiet openai-agents. Instalacja to pip install openai-agents albo uv add openai-agents. Dokumentacja podaje też dwie opcjonalne grupy: openai-agents[voice] dla głosu i openai-agents[redis] dla sesji w Redisie.
  • Klucz API w OPENAI_API_KEY. Ustaw go przed pierwszym uruchomieniem aplikacji - klucz jest czytany leniwie, dopiero gdy SDK po raz pierwszy tworzy klienta, więc ustawienie zmiennej w połowie skryptu jest za późne.

Jedyna wersja, którą znalazłem w dokumentacji, to 0.21.0, i przy niej opisana strona konfiguracji wymaga biblioteki openai>=3.0.0,<4. To nie jest deklaracja „najnowszej wersji”, tylko numer, przy którym napisano tę stronę - aktualny numer sprawdź w repozytorium, zanim przypniesz wersję w produkcji.

Pierwszy agent w kilkunastu linijkach

from agents import Agent, Runner

agent = Agent(
    name="Assistant",
    instructions="You are a helpful assistant",
)

result = Runner.run_sync(agent, "Write a haiku about recursion in programming.")
print(result.final_output)

Tu są trzy elementy. Agent to instrukcja: jak agent się nazywa i czego ma pilnować. run_sync wykonuje zadanie i zwraca wynik. W aplikacji z serwerem albo z bazą użyjesz wersji asynchronicznej, await Runner.run(agent, ...), a wynik zawsze czytasz z result.final_output.

Na tej ostatniej nazwie zatrzymajmy się na chwilę, bo na tej samej literówce tracisz godzinę. Część poradników w sieci - szczególnie tych pisanych pod eksperymentalny Swarm - pokazuje print(result.response.value). To stare API. W aktualnym SDK wynik siedzi w final_output; skopiujesz starszy wariant, kod nie ruszy i będziesz szukał błędu w miejscu, które działa.

Narzędzia, czyli jak agent działa w Twoim systemie

from agents import Agent, Runner
from agents.decorators import tool

@tool
def sprawdz_stan_magazynu() -> str:
    """Zwraca krótki stan magazynu."""
    return "Rezerwy: 340 sztuk"

agent = Agent(
    name="Konsultant magazynu",
    instructions="Odpowiedz jasno. Uzyj narzedzia, gdy pytanie dotyczy stanu magazynu.",
    tools=[sprawdz_stan_magazynu],
)

Mechanizm jest prosty: dekorator @tool zamienia zwykłą funkcję Pythona w narzędzie, a schemat argumentów powstaje automatycznie. Opis w docstringu nie jest ozdobnikiem - to on mówi modelowi, kiedy po narzędzie sięgnąć. Agent sam zdecyduje, czy potrzebuje stanu magazynu, i dopiero wtedy wywoła Twoją funkcję.

Tutaj zaczyna się decyzja, która nie jest techniczna. Dokumentacja mówi wprost: „Tool arguments and outputs cross the Responses API boundary.” To znaczy, że wszystko, co agent wpisuje w narzędzie i wszystko, co narzędzie zwraca, opuszcza Twoją masynę i przechodzi przez API OpenAI. Jeśli to narzędzie czyta bazę klientów, to od tej chwili te dane leżą również po Twojej stronie dostawcy modelu - i z tej strony trzeba je obsługiwać zgodnie z RODO i polityką retencji.

Tracing, czyli dziennik z przebiegu agenta

Tracing to zapis tego, co agent faktycznie zrobił. W SDK jest wbudowany i domyślnie włączony - dokumentacja: „Tracing is enabled by default”. Zapisuje wywołania modelu, wywołania narzędzi, handoffy, guardraile i zdarzenia własne, a podglądasz go w Trace Viewerze w panelu OpenAI. Dla firmy to najtańsza rzecz w całym pakiecie: zamiast zgadywać, dlaczego agent się pomylił, czytasz dokładnie, co wywołał i co dostał.

Teraz pułapka, o której nie ma w żadnym blogu, a dotyczy danych firmowych. Domyślnie SDK zapisuje w trace'ach wejście i wyjście modelu oraz wejście i wyjście każdego narzędzia - i domyślnie to zbieranie jest włączone. Cytat z dokumentacji brzmi: „By default, trace_include_sensitive_data is True.” Wyłączasz to zmienną OPENAI_AGENTS_TRACE_INCLUDE_SENSITIVE_DATA=0 ustawioną przed uruchomieniem aplikacji.

Dwie rzeczy warto wiedzieć o samym mechanizmie, bo obie zaskakują. Po pierwsze, wyłączenie tracingu nie oznacza, że dane przestaną się wysyłać - dokumentacja ostrzega, że wyłączenie „does not discard data that its processors already buffered”. Po drugie, przy polityce Zero Data Retention tracing po prostu nie działa, bo „Tracing is unavailable for organizations that use OpenAI's APIs under a Zero Data Retention (ZDR) policy”.

Wniosek jest krótki. Jeśli w firmie obowiązuje ZDR, wbudowany tracing odpada i musisz dołożyć własny eksport. Jeśli ZDR nie obowiązuje, ale przetwarzasz dane wrażliwe, ustaw tę zmienną zanim napiszesz pierwszego agenta, a nie potem - to przełącznik globalny na cały proces, więc dokładanie go w trakcie pracy oznacza pracę od nowa.

Handoffy, czyli przekazywanie pracy innemu agentowi

Handoff to przekazanie rozmowy innemu agentowi. Z perspektywy modelu wygląda to jak zwykłe narzędzie: jeśli istnieje przekazanie do agenta o nazwie „Refund Agent”, nazwa narzędzia brzmi transfer_to_refund_agent. Definicja jest krótka:

from agents import Agent, handoff

triage_agent = Agent(
    name="Triage agent",
    instructions="Route each question to the right specialist.",
    handoffs=[history_tutor_agent, handoff(refund_agent)],
)

I tu dochodzimy do pułapki, na którą natknąłem się w zasadzie przypadkiem. Na forum deweloperów 9 maja 2025 roku ktoś opisał dokładnie ten problem: manager z dwoma handoffami, z których jeden zależy od drugiego, a przy pierwszym przekazaniu wykonanie się zatrzymuje. Nie ma sposobu, żeby agent wrócił do managera i ruszył do kolejnego kroku. W wątku nie ma odpowiedzi przedstawiciela OpenAI, a dokumentacja tematu nie wyjaśnia - mówi tylko, że handoff() „always transfers control to the specific agent you passed in”.

Czyli nie planuj architektury, w której specjalista oddaje sprawę z powrotem i czeka na drugą turę. Jeśli potrzebujesz sekwencji kroków, masz dwa udokumentowane warianty, a wybór między nimi sprowadza się do jednego pytania: kto ma odpowiadać klientowi.

Agenci jako narzędzia, czyli wzorzec bez pułapki

main_agent = Agent(
    name="Research assistant",
    tools=[
        summarizer.as_tool(
            tool_name="summarize_text",
            tool_description="Generate a concise summary of the supplied text.",
        )
    ],
)

Różnica jest subtelna, ale fundamentalna. Przy handoffach to specjalista przejmuje rozmowę i odpowiada klientowi. Przy agents-as-tools manager zostaje w kontroli, wywołuje specjalistę jak narzędzie i sam pisze odpowiedź - a to druga opcja naturalnie obsługuje sekwencje, których pierwsza nie obsługuje.

Kiedy w ogóle dzielić agentów, dokumentacja mówi wprost: „Start with one agent whenever you can. Add specialists only when they materially improve capability isolation, policy isolation, prompt clarity, or trace legibility.” I dalej ostrzega: „Splitting too early creates more prompts, more traces, and more approval surfaces without necessarily making the workflow better.” To zasada niezależna od frameworka - dziesięć agentów, każdy z własnym promptem, to dziesięć miejsc, w których coś się psuje, i dziesięć miejsc do utrzymania przy każdej zmianie modelu. Jeśli pierwszy agent obsługuje całość, zacznij od niego.

MCP, czyli podpięcie Twoich danych i narzędzi

MCP to protokół, który standaryzuje sposób podłączania danych i narzędzi do modelu. Dokumentacja SDK porównuje go do USB-C: „Think of MCP like a USB-C port for AI applications.” Jedno gniazdo, wiele urządzeń - zamiast pisać osobną integrację z każdym źródłem danych. Jeśli temat jest dla Ciebie nowy, MCP przy n8n pokazuje ten sam protokół od strony praktycznej, bez Pythona.

SDK rozumie kilka transportów, ale wybór jest prosty. Do nowych integracji dokumentacja zaleca Streamable HTTP albo stdio, a SSE jest oznaczone jako przestarzałe: „The MCP project has deprecated the Server-Sent Events transport. Prefer Streamable HTTP or stdio for new integrations.” Podpięcie lokalnego serwera wygląda tak:

from pathlib import Path
from agents import Agent, Runner
from agents.mcp import MCPServerStdio

samples_dir = Path(__file__).parent / "sample_files"

async with MCPServerStdio(
    name="Filesystem Server via npx",
    params={
        "command": "npx",
        "args": ["-y", "@modelcontextprotocol/server-filesystem", str(samples_dir)],
    },
) as server:
    agent = Agent(
        name="Assistant",
        instructions="Use the files in the sample directory to answer questions.",
        mcp_servers=[server],
    )
    result = await Runner.run(agent, "List the files available to you.")

Tu trzeba się zatrzymać, bo to decyzja o dostępie do danych, a nie o kodzie. Dokumentacja ostrzega wprost: „MCP tools can expose data from the model context and perform actions with the credentials you provide. Connect only to servers you trust, use least-privilege credentials, keep access tokens in authorization fields or headers rather than URLs, and require approval for sensitive operations.” Serwer MCP to program działający z Twoimi danymi i Twoimi uprawnieniami - ten sam problem po stronie narzędzi, który opisuję przy atakach na agentów. Podpięcie byle jakiego serwera znalezionego w internecie jest jak przekazanie mu klucza do wszystkiego - a to, czy klucz jest zapisany w adresie URL, czy w nagłówku, decyduje o tym, czy wyciekł razem z logiem serwera.

Jest jeszcze asymetria, o której łatwo nie wiedzieć. Guardraile narzędzi, które możesz nałożyć na lokalny serwer MCP, nie obejmują HostedMCPTool - dokumentacja: „It does not add client-side tool guardrails to HostedMCPTool, which the Responses API executes as a hosted tool.” Jeśli korzystasz z hostowanego MCP, te zabezpieczenia po Twojej stronie po prostu nie istnieją.

Pułapki, o których dokumentacja nie pisze zprostu

  1. Domyślny model to wariant oszczędny, nie flagowy. Gdy agent nie ustawia modelu, SDK używa gpt-5.6-luna z wyłączonym rozumowaniem i niską rozwlekłością odpowiedzi - opisane to jako wariant „for cost-sensitive, high-volume agent workflows”. Tymczasem przykłady w tej samej dokumentacji ustawiają gpt-5.6-sol. Jeśli nie ustawisz modelu jawnie, nie dostaniesz modelu z przykładów, tylko ten cichy, domyślny.
  2. Guardraile nie chronią handoffów. Dokumentacja: „Tool input guardrails apply to function tools, not handoffs.” Do tego is_enabled przy handoffzie jest sprawdzane, zanim model zwróci argumenty, więc nie autoryzuje niczego wewnątrz argumentu. Sprawdzenie uprawnień musi siedzieć na początku on_handoff, przed jakąkolwiek operacją w systemie - dokumentacja mówi wprost, żeby w razie odmowy rzucić wyjątkiem, bo po powrocie SDK przekazuje sprawę dalej.
  3. Nie ma ustalonego limitu tur. Dokumentacja mówi tylko o „a built-in loop that continues until the task is complete”. Nie znajdziesz tam parametru typu max_turns. Jeśli budujesz coś, co może zapętlić się w koszty, limit musisz zaimplementować sam - i lepiej w narzędziu niż w bibliotece, bo tam też działa.
  4. Zagnieżdżona historia handoffów to beta i domyślnie wyłączona. A co ważniejsze, to nie jest redakcja danych: „Nested handoff history changes how the transcript is represented; it does not redact sensitive data.” Argumenty narzędzi mogą zostać w treści rozmowy przekazywanej dalej nawet wtedy, gdy usuniesz z niej pozycje narzędzi.
  5. „100+ innych modeli” to liczba z README. Przy dostawcy innym niż OpenAI spadasz do Chat Completions, a część funkcji - wyszukiwanie narzędzi, programowe wywoływanie narzędzi, tryb i kontekst rozumowania - przestaje działać, bo to ustawienia tylko dla Responses API. Przy pracy na innym modelu bez własnych ustawień SDK wraca do ustawień generycznych.
  6. Menedżer MCP po cichu gubi serwery. Domyślnie lista aktywnych serwerów zawiera tylko te, które się połączyły, a błędy trafiają do osobnej listy zamiast do wyjątku. Jeśli któryś serwer ci przepadnie, zobaczysz to dopiero po objawach - czyli wtedy, gdy agent zacznie odpowiadać na podstawie niepełnych danych.

Kiedy nie warto tego wdrażać

Nie dla każdego przypadku SDK jest właściwym narzędziem i nie zamierzam tego ukrywać. Jeśli masz jeden scenariusz, który wykonujesz raz w tygodniu, konfiguracja zajmie więcej czasu niż ręczne kliknięcia. Jeśli proces jest w pełni deterministyczny, znane integracje zrobią go bez modelu i bez pętli agentowej.

Przy koszcie muszę być ostrożny, bo nie chcę podawać liczb, których nie sprawdziłem. W dokumentacji SDK, którą przeszedłem, nie ma ani jednej kwoty: nie ma ceny tokena, nie ma kosztu pojedynczego przebiegu agenta, nie ma limitów API. Nie podam ich, bo realny koszt zależy od tego, ile tur i jakie narzędzia agent wykonuje przy Twoim procesie, i tylko pomiar na Twoim przypadku daje odpowiedź. Każda kwota w tym artykule byłaby zmyślona, a na takiej liczbie opiera się potem decyzja o budżecie.

Jeśli chcesz zobaczyć szerszy obraz, zanim napiszesz pierwszego agenta, co naprawdę potrafią agenci AI w firmie opisuje granice tej technologii na przykładach biznesowych. A jeśli ważniejsze pytanie brzmi „kod, workflow czy agent”, n8n vs Dify vs LangChain rozpisuje ten wybór bez SDK-a. Gdy zdecydujesz się na agenta, pamięć, narzędzia i człowiek w pętli pokazuje, które decyzje zostawić po stronie człowieka.

Napisz do mnie - odpowiadam zwykle tego samego dnia.

Robisz coś podobnego u siebie?Napisz do mnie

Masz proces, który zjada tydzień pracy? Odzyskajmy ten tydzień.

Napisz do mnie