Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie
CodeWorlds
Powrót do kolekcji
Przewodnik11 min czytania

OpenAI Agents SDK, agenci z przekazywaniem zadań

OpenAI Agents SDK buduje agentów z narzędziami, przekazywaniem zadań i barierkami. Sesje, śledzenie wywołań, wersje Python i TypeScript oraz porównanie z LangGraph.

OpenAI Agents SDK, mało abstrakcji, dużo kontroli

Biblioteka wyrosła z eksperymentu o nazwie Swarm i zachowała jego główną cechę: bardzo mało pojęć do nauczenia. Agent, narzędzie, przekazanie zadania, barierka i sesja. Na tych pięciu rzeczach da się zbudować całkiem złożony system, a każdą z nich zrozumiesz w kilka minut.

To odróżnia ją od bibliotek, które wprowadzają własny model przepływu, graf stanów albo warstwę pośrednią nad dostawcami modeli. Tutaj pisze się zwykły kod w Pythonie albo TypeScripcie, a biblioteka dokłada pętlę wywołań i obserwowalność.

Agent i narzędzia

Agent to model z instrukcją i zestawem narzędzi. Narzędzie to funkcja, której schemat argumentów powstaje z adnotacji typów.

Code
Bash
pip install openai-agents
Code
Python
from agents import Agent, Runner, function_tool

@function_tool
def sprawdz_status(numer: str) -> str:
    """Zwraca status zamowienia o podanym numerze.

    Wywolaj, gdy klient pyta o swoje zamowienie.
    """
    return baza.status(numer)

agent = Agent(
    name="Wsparcie",
    instructions="Odpowiadasz na pytania o zamowienia. Bez wstepow.",
    tools=[sprawdz_status],
)

wynik = Runner.run_sync(agent, "Gdzie jest zamowienie 1841?")
print(wynik.final_output)

Docstring funkcji nie jest tu komentarzem dla programisty, tylko opisem dla modelu. Zdanie mówiące, kiedy narzędzie wywołać, poprawia trafność mocniej niż jakakolwiek zmiana instrukcji systemowej. To najtańsza optymalizacja, jaką da się zrobić.

Wersja dla TypeScriptu ma ten sam układ pojęć, z opisem argumentów przez schemat zamiast adnotacji. Zespół pracujący na froncie może więc trzymać agentów w tym samym języku co resztę aplikacji.

Przekazywanie zadań

Ten mechanizm jest sercem biblioteki i jej najbardziej wyróżniającą cechą. Zamiast jednego agenta z dwudziestoma narzędziami budujesz kilku wyspecjalizowanych i pozwalasz im przekazywać sobie rozmowę.

Code
Python
agent_zwrotow = Agent(
    name="Zwroty",
    instructions="Obslugujesz zwroty i reklamacje.",
    tools=[zloz_zwrot, sprawdz_polityke],
)

agent_rozliczen = Agent(
    name="Rozliczenia",
    instructions="Obslugujesz faktury i platnosci.",
    tools=[pobierz_fakture, wyjasnij_oplate],
)

recepcja = Agent(
    name="Recepcja",
    instructions="Kierujesz rozmowe do wlasciwego dzialu.",
    handoffs=[agent_zwrotow, agent_rozliczen],
)

Technicznie przekazanie jest wywołaniem narzędzia, więc widać je w śladzie tak samo jak każdą inną akcję. To ważne przy diagnozowaniu, bo rozmowa, która trafiła do złego działu, ma widoczny moment tej decyzji.

Zaletą podziału jest krótsza instrukcja i mniejszy zestaw narzędzi u każdego agenta. Model wybierający spośród czterech narzędzi myli się rzadziej niż model wybierający spośród dwudziestu, a instrukcja opisująca jeden obszar jest precyzyjniejsza niż taka, która próbuje objąć wszystko.

Pułapką jest przesada w drugą stronę. Osiem agentów przekazujących sobie rozmowę w kółko to system, którego nikt nie prześledzi. Trzy do pięciu ról wystarcza w większości zastosowań.

Barierki, czyli kontrola wejścia i wyjścia

Barierka to osobne sprawdzenie działające równolegle do agenta, które przerywa pracę, gdy warunek nie jest spełniony.

Code
Python
from agents import input_guardrail, GuardrailFunctionOutput

@input_guardrail
async def tylko_o_zamowieniach(ctx, agent, wejscie: str):
    ocena = await Runner.run(klasyfikator, wejscie)
    return GuardrailFunctionOutput(
        output_info=ocena.final_output,
        tripwire_triggered=not ocena.final_output.dotyczy_zamowien,
    )

Sens tego rozwiązania jest ekonomiczny i praktyczny zarazem. Tanie sprawdzenie modelem lekkim odrzuca zapytania spoza zakresu, zanim uruchomi się droższy agent z dostępem do narzędzi. Oszczędzasz tokeny i ograniczasz powierzchnię, na której coś może pójść źle.

Barierka wyjściowa działa analogicznie na odpowiedzi. Typowe zastosowania to sprawdzenie, czy odpowiedź nie zawiera danych osobowych, czy trzyma się polityki firmy i czy nie obiecuje rzeczy, których obiecywać nie wolno.

Warto pamiętać, że barierka to nie zabezpieczenie w sensie bezpieczeństwa systemu. Chroni przed typowym błędnym zachowaniem, a nie przed celowym atakiem. Uprawnienia nadal egzekwuj w kodzie narzędzi, sprawdzając, kto wywołuje operację.

Jeśli wymagania idą dalej niż to, czyli obejmują wykrywanie wstrzykiwania promptu i wyciek danych osobowych na poziomie polityki firmy, tego się barierką napisaną samodzielnie nie załatwi i trzeba sięgnąć po osobny produkt, na przykład Prompt Security. Warto natomiast wiedzieć, że projekt nie jest już samodzielny: SentinelOne przejął go we wrześniu 2025 roku, więc zamiast wykupienia planu czeka Cię rozmowa handlowa z dostawcą bezpieczeństwa.

Agent jako narzędzie, czyli druga droga

Przekazanie zadania oddaje rozmowę w całości i nie ma powrotu. Bywa to niepożądane, gdy chcesz tylko zasięgnąć opinii i wrócić do własnego wątku. Do tego służy drugi mechanizm: agent udostępniony jako narzędzie.

Code
Python
tlumacz = Agent(name="Tlumacz", instructions="Tlumaczysz tekst na polski.")

glowny = Agent(
    name="Redaktor",
    instructions="Przygotowujesz odpowiedzi dla klientow.",
    tools=[tlumacz.as_tool(
        tool_name="przetlumacz",
        tool_description="Tlumaczy podany tekst na polski.",
    )],
)

Różnica jest zasadnicza dla przepływu. Przy przekazaniu kontrolę przejmuje inny agent i to on kończy rozmowę. Przy agencie jako narzędziu wynik wraca do agenta wywołującego, który dalej prowadzi wątek.

Reguła wyboru jest prosta. Jeśli sprawa należy do innego działu i tam ma się zakończyć, użyj przekazania. Jeśli potrzebujesz cząstkowej odpowiedzi, żeby złożyć z niej własną, użyj agenta jako narzędzia.

Ten drugi układ ma też zaletę kosztową. Wyspecjalizowany agent może działać na tańszym modelu, bo jego zadanie jest wąskie, a agent główny na mocniejszym. Podział na kroki pozwala dobrać model do trudności, zamiast płacić najwyższą stawkę za wszystko.

Zatrzymanie na decyzję człowieka

Nie każde działanie powinno wykonać się samo. Zwrot pieniędzy, wysłanie wiadomości do klienta albo zmiana danych w systemie to operacje, przy których warto zapytać człowieka.

Biblioteka pozwala oznaczyć narzędzie jako wymagające zatwierdzenia. Uruchomienie zatrzymuje się wtedy w miejscu wywołania, zwraca informację o oczekującej decyzji, a Ty wznawiasz je po zatwierdzeniu albo odrzuceniu.

W praktyce ten mechanizm rozwiązuje najczęstszy problem wdrożeniowy. Zespoły boją się wypuścić agenta z dostępem do operacji nieodwracalnych, więc albo nie dają mu takich narzędzi, albo nie wdrażają go wcale. Zatwierdzanie wybranych działań pozwala zacząć od układu, w którym agent proponuje, a człowiek zatwierdza, i stopniowo zdejmować kolejne blokady, gdy widać, że działa poprawnie.

Warto oznaczać operacje według skutku, a nie według trudności. Odczyt danych klienta może być trudny technicznie i całkowicie bezpieczny, a jednolinijkowe wywołanie zwrotu pieniędzy prostą operacją o poważnych konsekwencjach.

Strumieniowanie odpowiedzi

Agent wykonujący trzy wywołania narzędzi odpowie po kilku sekundach, a użytkownik przez ten czas patrzy na pusty ekran. Strumieniowanie pozwala pokazywać postęp na bieżąco.

Code
Python
wynik = Runner.run_streamed(agent, "Gdzie jest zamowienie 1841?")

async for zdarzenie in wynik.stream_events():
    if zdarzenie.type == "raw_response_event":
        pokaz_fragment(zdarzenie.data)

Przydatne jest nie tylko strumieniowanie tekstu, ale też zdarzeń o wywołaniach narzędzi. Komunikat „sprawdzam status zamówienia" pokazany w trakcie działania zmienia odbiór interfejsu bardziej niż skrócenie czasu odpowiedzi o sekundę.

Sesje i pamięć rozmowy

Bez sesji każde uruchomienie zaczyna się od zera i musisz ręcznie przekazywać historię. Sesja robi to za Ciebie, przechowując przebieg rozmowy pod identyfikatorem.

Code
Python
from agents import SQLiteSession

sesja = SQLiteSession("klient-1841", "rozmowy.db")

Runner.run_sync(agent, "Gdzie jest moje zamowienie?", session=sesja)
Runner.run_sync(agent, "A kiedy dotrze?", session=sesja)

Drugie pytanie działa, bo agent widzi poprzednią wymianę zdań. Bez sesji byłoby niezrozumiałe.

Ograniczenie jest takie samo jak wszędzie: historia rośnie i w pewnym momencie zaczyna kosztować więcej niż sama odpowiedź. Przy rozmowach długich albo powracających warto sięgnąć po warstwę pamięci pokroju Mem0, która wydobywa fakty zamiast przechowywać wszystko.

Śledzenie wywołań

Biblioteka zbiera ślad każdego uruchomienia: wywołania modelu, wywołania narzędzi, przekazania i barierki. To działa domyślnie, bez konfiguracji, i jest jednym z mocniejszych argumentów za tym rozwiązaniem.

Diagnozowanie agenta bez śladu sprowadza się do zgadywania, dlaczego zrobił coś dziwnego. Ze śladem widzisz dokładnie, które narzędzie wywołał, z jakimi argumentami i co dostał w odpowiedzi.

Ślady można też kierować do zewnętrznych systemów obserwacyjnych, na przykład Langfuse, jeśli chcesz mieć wszystko w jednym miejscu razem z resztą aplikacji.

Jedna rzecz wymaga decyzji przed wdrożeniem, bo domyślne zachowanie bywa zaskoczeniem: ślady zawierają treść rozmów i trafiają na panel śledzenia u dostawcy modelu, a nie na Twój dysk. Przy danych wrażliwych masz trzy wyjścia: wyłączyć zapisywanie samych treści, wyłączyć śledzenie w całości zmienną środowiskową albo ustawieniem przebiegu, albo podpiąć własny procesor śladów i kierować je wyłącznie do własnej infrastruktury. Osobny przypadek to organizacje objęte u dostawcy zerową retencją danych, bo tam śledzenie nie jest dostępne w ogóle.

Od prototypu do produkcji

Agent działający na dziesięciu ręcznie sprawdzonych pytaniach a agent obsługujący ruch to dwie różne rzeczy. Kilka kroków oddziela jedno od drugiego.

Pierwszy to limity. Ustaw maksymalną liczbę kroków w jednym uruchomieniu i limit czasu. Bez tego pętla, w której agent wywołuje narzędzie, dostaje błąd i próbuje ponownie, zużyje budżet dnia w kwadrans.

Drugi to obsługa błędów narzędzi. Funkcja rzucająca wyjątek przerywa uruchomienie, choć zwykle lepszym zachowaniem jest zwrócenie modelowi komunikatu, z którym może coś zrobić. Zdanie „nie znaleziono zamówienia o tym numerze" pozwala agentowi dopytać klienta, a wyjątek kończy rozmowę błędem.

Trzeci to zestaw przypadków testowych. Zbierz trzydzieści prawdziwych rozmów, zaznacz oczekiwany wynik i uruchamiaj je po każdej zmianie instrukcji. To jedyny sposób, żeby zauważyć, że poprawka pomagająca jednemu przypadkowi psuje trzy inne.

Czwarty to koszt jednego przebiegu. Zsumuj tokeny z pola zużycia w wyniku dla dziesięciu realnych rozmów i pomnóż przez spodziewany wolumen. Ta liczba mówi więcej niż jakiekolwiek szacowanie, bo uwzględnia Twoje narzędzia i Twoje instrukcje.

Piąty to plan na sytuację, w której agent nie wie. Odpowiedź „nie mam tej informacji, przekazuję do konsultanta" jest lepsza niż wymyślona treść, ale model sam z siebie rzadko ją wybiera. Trzeba to napisać wprost w instrukcji i sprawdzić na przypadkach testowych.

Instrukcje, które faktycznie działają

Instrukcja agenta to nie opis stanowiska, tylko zestaw reguł decyzyjnych. Ta różnica przekłada się wprost na zachowanie.

Instrukcja mówiąca „jesteś pomocnym asystentem obsługi klienta" nie zmienia niczego, bo model i tak stara się być pomocny. Instrukcja mówiąca „przy pytaniu o status zamówienia zawsze wywołaj narzędzie, nigdy nie zgaduj na podstawie rozmowy" zmienia konkretne zachowanie w konkretnej sytuacji.

Druga zasada dotyczy granic. Napisz wprost, czego agent nie robi i co ma zrobić zamiast tego. Zdanie „nie obiecujesz terminów dostawy, podajesz wyłącznie datę z systemu" zamyka całą kategorię problemów.

Trzecia dotyczy długości. Instrukcja na trzy strony działa gorzej niż na pół strony, bo model gubi fragmenty ze środka. Jeśli reguł jest dużo, to zwykle znak, że jeden agent robi za dużo i warto go podzielić.

Kontra alternatywy

NarzędzieMocna stronaSłabośćKiedy wybrać
OpenAI Agents SDKMało pojęć, przekazywanie zadań, ślady bez konfiguracjiNastawienie na jednego dostawcęZespół ról obsługujących różne obszary
LangGraphPełna kontrola nad przepływem, trwały stan, zatrzymaniaWięcej pracy przy prostych przypadkachProces z rozgałęzieniami i decyzją człowieka
PydanticAITypowane wyjście, testy bez modeluMniej gotowych integracjiWynik trafiający wprost do kodu
CrewAICzytelny podział ról, szybki startMniej kontroli nad szczegółamiPrototyp zespołu agentów

Biblioteka obsługuje też inne modele niż domyślne, przez interfejs zgodny z formatem tego dostawcy. Warto jednak wiedzieć, że część funkcji jest przygotowana pod jeden ekosystem i przy modelach zewnętrznych bywa uboższa.

Praktyczna uwaga na koniec porównania: wybór biblioteki rzadko decyduje o powodzeniu. O jakości agenta przesądzają opisy narzędzi, granice w instrukcji i to, czy masz zestaw przypadków, na którym mierzysz zmiany. Te trzy rzeczy przenoszą się między bibliotekami niemal bez zmian, więc praca w nie włożona nie przepada przy ewentualnej migracji.

Typowe błędy

Pierwszy to opisy narzędzi pisane dla programisty. Model czyta ten sam tekst i potrzebuje zdania o tym, kiedy narzędzie wywołać, a nie opisu implementacji.

Drugi to jeden agent ze wszystkimi narzędziami. Przy dwudziestu funkcjach trafność wyboru spada, a instrukcja rozrasta się do rozmiaru, w którym model gubi jej fragmenty.

Trzeci to brak limitu liczby kroków. Agent, który przekazuje rozmowę w pętli albo wywołuje to samo narzędzie w kółko, zużyje tyle tokenów, ile mu pozwolisz.

Czwarty to poleganie na barierce jako mechanizmie bezpieczeństwa. Sprawdzenie modelem da się obejść, więc uprawnienia egzekwuj w kodzie, sprawdzając tożsamość wywołującego.

Piąty to przekazywanie identyfikatora użytkownika w argumentach narzędzia. Model może podać cudzy, więc tożsamość powinna pochodzić z kontekstu uruchomienia, nie ze schematu.

Szósty to brak zestawu testowego. Zmiana instrukcji, która subiektywnie poprawia jedną rozmowę, zwykle psuje inną, a bez kilkudziesięciu zapisanych przypadków nikt tego nie zauważy.

FAQ

Czym to różni się od Swarma?

Swarm był eksperymentem edukacyjnym bez wsparcia produkcyjnego. Ta biblioteka jest jego następcą przeznaczonym do użytku produkcyjnego, z dodanymi barierkami, sesjami i śledzeniem wywołań. Pojęcia zostały te same, więc migracja jest prosta.

Czy działa z modelami innymi niż OpenAI?

Tak, przez interfejs zgodny z formatem tego dostawcy, więc podłączysz między innymi modele lokalne uruchomione przez Ollamę. Część funkcji jest jednak przygotowana pod jeden ekosystem, więc przy modelach zewnętrznych sprawdź, co dokładnie działa.

OpenAI Agents SDK czy LangGraph?

Tę bibliotekę wybierzesz, gdy problem naturalnie dzieli się na role przekazujące sobie rozmowę i zależy Ci na szybkim starcie. LangGraph wybierzesz, gdy przepływ ma jawne etapy, rozgałęzienia i miejsca, w których proces zatrzymuje się na decyzję człowieka.

Czy jest wersja dla TypeScriptu?

Tak, z tym samym zestawem pojęć: narzędzia, przekazywanie zadań, barierki, sesje, śledzenie i zatrzymanie na decyzję człowieka. Zespół pracujący w Next.js może więc trzymać agentów w tym samym języku co resztę kodu.

Ile to kosztuje?

Sama biblioteka jest darmowa i otwarta. Płacisz za wywołania modelu, przy czym barierki i klasyfikatory to dodatkowe wywołania, zwykle na tańszym modelu. Warto policzyć koszt jednej pełnej rozmowy na dziesięciu prawdziwych przypadkach, zanim proces ruszy na stałe.

Dokumentacja stoi na stronie projektu, a wersja dla TypeScriptu w repozytorium na GitHubie.