Ідея за 30 секунд
Human approval — це runtime-gate для ризикових write-дій: перед виконанням агент отримує approval_required і чекає підтвердження людини.
Коли це потрібно: коли агент може змінювати дані, відправляти повідомлення клієнтам або запускати незворотні дії в production.
Проблема
Без approval write-дії виконуються одразу, якщо вони дозволені policy. У demo це зручно. У production одна помилка агента перетворюється на реальний інцидент.
Проблема не тільки в "поганій" моделі. Навіть хороша модель інколи помиляється на нетипових запитах. Якщо між агентом і write-інструментом немає людського гейта, помилка одразу стає побічним ефектом у реальних системах.
Аналогія: це як платіж без 3D Secure. Поки все йде добре, затримки немає. Коли щось іде не так, наслідки стають дорогими за секунди.
Рішення
Рішення — додати в policy layer окремий approval flow для ризикових write-дій.
Policy повертає одне з рішень: allow, deny або approval_required.
approval_required не виконує дію одразу: runtime створює approval request, чекає рішення людини і лише після approval_granted виконує tool call.
Це рішення приймається на кожному кроці, а не лише в кінці run.
Human approval ≠ ручний режим
Це різні моделі:
- Manual mode: людина виконує майже кожну дію замість агента.
- Human approval: агент працює самостійно, а людина підтверджує тільки ризикові write-дії.
Одне без іншого не працює достатньо добре:
- без approval ризикові дії проходять без додаткового контролю
- якщо робити manual mode для всього, система втрачає швидкість і масштабованість
Приклад:
- без approval:
ticket.close_bulkвиконується одразу - з approval: policy повертає
approval_required, і дія чекає підтвердження
Метрики approval-контролю
Ці метрики і сигнали працюють разом на кожному кроці агента.
| Метрика | Що контролює | Ключові механіки | Навіщо |
|---|---|---|---|
| Approval scope | Для яких дій потрібне підтвердження | write policy risk tiers | Зменшує ризик для незворотних дій |
| Approval request context | Що саме бачить людина перед рішенням | preview + args hash reason + policy context | Дає змогу прийняти обґрунтоване рішення |
| TTL і скасування | Життєвий цикл approval request | approval TTL cancel flow | Не дає run зависати безкінечно |
| Execution gate | Фактичний запуск write-дії | approval token gateway enforcement | Гарантує, що write не піде без підтвердження |
| Approval observability | Видимість approval-рішень | audit logs alerts on timeout spikes | Не обмежує дію напряму, але допомагає виявити вузькі місця approval-процесу |
Як це виглядає в архітектурі
Policy layer (tool gateway) стоїть між runtime і tools та є єдиною точкою контролю доступу перед кожним кроком.
Кожне рішення (allow, deny, approval_required) фіксується в audit log.
Кожен крок агента проходить через цей flow перед виконанням: runtime не виконує write-дію напряму — спочатку policy-перевірка -> approval gate -> виконання.
Коротко по флоу:
- Runtime формує tool call
- Policy layer перевіряє ризик і може повернути
approval_required - при
approval_grantedwrite виконується - при
approval_deniedабоapproval_timeoutrun отримує stop reason - кожне рішення пишеться в audit log
У runtime deny так само перетворюється на явний stop reason, який видно в логах і відповіді run.
Approval request зазвичай містить:
- tool
- короткий preview дії
- args hash
- reason / risk tier
- TTL
Приклад
Агент підтримки хоче виконати email.send для клієнта.
Policy визначає, що для цього tool потрібне підтвердження людини.
Результат:
- без approval token write не виконується
- після
approval_grantedвиклик проходить - при timeout агент повертає
stop("approval_timeout")
Human approval зупиняє ризикову дію до побічного ефекту, а не після інциденту.
У коді це виглядає так
У спрощеній схемі вище показано основний control flow. На практиці перевірка і виконання мають йти через один policy/tool gateway.
Приклад approval-конфігурації:
approvals:
required_for:
- email.send
- ticket.close_bulk
- db.write
ttl_seconds: 300
fallback_when_not_approved: stop
decision = policy.evaluate(tool, user_context, mode="normal")
if decision.outcome == "approval_required":
request = approvals.create_request(
run_id=run_id,
tool=tool,
args_hash=hash_args(args),
ttl_seconds=300,
)
audit.log(run_id, decision.outcome, reason="pending_human_review", tool=tool, pending_id=request.id)
return stop("approval_required", pending_id=request.id)
elif decision.outcome == "deny":
audit.log(run_id, decision.outcome, reason=decision.reason, tool=tool)
return deny(decision.reason)
# later, in resume flow with pending_id
approval = approvals.get_decision(pending_id)
if approval.outcome != "approved":
audit.log(run_id, "deny", reason=approval.outcome, tool=tool, pending_id=pending_id)
return stop(approval.outcome)
audit.log(run_id, "approval_granted", reason="human_approved", tool=tool, approver=approval.approved_by)
result = tool.execute({**args, "approval_token": approval.token})
decision = Decision.allow(reason="policy_ok")
audit.log(run_id, decision.outcome, reason=decision.reason, tool=tool, result=result.status)
return result
У production approval flow зазвичай асинхронний: runtime створює request, повертає pending/stop стан без блокування worker і відновлює run після рішення людини.
Як це виглядає під час виконання
Сценарій 1: підтверджено (approval granted)
1. Runtime формує виклик email.send.
2. Policy повертає approval_required.
3. Runtime створює approval request і повертає pending/stop стан.
4. Людина підтверджує дію в межах TTL.
5. Runtime відновлює run, виконує tool call і пише `approval_granted -> allow`.
---
Сценарій 2: таймаут підтвердження (approval timeout)
1. Runtime формує виклик db.write.
2. Policy повертає approval_required.
3. Runtime створює approval request і повертає pending/stop стан.
4. Підтвердження не отримано до завершення TTL.
5. Runtime повертає stop (approval_timeout), дія не виконується.
---
Сценарій 3: policy deny без approval
1. Runtime формує write-виклик поза дозволеним scope.
2. Policy одразу повертає deny.
3. Runtime повертає stop reason.
4. Audit: decision=deny, reason=policy_denied.
5. Дія не виконується.
Типові помилки
- approval тільки в UI, але не в policy/tool gateway
- approval без TTL і без скасування
- однаковий підхід для low-risk і high-risk write-дій
- відсутність approval token при виконанні tool
- не логувати
approval_requiredіapproval_granted - блокувати всі run-и в очікуванні approval замість повернення явного stop/pending стану
У результаті система або пропускає небезпечні дії, або зависає в approval-чергах без прозорого стану.
Самоперевірка
Швидка перевірка human-approval перед запуском у production:
Прогрес: 0/8
⚠ Бракує базового governance-контролю
Перед production потрібні мінімум: контроль доступу, ліміти, audit logs і аварійна зупинка.
FAQ
Q: Для яких дій approval потрібен обов'язково?
A: Для незворотних або клієнтськи видимих write-дій: зміни даних, масові закриття, відправка повідомлень, фінансові операції.
Q: Як не втопити команду в approval-spam?
A: Розбий write-дії на рівні ризику. High-risk -> обов'язковий approval, low-risk -> окрема policy з tighter limits і аудитом.
Q: Чи потрібно блокувати worker, поки чекаємо approval?
A: Краще ні. Поверни pending/stop стан і віднови run після рішення, щоб не отримати черги й deadlocks.
Q: Чи може approval замінити RBAC і бюджети?
A: Ні. Approval — це додатковий gate для ризикових дій. RBAC, ліміти й бюджети все одно потрібні.
Q: Що логувати мінімально?
A: approval_required, approval_granted|approval_denied|approval_timeout, хто підтвердив, який tool, який reason і який результат виконання.
Де Human Approval у загальній системі
Human approval — це один із рівнів Agent Governance. Разом із allowlist/RBAC, бюджетами, лімітами і audit він формує єдину систему контролю виконання.
Пов'язані сторінки
Далі за темою:
- Огляд Agent Governance — загальна модель контролю агентів у production.
- Allowlist vs Blocklist — як будувати default-deny доступ до tools.
- Контроль доступу (RBAC) — як обмежувати доступ за ролями і tenant scope.
- Контроль бюджетів — як стримувати runaway-витрати і цикли.
- Audit logs для агентів — як пояснювати рішення approval/policy у інцидентах.