Audit logs для AI-агентів: як відновлювати ланцюг рішень у production

Практичний audit trail у production: policy decisions, stop reasons, actor/scope, redaction, immutable storage і швидке розслідування інцидентів.
На цій сторінці
  1. Ідея за 30 секунд
  2. Проблема
  3. Рішення
  4. Audit logs ≠ debug logs
  5. Компоненти audit-контролю
  6. Як це виглядає в архітектурі
  7. Приклад
  8. У коді це виглядає так
  9. Як це виглядає під час виконання
  10. Сценарій 1: policy stop
  11. Сценарій 2: approval_required
  12. Сценарій 3: allow + виконання
  13. Типові помилки
  14. Самоперевірка
  15. FAQ
  16. Де Audit Logs у загальній системі
  17. Пов'язані сторінки

Ідея за 30 секунд

Audit logs — це централізований runtime-журнал рішень агента: що саме сталося, чому це сталося і хто це ініціював.

Коли це потрібно:
коли агент працює з tools, approval, лімітами і будь-який інцидент треба розібрати по фактах, а не по припущеннях.

Проблема

Без audit logs команда бачить симптоми, але не бачить ланцюг рішень. У demo це майже непомітно. У production це перетворює кожен інцидент на ручне "вгадування".

Типові наслідки:

  • неясно, чому було deny або stop
  • неможливо відновити, який саме крок зробив side effects (зміни стану)
  • важко пояснити клієнту, хто і коли змінив policy або активував обмеження

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

І кожна хвилина без якісного audit trail подовжує інцидент і збільшує час відновлення.

Рішення

Рішення — додати централізований audit layer у runtime, який пише і policy-рішення, і факт виконання дії. Кожен крок агента логує стандартизовану подію: decision, reason, action, scope, actor, timestamp.

Для runtime важлива єдина модель рішень:

  • allow
  • stop
  • approval_required

Також важливо логувати не тільки блокування, а й успішне виконання. Інакше в інциденті видно "чому зупинили", але не видно "що реально було виконано".

Audit logs ≠ debug logs

Це різні задачі:

  • Audit logs — структурований і відтворюваний журнал рішень та дій.
  • Debug logs — технічні деталі для локальної діагностики.

Одне без іншого не працює:

  • без audit logs немає юридично й операційно надійної історії рішень
  • без debug logs складно локально дебажити деталі реалізації

Приклад:

  • audit: decision=stop, reason=rate_limited_tenant, tenant_id=t_42, action=crm.search
  • debug: stack trace, внутрішні retry-спроби, latency окремих залежностей

Компоненти audit-контролю

Ці компоненти працюють разом на кожному кроці агента.

КомпонентЩо контролюєКлючові механікиНавіщо
Event identityУнікальність подіїrun_id + step_id
event timestamp
Дозволяє відновити повну послідовність без пропусків
Decision contextПричину policy-рішенняdecision / reason
policy layer name
Пояснює, чому дія виконалась або була зупинена
Action contextЩо саме робив агентaction + action_key
scope (user/tenant/global)
Дає зв'язок між policy і реальною дією
Data safetyРизик витоку чутливих данихargs hash
redaction policy
Зберігає аудиторську цінність без сирих секретів і PII
Immutable storageЦілісність аудитуappend-only sink
retention + access control
Захищає журнал від "тихого" редагування після інциденту

Приклад alert:

Slack: 🛑 Support-Agent decision=stop, reason=approval_required, tenant=t_42, run_id=run_981.

Як це виглядає в архітектурі

Audit layer стоїть у runtime loop і фіксує рішення до та після виконання наступної дії агента. Кожен outcome (allow, stop, approval_required) пишеться у централізований audit trail.

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

Коротко по flow:

  • Runtime формує наступну дію агента
  • Policy повертає allow, stop або approval_required
  • Runtime логує pre-event з decision і reason
  • якщо дія виконалась, логує post-event з result
  • обидва типи подій доступні для пошуку, алертингу і розслідування

Приклад

Агент підтримки отримує запит на refund.create. Policy повертає approval_required.

Результат:

  • виконання не починається без підтвердження
  • у аудиті видно decision=approval_required, actor, scope, action_key
  • після підтвердження видно окрему подію decision=allow і результат виконання

Audit logs зменшують час розслідування інциденту на рівні runtime-кроків, а не після ручного збору артефактів.

У коді це виглядає так

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

Приклад audit-конфігурації:

YAML
audit:
  sink: append_only
  retention_days: 180
  redact_fields: ["email", "phone", "card_number"]
  hash_args: true
  sign_events: true
PYTHON
action = planner.next(state)
action_key = make_action_key(action.name, action.args)
decision = policy.evaluate(action, state.user_context)

base_event = {
    "run_id": run_id,
    "step_id": state.step,
    "tenant_id": state.tenant_id,
    "action": action.name,
    "action_key": action_key,
    "timestamp": clock.iso(),
}

audit.log(
    **base_event,
    phase="pre_exec",
    decision=decision.outcome,
    reason=decision.reason,
    args_hash=hash_args(action.args),
)

if decision.outcome == "approval_required":
    return stop("approval_required")

if decision.outcome == "stop":
    return stop(decision.reason)

result = executor.execute(action)

audit.log(
    **base_event,
    phase="post_exec",
    decision=decision.outcome,
    reason=decision.reason,
    result=result.status,
)

return result

Як це виглядає під час виконання

Сценарій 1: policy stop

  1. Runtime формує дію crm.search.
  2. Policy повертає stop (reason=rate_limited_tenant).
  3. Runtime пише pre-event в audit.
  4. Дія не виконується.
  5. Команда бачить stop reason одразу в логах.

Сценарій 2: approval_required

  1. Runtime формує refund.create.
  2. Policy повертає approval_required.
  3. Runtime пише pre-event і зупиняє виконання.
  4. Після рішення людини запускається окремий крок.
  5. В аудиті видно весь шлях: approval_required -> allow -> result.

Сценарій 3: allow + виконання

  1. Runtime формує наступну дію.
  2. Policy повертає allow.
  3. Runtime виконує дію.
  4. Пише post-event з result.
  5. У журналі є і рішення, і результат виконання.

Типові помилки

  • логувати тільки stop, але не логувати allow
  • зберігати сирі args без redaction/hash
  • не мати стабільного action_key для дедуплікації
  • змішувати audit і debug в один неструктурований текст
  • не фіксувати actor для policy-змін і operator-дій
  • дозволяти змінювати або видаляти audit події заднім числом

У результаті журнал ніби є, але в інциденті він не дає перевірюваної картини.

Самоперевірка

Швидка перевірка audit logging перед запуском у production:

Прогрес: 0/8

⚠ Бракує базового governance-контролю

Перед production потрібні мінімум: контроль доступу, ліміти, audit logs і аварійна зупинка.

FAQ

Q: Чим audit logs відрізняються від traces?
A: Trace показує технічний шлях виконання, а audit log — policy-рішення і дії в термінах "хто/що/чому". Для інцидентів зазвичай потрібні обидва.

Q: Чи можна логувати повні args для зручності?
A: Краще ні. Для production безпечніше зберігати hash або redacted-версію, щоб не витікали секрети й PII.

Q: Який мінімальний набір полів обов'язковий?
A: Мінімум: run_id, step_id, decision, reason, action, action_key, scope, timestamp.

Q: Коли писати подію: до чи після виконання?
A: Обидва етапи важливі: pre-event фіксує рішення, post-event фіксує факт і результат виконання.

Q: Де зберігати audit logs?
A: У централізованому append-only сховищі з контрольованим доступом, retention і можливістю швидкого пошуку по run_id/tenant_id/reason.

Де Audit Logs у загальній системі

Audit logs — це базовий шар прозорості в Agent Governance. Разом із RBAC, лімітами, budget controls, approval і kill switch вони дають контрольовану й пояснювану поведінку агента в production.

Пов'язані сторінки

Далі за темою:

⏱️ 6 хв читанняОновлено 27 березня 2026 р.Складність: ★★★
Реалізувати в OnceOnly
Budgets + permissions you can enforce at the boundary.
Використати в OnceOnly
# onceonly guardrails (concept)
version: 1
budgets:
  max_steps: 25
  max_tool_calls: 12
  max_seconds: 60
  max_usd: 1.00
policy:
  tool_allowlist:
    - search.read
    - http.get
writes:
  require_approval: true
  idempotency: true
controls:
  kill_switch: { enabled: true }
Інтегровано: продакшен-контрольOnceOnly
Додай guardrails до агентів з tool-calling
Зашип цей патерн з governance:
  • Бюджетами (кроки / ліміти витрат)
  • Дозволами на інструменти (allowlist / blocklist)
  • Kill switch та аварійна зупинка
  • Ідемпотентність і dedupe
  • Audit logs та трасування
Інтегрована згадка: OnceOnly — контрольний шар для продакшен агент-систем.

Автор

Микола — інженер, який будує інфраструктуру для продакшн AI-агентів.

Фокус: патерни агентів, режими відмов, контроль рантайму та надійність систем.

🔗 GitHub: https://github.com/mykolademyanov


Редакційна примітка

Ця документація підготовлена з допомогою AI, із людською редакторською відповідальністю за точність, ясність і продакшн-релевантність.

Контент базується на реальних відмовах, постмортемах та операційних інцидентах у розгорнутих AI-агентних системах.