- BrainTools - https://www.braintools.ru -

Меня зовут Михаил Афанасьев, я главный специалист в команде кибербезопасности Platform V в СберТехе, занимаюсь подготовкой продуктов к прохождению сертификации ФСТЭК России. Хочу рассказать о режиссуре LLM-агентов и о том, как выбор ролей и написание промптов превращают хаотичный поток запросов к нейросети в надёжную инженерную систему.
Всё началось с простой реплики в темноте зала: «Было бы круто, если бы кто‑то за меня бродил по репозиторию и вылавливал там секреты».
Поначалу это выглядело как монодрама. Один актёр (LLM), один микрофон (чат), одна задача: «Нужно найти в файлах что-то опасное». Но любой режиссёр скажет вам: хороший спектакль не строится на одном монологе. Если заставить одного актёра бегать по сцене, искать реквизит, анализировать улики и писать рецензию самому себе, он устанет, собьётся и начнёт импровизировать там, где нужно следовать сценарию.
Так родилась идея творческой команды, а вместо одинокого актера появилась труппа.
Почему аналогия с театром? Разработка сложной системы напоминает постановку спектакля: есть сценарий (промты), актёры (агенты), режиссёр (оркестратор), а пользовательский интерфейс или CI/CD-журнал — это зрительный зал. Я давно увлекаюсь театром, и мне показалось, что эта метафора лучше всего объясняет хаос, который возникает, когда один агент пытается сыграть всю труппу сразу. Поэтому далее я буду использовать термины из мира сцены, чтобы показать, как превратить импровизацию в отлаженную систему.
Эволюция [1] нашего проекта прошла две классические стадии, знакомые любому, кто ставит эксперименты с нейросетями.
Замысел: одна модель, один промпт: «Вот код, найди секреты»
Проблема: актёр пытается играть всё сразу. Он ищет, анализирует и пишет отчёт на одном дыхании. Результат непредсказуем: где-то гениально, где-то галлюцинации, а формат ответа меняется каждый раз. Встроить это в CI/CD невозможно — это как строить график спектакля по настроению ведущего актера.
Появляется желание разделить сцены. Отдельно поиск, отдельно анализ, отдельно финал.
Зачем нам эта труппа? Зачем вообще усложнять постановку и звать нейросеть, если есть сканеры? Проблема в шуме. Специальные инструменты, такие как GitLeaks, выдают тонну срабатываний. Человек не способен реально всё посмотреть и вынести вердикт вручную. Поэтому мы внедряем LLM-агент не вместо инструмента, а как умный фильтр. Как и в современных SAST-решениях, это нужно для уменьшения времени на разбор полётов и увеличения полноты анализа.
Требования к постановке. Система обретает форму труппы. Каждый агент — это характер со своей биографией (промптом) и задачей.
Система должна иметь свойства:
Воспроизводимость: одна и та же пьеса должна звучать одинаково.
Проверяемость: логика [2] не должна растворяться в импровизации.
Масштабируемость: завтра можно ввести нового персонажа (например, проверку лицензий), не переписывая всю пьесу.
Для достижения такой системы должны присутствовать роли:
Режиссёр (оркестратор): принимает заявку от зрителя и распределяет роли.
Сыщик (сканер): ходит по файлам, ищет улики.
Эксперт (аналитик): проверяет, настоящая ли это улика или ложный след.
Летописец (репортёр): пишет итоговый протокол для истории.
Если в классической UML-диаграмме классы — это просто сухие прямоугольники с методами и полями, то в мультиагентной системе каждый «прямоугольник» оживает. К структуре добавляется «психология»: системный промпт, стиль общения, приоритеты и жёсткие ограничения, которые определяют, как именно агент будет реагировать [3] на данные.
Распределение ролей
|
Роль |
Характер |
Задача на сцене |
|
Оркестратор |
Спокойный управленец |
Принимает запрос, разбивает на сцены, следит за таймингом. |
|
Сканер |
Внимательный, дотошный |
Сканирует текст и отчёты инструментов (например, GitLeaks), не упускает детали. На вход ему поступает не только код, но и результаты работы специализированных инструментов. |
|
Аналитик |
Критичный, скептичный |
Не верит Сканеру на слово. Перепроверяет каждую находку. |
|
Репортёр |
Педантичный писарь |
Превращает хаос данных от Аналитика в строгий JSON или Markdown. |
Чтобы актёры не перебивали друг друга, им нужна последовательность реплик. В нашем случае это структурированные сообщения (JSON) — что-то вроде текста роли.
Пример реплики от Режиссёра к Сыщику:
Чёткий контракт позволяет заменять актёров. Если завтра Сыщик устанет (например, модель станет дорогой), то вы сможете заменить его на другого, не меняя сценарий для Режиссёра.
{
"role": "code_scanner",
"task": "scan_files",
"payload": {
"root_path": "/repo",
"files": [
{ "path": "src/app.py", "content": "..."}
]
"tool_results": [
{ "source": "gitleaks", "findings": [...] }
]
},
"meta": {
"request_id": "123e4567",
"status": "pending"
}
}
Промпт в мультиагентной системе — как полноценный сценарий. В нём прописано не только «что сказать», но и «как играть», «какова мотивация» и «что делать в экстренной ситуации».
Структура идеального сценария. Хороший промпт — это баланс между свободой актёра и дисциплиной режиссёра.
Шаблон промпта для агента-Сыщика:
Роль: Ты — LLM‑агент, специализирующийся на обнаружении секретов в исходном коде. Твой характер — внимательный, дотошный и осторожный.
Цель (мотивация [4]):
— Найти потенциальные секреты (пароли, токены).
— Минимизировать ложные срабатывания (не поднимать шум напрасно).
— Дать чёткое обоснование каждой находке.
Контекст (декорации):
— Секреты живут в строках, переменных окружения, конфигурациях.
— На вход поступают файлы и результаты работы специализированных инструментов.
— Строки типа “TODO”, “FIXME” — это не секреты, игнорируй их.
— Краткие числа (1, 0, 123) не являются секретами.Формат выхода (регламент):
Отвечай строго в формате JSON. Никакого текста вне JSON.json > { > "secrets": [ > { > "file": "путь/к/файлу", > "line": номер_строки, > "snippet": "подозрительная строка", > "reason": "краткое объяснение" > } > ] > } >Ограничения (запреты):
— Не придумывай файлы. Используй только предоставленные данные.
— Если секретов нет, то верни{ "secrets": []}.
Важно не сваливать всё в одну кучу. Спектакль идёт по актам:
Акт 1 (Оркестратор): получает задачу «проанализировать репозиторий»; решает, какие сцены (файлы) играть.
Акт 2 (Сканер): получает файлы, ищет кандидатов.
Акт 3 (Аналитик): подтверждает или отбрасывает кандидатов.
Финал (Репортёр): собирает всё в читаемый вид.
Каждому акту — свой промпт, чтобы можно было отлаживать каждую мизансцену по отдельности.
Как это выглядит за кулисами? Принцип «одна театральная роль — один программный класс» упрощает разработку. Каждый класс инкапсулирует свой системный промпт, знает, какие данные принимать на вход, и строго регламентирует формат ответа.
Мы оборачиваем LLM-клиент в класс, который хранит свой системный промпт и знает, как взаимодействовать с залом.
class AnalyzerAgent:
def __init__(self, llm_client, system_prompt: str):
self.llm = llm_client
self.system_prompt = system_prompt # Сценарий роли
def analyze(self, text: str) -> dict:
# Формируем контекст диалога
messages = [
{ "role": "system", "content": self.system_prompt},
{ "role": "user", "content": f"Проанализируй этот текст:nn{text}"}
]
# Вызов модели (Игра актёра)
response = self.llm.chat(messages)
# Валидация ответа (Контроль режиссёра)
try:
return json.loads(response["content"])
except json.JSONDecodeError:
return {"error": "Actor broke character", "raw": response["content"]}
Перед написанием кода я задал себе вопросы, как и при подготовке пьесы:
Что актёр (агент) должен делать в одиночку?
Какой реквизит (данные) ему доступен?
Какие решения он принимает сам, а какие выносит на суд зрителя?
Так и записали в спецификации: Описание → Вход → Выход → Ограничения. Это спасёт от хаоса в промптах.
Чтобы теория не оставалась абстракцией, посмотрим, как агенты обмениваются «репликами» на конкретном примере. Допустим, мы сканируем файл config.py [5].
Входные данные: фрагмент кода API_KEY = "sk-1234567890".
Ответ агента (JSON):
{
"secrets": [
{
"file": "config.py",
"line": 15,
"snippet": "API_KEY = "sk-1234567890"",
"reason": "Похоже на ключ доступа API, высокая энтропия строки"
}
]
}
Входные данные: результат от Сканера.
Задача: подтвердить, не является ли это тестовым значением.
Ответ агента (JSON):
{
"verified": true,
"confidence": 0.95,
"comment": "Ключ имеет префикс sk-, характерный для продакшен-среды. Не похоже на заглушку."
}
Входные данные: подтверждённая находка от Аналитика.
Ответ агента (Markdown):
## Отчёт о безопасности
| Файл | Строка | Статус |
| --- | --- | --- |
| config.py | 15 | 🔴 Критично (Secret Found) |
Такой подход позволяет видеть журнал на каждом этапе и быстро находить, где «актёр» сбился с роли.
Почти каждая премьера проходит через стадию «что-то пошло не так». Вот типичные проблемы нашей труппы и способы их решения.
|
Ошибка [6] |
Почему спектакль рушится |
Как исправить режиссуру |
|
«Играй всё» |
«Найди, исправь, объясни». Актёр теряется, смешивает жанры. |
Дробите роли. Поиск, анализ, отчёт — это разные агенты. |
|
Импровизация |
Нет формата ответа. Невозможно понять конец сцены. |
Требуйте JSON. Закрепляйте формат: «Если тишина — верни пустой список». |
|
Галлюцинации |
Актёр выдумывает файлы, которых нет в декорациях. |
Жёсткие ограничения. «Используй только входные данные». |
|
Смешение амплуа |
Актёры есть, но они нарушают границы ответственности. Например, Оркестратор начинает сам сканировать код, а Репортёр — принимать решения о безопасности. Это нарушение субординации. |
Разделяйте сценарии. Оркестратор знает план, Репортёр — контекст задачи. Чёткие контракты на входе и выходе. |
Нам помогло проведение генеральных репетиций и тестирование промптов интерактивно (через playground), добейтесь стабильной игры, и только потом выпускайте на суд зрителей (в эксплуатацию).
Если снять весь технический грим, то LLM‑агент — это договорённость между разработчиком и моделью. Договорённость базируется на трёх принципах, которые мы последовательно утверждали в предыдущих актах нашей постановки:
Характер персонажа (акт II): о роли, которую играет агент.
Язык реплик (акт II): о формате, в рамках которого агент общается с «труппой».
Право на импровизацию (Акт III): о том, какие решения модель принимает самостоятельно.
Промпт-инженерия в этой картине — это не магия заклинаний, а драматургия. То же самое проектирование интерфейсов, только в текстовом виде и с участием полноценного (пусть и искусственного) актёра.
Когда мы начали проектировать систему через призму театра, хаос импровизации уступил место чёткой драматургии. Роли разделились, контракты стали жёсткими, а отладка каждой «сцены» — предсказуемой.
Сегодня эта «труппа» уже работает в production и регулярно проверztn репозитории на утечку секретов. Театральная метафора оказалась не просто красивой обёрткой: она помогла нам бесшовно встроить агенты в действующие CI/CD-процессы, упростить коммуникацию внутри команды и легко масштабировать систему — новых «актёров» мы подключаем, не переписывая оркестратора. Теперь это не эксперимент, а рабочий инженерный инструмент, чья логика и характер зафиксированы в коде и сценариях.
Автор: Skaslik
Источник [7]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/29814
URLs in this post:
[1] Эволюция: http://www.braintools.ru/article/7702
[2] логика: http://www.braintools.ru/article/7640
[3] реагировать: http://www.braintools.ru/article/1549
[4] мотивация: http://www.braintools.ru/article/9537
[5] config.py: http://config.py
[6] Ошибка: http://www.braintools.ru/article/4192
[7] Источник: https://habr.com/ru/companies/sberbank/articles/1031026/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1031026
Нажмите здесь для печати.