Условные рабочие процессы LangGraph: разветвление без хаотичных запросов
Кодируйте механизм маршрутизации LangGraph с использованием операторов if-else в виде именованных условных рёбер с чёткими условиями состояний и возможностью восстановления при сбоях, вместо того чтобы включать входные запросы в разветвлённые структуры.
Источники: 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()
Тестирование
Для тестирования определите входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Рассматривайте этот этап как контракт между входными данными и проверенными результатами. Дайте названия элементам, определите критерии успеха и не допускайте молчаливого частичного выполнения. Создавайте точки контроля после дорогостоящих вызовов модели, чтобы повторная попытка не влекла за собой повторной оплаты за одну и ту же работу.
Для основной модели мышления необходимо определить входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Записывайте время выполнения и затраты рядом с функциональными результатами. Раннее отслеживание помогает избежать неожиданных счетов при переходе от демо-среды к общедоступным средам. Устанавливайте точку контроля после дорогостоящих вызовов модели, чтобы повторные попытки не влекли за собой повторной оплаты той же работы. Для основной модели мышления необходимо определить входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Документируйте одновременно «идеальный» сценарий работы и сценарий восстановления. Повторные попытки, проверки человеком и обработка неработающих сообщений являются частью продукта, а не элементами последующей доработки.
Что дальше
Для дальнейших действий необходимо заранее определить входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Лучше использовать небольшие, тестируемые единицы вместо обширных скриптов. При сбое шага причина должна быть связана с конкретной функцией, а не с запутанной цепочкой операций. Разделяйте планирование и выполнение с помощью инструментов. Планировщик предлагает решения; исполнитель вносит изменения; проверщик сравнивает результаты с поставленной целью.
Структурированное обучение за пределами блогов
Разделяйте планирование и выполнение с помощью инструментов. Планировщик предлагает решения; исполнитель вносит изменения; проверщик сравнивает результаты с поставленной целью.
Курсы
Разделяйте планирование и выполнение с помощью инструментов. Планировщик предлагает решения; исполнитель вносит изменения; проверщик сравнивает результаты с поставленной целью.
Чек-лист операций
Точка контроля после дорогостоящих вызовов моделей, чтобы повторная попытка не приводила к повторной оплате за ту же работу.
Сохраняйте состояние графа простым и типизированным. Вложенные структуры данных скрывают информацию о том, какой узел записал какое поле, и мешают возобновлению работы после прерываний.
Напишите краткий руководство: как обновлять ключи, как опустошать очередь, как откатывать последние изменения.