Урок 3 из 8

Состояние: общая память процесса

Цель урока: понять, что такое состояние (State), почему это сердце любого графа и как правильно решать, что в нём хранить.

Зачем нужно состояние

Вспомни аналогию из урока 1: отдел, работающий по регламенту. Если сотрудники передают работу друг другу на словах - информация теряется. Поэтому заводят общую карточку заказа: каждый читает её и дописывает своё.

Состояние в LangGraph - это и есть такая карточка. По документации: «общая структура данных, представляющая текущий снимок приложения». Каждый узел получает состояние на вход и возвращает обновление - что изменилось.

Аналогия

Состояние - это бланк с полями, который ты сам придумываешь под свой процесс. Для обработки заявки: «текст заявки», «категория», «черновик ответа», «вердикт проверки». Проектирование состояния - это ответ на вопрос: что должны знать все участники процесса?

Главное правило узла

Узел не переписывает всю карточку - он возвращает только те поля, которые изменил. LangGraph сам аккуратно вливает обновление в общее состояние. Так узлы не мешают друг другу и не затирают чужую работу.

Карточка до заявка: «не могу оплатить» категория: - черновик: - вердикт: - Классификатор узел · вызов LLM + категория: оплата Карточка после заявка: «не могу оплатить» категория: оплата черновик: - вердикт: - читает вернул только изменение LangGraph сам вливает в карточку
Узел вернул одно поле - остальная карточка не тронута. Работа других шагов в безопасности.

Проектируя состояние, ты отвечаешь на два вопроса: какие поля нужны (бланк) и какое поле заполняет каждый шаг (зона ответственности). Это работа на уровне здравого смысла - код тут не нужен.

Как это выглядит в коде - заглянуть по желанию

Читать код не нужно: работу ты принимаешь по схемам и поведению (урок 8), а пишет его Claude Code. Это «внутренности» для любопытных - каждая строчка переведена на человеческий.

# Состояние - «бланк» процесса обработки заявки
class State(TypedDict):
    zayavka: str          # исходный текст от клиента
    kategoriya: str       # оплата / техподдержка / продажа
    chernovik: str        # черновик ответа
    verdict: str          # вердикт проверки: ok / dorabotat

# Узел - функция: получает состояние, возвращает ЧТО ИЗМЕНИЛОСЬ
def klassifikator(state: State):
    otvet = llm.invoke(f"Определи категорию: {state['zayavka']}")
    return {"kategoriya": otvet.content}  # только своё поле!

Поле-копилка и поле-перезапись

По умолчанию новое значение поля заменяет старое. Но некоторым полям нужно накапливаться: например, истории сообщений диалога. Для этого у поля назначают правило слияния - редьюсер (reducer).

Перезапись (по умолчанию) поле «вердикт» доработать пришло новое ок осталось только последнее Копилка (с редьюсером) поле «история сообщений» сообщение 1 сообщение 2 + сообщение 3 новое добавилось - история цела
Одно и то же действие - «узел вернул новое значение» - даёт разный результат: перезапись хранит последнее, копилка копит всё.

Самый ходовой готовый вариант - MessagesState: состояние с полем messages, где сообщения диалога накапливаются автоматически. Для чат-приложений его берут как основу.

Правило: храни сырьё, а не готовое блюдо

Официальная методичка LangGraph советует: в состоянии храни сырые данные (список найденных документов, цифры, факты), а не отформатированный текст («Вот что я нашёл: ...»). Причина: сырые данные каждый узел может использовать по-своему, а красивый текст пригоден только для показа.

Сырьё в состоянии список: 10 отзывов клиентов статистика цитаты выводы каждый узел использует по-своему Готовый текст в состоянии «Анализ показал, что...» показать пользователю больше ни для чего не годится
Сырьё оставляет свободу всем следующим шагам. Красивый текст оформляй в последнем узле - перед показом.
Частая ошибка

Свалить всё в одно поле «context», куда узлы дописывают текст. Через пять шагов там каша, из которой ничего не достать. Правильно: отдельное поле под каждый смысл - как отдельные графы в CRM, а не одна заметка «всё обо всём».

Проверь себя

1. Что возвращает узел после своей работы?

2. Полю «история сообщений диалога» нужен редьюсер-копилка. Зачем?

3. Агент нашёл 10 отзывов клиентов для анализа. Что положить в состояние?

Спроси своего Claude

Потренируйся проектировать: «Я делаю [твой процесс]. Помоги спроектировать состояние: какие поля нужны, какие из них копилки?» Именно так начинается любой LangGraph-проект.