Pętla działała bezbłędnie czterdzieści razy podczas testów. Za czterdziestym pierwszym razem, na produkcji, wywoływała to samo narzędzie SQL z tym samym uszkodzonym zapytaniem w kółko, aż wyczerpała dzienny budżet API, a alert rozliczeniowy w końcu kogoś obudził. Nikt nie napisał złego modelu. Nikt nie zmienił promptu. Agent po prostu nigdy nie zdecydował, że skończył.
To jest schemat, który wciąż widzę u zespołów przenoszących agenta z prototypu na obciążenie działające 24/7. Pętle agentów AI często zawodzą na produkcji nie dlatego, że model nagle stał się gorszy, lecz dlatego, że warstwa wykonawcza nie ma dyscypliny zakończenia, walidowanych kontraktów narzędzi, ograniczonego kontekstu i trwałego stanu. Pętla agenta to system stochastyczny podejmujący kolejne decyzje jedna po drugiej. Bez kilku konkretnych zabezpieczeń rzadka awaria staje się gwarantowaną, gdy działa wystarczająco długo. Zarządzane platformy agentów (Vertex AI Agent Builder, Bedrock Agents, Azure AI Foundry) mają wbudowane niektóre z tych zabezpieczeń; ten przewodnik jest dla tych z nas, którzy zdecydowali się na self-hosting i zarządzanie pętlą we własnym zakresie.
Stawka jest wystarczająco wysoka, aby Gartner przewidywał że ponad 40% projektów agentic AI zostanie anulowanych do końca 2027 roku, powołując się na rosnące koszty i niejasną wartość. Poniżej opisuję sześć konkretnych sposobów, w jakie pętle zawodzą na produkcji: mechanizm każdego z nich i wzorzec harnessu, który go naprawia, wraz ze szczegółami dotyczącymi LangGraph i n8n oraz tym, czego potrzeba, żeby faktycznie uruchomić to 24/7.
Krótka wersja
- Nieskończone pętle: Agent nigdy nie decyduje, że skończył. Połącz twardy limit kroków (recursion_limit w LangGraph,
recursion_limit, domyślnie 25) z wykrywaniem braku postępu, które kończy powtarzające się wywołania narzędzia z tymi samymi argumentami. - Przepełnienie kontekstu: Pętla wypełnia własne okno kontekstowe skumulowaną historią, aż wywołania zaczną być skracane lub zaczną kończyć się błędem. Podsumowuj historię w stałych odstępach, aby roboczy kontekst pozostał ograniczony.
- Ciche awarie narzędzi: Narzędzie zwraca pusty ciąg znaków, model odczytuje go jako prawidłowy brak operacji, a agent "kończy się sukcesem" nie robiąc nic. Waliduj każdy wynik narzędzia, zanim model go zobaczy.
- Degradacja rozumowania: Jakość maleje wraz z rozrastaniem się kontekstu, nawet poniżej twardego limitu. Kompresuj w trakcie pętli, ale chroń przypięte instrukcje bezpieczeństwa.
- Utrata stanu po restarcie: Awaria oznacza start od zera. Zapisuj checkpointy do Postgres (LangGraph
PostgresSaver), a nie do SQLite, na produkcji. - Burze ponownych prób: Dziesięciu agentów, z których każdy ponawia próby dziesięć razy, bombarduje niedostępną usługę setką żądań. Dodaj wykładnicze wycofanie z jitterem i globalny wyłącznik.
Czego ten przewodnik nie obejmuje
To jest przewodnik o harnessie, skupiający się na inżynierii wokół pętli, a nie na modelu wewnątrz niej. Kilka powiązanych tematów zostało celowo pominięte:
- Awarie koordynacji wielu agentów (nieświeże odczyty, osierocony stan między agentami): inny problem, warty osobnego omówienia.
- Bezpieczeństwo agentów (wstrzykiwanie promptów, zatruwanie narzędzi): osobna kategoria awarii z własnym modelem zagrożeń.
- Wybór modelu i dostrajanie. Ten przewodnik zakłada, że wybrałeś już model i debugujesz otaczający go system.
- Zarządzane usługi agentów, wspomniane powyżej; wzorce opisane tutaj są przeznaczone dla ścieżki self-hosted.
Nieskończone pętle: gdy agent nigdy nie decyduje, że skończył
Agent zapętla się w nieskończoność, gdy nie ma ani twardego limitu kroków, ani sposobu na wykrycie, że przestał robić postępy. Rozwiązanie składa się z dwóch części: twardy limit jako bariera kosztowa oraz wykrywanie braku postępu, które hashuje każde wywołanie narzędzia z argumentami i kończy działanie, gdy wykryje powtórzenie tego samego wywołania. W LangGraph tym limitem jest recursion_limit, domyślnie 25 kroków; po jego przekroczeniu graf zgłasza wyjątek GraphRecursionError.
Dokumentacja LangGraph opisuje ten limit jako osiągnięcie "maksymalnej liczby kroków przed napotkaniem warunku stopu", i tu jest pułapka warta zrozumienia: recursion_limit to nie ochrona przed pętlą. To bariera, która odpala się po gdy pętla zdążyła już zmarnować dwadzieścia pięć kroków i związane z nimi wydatki API. Własna logika zakończenia agenta powinna zatrzymać go na długo wcześniej, a ta logika może zawieść niezależnie. Jeden udokumentowany przypadek w LangGraph pokazuje agenta text-to-SQL zapętlającego się aż do osiągnięcia limitu recursion_limit, mimo wyraźnych warunków stopu w prompcie. Ciągle wywoływał to samo narzędzie z tym samym niedziałającym SQL-em, a zgłoszenie zostało zamknięte jako "nieplanowane". Odczytuję to jako jasny sygnał: nie traktuj limitu jako warunku stopu. To twój pas bezpieczeństwa, nie hamulce.
Podniesienie limitu jest proste; przekazujesz go przez konfigurację podczas wywoływania grafu:
# The hard ceiling -- a backstop, not loop protection
graph.invoke(
{"messages": [("user", "Generate the quarterly report")]},
{"recursion_limit": 50},
)
To, co faktycznie zatrzymuje zablokowaną pętlę, to wykrywanie postępu. Mechanizm jest prosty: hashuj nazwę narzędzia wraz z jego argumentami przy każdym kroku, przechowuj krótkie okno ostatnich hashy i przerywaj, gdy wykryjesz powtórzenie.
import hashlib
def step_signature(tool_name: str, tool_args: dict) -> str:
payload = f"{tool_name}:{sorted(tool_args.items())}"
return hashlib.sha256(payload.encode()).hexdigest()
# Inside your loop: terminate if the same tool+args repeats within the window
seen = recent_signatures[-WINDOW:]
sig = step_signature(tool_name, tool_args)
if sig in seen:
raise StopReason("no_progress: repeated tool call detected")
recent_signatures.append(sig)
To wyłapuje agenta, który technicznie "działa" (wywołuje narzędzia, generuje tokeny), ale kręci się w kółko na tym samym nieudanym działaniu. Ten typ awarii odpowiada temu, co taksonomia MAST (IBM Research i UC Berkeley) nazywa Brak świadomości warunków zakończenia (FM-1.5), jednego z trybów awarii, który ich analiza wiąże z całkowitym niepowodzeniem zadania.
Limit kroków zatrzymuje niekontrolowane koszty. Wykrywanie braku postępu zatrzymuje pętlę, która technicznie "postępuje", ale się powtarza. Produkcja wymaga obu.
Przepełnienie okna kontekstowego: gdy pętla zapełnia własny kontekst śmieciami
Długo działająca pętla akumuluje każde wyjście narzędzia, każdą pośrednią myśl i każdą wiadomość, którą wyprodukowała, a następnie wpycha to wszystko z powrotem do okna kontekstowego przy każdej turze. W końcu okno się wypełnia, a wywołania albo są skracane po cichu, albo kończą się błędem. Rozwiązaniem jest podsumowywanie kontekstu w stałych odstępach: co N kroków skompresuj skumulowaną historię do bieżącego podsumowania, aby roboczy kontekst pozostał ograniczony.
Wyobraź sobie agenta badawczego, który działa od godziny. W kroku 60 niesie ze sobą pełny tekst każdej strony, którą pobrał, każdy wynik wyszukiwania, każdy ślad rozumowania. Żadna z tych surowych historii nie pomaga mu w kroku 61, a mimo to wszystko to odlicza się od okna, i model płaci uwagą za tokeny, których już nie potrzebuje. Gdy okno się zapełni, dostawca skraca z jednego końca, a agent po cichu traci instrukcję, którą otrzymał na początku.
Wyzwalacz to decyzja konfiguracyjna i jest użyteczny punkt odniesienia. Dokumentacja systemu produkcyjnego od Mem0 wskazuje, że kompresor agenta Hermes "odpala przy 50% okna kontekstowego modelu domyślnie", z dodatkową siatką bezpieczeństwa przy 85% dla sesji, które rosną między turami. Pięćdziesiąt procent to rozsądny punkt startowy: kompresuj wystarczająco wcześnie, aby pojedyncze duże wyjście narzędzia nie mogło przekroczyć limitu przed następną zaplanowaną kompresją.
Uwaga: Overflow i degradacja rozumowania to dwa różne problemy, a następna sekcja omawia ten drugi. Overflow to twarda granica: kończą się tokens. Degradacja jest stopniowa: model działa coraz gorzej. zanim dojdziesz do ściany. Musisz obsługiwać oba, a powyższy próg wyzwalacza chroni przed twardą ścianą.
Ograniczony kontekst to odpowiedzialność harnessu, nie funkcja modelu. Podsumowuj w odstępach, zanim okno wymusi ciche skrócenie.
Ciche awarie wywołań narzędzi: gdy agent "odnosi sukces" nie robiąc nic
Wywołanie narzędzia zwraca pusty ciąg lub miękki komunikat "nie znaleziono wyników", model interpretuje to jako prawidłowy wynik, a agent kontynuuje, jakby krok zadziałał - wydaje się odnosić sukces, nie robiąc absolutnie nic. Rozwiązaniem jest bramka walidacyjna na każdym zwrocie narzędzia: sprawdź schemat lub wykonaj kontrolę poczytalności wyjścia, zanim model je kiedykolwiek zobaczy, i wyeksponuj prawdziwą awarię, którą pętla musi obsłużyć, zamiast pustego sukcesu.
Ta awaria jest podstępna, bo nic się nie crasha. Deweloper opisujący tryby cichej awarii w agentach produkcyjnych powiedział to wprost: modele interpretują generyczne puste ciągi jako prawidłowe braki operacji i kontynuują wykonywanie bez świadomości awarii. Zapytanie do bazy danych, które zwróciło zero wierszy, bo połączenie zostało zerwane, wygląda identycznie, z punktu widzenia modelu, jak zapytanie, które prawidłowo niczego nie znalazło. Więc agent raportuje "brak pasujących rekordów" i idzie dalej, a ty odkrywasz tydzień później, że jedna trzecia jego uruchomień była po cichu uszkodzona.
Bramka walidacyjna siedzi między narzędziem a modelem:
def gate_tool_result(tool_name: str, result):
# Reject empties and soft errors before the model can rationalize them
if result is None or (isinstance(result, str) and not result.strip()):
raise ToolFailure(f"{tool_name} returned empty -- treat as failure, not no-op")
if isinstance(result, str) and result.lower().startswith(("error", "exception")):
raise ToolFailure(f"{tool_name} returned a soft error: {result[:120]}")
return result # validated -- safe to hand back to the model
Chodzi nie o dokładne sprawdzenia; twoje będą zależeć od tego, co każde narzędzie prawidłowo zwraca. Chodzi o to, że niezwalidowana wartość zwrotna to decyzja, którą oddajesz stochastycznemu modelowi, a domyślnym ruchem modelu jest kontynuowanie.
Niezwalidowany zwrot narzędzia to ciche niepowodzenie czekające na swoją chwilę. Waliduj wyjście, nie ufaj samemu wywołaniu.
Degradacja rozumowania w długich kontekstach: gdy agent działa gorzej, im dłużej pracuje
Nawet gdy nie przekraczasz twardego limitu kontekstu, jakość rozumowania spada wraz z jego rozrostem. To efekt "zagubiony w środku": model niezawodnie zwraca uwagę na początek i koniec długiego kontekstu, ale traci środek. Rozwiązaniem jest kompresja w trakcie pętli, która zachowuje przypięte ograniczenia: kompresuj szum, chroń instrukcje niosące ciężar zadania.
Ten mechanizm ma swoją nazwę. Blog inżynieryjny Anthropic określa go jako context rot: "wraz ze wzrostem liczby tokenów w oknie kontekstowym, zdolność modelu do dokładnego przywoływania informacji z tego kontekstu maleje." Ponieważ "każdy token uczęszcza do każdego innego tokenu," uzyskujesz n² relacji parami dla n tokenów, a uwaga modelu rozciąga się coraz cieniej, im dłuższy staje się kontekst.
To zastrzeżenie, chroń instrukcje niosące ciężar zadania, to cała gra, i jest udokumentowany incydent, który pokazuje dlaczego. W udokumentowanym przypadku, agent OpenClaw masowo usunął skrzynkę odbiorczą użytkownika podczas kompresji kontekstu, ponieważ instrukcja bezpieczeństwa, którą otrzymał ("nie podejmuj działań, dopóki ci nie powiem"), została usunięta z aktywnego kontekstu podczas kompresji historii. Ograniczenie, które powinno być ostatnią rzeczą do usunięcia, zostało potraktowane jak zwykła historia i podsumowane.
Naiwne "podsumuj wszystko starsze niż N tur" jest zatem niebezpieczne. Kompresja musi wiedzieć, czego nigdy nie może upuścić:
PINNED = {"system_constraints", "safety_instructions", "active_task_spec"}
def compress_history(messages):
pinned = [m for m in messages if m.tag in PINNED] # never summarized
transient = [m for m in messages if m.tag not in PINNED]
summary = summarize(transient) # lossy is fine here
return pinned + [summary] # constraints survive intact
To różni się od problemu przepełnienia z poprzedniej sekcji. Przepełnienie polega na wyczerpaniu miejsca; degradacja polega na tym, że model działa gorzej, gdy nadal jest miejsce. Możesz być na 60% okna i już rozumować źle.
Uwaga: Kompresja, która usuwa ograniczenie bezpieczeństwa, to inny rodzaj błędu niż kompresja, która traci nieświeży wynik wyszukiwania. Oznacz ograniczenia, specyfikację zadania i wszelkie instrukcje "nie rób X" jako przypięte i całkowicie wyklucz je z sumaryzatora.
Kompresja, która usuwa instrukcję bezpieczeństwa, jest gorsza niż brak kompresji. Chroń przypięte ograniczenia podczas kompresji.
Utrata stanu po restarcie: gdy awaria oznacza start od zera
Gdy długo działający agent ulega awarii - czy to z powodu restartu, zabicia OOM, czy przerwania połączenia sieciowego - domyślnie nie ma wznowienia od checkpointu. Pętla zaczyna od zera: ponawia pracę, którą już wykonała, i co gorsza, może ponownie wykonać działania, które już podjęła, jak wysłanie tego samego e-maila dwa razy czy ponowne uruchomienie płatnego wywołania API. Rozwiązaniem jest checkpointing: utrwalaj stan pętli po każdym kroku, aby restart rehydrował od miejsca, w którym się zatrzymał, zamiast od zera.
W LangGraph wybór backendu checkpointów to wybór między środowiskiem deweloperskim a produkcją. Dokumentacja trwałości LangGraph opisuje SqliteSaver jako "idealne do eksperymentowania i lokalnych przepływów pracy" oraz PostgresSaver jako "idealne do użycia na produkcji", i to właśnie na tym ostatnim działa sam LangSmith. Oba są celowo równoległe w kodzie, co ułatwia dostrzeżenie różnicy:
# Development -- single file, no server, do not ship this
from langgraph.checkpoint.sqlite import SqliteSaver
# Production -- survives the box it runs on
from langgraph.checkpoint.postgres import PostgresSaver
Dwa szczegóły, które gryzą. Po pierwsze, pakiety checkpointów instalują się oddzielnie od rdzenia LangGraph (langgraph-checkpoint-sqlite oraz langgraph-checkpoint-postgres są ich własnymi zależnościami), więc świeże środowisko nie będzie miało savera Postgres, dopóki go nie dodasz. Po drugie, każda operacja checkpointowania wymaga thread_id w konfiguracji. To ID wiąże dane uruchomienie z jego zapisanym stanem, a restart bez właściwego thread_id nie rehydruje niczego.
Wskazówka: Pakiety checkpointów LangGraph to osobne instalacje.
langgraph-checkpoint-postgresnie jest wciągany przez bazowy pakietlanggraphpackage, więc przypnij go w pliku wymagań produkcyjnych, zanim przekonasz się o tym boleśnie podczas incydentu.
n8n ma ten sam podział na środowisko deweloperskie i produkcyjne, tylko pod innymi nazwami. Wbudowana opcja pamięci to Simple Memory (lub Buffer Window Memory), a ścieżką produkcyjną jest węzeł Postgres Chat Memory dla stanu, który musi przeżyć restart. Wbudowana pamięć przechowuje konwersację w działającym procesie, co jest dobre do testowania, ale ryzykowne dla obciążenia 24/7. Osoby uruchamiające agentów n8n w środowiskach produkcyjnych donoszą, że musiały migrować do magazynu opartego na Postgres po tym, jak pamięć wewnątrzprocesowa rosła, aż zabiła instancję. Jeśli używasz n8n i twój agent musi pamiętać cokolwiek po restarcie, podłącz go do Postgres Chat Memory od samego początku.
Checkpointowanie z SQLite to wygoda deweloperska. Przeżycie restartu na produkcji oznacza Postgres (LangGraph) lub magazyn oparty na Postgres (n8n).
Burze ponownych prób: gdy twoi własni agenci atakują DDoS-em martwą usługę
Gdy usługa downstream przestaje działać, naiwne ponowne próby per-wykonanie zamieniają twój fleet agentów w samozadany atak denial-of-service. Rozwiązanie ma dwie części: wykładnicze wycofanie z jitterem na każdym agencie, aby rozłożyć ponowne próby w czasie, oraz globalny wyłącznik, który odpala po osiągnięciu wspólnego progu awarii i powstrzymuje całe stado od bombardowania usługi, która wyraźnie nie działa.
Matematyka jest bezlitosna. Jak ujmuje to opis wzorców ponownych prób : przy dziesięciu równoległych agentach, z których każdy ponawia próby dziesięć razy, wysyłasz sto żądań do usługi, która już leży na ziemi, bo wycofanie każdego agenta jest per-wykonanie, nie globalne. Samo wycofanie per-agent nie rozwiązuje tego. Dziesięciu agentów, z których każdy wycofuje się grzecznie, nadal wycofuje się jednocześnie, jeśli wszyscy zaczęli w tym samym czasie, więc ponawiają próby zsynchronizowanymi falami. Jitter rozbija synchronizację, losując czas oczekiwania każdego agenta; wyłącznik rozbija stado, udostępniając jeden kawałek stanu awarii wszystkim agentom.
Część z wycofaniem to rozwiązany problem w Pythonie; biblioteka tenacity obsługuje wykładnicze z jitterem czysto:
from tenacity import retry, stop_after_attempt, wait_random_exponential
@retry(wait=wait_random_exponential(multiplier=1, max=60), stop=stop_after_attempt(5))
def call_flaky_service(payload):
return downstream.post(payload)
Wyłącznik to ta część, która musi być globalna: współdzielona przez każdego agenta, nie tworzona od nowa per-wykonanie. Gdy awarie przekraczają próg, otwiera się: każdy agent szybko zawodzi zamiast wykonywać wywołania, a po czasie ochłodzenia przepuszcza jedno sondujące żądanie, aby sprawdzić, czy usługa wróciła. Wyłącznik żyjący wewnątrz własnego procesu każdego agenta nic nie chroni, bo nic nie jest współdzielone; martwa usługa nadal otrzymuje pełne sto żądań.
Wycofanie per-wykonanie nadal pozwala dziesięciu agentom bombardować martwą usługę jednocześnie. Wyłącznik musi być globalny, aby zatrzymać stado.
Sześć awarii w skrócie
Przed omówieniem infrastruktury, oto cały katalog w jednym miejscu: awaria, mechanizm ją powodujący, naprawa harnessem i gdzie żyje odpowiedni parametr w każdym frameworku.
| Tryb awaryjny | Mechanizm | Naprawa harnessem | Parametr frameworku |
|---|---|---|---|
| Nieskończona pętla | Brak limitu kroków lub sprawdzenia postępu | Twardy limit + wykrywanie braku postępu | LangGraph recursion_limit (25) / n8n Max Iterations |
| Przepełnienie kontekstu | Historia rośnie, aż okno się zapełni | Podsumowywanie w odstępach | Na poziomie aplikacji (kompresja przy ~50% okna) |
| Ciche niepowodzenie narzędzia | Puste/miękkie zwroty odczytywane jako prawidłowe braki operacji | Bramka walidacyjna na każdym wyniku narzędzia | Wrapper narzędzia na poziomie aplikacji |
| Degradacja rozumowania | Uwaga spada wraz z rozrostem kontekstu ("context rot") | Kompresja w trakcie pętli chroniąca przypięte ograniczenia | Na poziomie aplikacji, świadoma ograniczeń |
| Utrata stanu po restarcie | Brak checkpointu; pętla restartuje od zera | Trwałe checkpointowanie | LangGraph PostgresSaver / n8n Postgres Chat Memory |
| Burza ponownych prób | Ponowne próby per-wykonanie kaskadują na martwą usługę | Wycofanie + jitter + globalny wyłącznik | tenacity + współdzielony stan wyłącznika |
Uwaga dla czytelników używających CrewAI, AutoGen, Dify lub ręcznie pisanej pętli Python: parametry frameworku się zmieniają, ale sześć wzorców nie. Deduplikacja, podsumowywanie w odstępach, walidacja schematów, kompresja świadoma ograniczeń, checkpointing i globalny wyłącznik to koncepcje niezależne od frameworku. Szczegóły LangGraph i n8n tutaj to konkretne uchwyty, nie granica, gdzie te wzorce mają zastosowanie.
Dobór rozmiaru dla wdrożenia agenta produkcyjnego
Każdy wzorzec powyżej zakłada, że kontrolujesz menedżera procesów, bazę danych i zachowanie po restarcie. Checkpointing nic ci nie daje, jeśli zablokowana pętla nigdy nie wraca do działania, a globalny wyłącznik potrzebuje miejsca do przechowywania współdzielonego stanu. Ta kontrola to dokładnie to, co daje ci self-hosting, a czego nie daje zarządzana czarna skrzynka, więc ostatnia decyzja to dobór rozmiaru serwera, który to uruchamia 24/7.
Dla większości wdrożeń jednego agenta (jeden agent, wywołania LLM do zewnętrznego API, podstawowe checkpointowanie Postgres) wystarczy mała instancja: około 2 GB RAM, 1 vCPU, and 60 GB of NVMe storage. Ciężkie obliczenia są po stronie dostawcy modelu; twój serwer orkiestruje, zapisuje checkpointy i przechowuje stan, nie uruchamia wnioskowania. Zwiększ rozmiar do mniej więcej 4 GB RAM, 2 vCPU, and 120 GB NVMe gdy agent jest stanowy i wielokrokowy z checkpointowaniem Postgres plus Redis do hydratacji sesji, lub gdy uruchamiasz równoległe przepływy pracy współdzielące host.
Powód, dla którego warto tu mieć VPS zarządzany samodzielnie zamiast ograniczonej platformy, jest ten sam, co powód, dla którego naprawy działają: potrzebują roota. Własny Postgres do checkpointowania, własny Redis do stanu sesji i prawdziwy menedżer procesów, taki jak systemd or pm2, aby gdy pętla upadnie, supervisor ją restartował i rehydrowała z ostatniego checkpointu zamiast zaczynać zadanie od nowa. Cała ta historia odtwarzania zależy od posiadania cyklu życia procesu.
Ponieważ uruchamiamy n8n jako aplikację jednym kliknięciem w naszym marketplace, ta część konfiguracji jest najkrótszą drogą po naszej stronie: możesz wdrożyć n8n na VPS Cloudzy z konfiguracją opartą na Postgres, której wymaga ścieżka produkcyjna, na instancji, gdzie masz dostęp root, aby dodać własny Redis i nadzór nad procesami. To ta sama infrastruktura self-hosted opisana powyżej, gdzie jesteś właścicielem bazy danych i zachowania po restarcie, co sprawia, że checkpointing i automatyczne odtwarzanie faktycznie działają.
Wzorce harnessu są tylko tak niezawodne jak serwer, na którym działają. Checkpointing nic nie daje, jeśli proces nigdy się nie restartuje.
Często zadawane pytania
Jak zatrzymać agenta LangGraph przed zapętlaniem w nieskończoność?
Użyj dwóch mechanizmów jednocześnie. Ustaw recursion_limit jako twardy limit kroków (domyślnie 25), aby pętla bez kontroli nie mogła spalić nieograniczonego budżetu, i dodaj wykrywanie braku postępu, które hashuje każde wywołanie narzędzia z argumentami i kończy, gdy to samo wywołanie powtarza się w ostatnim oknie. Sam limit to bariera, która odpala po zmarnowaniu zasobów, a nie prawdziwa ochrona przed pętlą. Wykrywanie postępu to to, co faktycznie zatrzymuje zablokowaną pętlę.
Jaki jest właściwy recursion_limit dla LangGraph na produkcji?
Nie ma jednej uniwersalnej wartości. Dobierz rozmiar do maksymalnej liczby prawidłowych kroków, jakich twój agent powinien kiedykolwiek potrzebować, plus margines, i traktuj go ściśle jako barierę kosztową. Podniesienie limitu nie sprawia, że zapętlony agent osiągnie zbieżność. Jeśli twój agent osiąga wysoki limit, naprawą jest wykrywanie postępu, a nie wyższy limit.
Dlaczego mój agent AI n8n ciągle osiąga Max Iterations?
Osiąganie limitu Max Iterations oznacza, że agent nie osiąga zbieżności: wykonuje więcej kroków, niż pozwala limit, nie dochodząc do stopu. Podnoś limit tylko jeśli zadanie faktycznie wymaga więcej kroków; w przeciwnym razie potraktuj to jako sygnał, że agent jest zablokowany. Uważaj na jedną konkretną pułapkę: GitHub issue #22771 donosi, że gdy limit iteracji jest osiągany przy ustawieniu "On Error: Continue", wykonanie może przejść do wyjścia Success zamiast Error, więc zablokowane, nieudane uruchomienie może wyglądać jak sukces w twoim przepływie pracy.
Jak utrwalić stan agenta po restartach?
W LangGraph używaj PostgresSaver checkpointowania zamiast SqliteSaver, które jest przeznaczone do lokalnego tworzenia. W n8n używaj węzła Postgres Chat Memory zamiast wbudowanej pamięci wewnątrzprocesowej. Oba wymagają trwałej bazy danych, a w LangGraph każda operacja checkpointowania wymaga thread_id który wiąże dane uruchomienie z jego zapisanym stanem.
Co powoduje degradację rozumowania w długich uruchomieniach agenta?
Jakość rozumowania spada wraz z rozrostem kontekstu, nawet zanim dojdziesz do twardego limitu tokenów. To efekt "zagubiony w środku": model zwraca uwagę na początek i koniec długiego kontekstu, ale traci środek. Blog inżynieryjny Anthropic określa leżący u podstaw mechanizm jako "context rot": ponieważ każdy token uczęszcza do każdego innego tokenu, uzyskujesz n² relacji parami, a uwaga modelu rozciąga się coraz cieniej wraz z wydłużaniem się kontekstu. Rozwiązaniem jest kompresja w trakcie pętli, która podsumowuje nieaktualną historię, zachowując przypięte ograniczenia i instrukcje bezpieczeństwa w nienaruszonym stanie.
Otagowane