Суть
Когда узел возвращает {"field": value}, движок должен решить: заменить старое значение или объединить. Это решение и есть reducer. Без reducer'а — перезапись. С reducer'ом — произвольная логика слияния (добавление в список, суммирование, дедупликация).
Зачем это нужно
Самый частый случай — история сообщений. Чат-бот не должен перезаписывать прошлые сообщения новым; их надо накапливать. Перезапись здесь потеряла бы весь диалог. Reducer add (или специальный add_messages) дописывает новое в конец списка вместо замены.
Как работает
- Синтаксис:
Annotated[<тип поля>, <reducer-функция>]. Reducer получает старое и новое значение, возвращает объединённое. - Готовые reducer'ы:
operator.add(конкатенация списков/сложение чисел),langgraph.graph.message.add_messages(умное слияние сообщений с учётом id). - Можно задать кастомную логику — обычную функцию или лямбду.
- Поле без
Annotated→ поведение по умолчанию: перезапись.
Пример
from typing import TypedDict, Annotated
from operator import add
from langgraph.graph.message import add_messages
class State(TypedDict):
simple_value: str # перезапись
numbers: Annotated[list, add] # накопление списка
total: Annotated[int, lambda x, y: x+y] # кастомная логика
messages: Annotated[list, add_messages] # история диалога
add или add_messages
add — обычная конкатенация: всё, что вернул узел, дописывается в конец. Этого достаточно для накопительных полей, где повторов не бывает по построению — собранные документы, лог шагов, найденные кандидаты.
add_messages умеет то, чего конкатенация не умеет: сопоставление по идентификатору. Сообщение с уже существующим id не добавляется вторым экземпляром, а заменяет прежнее. Это нужно ровно в двух ситуациях, и обе встречаются постоянно: повторный прогон узла после восстановления из чекпоинта или отмотки (LangGraph Time Travel) — без слияния по id история удвоится; и правка уже сказанного — редактирование сообщения человеком в точке HITL или замена черновика финальным ответом.
Практическое следствие: для поля с историей диалога всегда add_messages, для всего остального — add, пока не появится необходимость обновлять ранее записанное.
Связано с
- LangGraph State — reducer'ы — это правила обновления полей State
- LangGraph — часть базового механизма State Machine
- Context Window — накопление
messages↔ рост контекста, требует управления