Agent wyzwalany kontra agent długo żyjący

przez Łukasz | sie 24, 2026

Dwa poprzednie artykuły opisywały pętlę, która dostaje zadanie i ma je skończyć. Warunek zakończenia dotyczył całego agenta, budżet liczyliśmy na zadanie, a na wynik ktoś czekał.

Istnieje druga kategoria, w której żadne z tych założeń nie obowiązuje.

Dwa rytmy

Agent wyzwalany startuje od pytania albo zdarzenia zewnętrznego, wykonuje pracę i kończy. To model, który znasz z czatu i z większości wdrożeń. Ma początek, koniec i obserwatora.

Agent długo żyjący działa nieprzerwanie. Nie czeka na polecenie — budzi się w regularnych odstępach, sprawdza, czy jest coś do zrobienia, i albo działa, albo zasypia do następnego cyklu. Ten rytm nazywa się biciem serca.

Różnica wygląda na organizacyjną, ale jest architektoniczna: zmienia pięć rzeczy naraz.

Zmiana pierwsza: warunek zakończenia dotyczy cyklu

Cały poprzedni artykuł był o tym, kiedy pętla ma przestać. Tutaj pętla ma nie przestać — przestać ma pojedynczy cykl.

Limity kroków, budżetu i czasu nadal obowiązują, ale w skali jednego przebudzenia. Dochodzi natomiast problem, którego wcześniej nie było: cykl, w którym nie ma nic do zrobienia, musi umieć nic nie zrobić. Brzmi trywialnie, a jest częstą przyczyną wykolejenia — model zapytany „czy jest coś do zrobienia?” ma silną skłonność, by coś znaleźć.

Zmiana druga: budżet liczy się w czasie

Agent budzący się co pięć minut wykonuje niemal trzysta przebudzeń na dobę. Jeśli każde oznacza wywołanie modelu z promptem systemowym i definicjami narzędzi, płacisz trzysta razy dziennie za samo sprawdzenie, że nic się nie zmieniło.

Stąd wzorzec, który w tej architekturze jest obowiązkowy: tania bramka przed drogim modelem. Zwykły kod — bez żadnego modelu — sprawdza, czy w ogóle jest praca: czy przyszła nowa wiadomość, czy zmienił się rekord, czy minął termin. Model wchodzi do gry dopiero wtedy, gdy odpowiedź brzmi „tak”.

Przy typowym obciążeniu to różnica między rachunkiem stałym a rachunkiem proporcjonalnym do realnej pracy — zwykle o rząd wielkości.

Budżet warto przy tym ustawiać w oknie czasowym: limit na godzinę i na dobę, z zatrzymaniem po przekroczeniu. Agent bez takiego limitu potrafi w nocy zrobić coś kosztownego, o czym dowiesz się z faktury.

Zmiana trzecia: stan musi przetrwać restart

Agent wyzwalany trzyma cały stan w kontekście jednego przebiegu. Kiedy przebieg się kończy, nie ma czego tracić.

Agent długo żyjący jest procesem, a procesy padają: restart serwera, aktualizacja, wyjątek. Wszystko, czego nie zapisał poza kontekstem, znika.

Minimum, które musi być trwałe: co już zostało zrobione i na czym skończył. Bez pierwszego po restarcie wykona tę samą pracę ponownie — a jeśli ta praca miała skutki uboczne, skutki też się powtórzą.

Dlatego idempotencja przestaje tu być dobrą praktyką, a staje się warunkiem działania. Agent, który wysyła maile i nie prowadzi trwałego rejestru wysłanych, po każdym restarcie zacznie wysyłać je od nowa.

Zmiana czwarta: nikt nie patrzy

To najpoważniejsza różnica i najczęściej niedoceniana.

Przy agencie wyzwalanym potwierdzenie działa: użytkownik czeka na wynik, więc okno zgody pojawia się w naturalnym momencie. Przy agencie działającym w tle o trzeciej w nocy nie ma komu niczego zatwierdzić.

Modalne okno zgody przestaje więc być mechanizmem. Zamiast niego potrzebna jest kolejka do zatwierdzenia: agent przygotowuje operację, zapisuje ją jako oczekującą i zatrzymuje się. Człowiek zatwierdza asynchronicznie, gdy zajrzy. Reguły z artykułu o oknie zgody obowiązują nadal — kolejka musi pokazywać, co naprawdę się wydarzy, a nie streszczenie.

Konsekwencja jest też diagnostyczna: agent, który poszedł w złą stronę, wykona wiele cykli, zanim ktokolwiek to zauważy. Dziennik zdarzeń i alert przy przekroczeniu progów nie są tu dodatkiem, tylko warunkiem odpowiedzialnego uruchomienia.

Zmiana piąta: szersza powierzchnia ataku

Agent wyzwalany przetwarza treść, o którą poprosił użytkownik. Agent nasłuchujący przetwarza treść, której nikt nie zamawiał — przychodzące wiadomości, zdarzenia z zewnętrznych systemów, pliki pojawiające się w katalogu.

Każda z nich jest potencjalnym nośnikiem instrukcji skierowanej do modelu, co opisywaliśmy w artykule o zatrutym kontekście. Różnica polega na tym, że tutaj atakujący nie musi przekonać użytkownika, żeby coś kliknął — wystarczy, że wyśle wiadomość.

Ryzyko jest na tyle realne, że w marcu 2026 chińskie władze zakazały uruchamiania jednego z popularnych agentów tej klasy na komputerach służbowych w spółkach państwowych i urzędach.

Stąd wniosek sprzeczny z intuicją: uprawnienia agenta długo żyjącego powinny być węższe niż wyzwalanego, nie szersze. Pokusa idzie w drugą stronę, bo skoro działa sam, wygodnie jest dać mu więcej. Właśnie dlatego, że działa sam, trzeba dać mu mniej.

Kiedy to ma sens

Monitorowanie, przetwarzanie napływających zdarzeń, zadania cykliczne, obsługa kanałów asynchronicznych. Wszędzie tam, gdzie sensowne działanie polega na reagowaniu, a nie na odpowiadaniu.

Kiedy nie ma sensu: gdy zadanie da się wyzwolić zdarzeniem. Webhook uruchamiający agenta wyzwalanego jest prostszy, tańszy i łatwiejszy do nadzorowania niż proces sprawdzający co pięć minut, czy coś się wydarzyło. Bicie serca ma sens tam, gdzie nie ma czego nasłuchiwać — a nie jako domyślna architektura.

Jak to sprawdzić u siebie

Szkielet z tanią bramką, trwałym stanem i budżetem godzinowym. Model jest wywoływany wyłącznie wtedy, gdy jest praca.

python
import json, os, time
from openai import OpenAI

client = OpenAI()
STAN = "stan_agenta.json"
INTERWAL, LIMIT_TOKENOW_H = 60, 50000

def wczytaj():
    if os.path.exists(STAN):
        return json.load(open(STAN))
    return {"obsluzone": [], "tokeny_h": 0, "okno": time.time()}

def zapisz(s):
    json.dump(s, open(STAN, "w"))

def nowe_zdarzenia(obsluzone):
    # tania bramka — zwykły kod, zero modelu
    wszystkie = [{"id": "z-1", "tresc": "Klient pyta o status zamówienia 4471"}]
    return [z for z in wszystkie if z["id"] not in obsluzone]

stan = wczytaj()
while True:
    if time.time() - stan["okno"] > 3600:          # reset okna budżetu
        stan["tokeny_h"], stan["okno"] = 0, time.time()

    zdarzenia = nowe_zdarzenia(stan["obsluzone"])

    if not zdarzenia:
        print("cykl bez pracy — model nie wywołany")
    elif stan["tokeny_h"] >= LIMIT_TOKENOW_H:
        print("limit godzinowy wyczerpany — wstrzymanie")
    else:
        for z in zdarzenia:
            odp = client.chat.completions.create(
                model="gpt-4o-mini",
                messages=[{"role": "user",
                           "content": f"Zaproponuj odpowiedź: {z['tresc']}"}],
                max_tokens=200,
            )
            stan["tokeny_h"] += odp.usage.total_tokens
            stan["obsluzone"].append(z["id"])        # trwały ślad, przed skutkiem
            print("DO ZATWIERDZENIA:", odp.choices[0].message.content[:80])

    zapisz(stan)
    time.sleep(INTERWAL)

Zwróć uwagę na trzy miejsca. Bramka nowe_zdarzenia jest zwykłym kodem — cykl bez pracy nie kosztuje nic. Identyfikator trafia do obsluzone i jest zapisywany, zanim cokolwiek zostanie wysłane, więc restart nie powoduje powtórzenia. Odpowiedź nie jest wysyłana, tylko wypisana jako oczekująca na zatwierdzenie.

Ćwiczenie: usuń bramkę i wywołuj model w każdym cyklu, niezależnie od tego, czy są zdarzenia. Po godzinie porównaj zużyte tokeny. Przy interwale minutowym różnica jest natychmiast widoczna, a w wersji produkcyjnej, gdzie prompt systemowy ma tysiąc tokenów, staje się główną pozycją rachunku.

Drugie ćwiczenie: przerwij proces w połowie i uruchom ponownie. Sprawdź, czy zdarzenie zostało obsłużone dwa razy — a potem przenieś zapis obsluzone na po wysyłce i powtórz. Zobaczysz różnicę między agentem idempotentnym a takim, który przy każdym restarcie zaczyna od nowa.

Co dalej

Wiemy już, kiedy pętla ma się zatrzymać i w jakim rytmie działać. Pora zająć się tym, co model w niej widzi — bo katalog narzędzi to nie interfejs programistyczny, tylko tekst, który konkuruje o uwagę modelu przy każdym obrocie.

O tym jest artykuł czwarty: Anatomia definicji narzędzia.

Stan poza kontekstem

Stan poza kontekstem

W pierwszym artykule padło zdanie, że agent nie kontynuuje pracy — zaczyna od zera z coraz dłuższą notatką. Notatką jest kontekst, a jego rosnąca długość to główny składnik rachunku. Pytanie, które z tego wynika, brzmi: co właściwie musi być w tej notatce, a co...

Kiedy narzędzie zawodzi

Kiedy narzędzie zawodzi

Wszystkie dotychczasowe przykłady zakładały, że narzędzie działa. W produkcji to założenie jest fałszywe częściej, niż się zakłada przy projektowaniu: API mają awarie, limity, przeciążenia i czasy oczekiwania. To, co pętla zrobi w takim momencie — i co powie o tym...

Ile narzędzi to za dużo

Ile narzędzi to za dużo

Dodanie narzędzia wygląda na czynność addytywną. Agent umie o jedną rzecz więcej, reszta zostaje jak była. Nie zostaje. Każde kolejne narzędzie pogarsza wybór wszystkich pozostałych i podnosi cenę każdego obrotu pętli — a oba efekty są niewidoczne, dopóki ktoś ich nie...

Anatomia definicji narzędzia

Anatomia definicji narzędzia

Kiedy agent wybiera niewłaściwe narzędzie, pierwszym odruchem jest poprawianie promptu systemowego. Drugim — zmiana modelu na mocniejszy. Zwykle problem leży gdzie indziej i naprawia się go bez dotykania jednego i drugiego. Model nie widzi kodu To warto powiedzieć...