Strona główna / Artykuły / Agenci ReAct w LangGraph: Krok po kroku – myślenie, działanie, obserwacja

Agenci ReAct w LangGraph: Krok po kroku – myślenie, działanie, obserwacja

Zaimplementuj pętlę ReAct jako wyraźne węzły grafu z typowanym stanem, wywołaniami narzędzi oraz warunkami zatrzymania, które można przetestować.

4143 słów

To przewodnik odbudowuje funkcjonalną ścieżkę dla: ReAct Agents Explained: Krok po kroku – implementacja przy użyciu LangGraph. Skupia się na kontraktach, sprawdzaniach oraz kodzie, który można umieścić w repozytorium bez konieczności domyślania się intencji. Aby uzyskać ogólny obraz, należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Lepiej używać małych, testowalnych jednostek niż rozbudowanych skryptów. Gdy dany krok zawiedzie, powód awarii powinien wskazywać na konkretną odpowiedzialność, a nie na skomplikowany proces.

Wprowadzenie

W części wprowadzającej należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Traktuj tę fazę jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nazwij poszczególne elementy, zdefiniuj kryteria sukcesu i odrzuć ciche, częściowe ukończenie zadania. Rozdziel planowanie od wykonywania zadań za pomocą narzędzi. Planista proponuje rozwiązania; wykonawca je wdraża; sprawdzający porównuje wyniki z założonym celem.

Czym jest agent ReAct?

W rozdziale „Co to jest agent ReAct?” należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy rejestrować czasy wykonywania i koszty obok wyników funkcjonalnych. Wczesna widoczność zapobiega nieoczekiwanym rachunkom, gdy ścieżka przechodzi z środowiska demonstracyjnego do współdzielonych środowisk. Należy oddzielić planowanie od wykonywania zadań za pomocą narzędzi. Planista proponuje rozwiązania; wykonawca je modyfikuje; weryfikator sprawdza wyniki pod kątem realizacji celu.

Dlaczego ReAct jest lepszy od czystej metody Chain-of-Thought

Aby wyjaśnić, dlaczego ReAct jest lepszy od czystego podejścia Chain-of-Thought, należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Konfigurację należy przechowywać poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Należy oddzielić planowanie od wykonywania zadań za pomocą narzędzi. Planer proponuje rozwiązania; wykonawca je wdraża; sprawdzacz porównuje wyniki z założonym celem. Aby wyjaśnić, dlaczego ReAct jest lepszy od czystego podejścia Chain-of-Thought, należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy preferować małe, łatwe do przetestowania jednostki nad rozbudowanymi skryptami. Gdy dany krok zawiedzie, błąd powinien wskazywać na konkretną przyczynę.

zamiast skomplikowanego łańcucha przetwarzania.

Thought: I don’t know the answer yet. I should search.
Action: Search("Paris weather this week")
Observation: It will rain on Thursday.
Thought: I should suggest indoor activities.
Final Answer: ...

ReAct Prompting

W przypadku ReAct Prompting należy zdefiniować dane wejściowe, osobę odpowiedzialną za daną fazę oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić daną fazę na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Traktuj tę fazę jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nazwij poszczególne elementy, zdefiniuj kryteria sukcesu i odrzuć ciche, częściowe ukończenie zadania. Ściśle określ schematy narzędzi. Szerokie pola tekstowe sprzyjają infekcjom i sprawiają, że audyty są kosztowne.

Cel ReAct Prompting

Dla celów ReAct Prompting należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy rejestrować czasy wykonywania i koszty obok wyników funkcjonalnych. Wczesna widoczność zapobiega nieoczekiwanym rachunkom, gdy ścieżka przechodzi z środowiska demonstracyjnego do współdzielonych środowisk. Schematy narzędzi muszą być ściśle określone – szerokie pola tekstowe umożliwiają iniekcje i sprawiają, że audyty są kosztowne.

Kluczowe elementy ReAct Prompting

Dla kluczowych elementów techniki ReAct Prompting należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Konfigurację należy przechowywać poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności przeglądania całej struktury. Schematy narzędzi należy ściśle określić. Szersze argumenty tekstowe sprzyjają iniekcjom i utrudniają audyt. Dla kluczowych elementów techniki ReAct Prompting należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy preferować małe, testowalne jednostki zamiast rozbudowanych skryptów. Gdy dany krok zawiedzie, powinien wskazywać na konkretną odpowiedzialność, a nie na skomplikowaną ścieżkę przetwarzania.

1. Rozumowanie typu Chain-of-Thought

W przypadku rozumowania typu Chain-of-Thought należy zdefiniować dane wejściowe, osobę odpowiedzialną za daną krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie wykonać dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Traktuj tę fazę jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nazwij poszczególne elementy, zdefiniuj kryteria sukcesu i odrzuć przypadkowe, częściowe ukończenie zadań. Utwórz punkt kontrolny po kosztownych wywołaniach modelu, aby ponowna próba nie generowała dodatkowych opłat za tę samą pracę.

2. Wyraźna przestrzeń działań

Dla 2. Przestrzeni działań – określ dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Zapisuj czas trwania i koszty obok wyników funkcjonalnych. Wczesna widoczność zapobiega niespodziewanym rachunkom, gdy ścieżka przechodzi z środowiska demonstracyjnego do współdzielonych środowisk. Ustaw punkt kontrolny po kosztownych wywołaniach modelu, aby ponowna próba nie generowała dodatkowych opłat za tę samą pracę.

3. Integracja obserwacji

Dla punktu 3. Integracja obserwacji należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Konfigurację należy przechowywać poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Ustawiaj punkty kontrolne po kosztownych wywołaniach modeli, aby ponowne próby nie powodowały ponownego obliczania tych samych zadań. Dla punktu 3. Integracja obserwacji należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy preferować małe, testowalne jednostki nad rozbudowanymi skryptami. Gdy dany krok zawiedzie, powód awarii powinien wskazywać na konkretną odpowiedzialność, a nie na skomplikowaną strukturę procesów.

4. Pętle iteracyjne

Dla 4. iteracyjnego pętlenia należy zdefiniować dane wejściowe, osobę odpowiedzialną za daną etap oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić daną etap na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Traktuj tę fazę jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nazwij poszczególne elementy, zdefiniuj kryteria sukcesu i odrzuć ciche, częściowe ukończenie zadania. Rozdziel planowanie od wykonywania zadań za pomocą narzędzi. Planista proponuje; wykonawca wprowadza zmiany; weryfikator sprawdza wyniki pod kątem osiągnięcia celu.

5. Generowanie ostatecznej odpowiedzi

Dla etapu 5. Generowanie ostatecznej odpowiedzi należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy rejestrować czasy wykonywania i koszty obok wyników funkcjonalnych. Wczesna widoczność zapobiega nieoczekiwanym rachunkom, gdy ścieżka przechodzi z środowiska demonstracyjnego do współdzielonych środowisk. Należy oddzielić planowanie od wykonywania zadań za pomocą narzędzi. Planista proponuje rozwiązania; wykonawca je wdraża; sprawdzający porównuje wyniki z założonym celem.

Kanoniczna struktura promptu ReAct

Dla kanonicznej struktury promptu ReAct należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Konfigurację należy przechowywać poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Należy oddzielić planowanie od wykonywania zadań za pomocą narzędzi. Planer proponuje rozwiązania; wykonawca je wdraża; sprawdzacz porównuje wyniki z celem. Dla kanonicznej struktury promptu ReAct należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy preferować małe, łatwe do przetestowania jednostki nad rozbudowanymi skryptami. Gdy dany krok zawiedzie, powinno to wskazywać na konkretną przyczynę, a nie na skomplikowaną strukturę procesów.

Question: <user question>Thought: <reason about what to do next>

Action: <selected tool>
Action Input: <tool input>
Observation: <tool output>
... (repeat as needed)
Thought: I now know the final answer
Final Answer: <answer to the user>

Zero-Shot ReAct Prompting

W przypadku Zero-Shot ReAct Prompting należy zdefiniować dane wejściowe, osobę odpowiedzialną za daną etap oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić daną etap na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Traktuj tę fazę jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nazwij poszczególne elementy, zdefiniuj kryteria sukcesu i odrzuć ciche, częściowe ukończenie zadań. Ściśle określ schematy narzędzi. Szerokie pola tekstowe umożliwiają wstrzykiwanie złośliwego kodu i sprawiają, że audyty stają się kosztowne.

ReAct Prompting vs ReAct Agents

Dla podejścia ReAct Prompting w porównaniu z ReAct Agents należy zdefiniować dane wejściowe, osobę odpowiedzialną za daną etap oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić daną etap na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy rejestrować czasy wykonywania i koszty obok wyników funkcjonalnych. Wczesna widoczność zapobiega nieoczekiwanym rachunkom, gdy ścieżka przechodzi z środowiska demonstracyjnego do współdzielonych środowisk. Schematy narzędzi muszą być ściśle określone – szerokie pola tekstowe umożliwiają iniekcje i sprawiają, że audyty są kosztowne.

Dlaczego LangGraph do ReAct Agents?

Aby zrozumieć, dlaczego wybrać LangGraph dla agentów ReAct, należy przed zmianą kodu zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia. Operatorzy powinni móc ponownie uruchomić dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Konfigurację należy przechowywać poza kodem aplikacji. Pliki środowiskowe, magazyny poufnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności przeglądania całej struktury. Schematy narzędzi należy ściśle określić. Szersze argumenty tekstowe sprzyjają iniekcjom i utrudniają audyt. Aby zrozumieć, dlaczego wybrać LangGraph dla agentów ReAct, należy przed zmianą kodu zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia. Operatorzy powinni móc ponownie uruchomić dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy preferować małe, łatwe do przetestowania jednostki zamiast rozbudowanych skryptów. Gdy dany krok zawiedzie, powinien wskazywać na konkretną odpowiedzialność, a nie na skomplikowaną sekwencję operacji.

Główny problem: ReAct to maszyna stanowa, a nie prompt

W rozdziale „Główny problem: ReAct to maszyna stanowa, a nie prompt” należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie wykonać dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Traktuj tę fazę jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nazwij poszczególne elementy, zdefiniuj kryteria sukcesu i odrzuć ciche, częściowe ukończenie zadania. Ustaw punkt kontrolny po kosztownych wywołaniach modelu, aby ponowna próba nie generowała dodatkowych opłat za tę samą pracę.

Co się psuje bez LangGraph

Dla przypadków, które nie działają przy użyciu LangGraph, należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy rejestrować czasy wykonywania i koszty obok wyników funkcjonalnych. Wczesna widoczność zapobiega nieoczekiwanym rachunkom, gdy ścieżka przechodzi z środowiska demonstracyjnego do współdzielonych środowisk. Ustal punkt kontrolny po drogich wywołaniach modelu, aby ponowna próba nie generowała dodatkowych opłat za tę samą pracę.

1. Ukryty przepływ sterowania

Dla 1. Ukrytego przepływu sterowania należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Konfigurację należy przechowywać poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Ustawiaj punkty kontrolne po kosztownych wywołaniach modeli, aby ponowne próby nie powodowały ponownego naliczania tych samych zadań. Dla 1. Ukrytego przepływu sterowania należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy preferować małe, testowalne jednostki nad rozbudowanymi skryptami. Gdy dany krok zawiedzie, powód awarii powinien wskazywać na konkretną odpowiedzialność, a nie na skomplikowaną strukturę przepływu.

while True:
    llm_output = llm(prompt)
    if "Action:" in llm_output:
        tool_result = call_tool(...)
    else:
        break

2. Kruche zarządzanie stanem

Dla punktu 2. Zarządzanie kruchym stanem: zdefiniuj dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Traktuj tę fazę jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nadaj nazwy poszczególnym elementom, zdefiniuj kryteria sukcesu i odrzuć ciche, częściowe ukończenie zadania. Rozdziel planowanie od wykonywania zadań za pomocą narzędzi. Planista proponuje; wykonawca wprowadza zmiany; weryfikator sprawdza wyniki pod kątem osiągnięcia celu.

3. Brak semantyki pętli pierwszej klasy

Dla punktu 3: Brak semantyki pętli pierwszej klasy – należy zdefiniować dane wejściowe, osobę odpowiedzialną za daną etap oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić daną etap na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy rejestrować czasy wykonywania i koszty obok wyników funkcjonalnych. Wczesna widoczność zapobiega nieoczekiwanym rachunkom, gdy ścieżka przechodzi z środowiska demonstracyjnego do współdzielonych środowisk. Należy oddzielić planowanie od wykonywania przez narzędzia – planer proponuje, wykonawca wprowadza zmiany, a weryfikator sprawdza wyniki pod kątem celu.

4. Niska gotowość do produkcji

Dla punktu 4. Niska gotowość do produkcji: zdefiniuj dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Utrzymuj konfigurację poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Rozdziel planowanie od wykonywania zadań za pomocą narzędzi. Planista proponuje rozwiązania; wykonawca je wdraża; sprawdzający porównuje wyniki z założonym celem. Dla punktu 4. Niska gotowość do produkcji: zdefiniuj dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Woląć małe, testowalne jednostki nad rozbudowane skrypty. Gdy dany krok zawiedzie, powinno to wskazywać na konkretną odpowiedzialność, a nie na skomplikowaną strukturę procesów.

Kluczowe koncepcje w LangGraph (podejście skupione na agencie)

W ramach kluczowych koncepcji w LangGraph (podejście skupione na agencie) należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Traktuj tę fazę jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nazwij poszczególne elementy, zdefiniuj kryteria sukcesu i odrzucaj ciche, częściowe ukończenie zadań. Ściśle określ schematy narzędzi. Zbyt szerokie pola tekstowe sprzyjają infekcjom i utrudniają audyty.

1. Stan: Pamięć agenta

Dla stanu 1: Pamięć agenta – zdefiniuj dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Zapisuj czas trwania i koszty obok wyników funkcjonalnych. Wczesna widoczność zapobiega niespodziewanym rachunkom, gdy ścieżka przechodzi z środowiska demonstracyjnego do współdzielonych środowisk. Schematy narzędzi muszą być ściśle określone – szerokie pola tekstowe sprzyjają infekcjom i sprawiają, że audyty są kosztowne.

2. Węzły: Jednostki poznawcze i operacyjne

Dla węzłów 2: Jednostek poznawczych i operacyjnych, zdefiniuj wprowadzenia, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Utrzymuj konfigurację poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Ściśle określ schematy narzędzi. Szerokie pola tekstowe sprzyjają iniekcjom i utrudniają audyty. Dla węzłów 2: Jednostek poznawczych i operacyjnych, zdefiniuj wprowadzenia, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Wolimy małe, testowalne jednostki zamiast rozbudowanych skryptów. Gdy dany krok zawiedzie, powinien wskazywać na konkretną odpowiedzialność, a nie na skomplikowaną ścieżkę przetwarzania.

3. Krawędzie: Jasny przepływ sterowania

W przypadku 3. Krawędzie: Jasny przepływ sterowania należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Traktuj tę fazę jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nazwij poszczególne elementy, zdefiniuj kryteria sukcesu i odrzuć ciche, częściowe ukończenie zadania. Ustal punkt kontrolny po kosztownych wywołaniach modelu, aby ponowna próba nie generowała dodatkowych opłat za tę samą pracę.

4. Wykonywanie deterministyczne z elastycznością

Dla punktu 4. Deterministyczna eksploatacja z elastycznością: określ dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Zapisuj czas trwania i koszty obok wyników funkcjonalnych. Wczesna widoczność zapobiega nieoczekiwanym rachunkom, gdy ścieżka przechodzi z środowiska demonstracyjnego do współdzielonych środowisk. Ustal punkt kontrolny po kosztownych wywołaniach modelu, aby ponowna próba nie generowała dodatkowych opłat za tę samą pracę.

ReAct + LangGraph: doskonałe połączenie

Dla ReAct + LangGraph: doskonałe połączenie – zdefiniuj dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Konfigurację należy przechowywać poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Ustaw punkt kontrolny po kosztownych wywołaniach modelu, aby ponowna próba nie powodowała ponownego obliczania tych samych zadań. Dla ReAct + LangGraph: doskonałe połączenie – zdefiniuj dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Wolno preferować małe, łatwe do przetestowania jednostki nad rozbudowanymi skryptami. Gdy dany krok zawiedzie, powód awarii powinien wskazywać na konkretną odpowiedzialność, a nie na skomplikowaną sekwencję operacji.

Zastosowanie: Asystent ds. anulowania rezerwacji w hotelu (polityka + obliczanie zwrotu)

Dla zastosowania: Asystent ds. anulowania rezerwacji w hotelu (polityka + obliczanie zwrotu), należy zdefiniować dane wejściowe, osobę odpowiedzialną za daną czynność oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić tę czynność od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Traktuj tę fazę jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nazwij poszczególne elementy, zdefiniuj kryteria sukcesu i odrzuć ciche, częściowe ukończenie zadania. Rozdziel planowanie od wykonywania zadań za pomocą narzędzi. Planista proponuje rozwiązania; wykonawca je wdraża; sprawdzający porównuje wyniki z założonym celem.

Sformułowanie problemu

W celu sformułowania problemu należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy oddzielić planowanie od wykonywania narzędzi. Planista proponuje; wykonawca wprowadza zmiany; weryfikator sprawdza wyniki pod kątem osiągnięcia celu.

Krok 1: Zainstaluj zależności

Należy oddzielić planowanie od wykonywania narzędzi. Planista proponuje; wykonawca wprowadza zmiany; weryfikator sprawdza wyniki pod kątem osiągnięcia celu.

pip install -U langgraph langchain langchain-openai
export OPENAI_API_KEY="..."

Krok 2: Zdefiniuj narzędzia (twoje „Działania”)

Schematy narzędzi muszą być ściśle określone. Szersze argumenty tekstowe sprzyjają infekcjom i sprawiają, że audyty są kosztowne.

from typing import TypedDict, Annotated
from datetime import datetime
import json

from pydantic import BaseModel
from langchain_openai import ChatOpenAI
from langchain_core.messages import (
    BaseMessage,
    HumanMessage,
    ToolMessage,
    SystemMessage
)
from langchain_core.tools import tool
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langgraph.prebuilt import tools_condition

@tool
def get_cancellation_policy(rate_plan: str) -> str:
    """
    Returns cancellation policy text for a given rate plan.
    """
    policies = {
        "flexible": "Free cancellation until 24 hours before check-in. After that, first night is charged.",
        "semi-flex": "Free cancellation until 72 hours before check-in. After that, 50% of the stay is charged.",
        "non-refundable": "No refund after booking. Full stay amount is charged on cancellation."
    }
    key = rate_plan.strip().lower()
    return policies.get(key, "Policy not found. Supported: flexible, semi-flex, non-refundable.")
@tool
def calculate_refund(
    rate_plan: str,
    check_in: str,
    cancel_date: str,
    nightly_rate: float,
    nights: int
) -> str:
    """
    Calculates refund amount based on a simplified policy model.
    Dates format: YYYY-MM-DD
    """
    rp = rate_plan.strip().lower()
    ci = datetime.strptime(check_in, "%Y-%m-%d").date()
    cd = datetime.strptime(cancel_date, "%Y-%m-%d").date()
    total = nightly_rate * nights
    days_before = (ci - cd).days
    if rp == "non-refundable":
        refund = 0.0
        charged = total
        rule = "Non-refundable: no refund."
    elif rp == "flexible":
        if days_before >= 1:
            refund = total
            charged = 0.0
            rule = "Flexible: cancelled >= 24h before check-in, full refund."
        else:
            charged = nightly_rate  # 1 night penalty
            refund = max(total - charged, 0.0)
            rule = "Flexible: late cancel, 1 night charged."
    elif rp == "semi-flex":
        if days_before >= 3:
            refund = total
            charged = 0.0
            rule = "Semi-flex: cancelled >= 72h before check-in, full refund."
        else:
            charged = 0.5 * total
            refund = total - charged
            rule = "Semi-flex: late cancel, 50% charged."
    else:
        return "Unsupported rate plan. Use: flexible, semi-flex, non-refundable."
    return (
        f"Rule: {rule}\n"
        f"Days before check-in: {days_before}\n"
        f"Total: ${total:.2f}\n"
        f"Charged: ${charged:.2f}\n"
        f"Refund: ${refund:.2f}"
    )

Krok 3: Stwórz pętlę ReAct w LangGraph (Rozumowanie → Narzędzie → Rozumowanie)

Schematy narzędzi muszą być ściśle określone. Szersze argumenty tekstowe sprzyjają infekcjom i sprawiają, że audyty są kosztowne.

from typing import TypedDict, Annotated
from langchain_core.messages import BaseMessage, HumanMessage
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages

from langchain_openai import ChatOpenAI
from langchain_core.tools import Tool
from langgraph.prebuilt import ToolNode, tools_condition
# 1) Define state
class AgentState(TypedDict):
    messages: Annotated[list[BaseMessage], add_messages]
    booking_id: str
# 2) Define structured Output schema
class RefundDecision(BaseModel):
    booking_id: str
    rate_plan: str
    total_amount: float
    charged_amount: float
    refund_amount: float
    policy_summary: str
    explanation: str
# 2) Choose model and System prompt
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
SYSTEM_PROMPT = SystemMessage(
    content="""
You are a hotel cancellation assistant.
Rules:
- Use tools when needed.
- Never guess policy or refund.
- Final answer MUST be valid JSON with this schema:
{
  "booking_id": "...",
  "rate_plan": "...",
  "total_amount": number,
  "charged_amount": number,
  "refund_amount": number,
  "policy_summary": "...",
  "explanation": "..."
}
"""
)
# 3) Register tools
tools = [get_cancellation_policy, calculate_refund]
def safe_tool_node(state):
    last_msg = state["messages"][-1]
    if not hasattr(last_msg, "tool_calls") or not last_msg.tool_calls:
        return {}
    tool_call = last_msg.tool_calls[0]
    tool_name = tool_call["name"]
    if tool_name not in ALLOWED_TOOLS:
        return {
            "messages": [
                ToolMessage(
                    content=f"Tool '{tool_name}' is not allowed.",
                    tool_call_id=tool_call["id"]
                )
            ]
        }
    for tool in tools:
        if tool.name == tool_name:
            result = tool.invoke(tool_call["args"])
            return {
                "messages": [
                    ToolMessage(
                        content=result,
                        tool_call_id=tool_call["id"]
                    )
                ]
            }
# 4)Before reasoning, check if we already processed this booking.
REFUND_MEMORY = {}
def memory_lookup_node(state):
    booking_id = state["booking_id"]
    if booking_id in REFUND_MEMORY:
        return {
            "messages": [
                HumanMessage(
                    content=f"Cached decision found:\n{REFUND_MEMORY[booking_id]}"
                )
            ]
        }
    return {}
# 5) Reasoning node: LLM decides next action (tool call) or final answer
def agent_node(state: AgentState):
    # Bind tools so the model can produce tool calls
    llm_with_tools = llm.bind_tools(tools)
    response = llm_with_tools.invoke(state["messages"])
    return {"messages": [response]}
# 6) After final decision, store it.
def memory_write_node(state):
    booking_id = state["booking_id"]
    final_answer = state["messages"][-1].content
    REFUND_MEMORY[booking_id] = final_answer
    return {}

Budowanie i kompilacja grafu

Schematy narzędzi muszą być ściśle określone. Szerokie argumenty tekstowe zachęcają do iniekcji i sprawiają, że audyty są kosztowne.

# 7) Build the graph
builder = StateGraph(AgentState)

# Nodes
builder.add_node("memory_lookup", memory_lookup_node)
builder.add_node("agent", agent_node)
builder.add_node("tools", safe_tool_node)
builder.add_node("memory_write", memory_write_node)
# Flow
builder.add_edge(START, "memory_lookup")
builder.add_edge("memory_lookup", "agent")
builder.add_conditional_edges(
    "agent",
    tools_condition,
    {
        "tools": "tools",   # model wants to act
        END: "memory_write" # model finished reasoning
    }
)
builder.add_edge("tools", "agent")
builder.add_edge("memory_write", END)
graph = builder.compile()

Krok 4: Uruchomienie agenta w konkretnym przypadku użycia

Schematy narzędzi muszą być ściśle określone. Szerokie argumenty tekstowe zachęcają do iniekcji i sprawiają, że audyty są kosztowne.

query = """
Booking details:
Rate plan: Non-Refundable
Check-in: 2026-01-20
Nights: 2
Nightly rate: 120
Cancelled on: 2026-01-18
"""

result = graph.invoke({
    "booking_id": "BKG-12345",
    "messages": [
        SYSTEM_PROMPT,
        HumanMessage(content=query)
    ]
})
final_output = result["messages"][-1].content
print(final_output)

Wynik

Schematy narzędzi muszą być ściśle określone. Szerokie argumenty tekstowe zachęcają do iniekcji i sprawiają, że audyty są kosztowne.

{
  "booking_id": "BKG-12345",
  "rate_plan": "Non-Refundable",
  "total_amount": 240.0,
  "charged_amount": 240.0,
  "refund_amount": 0.0,
  "policy_summary": "Non-refundable bookings do not allow refunds after confirmation.",
  "explanation": "The booking was made under a non-refundable rate plan, which charges the full stay amount regardless of cancellation timing."
}

Co dzieje się wewnątrz (behawior ReAct)

Schematy narzędzi muszą być ściśle określone. Szerokie argumenty tekstowe zachęcają do iniekcji i sprawiają, że audyty są kosztowne.

1) Myśl (Uzasadnienie)

Schematy narzędzi muszą być ściśle określone. Szerokie argumenty tekstowe zachęcają do iniekcji i sprawiają, że audyty są kosztowne.

2) Działanie (wezwanie narzędzia)

Schematy narzędzi muszą być ściśle określone. Szerokie argumenty tekstowe zachęcają do iniekcji i sprawiają, że audyty są kosztowne.

3) Obserwacja (wyniki narzędzi)

Punkt kontrolny po drogich wywołaniach modelu, aby ponowna próba nie obciążała kosztami tej samej pracy.

4) Odpowiedź końcowa

Punkt kontrolny po drogich wywołaniach modelu, aby ponowna próba nie obciążała kosztami tej samej pracy.

Dlaczego to jest „ReAct” (a nie tylko narzędzia)

Punkt kontrolny po drogich wywołaniach modelu, aby ponowna próba nie obciążała kosztami tej samej pracy.

Wniosek

Rozdziel planowanie od wykonywania zadań za pomocą narzędzi. Planer proponuje; wykonawca wprowadza zmiany; weryfikator sprawdza wyniki pod kątem celu.

Lista kontrolna operacyjna

Schematy narzędzi muszą być ściśle określone. Szerokie argumenty tekstowe sprzyjają infekcjom i utrudniają audyty.

Krawędzie warunkowe powinny kodować zasady biznesowe jako nazwane funkcje, a nie jako ukryty tekst instrukcji.

Rodzaje danych powinny być umieszczane obok komponentów, a ich właściwości powinny być ograniczone. Zbyt liczne właściwości stanowią dług, którego TypeScript ma zapobiegać.

Napisz krótki przewodnik: jak rotować klucze, jak opróżnić kolejkę, jak cofnąć ostatnią zmianę.