LangGraph HITL

HITL в LangGraph — механизм паузы исполнения графа в критической точке, чтобы человек подтвердил/отредактировал действие, после чего исполнение возобновляется. Технически опирается на LangGraph Checkpointers: прервать и возобновить можно только персистентное состояние. Это конкретная реализация общего паттерна Human in the Loop.

Суть

Граф останавливается в заданной точке, отдаёт управление человеку, сохраняет состояние; человек одобряет/правит; граф продолжает с сохранённого места. Без прерывания (как в обычном ReAct-агенте) можно получить только итоговый результат, но не вмешаться по ходу.

Зачем это нужно

Контроль опасных и необратимых действий: банковская транзакция, отправка письма, удаление данных. HITL даёт три гарантии — контроль опасных действий, утверждение и исправление решений до их выполнения.

Как работает

  • Паттерны взаимодействия: Approval (агент предлагает → человек approve/reject → продолжение/отмена); Edit (агент создаёт черновик → человек правит → агент продолжает с правками); Co-authoring (агент и человек поочерёдно дополняют).
  • Статическое прерывание: известно заранее, где встать — compile(checkpointer=..., interrupt_before=["human_approval"], interrupt_after=["important_action"]).
  • Динамическое прерывание: решение прервать принимается в рантайме внутри узла — interrupt({...}) или Command(interrupt=True).
  • Возобновление: получить состояние (aget_state), затем ainvoke(Command(resume={...}), thread); либо отредактировать состояние update_state(thread, feedback, as_node="human_review") и продолжить.
  • Streaming (astream) выдаёт результат после каждого узла — нужен, чтобы показать человеку, на чём граф встал.
  • Superstep — один цикл исполнения графа от старта до точки прерывания.
  • Осторожно с идемпотентностью: interrupt() возобновляет узел с начала, поэтому необратимый код (списание денег) нельзя ставить до interrupt() — см. LangGraph Reliability.

Пример

from langgraph.types import Command, interrupt

def human_node(state: State):
    feedback = interrupt({"question": "Одобряете заказ?", "amount": state["amount"]})
    return {"approved": feedback["approved"]}

app = builder.compile(checkpointer=PostgresSaver(conn))
# первый запуск прервётся внутри human_node; затем:
await app.ainvoke(Command(resume={"approved": True}), thread)

Связано с

  • Human in the Loop — общий паттерн; здесь — его LangGraph-реализация
  • LangGraph Checkpointers — прерывание/возобновление требует персистентности
  • LangGraph Reliability — идемпотентность узлов до interrupt()
  • Guardrails — HITL как контроль опасных действий

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

  • approval fatigue (как не утопить пользователя в подтверждениях) → см. Human in the Loop (ждёт курс: лекция #22 Enterprise & MCP, 2026-07-16)