LangGraph wyjaśnione: grafy, stan, routowanie i wzorce produkcyjne
Jak modele LangGraph przedstawiają agenty jako cykliczne grafy z typowanym stanem, reduktorami, punktami kontrolnymi, routowaniem, narzędziami oraz pętlami ReAct, wraz z wzorcami do użycia w produkcji.
Źródła: Mastering LangGraph: The Complete Technical Guide to Building Production-Grade Agentic AI Systems
Pierwsza fala aplikacji opartych na LLM polegała na prostym wymianie: wysyłanie promptu i otrzymywanie odpowiedzi. Agenci to inny rodzaj programów – rozumują krok po kroku, decydują, co robić na podstawie tego, czego nauczyli się do tej pory, i podejmują działania w rzeczywistym świecie. Wymaga to infrastruktury zbudowanej wokół pętli, gałęzi i pamięci, a nie prostej linii od wejścia do wyjścia.
LangGraph to jeden z takich frameworków. Został zaprojektowany dla aplikacji z stanem, w których jeden lub więcej aktorów sterowanych przez LLM pracuje razem. Zamiast liniowej łańcuchowej struktury umożliwia opisanie grafu skierowanego, który może zawierać cykle, kierować przepływem danych warunkowo, przechowywać trwały stan oraz koordynować wywołania narzędzi. To nie są tylko udogodnienia – agent, który musi radzić sobie z niepewnością, odbudowywać się po błędach i udoskonalać swoją pracę w trakcie kilku prób, potrzebuje ich wszystkich.
W dalszej części omówiono, jak framework funkcjonuje wewnętrznie, dlaczego jego wybory projektowe są istotne oraz w jakich sytuacjach stosuje się poszczególne wzorce. Po przeczytaniu powinieneś być w stanie podejmować decyzje architektoniczne z pewnością siebie, naprawiać dziwne zachowania agentów oraz dostosowywać framework do własnych potrzeb.
Grafy jako podstawowe elementy budulcowe
Starsze narzędzia do orkiestracji modelują przepływ pracy jako prosty łańcuch lub co najwyżej graf skierowany acykliczny. To rozwiązanie sprawdza się przy zadaaniach przewidywalnych, ale zawodzi, gdy agent musi iterować, robić zapasy lub na bieżąco wybrać inną ścieżkę. LangGraph wychodzi od przeciwnej założenia i traktuje graf skierowany z cyklami jako swoją podstawową jednostkę.
Dlaczego łańcuch nie wystarcza
Różnica między łańcuchami a grafami jest praktyczna, a nie tylko estetyczna. łańcuch zakłada, że znasz dokładny porządek działań podczas pisania kodu. Graf zaś przyjmuje, że ścieżka w systemie zależy od stanu w czasie wykonywania, wyników pośrednich oraz warunków, których nikt nie może przewidzieć.
Pomyśl o agencie badającym firmę. Zaczyna od danych finansowych. To, czy następnie pójdzie po wiadomości, pobra raporty analityków lub przeczyta dokumenty konkurentów, zależy od tego, co ujawniły dane finansowe. Takie warunkowe, powtarzalne zachowanie wymaga zarówno pętli, jak i gałęzi, a łańcuch nie może wyrazić żadnego z nich.
Zwykły wzorzec agenta polega na pętli: rozważanie, co należy zrobić, podjęcie działań, obserwacja wyniku i powtarzanie tego procesu aż do osiągnięcia celu. W przypadku narzędzi opartych na łańcuchach mamy do wyboru dwie niekorzystne opcje – możemy rozwinąć pętlę na określoną liczbę kroków, co niszczy elastyczność, albo możemy sami napisać logikę sterowania poza ramami frameworka, co kosztuje nas możliwość kompozycji elementów. W LangGraph samej pętli traktuje się jako koncepcję pierwszej klasy, wyrażoną jako graf cykliczny z warunkowymi krawędziami.
Węzły
Węzeł to pojedynczy, dyskretny krok obliczeń. Otrzymuje aktualny stan, wykonuje jakieś działanie i zwraca aktualizacje. Tym działaniem może być wywołanie modelu językowego, które podejmuje decyzję, wywołanie narzędzia łączącego się z zewnętrznym systemem, transformacja danych lub jakaś logika routingu.
Węzły to zwykłe funkcje w Pythonie o określonej strukturze: wejściem jest aktualny stan, a wyjściem słownik z aktualizacjami. Ta funkcjonalna interfejs sprawia, że są one łatwe do łączenia i testowania. Węzeł nigdy nie edytuje stanu na miejscu – zgłasza zmiany, które chce wprowadzić, a LangGraph łączy je zgodnie z zasadami określonymi przez użytkownika.
Węzły mogą być tak proste jak pojedyncze wezwanie modelu LLM, a także tak złożone jak logika wieloetapowa. Niektóre wywołują całe inne grafy, co umożliwia tworzenie hierarchicznych agentów. Inne działają asynchronicznie lub wykorzystują logikę ponawiania prób z eksponencjalnym opóźnieniem. Framework nie przejmuje się tym, jak skomplikowany jest węzeł wewnętrznie.
Krawędzie
Krawędzie decydują, dokąd przejdzie kontrola, i istnieją dwa rodzaje o zupełnie różnej semantyce.
- Krawędzie statyczne są deterministyczne. Gdy węzeł A kończy swoją pracę, kontrola zawsze przechodzi do węzła B. Zachowują się jak zwykłe wywołania funkcji i nadają się do sekwencji znanych z góry. Po zainicjowaniu zadania badawczego zawsze następuje na przykład zbieranie danych.
- Krawędzie warunkowe kierują ruch dynamicznie w zależności od stanu. Gdy zbieranie danych się zakończy, może być konieczne podjęcie decyzji, czy ma się wystarczająco dużo danych, aby rozpocząć analizę, czy też należy ponownie spróbować nieudanych wywołań API. Decyzja ta nie może być podjęta w czasie projektowania, więc funkcja routingu dokonuje jej w czasie wykonywania.
Funkcja routingu sprawdza aktualny stan i zwraca ciąg znaków określający ścieżkę do przejścia. Framework przechowuje mapę od tych ciągów znaków do węzłów docelowych. W rezultacie powstaje sposób na budowanie drzew decyzyjnych, logiki ponawiania prób, obsługi błędów oraz adaptacyjnych procesów, przy jednoczesnym zachowaniu jasności i możliwości testowania routingu.
Stan jako pamięć współdzielona
Zarządzanie stanem to element, który sprawia, że projekt LangGraph staje się szczególnie interesujący. Obiekt stanu to struktura współdzielona, która przemieszcza się po grafie. Każdy węzeł odczytuje bieżący stan, a wszystkie zaktualizowane wartości są łączone przed uruchomieniem następnego węzła. Dlatego każdy krok opiera się na tym, czego nauczyły się poprzednie kroki.
Stan definiuje się za pomocą słowników typowanych lub modeli Pydantic, co zapewnia bezpieczeństwo typów oraz jasną umowę pomiędzy węzłami. Schemat określa, jakie pola istnieją, jakie mają typy oraz w jaki sposób łączone są aktualizacje. Ten ostatni aspekt łatwo przeoczyć, ale ma ogromne znaczenie.
Gdy węzeł zwraca aktualizację, LangGraph musi zdecydować, jak ją połączyć z tym, co już tam jest. W przypadku ciągu znaków lub liczby zastąpienie starej wartości jest oczywiste. W przypadku listy lub słownika tak nie jest. Czy zwróconą listę należy dodać na końcu, zastąpić staryą czy połączyć element po elemencie? Na to odpowiadają reduktory.
Reduktory
Reduktor to funkcja, która określa, w jaki sposób aktualizacja łączy się ze istniejącym stanem. Reduktory przekształcają stan LangGraph z zwykłego kontenera w coś, co potrafi obsługiwać wzorce akumulacji.
Domyślnie nowa wartość po prostu zastępuje staryą. To w porządku dla większości pól, ale nieprawidłowe w przypadku danych, które się gromadzą. Wyobraź sobie listę błędów, która zbiera problemy podczas działania. Nie chcesz, aby każdy element wymazywał poprzednie wpisy – chcesz, aby nowe błędy dodawano obok starych. Reduktor add_messages realizuje tę koncepcję, a ten wzorzec można zastosować również poza przypadkiem wiadomości.
Możesz napisać własny reduktor dla dowolnego pola. Jego wejściami są wartość już obecna w stanie oraz ta nowa, a wyjściem to, co pole powinno zawierać później. W przypadku błędów łączyłby listy, w przypadku słowników mógłby łączyć zagłębione struktury, a w przypadku liczników mógłby dodawać liczby.
Reduktorzy są przypisywani za pomocą wskaźników typu Annotated w Pythonie, dzięki czemu schemat pozostaje deklaratywny:
from typing import TypedDict, Annotated
def append_lists(existing: list, new: list) -> list:
return existing + new
class AgentState(TypedDict):
query: str # Simple replacement
results: Annotated[list, append_lists] # Custom accumulation
iteration: int # Simple replacement
To sprawia, że zachowanie łączenia pozostaje jawne i skoncentrowane, zamiast być rozproszone pomiędzy poszczególnymi węzłami.
Tworzenie punktów kontrolnych
Agenty produkcyjne często działają przez długi czas, wykonują kosztowne wywołania API lub obsługują operacje, które nie mogą zostać utracone z powodu tymczasowego awarii. Mechanizmem, który to rozwiązuje, jest tworzenie punktów kontrolnych. Gdy jest ono włączone, LangGraph zapisuje pełny stan po zakończeniu pracy każdego węzła. Jeśli proces się zatrzyma lub zabraknie pamięci, wykonywanie może zostać wznowione od ostatniego punktu kontrolnego, zamiast zaczynać od nowa. Krucha sekwencyjna skrypcja staje się przepływem pracy, który można wznowić.
Punkty kontrolne umożliwiają również projektowanie z udziałem człowieka. Wykonywanie może zostać wstrzymane w wybranym momencie, aby osoba mogła to przejrzeć lub dostarczyć informacji, a następnie kontynuowane po jej odpowiedzi. Ponieważ punkt kontrolny przechowuje dokładny stan w momencie wstrzymania, nie ma znaczenia, ile dni upłynie pomiędzy nimi.
Pamięć przechowawcza za nim jest wymienna. Punkty kontrolne w pamięci operacyjnej nadają się do rozwoju, SQLite zapewnia lokalną trwałość danych, a Redis pasuje do systemów rozproszonych. Graf pozostaje niezmieniony, zmienia się jedynie implementacja punktów kontrolnych.
Łączenie warunkowe
Łączenie jest momentem, w którym zachowanie staje się naprawdę dynamiczne. Wybór następnego kroku w czasie wykonywania programu na podstawie zgromadzonego stanu to to, co odróżnia sztywną automatyzację od agenta adaptacyjnego.
Funkcje łączenia i mapowanie krawędzi
Funkcja routingu to mała funkcja w Pythonie, która bierze pod uwagę stan i zwraca ciąg znaków. Gdy wykonywanie kodu dochodzi do warunkowego rozgałęzienia, LangGraph wywołuje tę funkcję, pobiera uzyskany ciąg znaków, znajduje odpowiadający węzeł w tabeli mapowania i przekazuje kontrolę nad nim. Ponieważ routowanie odbywa się poprzez ciągi znaków, a nie bezpośrednie odniesienia do węzłów, można edytować tabelę mapowania bez ingerencji w funkcję lub zastąpić ją inną funkcją routingu bez zmiany struktury grafu.
Typowe pytania związane z routowaniem obejmują sprawdzenie, czy istnieje wystarczająco dużo danych, aby kontynuować, czy operacja zakończyła się sukcesem lub należy ją ponowić, czy osiągnięto limit prób oraz czy poziom pewności co do analizy jest wystarczająco wysoki, aby podjąć działanie. Funkcja może przeglądać cały stan, dzięki czemu może porównywać różne pola, wykonywać obliczenia, sprawdzać warunki zewnętrzne lub kodować reguły biznesowe. Jedynym wymogiem jest to, aby była deterministyczna i czysta, dając tę samą odpowiedź dla tego samego stanu.
Unikanie nieskończonych cykli
Cykły umożliwiają skuteczną iterację, ale jednocześnie otwierają drogę do pętli nieskończonych. Agent uwięziony w próbach ponawiania może nieustannie zużywać zasoby, a LangGraph oferuje kilka sposobów na zapobieganie temu.
Najprostszym rozwiązaniem jest licznik w stanie. Funkcja routingu porównuje go z maksymalną wartością i przekazuje kontrolę do węzła zakończenia, gdy zostanie przekroczona ta granica. Prawie każdy agent produkcyjny wykorzystuje ten wzorzec. Bardziej zaawansowane opcje obejmują wykrywanie zbieżności, które zatrzymuje się, gdy zmiana pomiędzy iteracjami spada poniżej określonego progu, oraz zakończenie oparte na czasie oczekiwania, w którym routing bierze pod uwagę upływ czasu.
Wniosek jest taki, że zapobieganie pętlom to zadanie routingu, a nie ograniczenie ram roboczych. LangGraph dostarcza elementy niezbędne do stworzenia mechanizmów ochronnych dostosowanych do Twojego przypadku, zamiast narzucania ogólnych zasad.
Narzędzia: od języka do działania
Agenci stają się naprawdę przydatne, gdy model językowy może łączyć się z zewnętrznymi systemami. Narzędzia umożliwiają przekształcenie zrozumienia języka w rzeczywiste działania.
Wzorzec wykonywania
W LangGraph narzędzie to węzeł, który wykonywać coś poza procesem. Może ono wywołać API, zapytać bazę danych, uruchomić kod lub przeszukać internet. Bierze parametry ze stanu, wykonuje operację i zwraca wyniki jako aktualizacje stanu.
Ten schemat staje się potężny, gdy łączy się z oceną LLM. Węzeł LLM odczytuje stan i decyduje, jakie narzędzie wywołać. Funkcja routingu przekazuje kontrolę do odpowiedniego węzła narzędzia. Narzędzie jest uruchamiane i zapisuje swój wynik w stanie. Kontrola wraca do LLM, które interpretuje wynik i wybiera następny krok. Proces ten trwa, aż zostanie osiągnięty cel.
Współczesne modele obsługują wywoływanie funkcji, co oznacza, że wytwarzają ustrukturyzowaną prośbę z nazwą narzędzia i jego parametrami. Węzeł LLM analizuje taką prośbę w odpowiedzi modelu i zapisuje wybrane narzędzie w stanie. Funkcja routingu odczytuje tę decyzję i kieruje przepływ do odpowiedniego węzła narzędzia.
Radzenie sobie z błędami narzędzi
Zewnętrzne systemy zawodzą, wygasają, zwracają nieprawidłowe dane i podważają założenia. Węzły narzędzi muszą być na to przygotowane.
- Złap i zgłoś. Złap wyjątki, zapisz je i zwróć szczegóły błędu w stanie, zamiast pozwolić im sparaliżować agenta. Wtedy LLM może zobaczyć, co poszło nie tak, i spróbować ponownie z innymi parametrami lub zastosować inne podejście.
- Wygaszanie czasowe. Otocz operacje tak, aby wywoływały błąd po maksymalnym czasie trwania. Jeden wolny API nie powinien zatrzymywać całego agenta.
- Walidacja. Zinterpretuj odpowiedzi i sprawdź je pod kątem schematów. Nieprawidłowe dane powinny uruchomić ścieżkę błędu, a nie zostać zapisane w miejscu, gdzie mogą uszkodzić kolejne węzły.
- Rozwiązania awaryjne. Gdy główne źródło danych zawodzi, należy spróbować innego. Narzędzie może kolejno wywoływać kilka API, korzystać z danych w pamięci podręcznej lub zwracać częściowe wyniki wraz z jasnym komentarzem na temat brakujących informacji.
Pętla ReAct
ReAct, skrót od reasoning and acting, to podstawowa architektura agenta, którą LangGraph potrafi naturalnie przedstawić, a jej analiza pokazuje, jak pozostałe koncepcje ze sobą współgrają.
Jak działa pętla
Wszystko zaczyna się od węzła rozumowania. Model językowy analizuje aktualny stan i decyduje, co robić dalej: wywołać narzędzie, poprosić o dodatkowe informacje, udzielić ostatecznej odpowiedzi lub poprosić o interwencję człowieka. To tutaj liczą się umiejętności modelu, ponieważ może on ocenić złożony kontekst i podjąć precyzyjną decyzję.
Jeśli system zdecyduje się na działanie, kontrola przechodzi do węzła akcji, który wykonuje wybraną operację – czy to wywołanie API, obliczenie, czy zapytanie do bazy danych. Węzeł akcji pozostaje deterministyczny i precyzyjny, realizując żądanie i zwracając wyniki.
Następnie pojawia się węzeł obserwacji, który dodaje wyniki do stanu systemu i przygotowuje je dla LLM. Może on sformatować dane, usunąć niepotrzebne informacje lub obliczyć wskaźniki pomocne w łatwiejszej interpretacji wyników. Następnie pętla wraca do procesu rozumowania przy użyciu uzupełnionego stanu. LLM analizuje to, co się wydarzyło, i wybiera kolejny krok, kontynuując działanie aż będzie miał wystarczająco dużo informacji, by zakończyć proces.
Wiedza o tym, kiedy przestać
Decyzja o zakończeniu jest kluczową częścią pętli, a w praktyce występuje kilka typowych wzorców.
- Cel osiągnięty. Najprostszy przypadek: model LLM stwierdza, że zadanie zostało wykonane, i podaje ostateczną odpowiedź. Funkcja routingu to wykrywa i przechodzi do węzła zakończenia.
- Limit iteracji. Po osiągnięciu maksymalnej liczby cykli rozumowania i działania pętla się kończy, niezależnie od tego, czy cel został osiągnięty, więc agent zawsze w końcu się zatrzymuje.
- Progi pewności. Jeśli model osiąga wystarczającą pewność, na przykład 95%, może przerwać pracę wcześniej, zamiast zbierać informacje, które przynoszą coraz mniejsze korzyści.
- Błędy krytyczne. Gdy krytyczne operacje ciągle zawodzą lub agent napotyka sytuację, której nie może sobie poradzić, powinien zakończyć pracę z raportem błędu, zamiast kontynuować bez sensu.
Kilka agentów pracujących razem
Część zadań lepiej pasuje do zespołu specjalistycznych agentów niż do jednego monolitycznego agenta. Grafy ułatwiają zrozumienie kilku wzorców współpracy.
Hierarchia
W projekcie hierarchicznym planista na wyższym poziomie dzieli pracę i deleguje ją specjalistycznym agentom. On utrzymuje ogólny cel i koordynuje działania, ale nie wykonuje szczegółowej pracy. Pod względem implementacji niektóre węzły wywołują inne, skompilowane grafy. Węzeł planowania może przeanalizować skomplikowane zadanie, rozłożyć je na części i uruchomić odpowiedni graf dla każdej z nich. Wyniki wracają do planisty, który łączy je w ostateczny rezultat.
Główną zaletą jest separacja zadań. Każdego specjalistę można tworzyć, testować i dostosowywać oddzielnie, a planista musi znać tylko sposób ich koordynacji, a nie sposób ich działania.
Rówieśnicy
Agenci mogą również współpracować na równych zasadach, każdy wnosząc swój wkład merytoryczny. Zespół agentów oprogramowania może składać się z oddzielnych agentów odpowiedzialnych za architekturę, implementację, testowanie i dokumentację, wszyscy komunikujący się za pośrednictwem wspólnego bufora wiadomości. Buduje się to przy użyciu wspólnego stanu, który każdy agent może czytać i edytować. Funkcja routingu decyduje, kto będzie działał dalej, biorąc pod uwagę obecny stan oraz wymagane umiejętności. Każdy agent zapisuje swój wkład, oznacza go metadanymi dotyczącymi tematu, który poruszył, i przekazuje kontrolę dalej, a router wybiera następnego odpowiedniego agenta.
W takich strukturach współpracy pojawiają się różnorodne punkty widzenia, co umożliwia agentom wykrywanie błędów u siebie nawzajem, a jeden z nich może zauważyć błąd w rozumowaniu drugiego.
Dyskusja i konsensus
W przypadku ważnych decyzji kilku agentów może niezależnie rozwiązać problem, a następnie negocjować w celu osiągnięcia porozumienia. Metoda ta czerpie z koncepcji sztucznej inteligencji konstytucyjnej i traktuje niezgody jako sygnał jakościowy. Trzy agenty analizują sytuację, a każdy z nich proponuje rozwiązanie. Moderator prowadzi debatę na zmianę, podczas której każdy agent przedstawia swoje uzasadnienie i krytykuje pozostałych, musząc jednocześnie odpowiedzieć na konkretne zarzuty. Po kilku rundach etap konsensusu łączy wyniki dyskusji w jedną decyzję, ewentualnie przydając większą wagę najprzekonująwszym argumentom.
Taki podejście ujawnia halucynacje i błędy w rozumowaniu, które mogłyby umknąć uwadze pojedynczego agenta, ale zostają zauważone, gdy kilka agentów patrzy na problem z różnych perspektyw.
Pobieranie informacji wewnątrz agentów
Metoda generacji wzbogaconej o pobieranie informacji umożliwia agentom dostęp do dużych baz wiedzy oraz materiałów specjalistycznych, a grafy sprawiają, że jest to rozwiązanie szczególnie odpowiednie.
Pobieranie na żądanie
Klasyczny RAG pobiera informacje raz na początku zadania. W agentic RAG pobieranie informacji staje się narzędziem, którego agent korzysta za każdym razem, gdy zauważy brak danych. Agent zaczyna rozumowanie od swojej podstawowej wiedzy. Gdy napotka pytanie, na które nie potrafi odpowiedzieć, lub potrzebuje dodatkowego kontekstu, tworzy zapytanie do pobrania informacji, używa tego narzędzia i kontynuuje pracę z nowymi danymi dostępnymi w stanie.
To rozwiązanie jest lepsze od wcześniejszego pobierania wszystkich danych z dwóch powodów. Jest tańsze, ponieważ agent pobiera tylko to, czego potrzebuje. Jest też dokładniejsze, ponieważ zapytania są kształtowane na podstawie tego, co agent obecnie rozumie.
Zapytania kierowane stanem
Prawdziwa korzyść pojawia się wtedy, gdy zapytania odzwierciedlają wszystko, co zostało dotychczas zebrane, a nie tylko pierwotne pytanie. Weźmy na przykład dochodzenie w firmie – może ono rozpocząć się od zapytania o ogólny przegląd sytuacji. Wynik wskazuje na niedawne przejęcie, co skłania do złożenia celowanego zapytania dotyczącego tej transakcji. To z kolei ujawnia kwestie regulacyjne, które prowokują zapytanie o odpowiednie zasady. Każde poszukiwanie opiera się na poprzednim, dzięki czemu uzyskujemy skoncentrowane dochodzenie zamiast chaotycznego zbioru informacji.
Wielokrotne źródła
Agenci często korzystają z źródeł o różnej opóźnieniu, koszcie i niezawodności: dokumentów wewnętrznych, zewnętrznych API, wyszukiwarki internetowej, specjalistycznych baz danych. LangGraph obsługuje strategie wieloźródłowe. Agent może najpierw sprawdzić szybki lokalny cache, następnie uciec się do API, a drogie wyszukiwanie w internecie użyć tylko jako ostateczność. Może też zapytać kilka źródeł równocześnie i poprosić LLM o pogodzenie odpowiedzi, które mogą się ze sobą kłócić.
Logika routingu może wybrać źródło informacji w zależności od typu pytania. Zapytania faktograficzne kierowane są do strukturyzowanej bazy danych, pytania konceptualne do wyszukiwania wektorowego w dokumentach, najnowsze wydarzenia do wyszukiwarki internetowej, a pytania historyczne do starannie przygotowanej bazy wiedzy.
Przygotowanie do użycia w produkcji
Agenta typu proof-of-concept łatwo stworzyć za pomocą LangGraph. W warunkach produkcji pojawiają się wymagania dotyczące niezawodności, obserwowalności oraz zarządzania operacjami.
Rozwiązywanie błędów na każdym poziomie
Agenci produkcyjni radzą sobie z awariami na kilku poziomach. Węzły narzędziowy łapają oczekiwane błędy i zwracają je jako aktualizacje stanu, a nie jako wyjątki. Funkcje routingu sprawdzają warunki błędów i konfigurują ścieżki ponownych prób z wykorzystaniem eksponencjalnego opóźnienia. Graf zawiera dedykowane węzły obsługi błędów, które analizują zgromadzone błędy i decydują, czy należy spróbować ponownie, przejść na alternatywę czy zakończyć proces w sposób uporządkowany. W przypadku krytycznych operacji wyłącznik obwodowy może wstrzymać próby po powtarzających się awariach, zapobiegając kaskadom i chroniąc usługę z awarią przed dodatkowym obciążeniem.
Przegląd tego, co się stało
Gdy coś idzie nie tak, musisz wiedzieć, co zrobił agent i dlaczego. LangGraph integruje się z platformami takimi jak LangSmith, aby dostarczyć szczegółowe informacje o wykonywaniu każdego węzła, przejściach stanów oraz wywołaniach modeli LLM. Węzły powinny generować ustrukturyzowane logi zawierające wystarczająco dużo kontekstu, aby wyjaśnić swoje decyzje. Dane czasowe pokazują wąskie gardła, liczby tokenów pomagają w oszacowaniu kosztów, a śledzenie interakcji użytkowników służy do oceny. Odtwarzanie procesu na podstawie punktów kontrolnych jest szczególnie przydatne – możesz załadować dokładny stan, w którym wystąpił błąd, i krok po kroku znaleźć jego przyczynę.
Obniżanie kosztów
Wywołania modeli LLM stanowią główny element kosztów w większości agentów, ale istnieją pewne metody, które mogą je zmniejszyć bez pogorszenia jakości.
- Wybór modelu. Używaj potężnych modeli, takich jak GPT-4, tylko w przypadkach wymagających skomplikowanego rozumowania. Proste zadania klasyfikacyjne lub ekstrakcyjne przekazuj do szybszych i tańszych modeli, korzystając z logiki routingu, która analizuje charakter zadań.
- Cacheowanie odpowiedzi. Przechowywanie wyników dla identycznych lub semantycznie podobnych danych wejściowych. Gdy analiza powtarza się, cacheowanie eliminuje zbędne wywołania, a embeddingi mogą odpowiadać na zapytania sformułowane inaczej, ale oznaczające to samo.
- Redukcja promptów. Zwięzłe prompty zawierające tylko niezbędne informacje oszczędzają tokeny. Szablony z podstawieniem zmiennych zapewniają ich spójność.
- Wczesne zakończenie. Zatrzymanie procesu, gdy agent ma już wystarczająco dużo informacji, zamiast zużyć ustalony limit iteracji.
Wskazówki projektowe
Wdrożenie agentów LangGraph pokazuje, jakie wzorce odróżniają solidne systemy od kruchych prototypów.
Schemat stanu
Schemat stanowi podstawę. Używaj modeli Pydantic zamiast swobodnych słowników, aby walidacja mogła szybko wykrywać błędy, a także udokumentuj znaczenie i zastosowanie każdego pola. Pola opcjonalne umożliwiają różnym węzłom stopniowe dodawanie elementów, natomiast pola obowiązkowe gwarantują obecność kluczowych danych. Unie dyskryminowane obsługują stany, które przyjmują różne formy w zależności od wybranej ścieżki. Unikaj głębokiego nawijania, które utrudnia dostęp do pól. Uprość strukturę tam, gdzie to możliwe, używaj nazw pokazujących relacje i trzymaj metadane oddzielnie od danych domeny, aby informacje kontrolne pozostały odrębne.
Granice węzłów
Dobre węzły dobrze wykonywają jedną funkcję. Dzięki temu można je ponownie wykorzystywać w różnych grafach, a także łatwiej je testować i utrzymywać. Węzły narzędziowe powinny komunikować się wyłącznie z zewnętrznymi systemami, a nie przechowywać logiki biznesowej. Węzły transformacyjne przekształcają dane bez podejmowania decyzji. Węzły decyzyjne kierują przepływem danych bez wykonywania żadnych operacji. Unikaj ukrytych skutków ubocznych: węzły powinny być tak czyste, jak to tylko możliwe, wyraźnie zwracając każdą zmianę stanu, zamiast modyfikować zmienne globalne.
Kształt grafu
Struktura powinna odzwierciedlać sposób, w jaki agent dochodzi do wniosków. Zacznij od etapu przygotowawczego, w którym sprawdza się dane wejściowe i tworzy kontekst. Następnie zbieraj dane, ewentualnie równolegle. Dodaj węzły analityczne, potem węzły syntezy, które wytwarzają wynik, oraz węzły finalizacyjne, które go oczyszczają. Umieść krawędzie warunkowe w rzeczywistych punktach decyzyjnych, gdzie kolejny krok zależy od ustaleń, a krawędzie statyczne w przypadku przepływu deterministycznego. Zachowaj każdy graf na jednym poziomie abstrakcji. Jeśli jakaś jego część implementuje złożoną podprocedurę, przenieś ją do osobnego grafu i użyj jej jako węzła.
Testowanie
Wykresy można testować na kilku poziomach. Testuj węzły poprzez podanie symulowanego stanu i sprawdzenie aktualizacji. Testuj funkcje routingu, podając różne stany i sprawdzając zwracaną ścieżkę. Testuj całe wykresy w ramach testów integracyjnych przy użyciu znanych danych wejściowych i weryfikuj końcowy stan. Symuluj odpowiedzi LLM, aby testy były szybkie i deterministyczne, a także używaj nagranych rzeczywistych odpowiedzi do stworzenia realistycznych scenariuszy testowych. Testy oparte na właściwościach mogą weryfikować zachowanie w szerokim zakresie danych wejściowych. Dokładnie sprawdzaj krytyczne ścieżki, a szczególnie ścieżki błędowe, ponieważ trudno je wywołać w środowisku produkcyjnym, ale są niezbędne, gdy się pojawią.
Decyzja o konieczności ich użycia
LangGraph jest potężny, ale nie każda aplikacja oparta na LLM wymaga jego użycia.
Stosuje się to wtedy, gdy agent musi rozumować iteracyjnie, gromadząc i analizując informacje oraz decydując, czy szukać dalej. Pasuje to również w sytuacjach, gdy przepływ sterowania zależy od stanu w trakcie wykonywania, jak w przypadku ponawiania prób, naprawy błędów lub adaptacyjnych procesów pracy, gdy kilka narzędzi lub systemów ma złożone zależności, gdy stan musi być przechowywany między poszczególnymi krokami lub sesjami, gdy wykonywanie musi zostać wstrzymane i wznowione dla ludzi, lub gdy kilka agentów współpracuje ze sobą lub tworzy hierarchię.
Wystarczy coś prostszego, gdy zadanie polega na zwykłym pytaniu i odpowiedzi bez pętli czy gałęzi, przepływ jest liniowy i znany z góry, praca może składać się z sekwencji deterministycznych kroków, nic nie musi być przechowywane poza pojedynczym uruchomieniem, lub aplikacja wywołuje co najwyżej jedną lub dwie proste API. W takich przypadkach łańcuchy LangChain lub bezpośrednie wywołania API dają jaśniejszy i łatwiejszy w utrzymaniu kod niż przymuszanie rozwiązania do formy grafu.
Rozwój w tym kierunku
Wiele aplikacji zaczyna się prosto, a potem staje się złożonych. Tego należy się spodziewać w projektach związanych z projektowaniem dźwięku. Zacznij od łańcucha, ale utrzymuj pytania, narzędzia oraz logikę biznesową w formie modułów o luźnym powiązaniu, aby później łatwo było przekształcić je w graf. Gdy łańcuch osiągnie od pięciu do siedmiu kroków lub dodasz drugą gałąź warunkową, rozważ migrację, zanim złożoność wymknie się spod kontroli.
Zaawansowane techniki
Poza podstawami istnieje kilka technik, które otwierają nowe możliwości.
Wykonywanie równoległe. Węzły, które nie zależą od wyników innych węzłów, mogą działać jednocześnie. Na przykład węzły zbierające dane przez różne API skracają całkowity czas działania, gdy są uruchamiane równocześnie, a framework gromadzi i łączy wyniki. Potrzebne są wyraźne łącza równoległe, a także upewnienie się, że węzły są rzeczywiście niezależne, bez ukrytego powiązania poprzez wspólne zasoby lub stan globalny.
Przepływ danych. W przypadku agentów działających przez długi czas pokazywanie pośrednich wyników poprawia doświadczenie użytkownika. Węzły mogą wysyłać częściowe aktualizacje stanu, które obserwatorzy widzą natychmiast. To nadaje się do generowania raportów, gdzie akapity mogą pojawiać się w miarę ich pisania, oraz do wyszukiwarek, które pokazują wyniki w momencie ich znalezienia.
Podgrafy. Złożone agenty czerpią korzyści z hierarchicznego rozkładu. Podgrafy są kompilowane oddzielnie i wywoływane jako węzły w grafie nadrzędnym, otrzymując podzbiór stanu grafu nadrzędnego oraz zwracając aktualizacje, które są ponownie łączone. Różni inżynierowie mogą zarządzać różnymi podgrafami, wdrażać i testować je niezależnie oraz ponownie wykorzystywać te wspólne w kilku grafach nadrzędnych.
Dynamiczne zmiany w grafach. Większość grafów jest ustalana w momencie projektowania, ale w niektórych zaawansowanych przypadkach grafy są modyfikowane w trakcie działania. Agent planujący może stworzyć dostosowany graf po przeanalizowaniu zadania, tworząc węzły i krawędzie „na bieżąco”. Sprawia to, że zachowanie jest trudniejsze do zrozumienia, dlatego należy go używać z umiarem. Umożliwia to jednak meta-agentom projektowanie i uruchamianie dostosowanych procesów pracy dla nowych rodzajów zadań.
Podsumowanie
LangGraph stanowi przykład dojrzałego zestawu narzędzi dla systemów agentowych. Jego siłą nie jest złożoność, lecz to, jak dokładnie elementy bazowe odpowiadają zachowaniu agentów: rozumują, działają i obserwują w pętlach, podejmują decyzje na podstawie zgromadzonej wiedzy, koordynują narzędzia i dostosowują się, gdy coś idzie nie tak. Można bezpośrednio wyrazić te wzorce, zamiast budować je od zera.
Osiągnięcie dobrych wyników wymaga opanowania zarządzania stanem, warunkowego kierowania przepływem danych oraz integracji narzędzi jako wzorców architektonicznych, a nie tylko jako funkcji. Najlepsze aplikacje charakteryzują się starannym projektowaniem schematu stanu, jasnym rozdzieleniem obowiązków węzłów, przemyślanym radzeniem sobie z błędami oraz pełną możliwością obserwacji. Framework dostarcza narzędzi, a nie rozwiązań. To twoja wiedza z danej dziedziny oraz osąd decydują o tym, jak dobrze zostaną one zastosowane, więc zacznij od prostych rozwiązań, wcześnie sprawdzaj założenia i pozwól, by rzeczywiste wymagania, a nie wyobrażone, kształtowały architekturę.
Literatura pokrewna
- Agent czy proces pracy? Oddzielanie rozumowania od wykonywania zadań w korporacyjnej sztucznej inteligencji — Używaj agentów do identyfikacji intencji i wyszukiwania informacji, a deterministycznych procesów pracy do obsługi transakcji: jak RAG, LangGraph, MCP, procedury zatwierdzania i SQS tworzą bezpieczniejszą architekturę.
- Rekomendator K-dram z wieloma agentami uwzględniający gusta widzów: BERTopic, RAG i fuzja rankingu wzajemnego — Jak rekomendator K-dram, który bierze pod uwagę preferencje odbiorców, łączy tagi BERTopic, funkcje wyszukiwania ChromaDB, agenta do przeprowadzania wywiadów, rozszerzanie zapytań oraz fuzję rankingu wzajemnego przed ponownym sortowaniem przez model językowy.