LangGraph Reducers

Reducer — функция, определяющая, как обновление от узла соединяется со старым значением поля state. По умолчанию поле перезаписывается; reducer задаётся через Annotated[type, reducer_fn] и позволяет, например, накапливать список вместо замены.

Суть

Когда узел возвращает {"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] # история диалога

Связано с

  • LangGraph State — reducer'ы — это правила обновления полей State
  • LangGraph — часть базового механизма State Machine
  • Context Window — накопление messages ↔ рост контекста, требует управления

Открытые вопросы

  • add vs add_messages — когда важно умное слияние по id (дедуп, обновление сообщений)