Головна / Статті

Зупинка та відновлення агентів LangGraph за допомогою interrupt() та Command

Як функції interrupt() та Command у LangGraph використовують чекпоїнти та потоки для призупинення агента з метою отримання схвалення, внесення змін чи введення даних від людини, а потім безпечного його продовження пізніше.

Видавець: REACTAPP.TOP14 хв читання3224 слів

Джерела: LangGraph From First Principles — Part 4: Human-in-the-Loop, Interrupts, Commands and Resumable Agents

Агент, який може переміщувати гроші, видаляти ресурси чи запускатися у продакшні, не повинен завжди мати можливість довести до кінця те, що почав. Іноді граф мусить навмисно зупинитися, чекати кілька годин на людину, а потім продовжити саме з того місця, де зупинився. У цій статті пояснюється, як LangGraph реалізує це за допомогою interrupt() та Command, чому це залежить від чекпоїнтів та потоків, а також які рішення все ще залишаються у вашому контролі перед запуском агентів з участю людини (HITL) у продакшні.

Основні елементи

HITL базується на трьох шарах. По-перше, виконання графу: стан потрапляє у вузол, а ребро вибирає наступний вузол.

STATE
  ↓
NODE
  ↓
EDGE
  ↓
NEXT NODE

По-друге, керування станом: вузли повертають оновлення, а редьюсери об’єднують їх у новий стан.

NODE
  ↓
STATE UPDATE
  ↓
REDUCER
  ↓
NEW STATE

По-третє, персистентність: чекпоїнтер зберігає стан у вигляді чекпоїнтів, групованих за потоками.

STATE
  ↓
CHECKPOINT
  ↓
CHECKPOINTER
  ↓
THREAD
  ↓
PERSISTENCE

Разом це дозволяє агенту працювати, пам’ятати інформацію та виживати після перезапуску. Що бракує, — це способу вирішити, чи варто йому взагалі продовжувати роботу.

Коли агент не повинен просто продовжувати

Користувач просить асистента з оплатами: «Перекажіть 50 000 рупій на цей рахунок». Агент готує транзакцію, і технічно немає нічого, що б заважало її виконанню.

User
  ↓
Agent
  ↓
Prepare Transfer
  ↓
Transfer ₹50,000
  ↓
Execute

Для такої значущої дії людина повинна спочатку переглянути пропозицію, щоб процес розвивався залежно від людського рішення.

User
  ↓
Agent
  ↓
Prepare Transfer
  ↓
┌─────────────────────┐
│   HUMAN APPROVAL    │
└──────────┬──────────┘
           │
       ┌───┴───┐
       ↓       ↓
    Approve   Reject
       │       │
       ↓       ↓
    Execute   Cancel

Тепер граф повинен навмисно зупинитися: не через помилку чи збій, а тому що тут процес вимагає людського втручання.

Що означає участь людини

HITL включає людські рішення у автоматизований процес. Замість того, щоб безпосередньо переходити від рішення до дії,

Agent
  ↓
Decision
  ↓
Action

агент пропонує дію, зупиняється та чекає на перегляд.

Agent
  ↓
Proposed Action
  ↓
PAUSE
  ↓
Human Review
  ↓
Decision
  ↓
Continue

Рецензент може схвалити, відхилити пропозицію, внести зміни, надати бракуючі дані, виправити агента чи обрати один із варіантів. Це підходить для будь-якого кроку з реальними наслідками.

Financial transactions
Sending emails
Deleting resources
Production deployments
Database modifications
Legal workflows
Publishing content
Access approvals
Sensitive tool calls

Що насправді потрібно для призупинення графа

Візьмемо ланцюг із кроком схвалення перед останнім вузлом.

Node A
  ↓
Node B
  ↓
Human Approval
  ↓
Node C

Якщо рецензент відповідає через шість годин, блокування процесу — це неправильна відповідь: це марнує ресурси працівника та призводить до зупинки під час першого запуску.

sleep(21600)

Натомість потрібно зберегти стан та зупинитися,

Node B
  ↓
SAVE STATE
  ↓
PAUSE EXECUTION
  ↓

потім відновити його пізніше, можливо, в іншому процесі, та продовжити роботу на наступному вузлі.

Application can stop──────── 6 HOURS LATER ────────Human responds
  ↓
RESTORE STATE
  ↓
CONTINUE EXECUTION
  ↓
Node C

Персистентність вже розв’язує половину цієї проблеми. Контрольні точки, механізм контролю, потоки та thread_id — саме те, що потрібно для тривалої призупинки.

Checkpoint
Checkpointer
Thread
thread_id
Persistence

Як interrupt() зупиняє виконання

interrupt() зупиняє граф та запитує зовнішній світ про значення. Його викликають усередині вузла з навантаженням, яке можна серіалізувати у форматі JSON та яке описує, що має побачити користувач. Цей фрагмент написаний на Python, попри початкову позначку.

from langgraph.types import interrupt
def approval_node(state):
  decision = interrupt({
        "question": "Do you approve this transaction?",
        "amount": state["amount"]
    })
  return {
        "decision": decision
    }

Коли виконання доходить до цього виклику,

interrupt(...)

вузол не доходить до оператора повернення. Виконання призупиняється, а навантаження повертається викликаючому для відображення.

approval_node
      │
      ↓
 interrupt()
      │
      ↓
┌─────────────────┐
│ EXECUTION PAUSED│
└─────────────────┘

Важливі два моменти. interrupt() вимагає графу, скомпільованого з checkpointer, оскільки стан зупинки має бути де-небудь збережений. Коли виконання продовжується, LangGraph знову запускає перерваний вузол з початку, причому interrupt() тепер повертає значення, введене користувачем, тож код перед цим викликом виконується двічі. Утримуйте побічні ефекти подалі від цієї частини вузла та перевірте поведінку у вашій версії в документації LangGraph.

Що зберігається під час переривання

Розгляньмо цю діаграму.

START
  ↓
Prepare Transfer
  ↓
Human Approval
  ↓
Execute Transfer
  ↓
END

Вузол підготовки оновлює стан, записується контрольна точка, а вузол схвалення викликає interrupt().

START
  ↓
Prepare Transfer
  ↓
State Updated
  ↓
Checkpoint
  ↓
Approval Node
  ↓
interrupt()

Текущий стан фіксується та записується у пам’ять.

Current State
      │
      ↓
Checkpoint
      │
      ↓
Persistent Storage

Тепер потік містить деталі передачі, статус очікування та причину зупинки.

THREAD: transaction-123
Checkpoint
────────────────────
amount       ₹50,000
recipient    Account X
status       pending
────────────────────

Execution:
PAUSED

Reason:
Human approval required

Це все, що потрібно для подальшої роботи. Без збереження даних процес просто зникне після переривання.

Agent
  ↓
interrupt
  ↓
process disappears
  ↓
???

Коли перевіряючий наступного дня пише „Схвалено“, ніхто не може зрозуміти, що саме було схвалено, де зупинилася діаграма чи який вузол слідує далі. Завдяки контрольним точкам стан завантажується з потоку та відновлюється перед продовженням роботи.

                  INTERRUPT
                       │
                       ↓
                  CHECKPOINT
                       │
                       ↓
                    THREAD
                       │
                       ↓
              PERSISTENT STORAGE

               ...time passes...

                   HUMAN INPUT
                       │
                       ↓
                    THREAD
                       │
                       ↓
               LOAD CHECKPOINT
                       │
                       ↓
                 RESTORE STATE
                       │
                       ↓
                    RESUME

Повернення до роботи за командою

Додаток відображає зміст переривання у вигляді запитання

Approve transfer of ₹50,000?

з двома кнопками,

[ APPROVE ]   [ REJECT ]

і переглядач обирає одну з них.

APPROVE

Відповідь надсилається через Command, який вказує графу, як діяти далі. Щоб продовжити, викличте граф за допомогою Command(resume=...) замість звичайного введення.

from langgraph.types import Command

graph.invoke(
    Command(resume="approved"),
    config=config
)

config має мати ту саму потокову структуру, що й призупинений запуск,

thread_id = transaction-123

адже ідентифікатор потоку — це те, що дозволяє LangGraph визначити, про яку призупинену виконуваність йдеться.

Етапи життєвого циклу поетапно

Запуск починається зі звичайного виклику,

graph.invoke()

читає свій поток з конфігурації,

thread_id = transaction-123

входить у вузол підготовки,

START
  ↓
Prepare Transfer

та записує дані про передачу у стан системи.

amount    = ₹50,000
recipient = Account X
status    = pending

Вузол схвалення викликає interrupt(),

Approval Node
     ↓
interrupt()

і виконання призупиняється.

EXECUTION PAUSED

Останній пункт перевірки залишається в безпеці під потоком.

Thread
  ↓
Checkpoint
  ↓
Persistent Storage

Людина бачить запит

Approve ₹50,000 transfer?

і відповідає.

YES

Додаток надсилає команду відновлення

Command(resume="approved")

до того самого потоку.

transaction-123

LangGraph відновлює виконання, передає рішення вузлу схвалення та продовжує до кінця.

Restore Execution
       ↓
Human Decision = approved
       ↓
Continue Graph
       ↓
Execute Transfer
       ↓
END

Кожен з наведених нижче варіантів є модифікацією цього життєвого циклу.

Людські рішення, крім «так» чи «ні»

Відповідь переглядача не обов’язково має бути двійковою.

YES / NO

Схвалення виконує пропозицію.

Agent Proposal
      ↓
Human
      ↓
APPROVE
      ↓
Execute

Відхилення скасовує її.

Agent Proposal
      ↓
Human
      ↓
REJECT
      ↓
Cancel

Редагування змінює її частини, наприклад суму, перш ніж граф продовжить роботу.

Agent:
Send ₹50,000
      ↓
Human:
Change to ₹40,000
      ↓
Graph continues with
updated information

Надання відсутньої інформації перетворює переривання на запитання.

Agent
  ↓
Missing Account Number
  ↓
INTERRUPT
  ↓
Human provides account
  ↓
RESUME

Вибір дозволяє агенту пропонувати альтернативи та залишити остаточне рішення людині.

Agent generates:
Option A
Option B
Option C
    ↓
Human chooses B
    ↓
Graph continues

HITL — це загальний спосіб введення даних від користувача у діючу структуру графа, а не лише діалог затвердження.

Команда як потік даних та контрольний потік

Команда також може оновлювати стан та вибирати наступну точку призначення.

Resume Execution
Update State
Choose Next Destination

Одна команда може встановити статус та надіслати виконання до конкретного вузла; у LangGraph ця форма зазвичай повертається від вузла.

Command(
    update={
        "status": "approved"
    },
    goto="execute"
)

Це поєднує два аспекти,

DATA FLOW
   +
CONTROL FLOW

адже маршрутизація раніше належала лише до ребер.

Edges control where we go.

Тепер один об’єкт може містити як зміну стану, так і наступний крок.

Command can participate in
state updates + control decisions.

Корекція стану перед продовженням

Припустимо, що держава тримає цю суму,

amount = 50000

і перевіряючий схвалює її з внесенням корекцій.

Approve, but change amount to 40000.

Потік даних проходить від початкового значення, через перевірку, до оновленого значення, і лише тоді продовжується (другий фрагмент виводиться на одну лінію).

BEFORE
amount = 50000        ↓Human Review        ↓UPDATEamount = 40000        ↓RESUME

Запит змінюється з „Чи можу я продовжити?“ на „Перевірити, виправити за потреби, а потім продовжити“.

Контроль викликів чутливих інструментів

HITL є найбільш практичним для використання перед ризикованими інструментами.

search_web()
read_database()
send_email()
delete_resource()
transfer_money()

Пошук в Інтернеті може виконуватися автоматично,

search_web()
      ↓
Execute Automatically

тоді як при видаленні ресурсу потрібно чекати на схвалення.

delete_resource()
       ↓
    INTERRUPT
       ↓
Human Approval

Кожен виклик інструменту проходить перевірку на чутливість: безпечні виклики виконуються, а чутливі зупиняються для отримання схвалення або скасування.

                    Agent
                       │
                       ↓
                   Tool Call
                       │
                       ↓
                 Sensitive Tool?
                   /          \
                 NO            YES
                 │              │
                 ↓              ↓
              Execute       INTERRUPT
                 │              │
                 │              ↓
                 │            Human
                 │          /       \
                 │      Approve    Reject
                 │         │          │
                 └─────────┘          ↓
                                    Cancel

Щоб дізнатися більше про повну реалізацію з підтримкою сховища, дивіться агентів з контролем схвалення в LangGraph.

Перегляд як свідома межа контролю

Людський перегляд — це не спосіб виправити агента, який недостатньо розумний. Це межа, яку ви ставите навмисно. Робота з низьким рівнем ризику виконується автоматично,

LOW RISK
Search
Read
Summarize
  ↓
Automatic

а робота з високим рівнем ризику проходить через людину.

HIGH RISKSend
Delete
Purchase
Transfer
Deploy
 ↓
Human Approval

Мета — визначити, де доцільна автономія, а не скорочувати її всюди.

Обробка відхилень та мовчання

Відхилення вимагають належного проектування.

Agent
  ↓
Prepare Action
  ↓
Interrupt
  ↓
Human
  ↓
REJECT

Запишіть результат у стан,

status = "rejected"

потім спрямуйте виконання залежно від нього за допомогою умовного ребра.

                Decision
                /      \
          approved     rejected
              │           │
              ↓           ↓
           Execute       Cancel
              │           │
              ↓           ↓
             END         END

Усі попередні концепції беруть участь, а людський вхід — це просто додаткова інформація, яка впливає на виконання.

State
Reducers
Conditional Routing
Checkpoints
Threads
Commands

Рецензенти також можуть ніколи не відповісти.

Interrupt
   ↓
Waiting for approval
   ↓
1 hour
   ↓
1 day
   ↓
7 days

Зупинений поток може чекати необмежено, тому вашому додатку потрібні правила керування.

Expiration
Timeout
Cancellation
Reminder
Escalation

Поширеним рішенням є обмежений за часом очікування, яке зазвичай реалізується через планувальник, що відновлює застарілі потоки після закінчення тайм-ауту.

Approval Requested
       │
       ↓
Wait up to 24 hours
       │
   ┌───┴────┐
   ↓        ↓
Response   Timeout
   │        │
   ↓        ↓
Resume    Cancel

LangGraph надає примітиви; бізнес-правила — це ваша справа.

Кілька контрольних точок та стрімінг

Агент розгортання може просити схвалення свого плану, а також ще раз перед запуском у продакшені.

START
  ↓
Analyze Code
  ↓
Generate Deployment Plan
  ↓
Human Approval #1
  ↓
Deploy to Staging
  ↓
Run Tests
  ↓
Human Approval #2
  ↓
Deploy Production
  ↓
END

Кожна контрольна точка зупиняє та відновлює один і той самий поток, залишаючи історію контрольних точок та переривань.

Thread
  │
  ├── CP1
  │
  ├── CP2
  │
  ├── INTERRUPT
  │
  ├── RESUME
  │
  ├── CP3
  │
  ├── INTERRUPT
  │
  ├── RESUME
  │
  └── END

Це стійкий робочий процес, яким користуються люди та агент. До цього моменту кожен приклад використовував блокуючий виклик,

graph.invoke(...)

який повертається лише після завершення виконання або зупинки.

START → A → B → C → END
                         ↓
                      RESULT

Інтерактивні додатки потребують оновлень статусу у момент їх виникнення, аж до подання запиту на схвалення.

START
  ↓
Planner Update ─────────→ UI
  ↓
Tool Call ──────────────→ UI
  ↓
Tool Result ────────────→ UI
  ↓
Approval Required ──────→ UI

Стрімінг передає ці події, щоб інтерфейс користувача міг відображати завершені кроки та поточне рішення.

┌──────────────────────────────────┐
│          Deployment Agent        │
├──────────────────────────────────┤
│                                  │
│ ✓ Analyzed repository            │
│                                  │
│ ✓ Generated deployment plan      │
│                                  │
│ ✓ Staging tests passed           │
│                                  │
│ ⚠ Production deployment ready    │
│                                  │
│ Human approval required          │
│                                  │
│ [ APPROVE ]     [ REJECT ]       │
│                                  │
└──────────────────────────────────┘

За цим екраном події надходять на фронтенд, а рішення повертається через Command(resume=...).

LangGraph
    │
    ↓
Streaming
    │
    ↓
Frontend
    │
    ↓
Human Decision
    │
    ↓
Command(resume=...)
    │
    ↓
LangGraph

Повна модель виконання

У одній діаграмі: користувач ініціює виконання на певному потоці, статус переміщується між вузлами та редюсерами, записуються контрольні точки, маршрутизація вибирає наступний крок, а конфіденційні дії спрямовуються на переривання, яке вирішує людина.

                      USER
                        │
                        ↓
                  graph.invoke()
                        │
                        ↓
                     THREAD
                        │
                        ↓
                  CHECKPOINTER
                        │
                        ↓
                     STATE
                        │
                        ↓
                      NODE
                        │
                        ↓
                  STATE UPDATE
                        │
                        ↓
                     REDUCER
                        │
                        ↓
                   NEW STATE
                        │
                        ↓
                   CHECKPOINT
                        │
                        ↓
                 EDGE / ROUTING
                        │
                        ↓
                 SENSITIVE ACTION?
                    /          \
                  NO            YES
                  │              │
                  ↓              ↓
             NEXT NODE       interrupt()
                                 │
                                 ↓
                              PAUSED
                                 │
                                 ↓
                               HUMAN
                            /     |     \
                           /      |      \
                      Approve   Edit    Reject
                         │        │        │
                         └────────┼────────┘
                                  ↓
                          Command(resume)
                                  │
                                  ↓
                           SAME thread_id
                                  │
                                  ↓
                         RESTORE CHECKPOINT
                                  │
                                  ↓
                           CONTINUE GRAPH
                                  │
                                  ↓
                                 END

Як історія: надходить запит.

User Input

і починається виконання.

START

Вузли читають стан та повертають оновлення, редуктори їх об’єднують, чекпоїнти зберігають їх у межах потоку, а ребра визначають, що буде виконано далі. Граф може розгалужуватися, утворювати цикли чи викликати інструменти.

BRANCH
LOOP
CALL TOOLS

Коли потрібна допомога людини, переривання призупиняє виконання.

interrupt()

Людина реагує,

APPROVE
REJECT
EDIT
PROVIDE INPUT

команда продовження роботи продовжує виконання з збереженого потоку,

Command(resume=...)

і граф завершується.

END

Більшість проектів починаються з одного виклику моделі,

LLM
 ↓
Response

а закінчуються графом, який поєднує вузли LLM та інструментів, редуктори, чекпоїнти, механізми маршрутизації, переривання та команди.

                          USER
                           │
                           ↓
                         START
                           │
                           ↓
                         STATE
                           │
                           ↓
                         NODE
                           │
                    ┌──────┴──────┐
                    │             │
                  LLM           TOOL
                    │             │
                    └──────┬──────┘
                           ↓
                     STATE UPDATE
                           │
                           ↓
                        REDUCER
                           │
                           ↓
                       NEW STATE
                           │
                           ↓
                      CHECKPOINT
                           │
                           ↓
                        THREAD
                           │
                           ↓
                       ROUTING
                    /      |      \
                   /       |       \
                NODE      LOOP    INTERRUPT
                                    │
                                    ↓
                                  HUMAN
                              /      |      \
                         Approve    Edit    Reject
                              \      |      /
                               \     |     /
                                    ↓
                                COMMAND
                                    │
                                    ↓
                                 RESUME
                                    │
                                    ↓
                              NEXT NODE
                                    │
                                    ↓
                                   END

Чек-лист для продакшну

Зберігайте вузли фокусованими

Маленькі вузли з однією функцією легше тестувати, перезапускати та безпечно переривати,

Plan Node
Search Node
Validate Node
Execute Node

на відміну від одного вузла, який робить усе.

do_everything_agent()

Ретельно проектуйте стани та редуктори

Зберігайте лише те, що потрібно вузлам, адже все фіксується як контрольні точки та може бути показано перевіряючим. Ретельно обирайте редуктори для полів, які накопичують дані.

messages
events
results
observations

Робіть побічні ефекти ідемпотентними

З операціями, які не можна скасувати, потрібно бути обережними.

Send Email
Charge Card
Delete Resource
Deploy
Transfer Money

Перепробування та відновлення ніколи не повинні їх повторювати. Оскільки перерваний вузол запускається знову під час відновлення, розміщуйте операції, які не можна скасувати, після точки затвердження або у окремому вузлі, та використовуйте ключі ідемпотентності там, де це підтримують API.

Використовуйте надійне зберігання

Контрольні точки в пам’яті підходять для навчання; у продакшені потрібне надійне зберігання, що відповідає вашим вимогам до надійності.

Запишіть межі та обмеження

Чітко визначте їх для кожного робочого процесу,

What can AI do automatically?
What requires approval?
What can humans modify?
When does approval expire?

та вкажіть умови завершення циклів.

Maximum attempts
Timeouts
Validation
Failure paths
Escalation

Коли HITL є корисним

Людський огляд виправдовує себе у певних ситуаціях.

Cost of wrong action is high
Action is irreversible
Policy requires approval
Agent confidence is insufficient
Sensitive information is involved
Human judgment adds value

Розкидані скрізь, вони унеможливлюють автоматизацію та змушують оглядачів клацати далі, не читаючи.

Agent
 ↓
Ask Human
 ↓
Agent
 ↓
Ask Human
 ↓
Agent
 ↓
Ask Human

Кращий дизайн надає агенту автономну зону для планування та міркувань із одним кордоном перед виконанням дії.

AUTONOMOUS ZONE
        ┌───────────────────────┐
        │                       │
        │ Plan → Search → Think │
        │                       │
        └───────────┬───────────┘
                    │
                    ↓
              CONTROL BOUNDARY
                    │
                    ↓
                  HUMAN
                    │
                    ↓
              APPROVED ACTION

Як взаємодіють шари

Виконання графа охоплює вузли, ребра та маршрутизацію;

Graph
Nodes
Edges
START
END
Loops
Conditional Routing

Керування станом охоплює оновлення та редуктори;

State
State Updates
Reducers
Messages
State Evolution

Стабільність даних охоплює контрольні точки, потоки та відновлення;

Checkpoints
Checkpointer
Threads
thread_id
State History
Recovery

А HITL додає переривання, команди та шаблони огляду.

interrupt()
Command
Pause
Resume
Approve
Reject
Edit
Human Control

Зібрані разом, вони утворюють одну систему обробки.

GRAPH
  ↓
STATE
  ↓
NODE
  ↓
UPDATE
  ↓
REDUCER
  ↓
CHECKPOINT
  ↓
THREAD
  ↓
ROUTING
  ↓
INTERRUPT
  ↓
HUMAN
  ↓
COMMAND
  ↓
RESUME
  ↓
END

Основні висновки

Лексика може здаватися перевантаженою,

StateGraph
MessagesState
Reducers
Checkpointers
Threads
Commands
Interrupts

Але кожен елемент вирішує одну частину єдиної мети: агент, який знає, діє, оновлює інформацію, приймає рішення, зберігає прогрес, зупиняється у потрібний момент, запитує людину та безпечно продовжує роботу.

Remember what it knows
        ↓
Perform some work
        ↓
Update what it knows
        ↓
Decide what to do next
        ↓
Persist its progress
        ↓
Pause when necessary
        ↓
Ask a human
        ↓
Resume safely
        ↓
Continue until complete
  • Стан – це те, що знає агент; вузли – це те, що він робить; ребра – це напрямок його руху; редуктори – це способи зміни стану.
  • Чекпоїнти фіксують місце, де знаходився агент; потоки вказують, до якої історії належить певна операція.
  • interrupt() визначає місце зупинки та запиту; Command вказує, як продовжити роботу, завжди в тому самому потоці.
  • Перервані вузли перезапускаються під час продовження роботи, тому необхідно зберігати незворотні наслідки після точки схвалення.
  • Перевірку слід розміщувати на справжніх межах керування з чіткими правилами таймауту та ескалації.