Агентная инженерия: от вайб-кодинга к мультиагентным системам

Курс для энтузиастов, которые хотят перейти от простых промптов к профессиональной агентной инженерии. Вы освоите PEV-фреймворк, научитесь проектировать и оркестровать мультиагентные конвейеры, настраивать рабочие процессы в современных инструментах и выстраивать контроль качества и безопасности на каждом этапе.

1. Основы агентной инженерии и вайб-кодинга: от промптов к PEV-циклу

Основы агентной инженерии и вайб-кодинга: от промптов к PEV-циклу

Почему одни разработчики получают от AI-модели чистый, работающий код за один запрос, а другие тратят часы на бесконечные «исправь это, нет, верни обратно»? Ответ — не в выборе модели, а в подходе к организации процесса. Именно здесь начинается агентная инженерия.

Что такое агентная инженерия простыми словами

Представь, что ты нанял толкового стажёра. Можно сказать ему «сделай сайт» — и получить непонятно что. А можно дать чёткое техзадание, показать примеры, объяснить ограничения и проверять результат на каждом этапе. Агентная инженерия — это дисциплина проектирования процессов, контекста и инструментов так, чтобы AI-агент работал предсказуемо и качественно.

> Агентная инженерия — это не про «какой промпт написать». Это про то, как выстроить систему, в которой AI стабильно генерирует качественный код, проходящий ревью и деплоящийся в прод. > > Codenrock

Вайб-кодинг: начало пути

Вайб-кодинг — это подход, когда ты описываешь задачу на естественном языке, а AI-модель генерирует код. Звучит магически, но на практике без структуры это похоже на игру в рулетку: иногда попадает, чаще — нет.

Типичная ловушка новичка — промпт-монстр. Один длинный запрос, в котором смешаны требования к архитектуре, стеку, стилю кода, ограничениям и примерам. Модель теряет фокус, начинает «срезать углы» и выдаёт ИИ-шлак — код, который формально работает, но полон скрытых багов, устаревших паттернов и дыр в безопасности.

Решение — переход от хаотичных промптов к структурированному циклу.

PEV-цикл: планирование, выполнение, верификация

PEV (Plan-Execute-Verify) — это методология, которая превращает вайб-кодинг из азартной игры в инженерный процесс. Работает она так:

Планирование (Plan). Прежде чем просить модель написать код, определи что именно нужно. Не «напиши API», а конкретный контракт: эндпоинт, входные данные, варианты ответов, ограничения. Чем меньше модель додумывает — тем предсказуемее результат. На этом этапе полезно использовать spec-first подход: сначала спецификация, потом реализация.

Выполнение (Execute). Модель генерирует код в рамках заданного плана. Ключевой приём здесь — чанкинг: одна задача — один промпт. Не проси «напиши CRUD API с авторизацией, валидацией и тестами» — разбей на шаги: сначала типы, потом сервисы, потом обработку ошибок, потом роуты. Каждый шаг — отдельный промпт с ревью результата.

Верификация (Verify). Проверка сгенерированного кода. Не глазами — хотя и ими тоже — а системно. Прогон тестов, проверка типов, линтеры, code review. Именно на этом этапе отлавливается ИИ-шлак: галлюцинированные API, устаревший синтаксис, security-дыры.

Аналогия из жизни: PEV похож на работу шеф-повара. Сначала план меню и закупка ингредиентов (Plan), потом приготовление по рецепту (Execute), потом дегустация и корректировка вкуса (Verify). Пропустил любой этап — блюдо не получится.

Шесть приёмов промпт-инженерии, которые работают

PEV-цикл задаёт структуру, но качество зависит от того, как именно ты формулируешь задачи внутри каждого этапа. Вот приёмы, которые реально работают при генерации кода:

  • Контекст-фрейм. Начни с ограничений, а не с задачи. «Проект: Next.js 15, TypeScript strict, Zod, Prisma + PostgreSQL. Не используй any» — один абзац контекста экономит три итерации переписывания.
  • Примеры входа-выхода. Два-три конкретных примера задают формат точнее, чем абзац требований. user@domain.com → valid: true. test@ → valid: false, причина: нет домена.
  • Negative prompting. Скажи, чего НЕ делать. «НЕ меняй сигнатуру. НЕ добавляй зависимости. НЕ трогай /src/core/». Каждое «не» сужает пространство решений.
  • Чанкинг. Одна задача — один промпт. При большом объёме задачи модель теряет фокус и начинает генерировать шаблонный код.
  • Spec-first. Опиши, как API выглядит снаружи, прежде чем просить реализацию. Когда контракт определён, реализация становится механической задачей — именно то, что модель делает лучше всего.
  • Привязка к реальности. Модели выдумывают методы и пакеты. Решение — дать фрагмент реальной документации прямо в промпте. Чем больше конкретных фрагментов кода и типов — тем меньше галлюцинаций.
  • От промпта к системе

    Один хорошо составленный промпт — это здорово. Но профессиональная агентная инженерия начинается там, где заканчивается один промпт и начинается система: конфигурационные файлы, которые задают правила для всех сессий, инструменты, которые дают агенту доступ к реальному миру, и процессы верификации, которые ловят ошибки до продакшена.

    Именно поэтому следующий шаг после освоения PEV — это проектирование мультиагентных систем, где несколько специализированных агентов работают командой. Но об этом — в следующей статье.

    2. Проектирование мультиагентных систем: роли, связи и архитектура команды агентов

    Проектирование мультиагентных систем: роли, связи и архитектура команды агентов

    Зачем нужна команда, если можно нанять одного универсального гения? Вопрос риторический — мы знаем ответ из реальной жизни. Универсальный гений не существует, а вот команда специалистов, каждый из которых делает своё дело отлично, — вполне рабочая модель. С AI-агентами та же история.

    Когда один агент перестаёт справляться

    Один агент справляется с конкретными задачами: написать функцию, провести анализ, ответить на вопрос. Но когда задача требует нескольких компетенций одновременно — например, исследование рынка, затем анализ данных, затем написание отчёта — один агент начинает путаться. Он пытается держать в голове слишком много контекста, переключается между ролями и в итоге делает всё средне.

    Мультиагентная система (МАС) — это архитектура, в которой несколько AI-агентов работают совместно над одной задачей, каждый в своей зоне ответственности. Ключевое условие: агенты должны иметь либо разные наборы возможных действий, либо разные задачи в системном промпте с изолированным контекстом. Просто запустить три копии одного агента — это не МАС, а три экземпляра одного и того же кода.

    Четыре архитектурных паттерна

    Проектирование МАС начинается с выбора паттерна взаимодействия. Вот четыре основных:

    Последовательный пайплайн

    Агенты работают цепочкой: Агент A передаёт результат Агенту B, B — C. Пример: Исследователь → Аналитик → Писатель. Просто реализовать, легко отлаживать, но нет обратной связи — если Агент B получил плохие данные от A, он не может попросить переделать.

    Менеджер-исполнители (иерархия)

    Агент-координатор получает задачу, разбивает на подзадачи, назначает их специалистам и агрегирует результаты. Это самый распространённый паттерн для МАС на языковых моделях. Менеджер решает, кто что делает и когда, — как тимлид в команде разработчиков.

    Коллаборативный (равноправный)

    Агенты общаются напрямую, договариваются и обмениваются информацией без центрального координатора. Гибче иерархии, но сложнее контролировать и отлаживать. Подходит для творческих задач, где важен обмен идеями.

    Состязательный (Adversarial)

    Несколько агентов предлагают решения, затем критикуют работы друг друга. Выбирается или синтезируется лучший вариант. Хорош для аналитических задач, где важны разные точки зрения — по сути, это автоматизированный code review или дебаты.

    Роли в команде агентов

    Как и в реальной команде, в МАС агенты различаются по ролям. Роль определяется тремя вещами: системным промптом (кто ты и что делаешь), набором инструментов (какие действия доступны) и зоной контекста (какую информацию ты видишь).

    Типичный набор ролей для команды разработки:

  • Архитектор — проектирует структуру, предлагает паттерны, не пишет код
  • Разработчик — реализует функционал по спецификации
  • Ревьюер — проверяет код на баги, security-дыры и соответствие стандартам
  • Тестировщик — генерирует и запускает тесты
  • Каждый агент получает свой системный промпт, свои инструменты и свой изолированный контекст. Архитектор не видит код тестировщика, разработчик не получает замечания ревьюера напрямую — всё проходит через оркестратора.

    Связи и каналы коммуникации

    Агенты в МАС должны обмениваться данными. Способ передачи определяет архитектуру системы. Протокол A2A (Agent-to-Agent) стандартизирует это взаимодействие: каждый агент имеет карточку (Agent Card) с описанием навыков, а обмен происходит через объекты Task (задача), Message (сообщение) и Artifact (результат). Важный нюанс: навыки в A2A — это не функции. Функции описываются через протокол MCP, а навыки — это более высокоуровневое описание возможностей агента.

    > Мультиагентная система — это множество AI-агентов, взаимодействующих друг с другом для решения задачи, выполняющих хотя бы одно из условий: агенты имеют разные наборы возможных действий, либо агенты имеют разные задачи и их контекст не является общим. > > Хабр

    Когда МАС — оверинжиниринг

    Не каждая задача требует мультиагентной архитектуры. Добавление каждого нового агента — это дополнительные вызовы модели, рост стоимости, увеличение задержки и сложности отладки. Если один агент справляется — не усложняй. МАС оправдана, когда:

  • Один агент путается на сложных задачах
  • Подзадачи требуют разных инструментов и компетенций
  • Задача имеет чётко разделённые этапы
  • Нужна специализированная экспертиза в разных доменах
  • Начинай с одного агента. Добавляй второго, когда упрёшься в пределах первого. Масштабируй только когда это измеримо улучшает результат.

    3. Оркестрация агентов и субагентов: конвейеры, ACP и управление потоками задач

    Оркестрация агентов и субагентов: конвейеры, ACP и управление потоками задач

    Представь ресторан с десятью поварами, но без шефа. Каждый готовит что-то своё, блюда копятся на столе, никто не знает, что уже готово, а что — нет. Знакомо? Именно так выглядит мультиагентная система без оркестрации. Оркестрация — это слой управления, который решает, кто, когда и что делает.

    Что такое оркестрация агентов

    Оркестрация — это не просто «запусти агентов и они разберутся». Это чёткий план: какой агент получает задачу первой, как передаёт результат следующему, что происходит при ошибке, и когда процесс считается завершённым. Без оркестрации агенты либо дублируют работу, либо зависают в бесконечных циклах обмена сообщениями.

    В терминологии курса используется концепция ACP (Agent Coordination Protocol) — протокол координации агентов, субагентов и внешних инструментов. ACP определяет не только порядок вызовов, но и правила обработки ошибок, таймауты и стратегии повторных попыток.

    Конвейер: самый простой и надёжный паттерн

    Конвейер (Pipeline) — это линейная цепочка агентов, где каждый выполняет свою часть и передаёт результат дальше. Как конвейер на заводе: один рабочий прикручивает колесо, следующий — дверь, третий — красит.

    Пример конвейера для генерации технической документации:

  • Агент-исследователь анализирует кодовую базу и извлекает информацию о функциях
  • Агент-структуризатор организует информацию в логические блоки
  • Агент-писатель генерирует читаемый текст документации
  • Агент-форматтер приводит к единому стилю и формату
  • Преимущество конвейера — предсказуемость. Ты точно знаешь путь данных и можешь отловить ошибку на конкретном этапе. Недостаток — жёсткость. Если Агент-писатель получает плохие данные от структуризатора, он не может попросить переделать — только выдать мусор или упасть.

    Субагенты: вложенная оркестрация

    Субагент — это агент, которого вызывает другой агент для выполнения подзадачи. Это как тимлид, который делегирует часть работы джуниору. Субагент работает в изолированном контексте, выполняет задачу и возвращает результат родительскому агенту.

    Почему субагенты важны? Потому что одна из главных проблем мультиагентных систем — перегрузка агента. Когда один агент пытается держать в контексте слишком много задач, он начинает «срезать углы»: упрощает типы, забывает edge cases, генерирует шаблонный код. Решение — грануляризация: разбить сложную роль на несколько взаимосвязанных агентов.

    > Более надёжная архитектура — рассматривать рабочий процесс как конвейер, где каждый агент выполняет свою часть и передаёт результат следующему. Не стоит передавать всю контекстную информацию по цепочке агентов: это может перегрузить последующие узлы. > > AI Лента

    Управление потоками: таймауты, повторы и эскалация

    Реальные системы падают. Агенты галлюцинируют, инструменты возвращают ошибки, сети обрываются. Оркестрация должна это предусматривать.

    Таймауты. Каждый агент и каждый вызов инструмента должны иметь ограничение по времени. Если агент не ответил за N секунд — оркестратор прерывает его и запасной стратегией.

    Повторные попытки (Retries). При_transient_ ошибке (таймаут сети, временная недоступность сервиса) оркестратор повторяет вызов. Но не бесконечно — обычно 2-3 попытки с экспоненциальной задержкой.

    Эскалация. Если агент не справляется после нескольких попыток, задача эскалируется: либо другому агенту, либо человеку. Это критически важно для production-систем — никогда не оставляй агента наедине с проблемой, которую он не может решить.

    Кнопка отключения. Иногда требуется немедленно остановить все автономные процессы — например, при обнаружении нежелательного поведения. Для критичных процессов важно, чтобы отключение не приводило к полной остановке: нужен детерминированный резервный режим.

    Бесконечные циклы: главная ловушка МАС

    Одна из специфических проблем мультиагентных систем — круговой обмен сообщениями. Два агента начинают переписываться, уточняя детали, и запрос никогда не завершается. Решение — механизм обнаружения циклического поведения: отслеживание истории коммуникаций и прерывание процесса при чрезмерном росте переписки.

    Практический приём: задай лимит на количество итераций между агентами. Если за 5 обменов задача не решена — эскалируй человеку или переключайся на альтернативную стратегию.

    Практическая схема оркестрации

    На практике оркестрация выглядит как конфигурационный файл или код, который описывает граф задач:

    | Элемент | Назначение | |---|---| | Узел (Node) | Один агент или действие | | Ребро (Edge) | Связь между узлами: «после A → B» | | Условие (Condition) | Ветвление: если результат A плох → C, иначе → B | | Таймаут | Максимальное время на узел | | Retry policy | Сколько раз повторять при ошибке |

    Такой граф — это и документация, и исполняемый план. Его можно визуализировать, протестировать и модифицировать, не переписывая логику агентов.

    4. Инструменты и рабочие процессы: Cursor, CLAUDE.md, харнессы и автоматизация

    Инструменты и рабочие процессы: Cursor, CLAUDE.md, харнессы и автоматизация

    Почему два разработчика с одинаковыми навыками получают от AI-модели принципиально разный результат? Один тратит часы на переписывание сгенерированного кода, другой — получает работающий модуль за два запроса. Разница не в модели и не в «удачном промпте». Разница в инструментальной среде, которую каждый из них выстроил вокруг агента. Именно об этом — рабочие процессы агентной инженерии.

    CLAUDE.md: онбординг-документ для AI-агента

    Промпт-инженерия работает на уровне отдельного запроса. Но каждый раз заново прописывать стек, архитектуру и правила проекта — нереально. Всё, что ты пишешь руками в промпте, можно зафиксировать один раз в конфигурационном файле, и агент будет загружать его автоматически.

    CLAUDE.md — это не документация и не README. Это онбординг для AI-агента. Точно так же, как ты вводишь нового разработчика в проект — объясняешь архитектуру, показываешь паттерны, предупреждаешь о граблях — ты делаешь это для модели. Один раз. Дальше агент читает этот файл перед каждой задачей и работает в рамках твоих правил.

    Аналогичные механизмы есть в других средах: Cursor использует .cursorrules, Windsurf — .windsurfrules, Copilot — .github/copilot-instructions.md. Принцип одинаковый, формат файла отличается.

    Структура из пяти секций

    Рабочий CLAUDE.md строится по шаблону, который покрывает 90% ситуаций:

    Проект — краткое описание, стек, архитектура. Одним абзацем: «SaaS-платформа. Next.js 15, Prisma, PostgreSQL, мультисхемная архитектура».

    Структура директорий — где что лежит. src/app/api/ — роуты, src/models/ — схемы, src/components/ — компоненты. Агент должен знать, куда класть новый файл.

    Паттерны кода — один-два примера типичного эндпоинта или компонента. Не описание, а реальный фрагмент. Модель копирует стиль из примера.

    Правила — что делать всегда: async/await вместо промисов, валидация через Zod, формат ошибок, согласование новых зависимостей.

    Запрещено — что не делать никогда: any в TypeScript, console.log в продакшене, прямые SQL-запросы, изменение ядра без явного указания.

    Аналогия из жизни: CLAUDE.md — это как памятка новому сотруднику на первом рабочем дне. Не энциклопедия на 500 страниц, а лист А4 с ключевыми правилами, контактами и «вот тут — грабли, не наступи».

    Три ошибки, которые убивают эффективность

    Слишком длинный. Больше 1000 строк сложно поддерживать в актуальном состоянии. Чем больше правил — тем чаще они противоречат друг другу, и модель начинает выбирать между конфликтующими инструкциями. Держи документ компактным.

    Слишком абстрактный. «Пиши чистый код» — бесполезно. «Каждый API-эндпоинт возвращает { data, error, meta } — вот пример» — работает. Без реальных фрагментов кода CLAUDE.md превращается в корпоративную миссию на стене.

    Устаревший. Переименовали директорию, сменили ORM, обновили фреймворк — а CLAUDE.md описывает прошлую архитектуру. Агент будет генерировать код для проекта, которого больше нет.

    > Начните с 50 строк. Запустите агента, посмотрите, где он ошибается. Добавьте правило. Снова ошибся — добавьте пример. Через неделю у вас будет рабочий документ, выросший из реальных проблем. CLAUDE.md — живой артефакт, не высеченный в камне манифест. > > codenrock.com

    Model Context Protocol: мост между агентом и реальным миром

    CLAUDE.md даёт агенту знания о проекте. Но чтобы агент мог действовать — создавать задачи, отправлять письма, запрашивать данные из базы — ему нужен протокол взаимодействия с внешним миром. Это Model Context Protocol (MCP).

    Архитектура: три роли

    MCP разделяет агента на три компонента:

    Host — приложение, в котором живёт агент: IDE, терминальный клиент или кастомное приложение. Host управляет жизненным циклом и принимает решение, какой инструмент вызвать.

    Client — компонент внутри Host, который держит соединение с конкретным сервером. Один Host содержит несколько Client.

    Server — отдельный процесс, предоставляющий возможности: доступ к файлам, базам данных, API-сервисам. Сервер описывает свои инструменты, и Client получает эти описания при подключении.

    При запуске нового агента по протоколу MCP происходит следующее: Client отправляет на известные ему сервера дискавери-запрос — получает список доступных инструментов с описаниями и схемами параметров. Эти описания записываются в системный промпт агента. Когда пользователь задаёт вопрос, модель читает список инструментов и решает, какой вызвать. Client отправляет запрос нужному Server, получает результат и возвращает его в Host.

    Три примитива MCP

    Tools — функции, которые агент вызывает: создать задачу, выполнить SQL-запрос, отправить письмо. Это основной примитив; подавляющее большинство серверов используют только tools.

    Resources — данные для чтения без побочных эффектов: файлы, конфиги, состояние системы. Resources нужны, когда агенту важно увидеть текущее состояние перед принятием решения.

    Prompts — шаблоны для типовых сценариев. Используются реже, но полезны для стандартизации повторяющихся задач.

    Транспорт

    Два варианта. stdio — для локальных серверов: хост запускает процесс и общается через stdin/stdout. Просто, быстро, без сети. Streamable HTTP — для удалённых серверов: HTTP-запросы с стримингом через Server-Sent Events. Подходит для облачных деплоев.

    Под капотом — JSON-RPC 2.0. Каждый вызов инструмента — пара запрос/ответ. Всё типизировано через JSON Schema — модель точно знает, какие аргументы передать.

    Как агент выбирает инструмент

    Ключевой момент: описание инструмента — это промпт для модели, а не комментарий для человека. Описание «работает с данными» бесполезно. Описание «Возвращает список открытых задач проекта. Принимает статус фильтрации. Если задач нет — пустой массив» — работает. Плохое описание = tool не будет вызван, даже если он делает именно то, что нужно.

    Три грабли при создании MCP-серверов

    Абстрактные описания. «Работает с задачами» — агент не поймёт. «Добавляет задачу в TODO-список. Принимает название и приоритет. Возвращает ID» — поймёт сразу.

    Нет error handling. Когда tool падает с необработанным исключением, агент получает stack trace и пытается его «починить» — обычно делая хуже. Оборачивай в try/catch и возвращай понятное сообщение.

    Переусложнённые параметры. Tool с 10 обязательными полями — лабиринт. Агент запутается и начнёт галлюцинировать значения. Лучше пять простых tools, чем один универсальный.

    Харнессы: упряжь для AI-агента

    Харнес (harness) — это программная оболочка, которая управляет жизненным циклом AI-агента: запускает, контролирует, ограничивает и верифицирует его работу. Если агент — лошадь, то харнес — упряжь, которая направляет её силу в нужное русло.

    Харнес решает три задачи:

    Контроль выполнения. Ограничение по времени, количеству итераций, потреблённым токенам. Если агент «залип» на задаче — харнес прерывает его.

    Санбоксинг. Запуск сгенерированного кода в изолированной среде: контейнере, песочнице, временном worktree. Агент может экспериментировать свободно, но не навредит основному проекту.

    Верификация результата. Автоматический прогон тестов, линтеров, проверки типов после каждого шага агента. Если результат не проходит проверку — харнес возвращает агенту ошибку с контекстом.

    На практике харнес — это набор скриптов и конфигураций, которые оборачивают вызовы агента. Например, перед запуском агента харнес создаёт временную ветку git, после завершения — прогоняет тесты, и только при успехе предлагает создать pull request.

    Git Worktrees: параллельная работа без конфликтов

    Одна из неочевидных проблем AI-разработки: агент занят долгой задачей в одной ветке, а тебе нужно параллельно делать что-то в другой. Переключать ветки нельзя — агент работает с файлами. Клонировать репозиторий заново — долго и неудобно.

    Git worktree — это дополнительная рабочая копия того же репозитория, привязанная к другой ветке. Один .git, несколько директорий с кодом. Каждая может быть открыта в своей сессии AI-агента одновременно.

    Создать worktree: git worktree add ../my-project-feature feature/new-api. Теперь в ../my-project-feature — полная копия проекта на ветке feature/new-api. Открываешь там отдельную сессию — и работаешь параллельно.

    Для мультиагентных воркфлоу это критически важно: каждый агент работает в своём worktree, никто не мешает друг другу. Если результат не понравился — удаляешь директорию. Основная ветка не тронута.

    Автоматизация: от ручных промптов к CI/CD для агентов

    На старте ты работаешь с агентом interactively: пишешь промпт, получаешь код, проверяешь, исправляешь. Но настоящая эффективность приходит, когда этот процесс автоматизируется.

    Автоматизированный пайплайн выглядит так: триггер (push в ветку, создание issue) → запуск агента в sandbox → генерация кода → прогон тестов → создание PR. Человек проверяет только финальный PR, а не каждую строчку.

    Ключевые элементы автоматизации:

  • Триггеры: webhook от git, расписание, ручной запуск
  • Sandbox: контейнер или worktree для изолированного выполнения
  • Верификация: тесты, линтеры, проверка типов — всё, что можно запустить автоматически
  • Уведомления: агент сообщает о результате — успех, ошибка, требуется ревью
  • Такой пайплайн превращает агента из «умного автодополнения» в полноценного участника команды, который работает по тем же процессам, что и разработчики-люди.

    MCP-сервер за пять шагов

    Чтобы закрепить теорию практикой, построим простой MCP-сервер:

    Шаг 1. Инициализация. npx @modelcontextprotocol/create-server todo-server — готовая структура проекта: index.ts, tsconfig, зависимости.

    Шаг 2. Tools. У каждого tool четыре составляющих: имя (add_todo), описание на естественном языке, схема параметров через Zod и обработчик — async-функция. Критически важно: у каждого параметра .describe(). Агент читает именно эти описания.

    Шаг 3. Resources. Текущее состояние данных в JSON — чтение без побочных эффектов.

    Шаг 4. Подключение. В .mcp.json добавляешь сервер: имя и команду запуска. Перезапуск IDE — агент видит tools.

    Шаг 5. Отладка. npx @modelcontextprotocol/inspector — визуальный клиент, показывающий то, что видит агент: список tools, параметры, описания. Можно вызвать любой tool вручную.

    MCP отвязывает инструмент от модели. Написал сервер один раз — он работает с любой моделью, поддерживающей протокол. Это и есть экосистема, в которой агентная инженерия выходит за рамки одного проекта.

    5. Безопасность и контроль качества: борьба с ИИ-шлаком и защита мультиагентных систем

    Безопасность и контроль качества: борьба с ИИ-шлаком и защита мультиагентных систем

    Представь, что твой AI-агент написал 200 строк кода, тесты прошли, PR создан. Ты мёрджишь. Через неделю выясняется, что агент использовал устаревший метод ORM, который silently теряет данные при конкурентных запросах. Код работал — в однопользовательском режиме. В проде с десятью тысячами одновременных сессий — нет. Это и есть ИИ-шлак: код, который формально функционирует, но содержит скрытые дефекты, которые проявляются только в реальных условиях. Борьба с ним — не опция, а необходимость.

    Что такое ИИ-шлак и почему он опасен

    ИИ-шлак — это сгенерированный код, который проходит поверхностную проверку, но содержит один или несколько из следующих дефектов:

  • Галлюцинированные API: вызовы методов и библиотек, которых не существует или которые работают не так, как описано
  • Устаревший синтаксис: использование deprecated-методов, которые ещё не удалены, но уже не рекомендуются и будут сломаны в следующей мажорной версии
  • Security-дыры: SQL-инъекции через string interpolation, XSS через непроверенный вывод, хардкод секретов
  • Happy path only: код, который обрабатывает только идеальный сценарий и падает при любом отклонении
  • Phantom dependencies: импорт пакетов, которые не добавлены в package.json, или наоборот — использование кода, который предполагает наличие неустановленной зависимости
  • Главная опасность ИИ-шлака — его маскировка. Он выглядит правдоподобно, проходит линтер (если линтер настроен слабо), и даже может пройти тесты (если тесты покрывают только happy path). Обнаруживается он позже — в code review, в staging, а иногда — в проде.

    Как ловить систематически

    Ручной code review — необходимый, но недостаточный барьер. AI-агент генерирует код быстрее, чем человек может его ревьюить. Решение — многоуровневая система проверок:

    Уровень 1: Статический анализ. TypeScript strict mode, ESLint с security-плагинами, no-any правило. Автоматически отсекает грубые ошибки ещё до запуска.

    Уровень 2: Unit-тесты. Не просто «тест прошёл», а проверка edge cases: пустые строки, null, отрицательные числа, граничные значения. Если агент генерирует и код, и тесты — убедись, что тесты не тавтологичны (тест проверяет ровно то, что делает код, а не то, что код должен делать).

    Уровень 3: Интеграционные тесты. Запуск в sandbox-окружении, максимально приближённом к проду. Именно здесь всплывают проблемы с конкурентностью, таймаутами и edge cases, которые unit-тесты не покрывают.

    Уровень 4: Human review. Финальный барьер. Но теперь человек ревьюит не 500 строк, а проверяет архитектурные решения и security-аспекты, потому что грубые ошибки уже отловлены на предыдущих уровнях.

    Защита мультиагентных систем: модель угроз

    Когда один агент работает с инструментами через MCP, а несколько агентов общаются друг с другом через A2A, поверхность атаки растёт экспоненциально. Каждый протокол, каждый канал связи, каждый инструмент — потенциальная точка компрометации.

    Угрозы уровня MCP

    Отравление описаний инструментов. MCP-сервер хранит описания своих tools. Пользователь этих описаний не видит — они попадают напрямую в системный промпт агента. Если сервер скомпрометирован, злоумышленник может внести промпт-атаку прямо в описание инструмента. Агент будет «добровольно» выполнять вредоносные действия, потому что описание tool'а говорит ему это сделать.

    > Описание инструментов MCP-сервера пользователь не видит, следовательно, самостоятельно потенциальную промпт-атаку при компрометации сервера не заметит. > > habr.com

    Подмена кода легитимных инструментов. Агент вызывает tool по имени. Если злоумышленник заменяет реализацию tool'а — агент об этом не узнает, потому что GenAI-модель не видит код функции, только её описание. Результат: агент думает, что отправляет письмо, а на деле — экспортирует базу данных.

    Докстринг-инъекция. Распространённая практика — поставлять описания MCP-tools в докстрингах функций. Это удобно для разработки, но создаёт вектор атаки: злоумышленник может прервать контекст докстринга тройными кавычками, вредоносный код и закрыть оставшийся контекст.

    Угрозы уровня A2A

    Отсутствие иерархии и ролевой модели. На данный момент все агенты в A2A равноправны — протокол не предусматривает организационных элементов в карточках агентов. Это значит, что любой агент может отправить задачу любому другому агенту без проверки полномочий.

    Проблемы дискаверинга. Спецификация A2A предлагает два способа обнаружения агентов: задать URL в конфигах или создать реестр агентов. Второй вариант вызывает вопрос доверенности реестра — кто гарантирует, что зарегистрированный агент тем, за кого себя выдаёт?

    Круговой обмен сообщениями. Два агента начинают бесконечный диалог, уточняя детали. Запрос никогда не завершается, ресурсы расходуются. Без механизма обнаружения циклического поведения это приводит к denial-of-service внутри собственной системы.

    Принципы защиты: что делать в первую очередь

    Политики доступа: policy-as-code

    Каждый агент должен иметь явно определённый набор разрешений. Не «агент может делать всё, что описано в его tools», а «агент может вызывать tool X только с параметрами, удовлетворяющими условию Y». Политики задаются в коде и применяются автоматически — не в промпте, который модель может «забыть» или проигнорировать, а в харнесе, который работает детерминированно.

    Аналогия: в больнице у медсестры есть доступ к картам пациентов, но не к финансовой отчётности. Не потому что её «попросили не лезть в финансы», а потому что система физически не пустит. Политики для агентов работают так же.

    Human-in-the-loop для критичных действий

    Не все действия агент должен выполнять автономно. Набор заранее заданных правил определяет ситуации, в которых требуется подтверждение человека. Эти правила могут указываться в системном промпте или, в более критичных сценариях, реализовываться детерминированным кодом вне агента.

    Например, для агента по закупкам правило может звучать так: «Все закупки свыше 50 000 руб. должны быть предварительно проверены и подтверждены человеком». Агент вызывает функцию проверки и не продолжает работу до получения ответа.

    Агент-защитник

    Можно ввести отдельного «агента-защитника», который проверяет рискованное, неэтичное или несоответствующее требованиям поведение других агентов. Основной агент сверяет свои действия с агентом-защитником и не продолжает выполнение, пока не получит разрешение.

    Это похоже на пару «пилот — штурман»: один управляет, второй следит за картой и предупреждает об опасностях. Ни один из них не имеет полного контроля — только вместе они обеспечивают безопасный полёт.

    Кнопка отключения

    Иногда требуется немедленно остановить все автономные процессы — например, при обнаружении нежелательного поведения. Для критичных процессов важно, чтобы отключение не приводило к полной остановке: нужен детерминированный резервный режим, который вступает в действие при отключении автономности.

    Представь автопилот: если система обнаруживает аномалию, она не просто выключается и бросает машину на дороге — она передаёт управление водителю с предупреждением. Агентные системы должны работать так же.

    Санбоксинг и изоляция

    Каждый агент и каждый субагент должны работать в изолированной среде. Контейнеры, виртуальные машины, git worktrees — любой механизм, который гарантирует, что агент не может выйти за пределы своей зоны ответственности.

    Особенно важно это для агентов, которые генерируют и исполняют код. Запуск произвольного кода без санбокса — это как дать незнакомцу ключи от квартиры и сказать «почини мне кран».

    Тестирование мультиагентных систем

    Использование языковых моделей в роли «мозга» агентов добавляет устойчивости, но снижает предсказуемость. Традиционные подходы к тестированию нужно адаптировать к особенностям агентных систем, которые фактически представляют собой «чёрные ящики» в рабочих процессах.

    Подход «разделяй и властвуй»

    Тестируй подсистемы, начиная с разных узлов и точек входа. Не пытайся прогнать всю мультиагентную систему целиком — начни с отдельных агентов, затем с их пар, затем с цепочек.

    Генеративные тесты

    Используй AI-модели для автоматической генерации тестовых сценариев, запускаемых против сети агентов. Это позволяет находить уязвимости и слабые места, которые человек не придумал бы — потому что модель мыслит в других паттернах.

    Песочница перед продом

    Запускай систему в песочнице — в меньшем масштабе и в контролируемой среде — перед постепенным развёртыванием. Не переводи все рабочие процессы на агентов одновременно. Начни с одного, убедись что работает, затем масштабируй.

    Оценка неопределённости

    Языковые модели склонны к фабрикации фактов. Методика оценки неопределённости позволяет повысить надёжность: для критичных задач генерируй несколько вариантов ответа, ранжируй по степени уверенности и выбирай наименее сомнительный. Это повышает надёжность, но замедляет систему и увеличивает стоимость — применяй только для наиболее критичных агентов.

    Надёжность: checkpoints, идемпотентность, graceful degradation

    Production-агентная система должна переживать сбои. Три принципа:

    Checkpoints. Сохраняй промежуточное состояние после каждого значимого шага. Если агент упал на шаге 7 из 10 — не нужно начинать сначала. Восстанови из чекпоинта и продолжи.

    Идемпотентность. Каждое действие агента должно быть безопасно повторять. Если агент дважды отправил один и тот же запрос — результат должен быть одинаковым, а не «создались две копии записи».

    Graceful degradation. Если один агент в системе недоступен — система не должна падать целиком. Она должна переключиться на упрощённый режим: либо на резервного агента, либо на детерминированную логику, либо — на эскалацию к человеку.

    От хаоса к контролируемой системе

    Безопасность мультиагентных систем — это не один инструмент и не одна настройка. Это слой практик, которые накладываются друг на друга: санбоксинг изолирует, политики ограничивают, human-in-the-loop подстраховывает, тестирование проверяет, а мониторинг обнаруживает аномалии в реальном времени.

    Самая частая ошибка в агентных системах простая: сначала все пытаются добиться максимальной автономности, и только потом вспоминают про управляемость. На практике лучше работает другой путь: сначала предсказуемый workflow, потом локальная и измеримая автономность, и только потом — расширение границ самостоятельности агента. Каждый шаг — с верификацией, с политиками, с кнопкой отключения.