Головна / Статті

Умовні робочі потоки LangGraph: розгалуження без хаотичних запитів

Замість того, щоб вкладати розгалуження у запити, кодуйте механізм маршрутизації LangGraph типу if-else як іменовані умовні ребра з чіткими умовами стану та можливістю відновлення після збоїв.

Видавець: REACTAPP.TOP10 хв читання2192 слів

Джерела: Conditional Workflows in LangGraph: The If-Else of Agentic AI

У цьому посібнику створюється функціональний шлях для реалізації умовних робочих процесів у LangGraph: механізму If-Else в агентному ШІ. Основна увага приділяється контрактам, перевіркам та коду, який можна додати до репозиторію без необхідності здогадуватися щодо його призначення. Для отримання загального огляду спочатку визначте вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись здогадатися про прихований стан. Документуйте як успішний, так і відновлювальний шляхи виконання. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації.

Що взагалі таке умовний робочий процес?

Для чого взагалі потрібен умовний робочий процес? Спочатку необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись здогадатися про прихований стан. Краще використовувати невеликі, перевірювані одиниці коду замість об’ємних скриптів. Коли крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану структуру процесу. Схеми інструментів слід суворо обмежувати. Широкі параметри у вигляді вільного тексту сприяють втручанню ззовні та ускладнюють аудит.

Робочий процес №1: Розв’язання квадратного рівняння

Для робочого процесу №1: розв’язання квадратного рівняння, перед зміною коду необхідно визначити вхідні дані, виконавця кроку та критерії завершення. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не здогадуючись про прихований стан. Розглядайте цю стадію як контракт між вхідними даними та перевіреними результатами. Призначте назви елементів, визначте критерії успіху та не допускайте мовчазного часткового завершення. Суворо обмежуйте схеми інструментів. Широкі параметри у вигляді вільного тексту сприяють втручанню ззовні та ускладнюють аудит.

Структура робочого процесу

Щодо структури робочого процесу, необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Записуйте час виконання та витрати поруч із функціональними результатами. Рання видимість допомагає уникнути несподіваних рахунків, коли процес переходить від демо-версії до спільних середовищ. Суворо обмежуйте схеми інструментів. Широкі параметри у вигляді вільного тексту сприяють втручанню ззовні та роблять аудити дорогими. Щодо структури робочого процесу, необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Документуйте як оптимальний, так і альтернативний шлях виконання. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації.

Створення стану

Для створення системи необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись здогадатися про прихований стан. Краще використовувати невеликі, перевірювані одиниці коду замість об’ємних скриптів. Коли крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану структуру обробки даних. Створюйте точки контролю після дорогих викликів моделей, щоб повторна спроба не призводила до подвійного обчислення тієї самої роботи.

class QuadState(TypedDict):
    a: float
    b: float
    c: float
    equation: str
    discriminant: float
    result: str

Вузли

Для вузлів необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Розглядайте цю стадію як контракт між вхідними даними та перевіреними результатами. Призначте назви елементів, визначте критерії успіху та не допускайте мовчазного часткового завершення. Створюйте точки контролю після дорогих викликів моделі, щоб повторна спроба не призводила до подвійного оплати однакової роботи.

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"}

Функція маршрутизації — це ключова частина

Для функції маршрутизації — це ключова частина: перед зміною коду необхідно визначити вхідні дані, власника кроку та критерії завершення. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Записуйте час виконання та витрати поруч із функціональними результатами. Раннє відображення інформації запобігає несподіваним рахункам, коли процес переходить з демо-середовища у спільні. Створюйте точку контролю після дорогих викликів моделей, щоб повторна спроба не призводила до подвійного оплати того самого роботи. Для функції маршрутизації — це ключова частина: перед зміною коду необхідно визначити вхідні дані, власника кроку та критерії завершення. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Документуйте як успішний, так і відновлювальний сценарії роботи. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації.

def check_condition(state: QuadState):
    if state['discriminant'] > 0:
        return "real_roots"
    elif state['discriminant'] == 0:
        return "repeated_root"
    else:
        return "no_real_roots"

Об’єднання елементів

Щоб з’єднати все разом, необхідно визначити вхідні дані, виконавця кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Краще використовувати невеликі, перевірювані одиниці коду замість об’ємних скриптів. Коли крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність дій. Розділяйте планування та виконання завдань за допомогою інструментів. Планувальник пропонує рішення; виконавець його змінює; перевіряючий порівнює результати з поставленими цілями.

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()

Робочий процес №2: Обробник відгуків клієнтів (на основі LLM)

Для робочого процесу №2: Обробник відгуків клієнтів (на основі LLM), перед зміною коду необхідно визначити вхідні дані, власника кроку та критерії завершення. Оператори мають мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Розглядайте цю стадію як контракт між вхідними даними та перевіреними результатами. Призначте назви елементів, визначте критерії успіху та не допускайте беззвучного часткового завершення. Розділіть планування та виконання завдань за допомогою інструментів. Планувальник пропонує; виконавець здійснює зміни; перевіряючий порівнює результати з поставленими цілями.

Сценарій

Для цього сценарію необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість знову виконати крок з відомої точки контролю, не намагаючись вгадати прихований стан. Записуйте час виконання та витрати поруч із функціональними результатами. Раннє відображення інформації запобігає несподіваним рахункам, коли процес переходить від демо-середовища до спільних. Розділяйте планування та виконання за допомогою інструментів. Планувальник пропонує; виконавець здійснює зміни; перевіряючий порівнює результати з поставленими цілями. Для цього сценарію необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість знову виконати крок з відомої точки контролю, не намагаючись вгадати прихований стан. Документуйте як оптимальний, так і альтернативний шляхи виконання. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації.

Структуровані схеми вихідних даних

Для схем структурованого виводу необхідно перед зміною коду визначити вхідні дані, власника кроку та критерії завершення. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись визначити прихований стан. Краще використовувати невеликі, перевірювані одиниці коду замість об’ємних скриптів. Коли крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на складну ієрархію процесів. Схеми інструментів слід суворо обмежувати. Широкі параметри у вигляді вільного тексту сприяють втручанню ззовні та ускладнюють аудит.

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)

Стан

Для держави необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Розглядайте цю стадію як контракт між вхідними даними та перевіреними результатами. Позначте елементи проекту, визначте критерії успіху та не допускайте мовчазного часткового завершення роботи. Суворо обмежуйте схеми інструментів. Широкі параметри у вигляді вільного тексту сприяють втручанню ззовні та ускладнюють аудит.

class ReviewState(TypedDict):
    review: str
    sentiment: Literal["positive", "negative"]
    diagnosis: dict
    response: str

Вузли

Для The Nodes необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Записуйте час виконання та витрати поруч із функціональними результатами. Чітке бачення ситуації заздалегідь запобігає несподіваним рахункам під час переходу з демо-середовища у спільні. Суворо обмежуйте схеми інструментів. Широкі параметри у вигляді вільного тексту сприяють втручанню ззовні та роблять аудити дорогими. Для The Nodes необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Документуйте як успішний, так і відновлювальний сценарії роботи. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації.

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"

Граф

Для The Graph необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Краще використовувати невеликі, тестовані одиниці замість об’ємних скриптів. Коли крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану структуру обробки даних. Створюйте точки контролю після дорогих викликів моделі, щоб повторна спроба не призводила до подвійного обчислення тієї самої роботи.

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()

Тестування

Для тестування необхідно визначити вхідні дані, виконавця кроку та критерії завершення ще до змін у коді. Оператори мають мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Розглядайте цю стадію як контракт між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте мовчазного часткового виконання. Створюйте точки контролю після дорогих викликів моделі, щоб повторна спроба не призводила до подвійного оплати однакової роботи.

Для основної ментальної моделі необхідно визначити вхідні дані, відповідальну особу за кожен крок та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Записуйте час виконання та витрати поруч із функціональними результатами. Чим раніше це відбувається, тим менше ризик несподіваних рахунків під час переходу з демо-середовища у спільні. Створюйте точку контролю після дорогих викликів моделі, щоб повторна спроба не призводила до подвійного оплати однакової роботи. Для основної ментальної моделі необхідно визначити вхідні дані, відповідальну особу за кожен крок та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Документуйте як успішний, так і відновлювальний сценарії роботи. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації.

Що далі

Щодо наступних кроків, необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Краще використовувати невеликі, перевірювані одиниці коду замість об’ємних скриптів. Коли крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність дій. Розділяйте планування та виконання за допомогою інструментів. Планувальник пропонує; виконавець змінює; перевіряючий порівнює результати з поставленою метою.

Структуроване навчання за межами блогів

Розділяйте планування та виконання за допомогою інструментів. Планувальник пропонує; виконавець змінює; перевіряючий порівнює результати з поставленою метою.

Курси

Розділяйте планування та виконання за допомогою інструментів. Планувальник пропонує; виконавець змінює; перевіряючий порівнює результати з поставленою метою.

Чек-лист для операцій

Пункт перевірки після дорогих викликів моделей, щоб повторна спроба не стягувала плату за ту саму роботу.

Зберігайте стан графа у простій та типованій формі. Вкладені блоки приховують інформацію про те, який вузол заповнив яке поле, і ускладнюють продовження роботи після перерв.

Напишіть короткий посібник: як змінювати ключі, як спорожнювати чергу, як скасовувати останні зміни.