LangGraph объяснен: графы, состояние, маршрутизация и шаблоны для производства
Как LangGraph моделирует агентов как циклические графы с типизированным состоянием, редукторами, точками контроля, маршрутизацией, инструментами и циклами ReAct, а также шаблонами для промышленного использования.
Источники: Mastering LangGraph: The Complete Technical Guide to Building Production-Grade Agentic AI Systems
Первая волна приложений на основе LLM представляла собой простой обмен: отправляется запрос, получается ответ. Агенты — это другой тип программ. Они рассуждают на нескольких этапах, принимают решения на основе того, что узнали до этого, и совершают действия в внешнем мире. Для этого требуется инфраструктура, построенная на циклах, ветвлениях и памяти, а не прямая линия от входных данных к выходным.
LangGraph — одна из таких платформ. Она предназначена для приложений с состоянием, в которых один или несколько агентов, управляемых LLM, работают вместе. Вместо линейной цепи она позволяет описывать ориентированную графу, который может содержать циклы, осуществлять условное направление потока данных, сохранять постоянное состояние и координировать вызовы инструментов. Это не просто удобства. Агенту, который должен справляться с неопределенностью, восстанавливаться после ошибок и совершенствовать свою работу в течение нескольких попыток, необходимы все эти возможности.
В следующем разделе рассматривается внутренняя работа фреймворка, почему важны выбранные им принципы проектирования и в каких случаях применимы те или иные шаблоны. К концу вы сможете уверенно принимать архитектурные решения, отлаживать поведение агентов, которое кажется странным, и адаптировать фреймворк под собственные потребности.
Графы как основной строительный блок
Более старые инструменты оркестрации моделируют рабочий процесс в виде прямой цепи или, в лучшем случае, ориентированного ациклического графа. Это подходит для предсказуемых задач, но теряет эффективность, когда агенту необходимо повторять действия, делать резервные копии или выбирать другой путь в процессе выполнения. LangGraph исходит из противоположной предпосылки и считает ориентированный граф с циклами своей основной примитивной структурой.
Почему цепь недостаточна
Разница между цепями и графами носит практический, а не формальный характер. Цепь предполагает, что при написании кода вы знаете точный порядок выполнения операций. Граф же принимает тот факт, что путь в системе зависит от состояния во время выполнения, промежуточных результатов и условий, которые никто не может предсказать.
Представьте агента, исследующего компанию. Он начинает с финансовых данных. То, будет ли он затем собирать новости, аналитические отчеты или изучать документы конкурентов, зависит от того, что покажут финансовые показатели. Такое условное, повторяющееся поведение требует как циклов, так и ветвлений, а цепь не может выразить ни то, ни другое.
Типичный паттерн агента представляет собой цикл: анализируются действия, которые необходимо выполнить, они выполняются, наблюдается результат, и процесс повторяется до достижения цели. При использовании инструментов на основе цепочек у вас есть два не очень хороших варианта: либо развернуть цикл в фиксированное количество шагов, что убивает гибкость, либо написать логику управления самостоятельно вне фреймворка, что жертвует возможностью комбинирования компонентов. В LangGraph сам цикл является первоклассной концепцией, выраженной в виде циклической графики с условными ребрами.
Узлы
Узел — это отдельный шаг вычислений. Он получает текущее состояние, выполняет какие-то действия и возвращает обновления. Эти действия могут включать вызов большой языковой модели для принятия решения, вызов инструмента для взаимодействия с внешней системой, преобразование данных или какую-то логику маршрутизации.
Узлы — это обычные функции на Python с определённой структурой: входом служит текущее состояние, а выходом — словарь с обновлениями. Такой функциональный интерфейс позволяет их комбинировать и легко тестировать. Узел никогда не изменяет состояние на месте; он сообщает о желаемых изменениях, а LangGraph объединяет их согласно заданным правилам.
Узлы могут быть настолько простыми, как один вызов большой языковой модели, или настолько сложными, как логика с несколькими шагами. Некоторые вызывают другие целые графы, что позволяет создавать иерархические агенты. Другие работают асинхронно или используют логику повторных попыток с экспоненциальным откладыванием. Фреймворк не интересуется тем, насколько сложен узел внутри.
Рёбра
Рёбра определяют, куда будет направлено управление дальше, и существуют два вида рёбер с совершенно разной семантикой.
- Статические ребра являются детерминистичными. Как только узел A завершает свою работу, управление всегда переходит к узлу B. Они ведут себя как обычные вызовы функций и подходят для последовательностей, известных заранее. После инициализации исследовательской задачи, например, всегда следует сбор данных.
- Условные ребра определяют маршрут динамически в зависимости от состояния. После завершения сбора данных может потребоваться решить, достаточно ли данных для начала анализа или следует попытаться снова выполнить неудачные запросы API. Такое решение невозможно принять на этапе проектирования, поэтому функция маршрутизации принимает его во время выполнения программы.
Функция маршрутизации анализирует текущее состояние и возвращает строку с указанием пути, который следует выбрать. Фреймворк хранит сопоставление этих строк с целевыми узлами. В результате получается способ создания деревьев принятия решений, логики повторных попыток, обработки ошибок и адаптивных потоков, при этом маршрутизация остается явной и поддающейся тестированию.
Состояние как общая память
Управление состоянием — это та часть дизайна LangGraph, которая делает его особенно интересным. Объект состояния представляет собой общую структуру, перемещающуюся по графу. Каждый узел считывает текущее состояние, а любые внесенные изменения объединяются до того, как будет обработан следующий узел. Таким образом, каждый шаг основывается на результатах предыдущих шагов.
Состояние определяется с помощью словарей с типизацией или моделей Pydantic, что обеспечивает типобезопасность и четкие правила взаимодействия между узлами. Схема указывает, какие поля существуют, какой у них тип и как происходит объединение обновлений. Этот аспект легко упустить из виду, но он имеет огромное значение.
Когда узел возвращает обновление, LangGraph должен решить, как его объединить с уже существующим содержимым. Для строки или числа замена старого значения кажется очевидной. Однако с списком или словарем всё не так просто. Следует ли добавить возвращённый список в конец, заменить старый список или объединить их элемент за элементом? На эти вопросы отвечают редьюсеры.
Редьюсеры
Редьюсер — это функция, которая определяет, как обновление объединяется с существующим состоянием. Благодаря редьюсерам состояние LangGraph превращается из простого контейнера в структуру, способную обрабатывать паттерны накопления данных.
По умолчанию новое значение просто заменяет старое. Это подходит для большинства полей, но не подходит для данных, которые накапливаются. Представьте список ошибок, собирающий проблемы во время работы. Вы не хотите, чтобы каждый новый элемент стирал предыдущие записи — вам нужно, чтобы новые ошибки добавлялись рядом со старыми. Редьюсер add_messages следует этой идее, и этот подход применим и к другим типам данных.
Вы можете написать собственный редьюсер для любого поля. Его входными данными являются значение, уже находящееся в состоянии, и новое значение; выходным — значение, которое поле должно содержать в итоге. Для списков ошибок он может объединять их, для словарей — глубоко объединять вложенные структуры, а для счетчиков — складывать числа.
Редьюсеры привязываются с помощью типовых хэштегов Annotated в Python, поэтому схема остается декларативной:
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
Это делает поведение слияния явным и централизованным, вместо того чтобы оно было рассеяно по отдельным узлам.
Создание точек контроля
Агенты в производственной среде часто работают длительное время, выполняют дорогостоящие запросы к API или обрабатывают операции, которые не должны потеряться из-за временных сбоев. Механизм создания точек контроля решает эту проблему. При его включении LangGraph сохраняет полное состояние после завершения работы каждого узла. Если процесс зависает или у него заканчивается память, выполнение может быть возобновлено с последней точки контроля, вместо того чтобы начинаться заново. Хрупкий последовательный скрипт превращается в рабочий процесс, возможный к возобновлению.
Точки контроля также позволяют использовать подход с участием человека. Выполнение может быть приостановлено в выбранной точке, чтобы человек мог её проверить или внести изменения, после чего продолжиться после его ответа. Поскольку точка контроля фиксирует точное состояние на момент приостановки, не имеет значения, сколько дней пройдёт между этими моментами.
Хранилище, используемое за его спиной, является подключаемым. Проверка состояния в памяти подходит для разработки, SQLite обеспечивает локальную сохранность данных, а Redis подходит для распределённых систем. Структура графа остаётся прежней, меняется только реализация проверки состояния.
Условное маршрутизирование
Маршрутизирование — это тот момент, когда поведение становится по-настоящему динамичным. Выбор следующего шага во время выполнения на основе накопленного состояния — вот что отличает жёсткую автоматизацию от адаптивного агента.
Функции маршрутизирования и сопоставления рёбер
Функция маршрутизации — это небольшая функция на Python, которая анализирует состояние и возвращает строку. Когда выполнение достигает узла с условием, LangGraph вызывает эту функцию, берёт полученную строку, находит соответствующий узел в таблице сопоставлений и передаёт управление ему. Поскольку маршрутизация осуществляется через строки, а не напрямую через ссылки на узлы, вы можете редактировать таблицу сопоставлений, не меняя функцию, или заменить её на другую функцию маршрутизации, не изменяя структуру графа.
Типичные вопросы маршрутизации включают определение наличия достаточного количества данных для продолжения работы, проверку успешности операции или необходимости её повторной попытки, выяснение, не достигнут ли лимит повторных попыток, а также оценку степени надёжности анализа для принятия решения. Функция может видеть весь состояние, поэтому она может сравнивать несколько полей, выполнять расчёты, учитывать внешние условия или применять бизнес-правила. Единственное требование — чтобы функция была детерминистичной и чистой, то есть возвращала одинаковый результат для одинакового состояния.
Избегание бесконечных циклов
Циклы позволяют осуществлять мощную итерацию, но в то же время создают риск возникновения бесконечных петель. Агент, застрявший в попытках повторения действий, может бесконечно потреблять ресурсы, и LangGraph предлагает несколько способов этого предотвратить.
Самый простой способ — использование счётчика в состоянии. Функция маршрутизации сравнивает его с максимальным значением и направляет управление на узел завершения, как только значение превышает этот лимит. Почти каждый производственный агент использует эту схему. Более совершенные варианты включают обнаружение сходимости, при котором процесс останавливается, когда разница между итерациями становится меньше заданного порога, а также завершение на основе истечения времени, при котором маршрутизация учитывает пройдённое время.
Главный вывод заключается в том, что предотвращение циклов — это задача маршрутизации, а не ограничение самой рамочной структуры. LangGraph предоставляет инструменты для создания защитных механизмов, адаптированных под конкретные случаи, вместо того чтобы навязывать универсальные правила.
Инструменты: от языка к действию
Агенты становятся по-настоящему полезными, когда большие языковые модели могут взаимодействовать с внешними системами. Инструменты позволяют преобразовывать понимание языка в реальные действия в реальном мире.
Шаблон выполнения
В LangGraph инструмент представляет собой узел, выполняющий какую-либо операцию вне процесса. Он может вызывать API, запрашивать данные из базы данных, выполнять код или искать информацию в Интернете. Инструмент берет параметры из текущего состояния, выполняет операцию и возвращает результаты в виде обновлений состояния.
Эта схема становится мощной при сочетании с способностью к принятию решений у ИИ. Узел ИИ считывает текущее состояние и определяет, какой инструмент необходимо вызвать. Функция маршрутизации направляет управление к соответствующему узлу инструмента. Инструмент выполняет свою работу и записывает результат в состояние. Управление возвращается к ИИ, который интерпретирует результат и выбирает следующий шаг. Этот процесс продолжается до достижения цели.
Современные модели поддерживают вызов функций, то есть они генерируют структурированные запросы с указанием инструмента и его параметров. Узел ИИ парсит такой запрос из ответа модели и записывает выбранный инструмент в состояние. Функция маршрутизации считывает это решение и направляет поток к соответствующему узлу инструмента.
Обработка ошибок инструментов
Внешние системы могут выходить из строя, истекать по времени, возвращать некорректные данные и нарушать предположения. Узлы инструментов должны учитывать такие ситуации.
- Ловля и отчетность. Ловить исключения, записывать их в журнал и возвращать детали ошибки в состоянии, вместо того чтобы позволять им привести к сбою агента. Тогда большая языковая модель сможет понять, что пошло не так, и попробовать снова с другими параметрами или выбрать другой подход.
- Истечение времени. Оборачивать операции так, чтобы они прерывались после достижения максимального времени выполнения. Одна медленная API не должна замедлять весь агент.
- Проверка корректности. Анализировать ответы и проверять их согласно схемам. Некорректные данные должны запускать процедуру обработки ошибок, а не сохраняться там, где они могут нарушить работу последующих узлов.
Цикл ReAct
ReAct, сокращение от reasoning and acting, — это базовая архитектура агента, которую LangGraph естественным образом реализует, и рассмотрение её показывает, как взаимосвязаны остальные концепции.
Как работает цикл
Он начинается с узла рассуждений. Языковая модель анализирует текущее состояние и решает, что делать дальше: вызвать инструмент, запросить дополнительную информацию, дать окончательный ответ или попросить ввод от человека. Именно здесь проявляются способности модели, поскольку она может оценить сложный контекст и сделать тонкий выбор.
Если принято решение о действии, управление переходит к узлу действия, который выполняет выбранную операцию — будь то вызов API, вычисления или запрос к базе данных. Узел действия остается детерминированным и специализированным, выполняет запрос и возвращает результаты.
Затем следует узел наблюдения, который добавляет результаты в состояние системы и готовит их для использования большой языковой моделью. Он может форматировать данные, удалять лишние элементы или вычислять дополнительные показатели, делающие результаты более понятными. После этого цикл возвращается к процессу рассуждений с обновлённым состоянием. Большая языковая модель анализирует произошедшее и выбирает следующий шаг, продолжая работу до тех пор, пока у неё не будет достаточно информации для завершения задачи.
Как понять, когда остановиться
Решение о моменте завершения является важной частью цикла, и на практике наблюдаются несколько типовых подходов к этому.
- Цель достигнута. Самый простой случай: большая языковая модель сообщает, что задача выполнена, и предоставляет окончательный ответ. Функция маршрутизации это замечает и переходит к узлу завершения.
- Лимит итераций. После достижения максимального количества циклов «анализ — действие» цикл прекращается независимо от того, была ли цель достигнута, поэтому агент в конечном итоге всегда останавливается.
- Порог уверенности. Если модель достигает достаточного уровня уверенности, например 95%, она может прекратить работу раньше времени, вместо того чтобы собирать информацию с убывающей пользой.
- Критические ошибки. Когда критически важные операции продолжают сбоить или агент сталкивается с ситуацией, с которой не может справиться, он должен завершить работу с отчетом об ошибке, вместо того чтобы бесполезно продолжать.
Несколько агентов, работающих вместе
Некоторые задачи лучше решаются командой специализированных агентов, чем одним монолитным агентом. Графическое представление помогает наглядно показать основные модели сотрудничества.
Иерархия
В иерархической структуре планировщик высокого уровня делим работу и поручает её специализированным агентам. Он определяет общую цель и координирует действия, но не выполняет детальную работу. С точки зрения реализации некоторые узлы вызывают другие скомпилированные графы. Узел планирования может проанализировать сложную задачу, разложить её на части и запустить соответствующий граф для каждой части. Результаты возвращаются планировщику, который объединяет их в итоговый результат.
Основное преимущество — разделение ответственностей. Каждого специалиста можно разрабатывать, тестировать и настраивать отдельно, а планировщику достаточно знать, как их координировать, а не как они работают.
Равноправные узлы
Агенты также могут сотрудничать на равных, каждый внося свой экспертный вклад. Команда программных агентов может включать отдельных агентов для проектирования архитектуры, реализации, тестирования и документирования, причем все они обмениваются информацией через общий канал сообщений. Это достигается с помощью общего состояния, которое каждый агент может читать и изменять. Функция маршрутизации определяет, кто будет действовать дальше, исходя из текущего состояния и необходимых навыков. Каждый агент записывает свой вклад, сопровождая его метаданными о рассмотренных вопросах, затем передает управление дальше, а маршрутизатор выбирает следующего подходящего агента.
Сотрудничество на равных позволяет учитывать разнообразные точки зрения и помогает агентам обнаруживать ошибки друг у друга, поскольку один агент может заметить недостаток в рассуждениях другого.
Дебаты и консенсус
При принятии важных решений несколько агентов могут независимо решать проблему, а затем договариваться между собой. Этот подход заимствует идеи конституционного ИИ и рассматривает разногласия как сигнал качества. Три агента анализируют ситуацию, и каждый из них предлагает решение. Модератор поочередно проводит дебаты, в ходе которых каждый агент излагает свои аргументы и критикует остальных, а также должен ответить на конкретные замечания. После нескольких раундов на этапе формирования консенсуса обсуждение синтезируется в решение, при этом могут учитываться наиболее убедительные аргументы.
Такой подход позволяет выявлять галлюцинации и ошибки в логических рассуждениях, которые могли бы остаться незамеченными у одного агента, но будут обнаружены, когда несколько агентов рассматривают проблему с разных точек зрения.
Поиск информации внутри агентов
Метод генерации с усилением поиском предоставляет агентам доступ к большим базам знаний и материалам конкретной области, причем графическая структура делает его идеальным инструментом для этой цели.
Поиск по запросу
В классическом RAG информация загружается один раз в начале выполнения задачи. В агентном RAG поиск становится инструментом, который агент использует каждый раз, когда обнаруживает пробел в знаниях. Агент начинает рассуждения, опираясь на свои базовые знания. Когда он сталкивается с вопросом, на который не может ответить, или ему нужен дополнительный контекст, он формирует запрос на поиск, вызывает соответствующий инструмент и продолжает работу с полученной новой информацией.
Этот подход превосходит метод предварительной загрузки по двум причинам. Во-первых, он дешевле, поскольку агент загружает только необходимые данные. Во-вторых, он более точен, так как запросы формируются на основе того, что агент в данный момент понимает.
Запросы, определяемые состоянием
Настоящая польза проявляется тогда, когда запросы отражают всю собранную до этого информацию, а не только первоначальный вопрос. Возьмём, к примеру, расследование в компании: оно может начаться с запроса на получение общего обзора. В результате упоминается недавнее приобретение, что побуждает сформулировать целенаправленный запрос об этой сделке. Это выявляет регуляторные проблемы, которые заставляют задать вопрос о соответствующих правилах. Каждый поиск опирается на предыдущий, поэтому получается сфокусированное расследование вместо разрозненного сбора данных.
Несколько источников
Агенты часто обращаются к источникам с разной задержкой, стоимостью и надёжностью: внутренним документам, внешним API, поиску в Интернете, специализированным базам данных. LangGraph поддерживает стратегии работы с несколькими источниками. Агент может сначала проверить быструю локальную кэш-память, затем обратиться к API и использовать дорогостоящий поиск в Интернете только в крайнем случае. Или же он может одновременно запрашивать несколько источников и просить большую языковую модель согласовать возможные противоречивые ответы.
Логика маршрутизации может выбирать источник в зависимости от типа вопроса: фактологические запросы направляются в структурированную базу данных, концептуальные вопросы — в систему векторного поиска среди документов, запросы о недавних событиях — в поисковик в интернете, а исторические вопросы — в тщательно отобранную базу знаний.
Подготовка к использованию в производстве
Агент для демонстрации концепции легко создать с помощью LangGraph. Однако для использования в производстве требуются дополнительные условия, связанные с надежностью, возможностями мониторинга и операционными аспектами.
Обработка ошибок на всех уровнях
Агенты обработки производства устраняют сбои на нескольких уровнях. Узлы инструментов захватывают ожидаемые ошибки и возвращают их в виде обновлений состояния, а не исключений. Функции маршрутизации проверяют условия ошибок и настраивают пути повторных попыток с экспоненциальным откладыванием. В графе предусмотрены специальные узлы обработки ошибок, которые анализируют накопленные ошибки и принимают решение о том, следует ли повторить попытку, перейти на резервный вариант или корректно завершить работу. Для критически важных операций механизм разрыва цепочки сбоев может приостановить попытки после многократных неудач, предотвращая каскадные сбои и снижая дополнительную нагрузку на неисправный сервис.
Просмотр произошедшего
Когда что-то идет не так, необходимо знать, что сделал агент и почему. LangGraph интегрируется с такими платформами, как LangSmith, чтобы предоставлять подробную информацию о выполнении каждого узла, переходах состояний и вызовах LLM. Узлы должны генерировать структурированные логи с достаточным количеством контекста для объяснения принятых ими решений. Информация о времени выполнения помогает выявить узкие места, подсчет токенов способствует оценке затрат, а отслеживание взаимодействия с пользователем используется для оценки эффективности. Особенно удобно воспроизведение действий с точек контроля: вы загружаете именно то состояние, в котором возникла ошибка, и пошагово выясняете коренную причину.
Снижение затрат
В большинстве агентов основную часть затрат составляют вызовы LLM, но существуют некоторые подходы, позволяющие сократить их без снижения качества.
- Выбор модели. Используйте мощные модели, такие как GPT-4, только для сложных задач на рассуждения. Простые задачи на классификацию или извлечение данных лучше передавать более быстрым и дешевым моделям, применяя логику маршрутизации, основанную на анализе задачи.
- Кэширование ответов. Хранение результатов для идентичных или семантически похожих входных данных. Если анализ повторяется, кэширование позволяет избежать избыточных вызовов, а эмбеддинги могут соответствовать запросам, сформулированным по-разному, но означающим одно и то же.
- Ограничение длины запросов. Краткие запросы, содержащие только необходимую информацию, экономят токены. Шаблоны с заменой переменных обеспечивают их последовательность.
- Раннее завершение. Прекращение работы, когда у агента уже достаточно информации, вместо использования всего установленного лимита итераций.
Руководящие принципы проектирования
Развертывание агентов LangGraph показывает, какие особенности отличают надежные системы от хрупких прототипов.
Схема состояния
Схема является основой. Используйте модели Pydantic вместо свободных словарей, чтобы проверка позволяла выявлять ошибки на ранней стадии, а также документируйте значение и назначение каждого поля. Опциональные поля позволяют разным узлам постепенно добавлять свои данные, в то время как обязательные поля гарантируют наличие критически важной информации. Союзы с дискриминацией позволяют обрабатывать состояния, которые меняются в зависимости от выбранного пути. Избегайте глубокой вложенности, которая затрудняет доступ к полям. Возможно, стоит упростить структуру, использовать названия, отражающие взаимосвязи между элементами, и разделять метаданные от данных собственно домена, чтобы информация управления оставалась отдельной.
Границы узлов
Хорошие узлы эффективно выполняют одну задачу. Это позволяет использовать их в разных графах, а также упрощает тестирование и обслуживание. Узлы-инструменты должны взаимодействовать только с внешними системами, не содержащими бизнес-логику. Узлы-трансформации выполняют преобразования без принятия решений. Узлы-решения направляют поток данных без выполнения операций. Избегайте скрытых побочных эффектов: узлы должны быть максимально «чистыми», явно возвращая информацию обо всех изменениях состояния вместо того, чтобы изменять глобальные переменные.
Форма графа
Структура должна отражать способ рассуждений агента. Начните с этапа настройки, в ходе которого проверяются входные данные и формируется контекст. Затем собирайте данные, возможно, параллельно. Добавьте узлы анализа, затем узлы синтеза, которые генерируют результат, и узлы завершения, отвечающие за очистку. Размещайте условные ребра в точках принятия решений, где следующий шаг зависит от полученных данных, а статические ребра — там, где поток является детерминированным. Сохраняйте каждую графику на одном уровне абстракции. Если часть графики реализует сложную подпроцедуру, вынесите её в отдельную графику и представьте в виде узла.
Тестирование
Графы можно тестировать на нескольких уровнях. Проводите тесты отдельных узлов путем передачи имсимулированных состояний и проверки полученных обновлений. Тестируйте функции маршрутизации, подавая различные состояния и проверяя возвращаемый путь. Проводите интеграционные тесты всего графа с известными входными данными и проверяйте конечное состояние. Имитируйте ответы больших языковых моделей, чтобы тесты были быстрыми и детерминированными, а также используйте записанные реальные ответы для создания реалистичных условий тестирования. Тестирование на основе свойств позволяет проверять поведение в широком диапазоне входных данных. Тщательно протестируйте критические пути, особенно пути с ошибками, поскольку их трудно вызвать в реальных условиях, но они крайне важны, когда это происходит.
Решение о необходимости использования
LangGraph — мощный инструмент, но не каждое приложение, использующее большие языковые модели, требует его применения.
Этот подход подходит тогда, когда агент должен итеративно рассуждать, собирать и анализировать информацию и принимать решение о необходимости дальнейших действий. Он также применим, когда поток управления зависит от состояния во время выполнения, как в случае повторных попыток, восстановления после ошибок или адаптивных рабочих процессов, когда несколько инструментов или систем имеют сложные взаимосвязи, когда состояние должно сохраняться между этапами или сессиями, когда выполнение должно приостанавливаться и возобновляться для людей, или когда несколько агентов сотрудничают или образуют иерархию.
Достаточно чего-то проще, когда задача заключается в простом запросе и ответе без циклов или ветвлений, поток является линейным и известен заранее, работа может представлять собой цепочку детерминированных шагов, ничто не должно сохраняться после одной только экспекуляции, или приложение обращается не более чем к одному-двум простым API. В таких случаях использование цепочек LangChain или прямых вызовов API даёт более понятный и легко обслуживаемый код по сравнению с принудительным преобразованием задачи в граф.
Постепенное развитие
Многие приложения начинаются просто и становятся сложнее. Это ожидается при разработке звукового дизайна. Начните с цепочки, но сохраняйте запросы, инструменты и бизнес-логику в виде модулей с слабой связностью, чтобы позже было легко преобразовать их в граф. Как только цепочка достигнет пяти-семи шагов или вы добавите вторую условную ветвь, подумайте о миграции, пока сложность не вышла из-под контроля.
Продвинутые техники
Помимо основ, существует несколько техник, которые открывают дополнительные возможности.
Параллельная обработка. Узлы, которые не зависят друг от друга по результатам своей работы, могут выполняться одновременно. Например, узлы сбора данных, обращающиеся к разным API, сокращают общее время выполнения при параллельной работе, а фреймворк собирает и объединяет результаты. Для этого необходимы явные параллельные связи, и нужно убедиться, что узлы действительно независимы, без скрытой взаимосвязи через общие ресурсы или глобальное состояние.
Стриминг. Для длительно работающих агентов отображение промежуточных результатов улучшает пользовательский опыт. Узлы могут отправлять частичные обновления состояния, которые наблюдатели видят мгновенно. Это подходит для генерации отчетов, где абзацы могут появляться по мере их написания, а также для поиска, при котором результаты отображаются по мере их нахождения.
Подграфы. Сложные агенты получают преимущества от иерархического разложения. Подграфы компилируются отдельно и используются в качестве узлов в родительском графе, получая подмножество состояния родителя и возвращая обновления, которые затем сливаются обратно. Разные инженеры могут отвечать за разные подграфы, развертывать и тестировать их независимо, а также повторно использовать общие подграфы в нескольких родительских структурах.
Динамические изменения графа. Большинство графов фиксируются на этапе проектирования, но в некоторых сложных случаях граф может изменяться во время выполнения. Агент-планировщик может создать специальный граф после анализа задачи, динамически формируя узлы и рёбра. Это затрудняет понимание поведения, поэтому такой подход следует применять осторожно. Однако он позволяет мета-агентам проектировать и запускать специальные рабочие процессы для новых типов задач.
Заключительные замечания
LangGraph отражает развитие набора инструментов для агентных систем. Его сила заключается не в сложности, а в том, насколько примитивы соответствуют поведению агентов: они рассуждают, действуют и наблюдают в циклах, принимают решения на основе накопленных знаний, координируют использование инструментов и адаптируются при возникновении проблем. Вы можете напрямую использовать эти шаблоны, вместо того чтобы создавать их с нуля.
Для получения хороших результатов необходимо овладеть управлением состоянием, условным маршрутизированием и интеграцией инструментов как архитектурными шаблонами, а не просто как функциями. Лучшие приложения характеризуются тщательно спроектированными схемами состояния, четким распределением обязанностей между узлами, продуманной обработкой ошибок и высоким уровнем наблюдаемости. Фреймворк предоставляет инструменты, а не готовые решения. Качество их применения зависит от ваших знаний в области и собственного суждения, поэтому начните с простого, заранее проверяйте предположения и позвольте реальным требованиям, а не вымышленным, формировать архитектуру.
Связанные материалы
- Агенты или рабочие процессы? Разделение процессов рассуждения и выполнения в корпоративном ИИ — Используйте агентов для определения намерений и поиска информации, а детерминистические рабочие процессы — для обработки транзакций: как RAG, LangGraph, MCP, механизмы утверждения и SQS создают более безопасную архитектуру.
- Рекомендатор K-драм с использованием нескольких агентов: BERTopic, RAG и метод слияния рангов — Как рекомендатор K-драм, учитывающий предпочтения зрителей, объединяет теги BERTopic, поиск в ChromaDB, агента для анализа интервью, расширение запросов и метод слияния рангов перед повторной оценкой с помощью большой языковой модели.