Анти-патерн Write Access by Default: доступ на запис за замовчуванням

Anti-pattern, коли агент має write-доступ без обмежень.
На цій сторінці
  1. Ідея за 30 секунд
  2. Приклад анти-патерну
  3. Чому виникає і що йде не так
  4. Правильний підхід
  5. Швидкий тест
  6. Чим відрізняється від інших анти-патернів
  7. Blind Tool Trust vs Write Access by Default
  8. Agents Without Guardrails vs Write Access by Default
  9. Tool Calling for Everything vs Write Access by Default
  10. Самоперевірка: чи немає у вас цього анти-патерну
  11. FAQ
  12. Що далі

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

Write Access by Default — це анти-патерн, коли агент отримує write-інструменти за замовчуванням, без policy-gate і перевірки перед виконанням дії.

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

Просте правило: write має бути не "за замовчуванням", а тільки через окремий контрольований шлях із явною перевіркою прав, контексту й умов виконання.


Приклад анти-патерну

Команда будує support-агента, який читає статус замовлення і за потреби може закрити тікет або надіслати лист.

Агент отримує write-tools одразу, без окремого етапу перевірки перед дією.

PYTHON
decision = agent.decide_next_action(user_message)
# route помилковий, але write все одно доступний
result = run_tool(decision.tool, decision.args)
return result

У такій схемі немає базового захисту:

PYTHON
# немає deny-by-default для write-tools
# немає approval_required для ризикових дій
# немає idempotency_key для повторних запусків
# немає жорсткого tenant/env scope

Для цього кейсу потрібен policy-gate перед будь-яким write-кроком:

PYTHON
if decision.tool in WRITE_TOOLS and not is_write_allowed(ctx, decision):
    return stop("approval_required")

Якщо умови не виконані, run не має переходити до зовнішньої write-дії.

У цьому випадку Write Access by Default додає:

  • ризик небажаних змін у зовнішніх системах
  • дубльовані write-операції при retries
  • більший blast radius у multi-tenant середовищі

Чому виникає і що йде не так

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

Типові причини:

  • демо-підхід: спочатку дати всі інструменти, а обмеження додати потім
  • відсутність явного розділення read і write маршрутів
  • правила доступу описані в prompt, а не примусово застосовані у gateway
  • немає обов’язкового idempotency_key для write-операцій

У результаті виникають проблеми:

  • небезпечні side effects (зміни стану) — агент може виконати write там, де мав лише читати
  • повторні дії — retry або loop повторює ту саму write-операцію
  • високий blast radius — без жорсткого scope помилка торкається не того tenant/env
  • складний інцидент-аналіз — важко швидко довести, чому write був дозволений
  • втрата передбачуваності — команда не контролює, коли саме система переходить до write

На відміну від Blind Tool Trust, тут головна проблема не у валідації payload, а в тому, що write-доступ відкритий за замовчуванням.

Типові production-сигнали, що write-контроль слабкий:

  • write-tools викликаються навіть у сценаріях, які мали бути read-only
  • у логах багато write-викликів з однаковим args_hash або без idempotency_key
  • approval_required майже не з’являється, хоча частка write-операцій висока
  • blocked write attempts майже не трапляються, хоча система регулярно пропонує risky actions
  • audit-логи не показують, яке policy-правило дозволило write
  • команда не може чітко пояснити, чому конкретний write був дозволений саме в цьому run
  • помилки виявляються вже після зовнішньої дії, а не на policy-gate

Важливо, що кожен write-call змінює зовнішній стан і часто не має простого rollback. Без deny-by-default і контрольованого write-шляху один невдалий inference стає production-інцидентом.

Правильний підхід

Починайте з read-first моделі: read-інструменти доступні за маршрутом, а write-кроки проходять окрему перевірку через policy-gate.

Практична рамка:

  • застосовуйте deny-by-default для всіх write-tools
  • розділяйте маршрути read_only і write_candidate
  • вимагайте approval для ризикових write-дій
  • беріть tenant_id і env лише з authenticated context, а не з model output
  • додавайте idempotency_key до кожної write-операції
  • логуйте stop_reason і рішення policy-gate для кожного write-кроку
PYTHON
WRITE_TOOLS = {"ticket.close", "refund.create", "email.send"}


def execute_action(user_message: str, ctx: dict):
    decision = agent.next_action(user_message)

    if decision.tool in WRITE_TOOLS:
        if not is_write_allowed(ctx, decision):  # policy gate: role, route allowlist, tenant/env scope
            return stop("approval_required")

        scoped_args = enforce_scope(
            decision.args,
            tenant_id=ctx["tenant_id"],
            env=ctx["env"],
        )
        scoped_args["idempotency_key"] = make_idempotency_key(ctx["run_id"], decision)
        return run_tool(decision.tool, scoped_args)

    return run_tool(decision.tool, decision.args)  # read-only tool from allowed set

У такій схемі write-крок стає контрольованим: система або безпечно виконує дію, або прозоро зупиняє run.

Швидкий тест

Якщо на ці питання відповідь "так", у вас є ризик анти-патерну Write Access by Default:

  • Чи write-інструмент може викликатись без явної policy/approval перевірки?
  • Чи retry інколи повторює ту саму write-дію без idempotency_key?
  • Чи команда не може швидко пояснити, чому конкретний write був дозволений?

Чим відрізняється від інших анти-патернів

Blind Tool Trust vs Write Access by Default

Blind Tool TrustWrite Access by Default
Основна проблема: tool output приймають без валідації.Основна проблема: write-доступ відкритий за замовчуванням.
Коли виникає: коли немає parse/schema/invariant перевірок перед рішенням.Коли виникає: коли write-крок не проходить через deny-by-default і approval-gate.

Якщо коротко: Blind Tool Trust — про якість даних перед дією, а Write Access by Default — про права на саму дію.

Agents Without Guardrails vs Write Access by Default

Agents Without GuardrailsWrite Access by Default
Основна проблема: загалом відсутні runtime-межі і policy-контроль.Основна проблема: саме write-операції не мають жорсткого доступного контуру.
Коли виникає: коли система не має чітких safety-policy для execution.Коли виникає: коли write дозволяється як стандартний шлях, а не як виняток через policy-gate.

Якщо коротко: Agents Without Guardrails — ширша проблема меж виконання, а Write Access by Default — конкретно про небезпечну модель доступу до write.

Tool Calling for Everything vs Write Access by Default

Tool Calling for EverythingWrite Access by Default
Основна проблема: tools викликають зайво, навіть коли можна без них.Основна проблема: коли вже стався tool-call, write може пройти без належного контролю.
Коли виникає: коли немає стабільного no_tool маршруту для простих кейсів.Коли виникає: коли система не розділяє read і write рівні доступу.

Якщо коротко: Tool Calling for Everything збільшує кількість викликів, а Write Access by Default збільшує ціну помилки кожного write-виклику.

Самоперевірка: чи немає у вас цього анти-патерну

Швидка перевірка на anti-pattern Write Access by Default.
Відмічайте пункти під вашу систему і дивіться статус нижче.

Перевірте свою систему:

Прогрес: 0/8

⚠ Є ознаки цього anti-pattern

Спробуйте винести прості кроки у workflow і залишити агента лише для складних рішень.

FAQ

Q: Чи означає це, що агенту взагалі не можна робити write-дії?
A: Ні. Write-дії можливі, але тільки через контрольований шлях: policy-gate, approval (де потрібно), scope enforcement і idempotency.

Q: Чим відрізняються policy-gate і approval?
A: Policy-gate — це детермінована перевірка правил під час виконання. Approval — окреме підтвердження для конкретної ризикової дії. Це різні рівні контролю.

Q: Який мінімум треба впровадити першим?
A: Почніть із deny-by-default для write, обов’язкового idempotency_key, жорсткого tenant/env scope і логування stop_reason для заблокованих write-спроб.


Що далі

Схожі anti-patterns:

Що будувати замість цього:

  • Allowed Actions — як фіксувати дозволені дії через явні правила.
  • Tool Execution Layer — де централізувати policy, scope і idempotency.
  • Stop Conditions — як безпечно зупиняти run, коли write не має права пройти.
⏱️ 7 хв читанняОновлено 17 березня 2026 р.Складність: ★★★
Реалізувати в OnceOnly
Safe defaults for tool permissions + write gating.
Використати в OnceOnly
# onceonly guardrails (concept)
version: 1
tools:
  default_mode: read_only
  allowlist:
    - search.read
    - kb.read
    - http.get
writes:
  enabled: false
  require_approval: true
  idempotency: true
controls:
  kill_switch: { enabled: true, mode: disable_writes }
audit:
  enabled: true
Інтегровано: продакшен-контрольOnceOnly
Додай guardrails до агентів з tool-calling
Зашип цей патерн з governance:
  • Бюджетами (кроки / ліміти витрат)
  • Дозволами на інструменти (allowlist / blocklist)
  • Kill switch та аварійна зупинка
  • Ідемпотентність і dedupe
  • Audit logs та трасування
Інтегрована згадка: OnceOnly — контрольний шар для продакшен агент-систем.

Автор

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

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

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


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

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

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