Warunkowe przepływy pracy LangGraph: tworzenie gałęzi bez chaotycznego zbierania informacji z promptów
Zamień routowanie typu if-else w LangGraph na nazwane krawędzie warunkowe z jasno określonymi kontraktami stanów oraz możliwością przywrócenia po awarii, zamiast umieszczania struktur rozgałęziających się w promptach.
Źródła: Conditional Workflows in LangGraph: The If-Else of Agentic AI
To przewodnik pokazuje, jak odbudować sprawny schemat działania dla: Warunkowych przepływów pracy w LangGraph: mechanizmu If-Else w sztucznej inteligencji agentowej. Skupiamy się na kontraktach, sprawdzaniach oraz kodzie, który można bez problemu dodać do repozytorium, nie musząc zgadywać intencji twórcy. 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 na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu systemu. Należy udokumentować zarówno prawidłowy przebieg działania, jak i ścieżkę naprawczą. Próby ponownego wykonania, kontrola przez człowieka oraz obsługa błędów stanowią integralną część produktu, a nie elementy dodawane później.
Czym właściwie jest warunkowy przepływ pracy?
Dlaczego w ogóle potrzebny jest warunkowy przepływ pracy? 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. Lepiej używać małych, testowalnych jednostek niż rozbudowanych skryptów. Gdy dany krok zawiedzie, powinien wskazywać na konkretną odpowiedzialność, a nie na skomplikowany łańcuch operacji. Schematy narzędzi muszą być ściśle określone. Szerokie pola tekstowe sprzyjają infekcjom i sprawiają, że audyty są kosztowne.
Przepływ pracy nr 1: Rozwiązywanie równania kwadratowego
Dla procesu pracy nr 1: Rozwiązywanie równania kwadratowego, należy zdefiniować dane wejściowe, osobę odpowiedzialną za daną etap oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić ten 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. Ściśle określ schematy narzędzi. Szerokie pola tekstowe umożliwiają wstrzykiwanie złośliwego kodu i sprawiają, że audyty są kosztowne.
Struktura procesu pracy
Dla struktury przepływu pracy 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. Zapisuj czas trwania i koszty obok wyników funkcjonalnych. Wczesna widoczność zapobiega niespodziewanym rachunkom, gdy ścieżka przechodzi z wersji demonstracyjnej do środowisk współdzielonych. Schematy narzędzi muszą być ściśle określone. Szerokie pola tekstowe umożliwiają wstrzykiwanie złośliwego kodu i sprawiają, że audyty są kosztowne. Dla struktury przepływu pracy 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. Dokumentuj zarówno ścieżkę prawidłowego działania, jak i ścieżkę naprawczą. Próby ponownych działań, kontrolne punkty ludzkie oraz obsługa wiadomości błędnych stanowią część produktu, a nie elementy dodawane później.
Budowanie stanu
Aby zbudować system, przed modyfikacją kodu należy określić 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 systemu. Należy preferować małe, łatwe do przetestowania jednostki nad rozbudowanymi skryptami. Gdy dany krok zawiedzie, powinien wskazywać na konkretną odpowiedzialność, a nie na skomplikowaną strukturę procesów. Ustawiaj punkty kontrolne po kosztownych wywołaniach modeli, aby ponowna próba nie powodowała ponownego obliczania tych samych zadań.
class QuadState(TypedDict):
a: float
b: float
c: float
equation: str
discriminant: float
result: str
Węzły
Dla węzłów 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. 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 zadania. Utwórz punkt kontrolny po kosztownych wywołaniach modelu, aby ponowna próba nie generowała dodatkowych opłat za tę samą pracę.
def show_equation(state: QuadState):
equation = f"{state['a']}x² + {state['b']}x + {state['c']}"
return {"equation": equation}
def calculate_discriminant(state: QuadState):
discriminant = (state['b'] ** 2) - (4 * state['a'] * state['c'])
return {"discriminant": discriminant}
def real_roots(state: QuadState):
r1 = (-state['b'] + state['discriminant'] ** 0.5) / (2 * state['a'])
r2 = (-state['b'] - state['discriminant'] ** 0.5) / (2 * state['a'])
result = f"The roots are {r1} and {r2}"
return {"result": result}
def repeated_root(state: QuadState):
root = -state['b'] / (2 * state['a'])
result = f"Only repeating root is {root}"
return {"result": result}
def no_real_roots(state: QuadState):
return {"result": "No real roots"}
Funkcja routingu — to kluczowa część
Dla funkcji routingu – to jest kluczowa część: przed zmianą kodu należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia. Operatorzy powinni móc ponownie uruchomić ten krok od 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. Ustal punkt kontrolny po drogich wywołaniach modelu, aby ponowna próba nie generowała dodatkowych opłat za tę samą pracę. Dla funkcji routingu – to jest kluczowa część: przed zmianą kodu należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Zdokumentuj zarówno ścieżkę prawidłowego działania, jak i ścieżkę naprawczą. Próby ponowne, mechanizmy kontroli ludzkiej oraz obsługa wiadomości błędnych stanowią część produktu, a nie elementy dodawane później.
def check_condition(state: QuadState):
if state['discriminant'] > 0:
return "real_roots"
elif state['discriminant'] == 0:
return "repeated_root"
else:
return "no_real_roots"
Łączenie wszystkiego razem
Aby to połączyć, zdefiniuj wejścia, 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. Wolno preferować małe, testowalne jednostki zamiast rozbudowanych skryptów. Gdy krok się nie powiedzie, przyczyna błędu powinna wskazywać na konkretną odpowiedzialność, a nie na skomplikowany proces. Rozdziel planowanie od wykonywania zadań za pomocą narzędzi. Planista proponuje; wykonawca wprowadza zmiany; weryfikator sprawdza wyniki pod kątem osiągnięcia celu.
graph = StateGraph(QuadState)
graph.add_node("show_equation", show_equation)
graph.add_node("calculate_discriminant", calculate_discriminant)
graph.add_node("real_roots", real_roots)
graph.add_node("repeated_root", repeated_root)
graph.add_node("no_real_roots", no_real_roots)
graph.add_edge(START, "show_equation")
graph.add_edge("show_equation", "calculate_discriminant")
# This is the magic line
graph.add_conditional_edges("calculate_discriminant", check_condition)
graph.add_edge("real_roots", END)
graph.add_edge("repeated_root", END)
graph.add_edge("no_real_roots", END)
workflow = graph.compile()
Workflow #2: Obsługa recenzji klienta (oparta na LLM)
Dla procesu pracy nr 2: Obsługa recenzji klienta (oparta na LLM), 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; wykonawca wprowadza zmiany; weryfikator sprawdza wyniki pod kątem osiągnięcia celu.
Sytuacja
Dla danego scenariusza 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. 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. 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 danego scenariusza 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. Dokumentuj razem ścieżkę pomyślnego przebiegu oraz ścieżkę naprawczą. Próby ponownych działań, mechanizmy kontroli ludzkiej oraz obsługa wiadomości błędowych stanowią część produktu, a nie elementy dodawane później.
Strukturyzowane schematy wyjściowe
Dla schematów strukturyzowanego wyjścia 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 preferować małe, łatwe do przetestowania jednostki zamiast rozbudowanych skryptów. Gdy dany krok zawiedzie, powinno to wskazywać na konkretną odpowiedzialność, a nie na skomplikowaną strukturę procesu. Schematy narzędzi należy ściśle określić. Szerokie pola tekstowe umożliwiają wstrzykiwanie złośliwego kodu i sprawiają, że audyty są kosztowne.
from pydantic import BaseModel
from typing import Literal
class SentimentSchema(BaseModel):
sentiment: Literal["positive", "negative"]
class DiagnosisSchema(BaseModel):
issue_type: Literal["UI", "performance", "bug", "support", "other"]
tone: Literal["frustrated", "angry", "disappointed", "neutral"]
urgency: Literal["low", "medium", "high"]
from langchain_openai import ChatOpenAI
model = ChatOpenAI(model="gpt-4o-mini")
structured_model_sentiment = model.with_structured_output(SentimentSchema)
structured_model_diagnosis = model.with_structured_output(DiagnosisSchema)
Stan
Dla państwa 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. 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. Zbyt szerokie pola tekstowe sprzyjają infekcjom i sprawiają, że audyty są kosztowne.
class ReviewState(TypedDict):
review: str
sentiment: Literal["positive", "negative"]
diagnosis: dict
response: str
Węzły
Dla The Nodes 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 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. Szersze pola tekstowe sprzyjają infekcjom i sprawiają, że audyty są kosztowne. Dla The Nodes 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 na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy udokumentować zarówno ścieżkę prawidłowego działania, jak i ścieżkę naprawczą. Próby ponownych działań, mechanizmy ludzkiej kontroli oraz obsługa wiadomości błędowych stanowią część produktu, a nie elementy dodawane później.
def find_sentiment(state: ReviewState):
prompt = f"For the following review, find out the sentiment:\n{state['review']}"
result = structured_model_sentiment.invoke(prompt)
return {"sentiment": result.sentiment}
def positive_response(state: ReviewState):
prompt = f"""Write a warm thank you message in response to this review:
{state['review']}
Also kindly ask the user to leave feedback on our website."""
result = model.invoke(prompt)
return {"response": result.content}
def run_diagnosis(state: ReviewState):
prompt = f"""Diagnose this negative review:
{state['review']}
Return issue type, tone, and urgency."""
result = structured_model_diagnosis.invoke(prompt)
return {"diagnosis": result.model_dump()}
def negative_response(state: ReviewState):
diagnosis = state['diagnosis']
prompt = f"""You are a support assistant. The user had a {diagnosis['issue_type']} issue,
sounded {diagnosis['tone']}, and marked urgency as {diagnosis['urgency']}.
Write an empathetic, helpful resolution message."""
result = model.invoke(prompt)
return {"response": result.content}
def check_sentiment(state: ReviewState):
if state['sentiment'] == "positive":
return "positive_response"
else:
return "run_diagnosis"
Graph
Dla The Graph 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 preferować małe, łatwe do przetestowania jednostki nad rozbudowanymi skryptami. Gdy dany krok zawiedzie, powinno to wskazywać na konkretną odpowiedzialność, a nie na skomplikowaną strukturę przepływu. Ustawiaj punkty kontrolne po kosztownych wywołaniach modelu, aby ponowna próba nie generowała dodatkowych opłat za tę samą pracę.
graph = StateGraph(ReviewState)
graph.add_node("find_sentiment", find_sentiment)
graph.add_node("positive_response", positive_response)
graph.add_node("run_diagnosis", run_diagnosis)
graph.add_node("negative_response", negative_response)
graph.add_edge(START, "find_sentiment")
graph.add_conditional_edges("find_sentiment", check_sentiment)
graph.add_edge("positive_response", END)
graph.add_edge("run_diagnosis", "negative_response")
graph.add_edge("negative_response", END)
workflow = graph.compile()
Testowanie
Aby to przetestować, zdefiniuj 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. Nadaj nazwy poszczególnym elementom, zdefiniuj kryteria sukcesu i odrzuć przypadkowe, częściowe ukończenie zadań. Ustal punkt kontrolny po kosztownych wywołaniach modelu, aby ponowna próba nie generowała dodatkowych opłat za tę samą pracę.
Główny model myślowy
Dla podstawowego modelu mentalnego 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 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 wersji demonstracyjnej do środowisk współdzielonych. Ustal punkt kontrolny po kosztownych wywołaniach modelu, aby ponowna próba nie generowała dodatkowych opłat za tę samą pracę. Dla podstawowego modelu mentalnego 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 na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Zdokumentuj zarówno ścieżkę prawidłowego działania, jak i ścieżkę naprawczą. Próby ponowne, mechanizmy kontroli ludzkiej oraz obsługa wiadomości błędowych stanowią część produktu, a nie elementy dodawane później.
Co dalej
Aby przejść do następnego kroku, należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany etap oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić dany etap na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Lepiej używać małych, testowalnych jednostek niż rozbudowanych skryptów. Gdy jakiś etap zawodzi, powinno to wskazywać na konkretną odpowiedzialność, a nie na skomplikowaną strukturę procesu. Trzeba oddzielić planowanie od wykonywania zadań za pomocą narzędzi. Planista proponuje rozwiązania; wykonawca je modyfikuje; sprawdzający porównuje wyniki z założonym celem.
Ustrukturyzowane uczenie się poza blogami
Trzeba oddzielić planowanie od wykonywania zadań za pomocą narzędzi. Planista proponuje rozwiązania; wykonawca je modyfikuje; sprawdzający porównuje wyniki z założonym celem.
Kursy
Trzeba oddzielić planowanie od wykonywania zadań za pomocą narzędzi. Planista proponuje rozwiązania; wykonawca je modyfikuje; sprawdzający porównuje wyniki z założonym celem.
List kontrolny operacyjny
Punkt kontrolny po drogich wywołaniach modeli, aby ponowna próba nie generowała dodatkowych opłat za tę samą pracę.
Zachowuj prosty i typowany stan grafu. Wkładki nawarstwione utrudniają określenie, który węzeł zapisał dane w danym polu, oraz powodują problemy przy kontynuowaniu pracy po przerwach.
Napisz krótki przewodnik: jak rotować klucze, jak opróżniać kolejkę z zadań, jak cofnąć ostatnią zmianę.