К содержимому
Завалищев
База знаний
Исследования ИИ 9 мин чтения

Почему системный промпт — плохая линия защиты: архитектура безопасности агентов

Фильтрация вывода, 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 перед деструктивными операциями

Но это фрагментарно. Нет стандарта. Нет общепринятой архитектуры.

Что делать прямо сейчас

  1. Запускайте агента в sandbox. Docker-контейнер с минимальными правами — базовый минимум.
  2. Внедрите allowlist для tool calls. Всё, что не разрешено явно — запрещено.
  3. Добавьте approval для мутаций. Любое действие, меняющее состояние — через подтверждение.
  4. Логируйте каждый tool call. Не вывод модели — а именно вызовы инструментов с аргументами и результатами.
  5. Установите бюджеты. Максимум вызовов за сессию, максимум токенов, максимум стоимости. Hard limits, не рекомендации.

Итог

Безопасность агента — это не свойство модели. Это свойство архитектуры. Промпт-гарды работают на уровне намерений. Execution layer работает на уровне действий. Когда агент может действовать — защищать нужно действия, а не намерения.

Системный промпт «не удаляй файлы» — это записка на двери. Execution layer с allowlist и sandbox — это замок. Разница между ними — разница между инцидентом и контролем.