Почему системный промпт — плохая линия защиты: архитектура безопасности агентов
Фильтрация вывода, jailbreak-защита и выравнивание модели перестают работать, когда агент управляет реальными инструментами. Разбираем цепочку intent → агент → tool call → исполнение и находим, где должны стоять настоящие барьеры.
Иллюзия контроля через промпт
Индустрия потратила два года на то, чтобы научить модели «не делать плохого». Alignment, RLHF, Constitutional AI, output filtering, jailbreak-детекторы — весь арсенал направлен на один слой: что модель говорит.
Это работало, пока LLM был чат-ботом. Ты пишешь — он отвечает. Если ответ плохой, фильтруй вывод. Проблема замкнута внутри текстового обмена.
Но в 2025-2026 годах модели перестали просто отвечать. Они начали действовать. Агент вызывает API, модифицирует файлы, запускает скрипты, управляет браузером, стучится во внутренние системы. И вот здесь все промпт-гарды превращаются в декорацию.
Что изменилось: от чата к исполнению
Типичный агентный стек: intent → агентный цикл → tool call → исполнение. Четыре этапа. Безопасность в большинстве реализаций живёт внутри агентного цикла — того же контекстного окна, где модель принимает решения. Системный промпт говорит «не удаляй файлы». Output filter проверяет ответ.
Проблема: tool call — это не текст для пользователя. Это JSON, который уходит напрямую в исполнительный слой. Фильтр вывода его не видит или не понимает семантику. Системный промпт — это рекомендация, которую модель может проигнорировать или «забыть» в длинном контексте.
Конкретные сценарии, при которых промпт-гарды не спасают:
Спиральные повторы. Агент получает ошибку, пробует снова, адаптирует подход. Каждый retry — потенциально новый side-effect. Системный промпт не ограничивает количество попыток.
Цепочки побочных эффектов. Агент создаёт файл, затем вызывает скрипт, который его читает и отправляет по API. Каждый шаг по отдельности выглядит безобидно. Цепочка — нет.
Размытие прав. Агент имеет доступ к shell — значит, имеет доступ ко всему, к чему имеет доступ пользователь. «Не делай rm -rf» в промпте — не замена отсутствию sudo.
Отсутствие hard stop. Между решением модели вызвать инструмент и фактическим исполнением нет обязательного шлюза.
Аналогия с распределёнными системами
В распределённых системах эту проблему решили давно. И решили не тем, что заставили приложения «вести себя хорошо». Несанкционированный доступ — auth перед приложением. Перегрузка — rate limits перед приложением. Неконтролируемая мутация — транзакции между приложением и хранилищем. Каскадный отказ — bulkheads в инфраструктурном слое.
Ни одно из этих решений не работает через «пожалуйста, не перегружай сервер» в конфиге приложения. Они принудительны и внешни по отношению к приложению. Агентные системы сейчас там, где были веб-приложения в начале 2000-х: безопасность на уровне «пожалуйста, валидируйте ввод в контроллере». До WAF, до zero-trust.
Где ставить барьеры: execution layer
Единственное место, где контроль может быть принудительным — между tool call и execution layer. Именно здесь нужен шлюз, который отвечает на вопрос: разрешено ли это действие к исполнению?
Что должен делать execution layer
1. Явные разрешения (allowlist, не denylist). Не «запрети rm -rf», а «разреши только чтение файлов из /workspace и запись в /output». Denylist всегда неполон. Allowlist требует явного расширения.
2. Авторизация перед каждым вызовом. Каждый tool call проходит проверку: имеет ли агент право выполнять это действие с этими аргументами? Это не вопрос к модели — это вопрос к policy engine.
3. Rate limiting и бюджеты. Агент может вызвать инструмент максимум N раз за сессию. Суммарная стоимость API-вызовов не превышает X. Количество мутаций файловой системы ограничено.
4. Транзакционность. Критичные операции оборачиваются в транзакцию с возможностью отката. Если цепочка действий прервалась — откат.
5. Human-in-the-loop как circuit breaker. Определённые категории действий требуют подтверждения человека. Не «модель спрашивает» — а execution layer блокирует и ждёт внешнего approval.
Почему промпт-гарды всё ещё нужны (но не для безопасности)
Не стоит выбрасывать системные инструкции. Они полезны для качества (направлять агента к правильным инструментам), эффективности (уменьшить количество бесполезных tool calls) и UX (формировать тон и формат ответов).
Но полагаться на них как на механизм безопасности — всё равно что полагаться на атрибут maxlength в HTML как на защиту от SQL-инъекций. Это подсказка для UI, а не контроль.
Текущее состояние экосистемы
Большинство агентных фреймворков (LangChain, CrewAI, AutoGen) по умолчанию не имеют execution layer с принудительными политиками. Tool executor получает вызов и выполняет его. Некоторые проекты двигаются в правильном направлении:
- Sandboxing: Docker-контейнеры, gVisor, Firecracker — изоляция среды исполнения
- Policy engines: OPA (Open Policy Agent) для авторизации tool calls
- Approval workflows: human-in-the-loop перед деструктивными операциями
Но это фрагментарно. Нет стандарта. Нет общепринятой архитектуры.
Что делать прямо сейчас
- Запускайте агента в sandbox. Docker-контейнер с минимальными правами — базовый минимум.
- Внедрите allowlist для tool calls. Всё, что не разрешено явно — запрещено.
- Добавьте approval для мутаций. Любое действие, меняющее состояние — через подтверждение.
- Логируйте каждый tool call. Не вывод модели — а именно вызовы инструментов с аргументами и результатами.
- Установите бюджеты. Максимум вызовов за сессию, максимум токенов, максимум стоимости. Hard limits, не рекомендации.
Итог
Безопасность агента — это не свойство модели. Это свойство архитектуры. Промпт-гарды работают на уровне намерений. Execution layer работает на уровне действий. Когда агент может действовать — защищать нужно действия, а не намерения.
Системный промпт «не удаляй файлы» — это записка на двери. Execution layer с allowlist и sandbox — это замок. Разница между ними — разница между инцидентом и контролем.
- AI-агенты
- безопасность
- prompt guardrails
- jailbreak
- execution layer
- архитектура агентов
- tool calls
- красная команда