Промпти — це пропозиції. Хуки — це жорсткі обмеження.
Протягом місяців я ставився до Claude Code як до junior-розробника, якому просто потрібні чіткі правила гри. Мої інструкції до проєкту були однозначними: ніколи не робити force-push, ніколи не видаляти гілки, ніколи не запускати деструктивні команди. Більшість вечорів це працювало. Агент писав тести, рефакторив функції та не чіпав git-історію. Потім один rebase пішов не за планом.
Контекстне вікно заповнилося виводом помилок git. Маркери конфліктів, повідомлення про detached HEAD та попередження про розходження гілок накопичувалися токен за токеном. Під усім цим шумом була схована моя ввічлива інструкція уникати force-push. Для моделі найсвіжішим і найбільш помітним текстом у потоці був потік помилок. Статистична увага перемогла над політикою. Агент виконав команду, яка стерла дві години незакомічених локальних змін. Це не було злим наміром; це була неуважність. Ця різниця має значення. LLM не порушує правила зі злості. Вона порушує їх тому, що гучніший патерн у контекстному вікні тимчасово перекриває попередню інструкцію.
Цей інцидент змінив моє ставлення до безпеки агентів. Запобіжник, який працює у дев'яноста дев'яти відсотках випадків, — це ризик. Якщо помилка коштує вам часу, грошей або робочих даних, ви не можете залишати це всередині промпту. Вам потрібне забезпечення виконання поза циклом міркувань моделі.
Хуки Claude Code вирішують саме цю проблему. Це невеликі скрипти, які перехоплюють виклики інструментів у три конкретні моменти: перед виконанням інструмента (PreToolUse), після завершення інструмента (PostToolUse) та коли агент вирішує, що він закінчив (Stop). Оскільки вони працюють як зовнішній код, вони не залежать від пам'яті, настрою чи тиску контексту моделі. Модель може забути кожну інструкцію, яку ви їй коли-небудь давали; хук все одно скаже «ні».
Ось каркас, який я побудував після того втраченого вечора.
The Guard Hook: Перехоплення до заподіяння шкоди
Мій PreToolUse хук перевіряє кожну Bash-команду перед тим, як її торкнеться shell. Я веду суворий denylist деструктивних патернів. Якщо рядок команди збігається з чимось небезпечним, хук перериває виконання і повертає помилку безпосередньо агенту.
Патерни, які я блокую, прості та однозначні:
git push --forceабо будь-який варіантforce-with-lease, якому я ще не довіряюgit reset --hardrm -rf
Це не складне дослідження безпеки. Це ремінь безпеки. Але критично важливим є те, що відбувається після блокування.
Я ніколи не повертаю сухе «Заблоковано». Категорична відмова заплутує агента і може загнати його в цикл, де він намагатиметься повторювати варіації тієї самої деструктивної команди. Замість цього повідомлення про помилку містить шлях до відступу. Коли хук перехоплює hard reset, він каже агенту: «Ця команда заблокована для захисту незакомічених змін. Спочатку зробіть checkpoint, а потім перегляньте дії». Це додаткове речення повністю змінює поведінку агента. Він перемикається з намагання мінімізувати шкоду на створення безпеки. Хук — це не просто стіна; це регулювання руху.
Я також обрав denylist замість allowlist для shell-команд. Спочатку я думав дозволити лише чітко визначений набір безпечних підкоманд git. Це швидко провалилося. Агенти бувають творчо буквально. Вони запускають легітимні, але неочікувані команди, як-от git stash push -m "wip" або git branch --show-current, щоб перевірити стан. Allowlist ламає нормальний робочий процес у той момент, коли модель вигадує валідну, але не внесена до списку команду. Короткий, ретельно підібраний denylist справді деструктивних патернів дає агенту простір для маневру, захищаючи при цьому кордони.
The Formatter Hook: Автоматизація рутини
Раніше я витрачав токени промпту, наказуючи агенту «завжди запускати форматер після редагування файлу». Він забував про це в половині випадків. В іншій половині він зупинявся і питав, чи потрібно форматувати, витрачаючи виклик інструмента на рішення, яке мало лише одну правильну відповідь.
Тепер я вирішую це за допомогою PostToolUse хука. Після того, як агент редагує файл, хук перевіряє розширення файлу. Якщо це Python, він запускає Ruff. Якщо це JavaScript або TypeScript, він запускає Prettier. Якщо це Go, він запускає gofmt. Агент навіть не знає про існування форматера. Йому це і не потрібно.
Винесення цього за межі промпту дало два ефекти. По-перше, код стає стабільно чистим, не створюючи когнітивного навантаження на модель. По-друге, мої інструкції до проєкту стали коротшими. Кожне «завжди» та «ніколи», яке ви прибираєте з промпту, — це токен, який модель може витратити на реальне вирішення проблем. Хук відповідає за інваріанти; промпт — за наміри.
The Quality Gate: Переосмислення поняття «Готово»
Хук Stop запускається, коли агент вирішує, що завершив завдання, і намагається завершити сесію. Я цього не дозволяю. Замість цього хук запускає повний набір тестів. Якщо будь-який тест не проходить, хук блокує команду зупинки та повертає агенту результат помилки.
Це змінює визначення завершення. «Готово» — це більше не відчуття моделі. Це вимірюваний бар'єр. Агент може завершити роботу лише тоді, коли harness підтверджує, що код працює. На практиці це створює тісний цикл зворотного зв'язку. Агент пише код, вважає, що закінчив, натискає кнопку зупинки і миттєво бачить traceback від pytest. Потім він самостійно виправляє помилку, виправляє помилку імпорту або зламану перевірку (assertion) і намагається зупинитися знову. Я спостерігав, як агенти роблять три або чотири ітерації всередині цього циклу без втручання людини. Harness забезпечує якість; модель надає патчі.
Чого це вчить в інженерії агентів
Побудова надійних автономних систем потребує зміни мислення. Ви переходите від написання довших промптів до створення жорсткіших harness.
Використовуйте хуки для забезпечення виконання правил, а промпти — для політики. Якщо правило має виконуватися у сто відсотків випадків, воно має бути в коді, а не в природній мові. Промпти чудово справляються з неоднозначністю, смаком та архітектурою. Вони жахливі в інваріантах. Якщо помилка коштуватиме вам післяобіднього часу на відновлення або, що гірше, часу безперебійної роботи (uptime) у продакшені, напишіть хук.
Коротші промпти дають кращі результати. Коли ви переносите механічні правила в скрипти, моделі потрібно менше запам'ятовувати та менше суперечити собі. Контекстне вікно агента — це обмежений ресурс. Не забивайте його нагадуваннями про форматування.
Нарешті, прийміть те, що ваша роль змінюється. Оскільки агенти стають автономнішими, робота людини зміщується від створення контенту до проектування обмежень (guardrails). Ви будуєте harness, який вирішує, до чого модель може торкатися, коли вона може завершити роботу і як вона має поводитися, коли щось іде не так. Це інженерія, а не промптинг.
Джерело, яке надихнуло на цей підхід, та додаткові деталі реалізації можна знайти тут.
Якщо ви розробляєте системи з використанням ШІ-агентів і хочете обмінятися досвідом з іншими фахівцями, ви можете знайти навчальну спільноту GyaanSetu тут.
