← Назад в блог

Программирование с ИИ приносит заботы, которые стандартные инструменты не решают

Иллюстрация, противопоставляющая хаотичные изменения кода ИИ структурированному подходу AITM

Современный ИИ способен за несколько секунд написать функцию, компонент или целый endpoint. Проблема проявляется не там, где её ждут, — не в синтаксисе и не в скорости. Она проявляется в тот момент, когда ИИ приходится затрагивать существующую систему: десятки файлов, историю решений, бизнес-правила, которые нигде не записаны, кроме как «в головах» разработчиков. Как систематически предотвращать эту проблему — тема всей этой серии, а инструмент, к которому мы постепенно придём, называется AITM.

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

Как это выглядит на практике

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

Это не единичные ошибки, а системная проблема: у ИИ-агента нет контекста всей системы — только то, что помещается в prompt и что ему удаётся прочитать через полнотекстовый поиск. Он принимает решения на основе слов, а не бизнес-логики. Если документация доступна, он часто загружает её целиком — включая ту часть, которая не имеет никакого отношения к данному prompt. И это верно даже для самых сильных доступных моделей (Opus, Fable, Astra и подобных): дело не в том, что модель недостаточно умна, а в том, что ей негде систематически хранить эти знания между отдельными вмешательствами.

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

Где именно возникает затык

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

По опыту, практический порог, за которым базовых средств вроде Skill или подсказки в md-файле перестаёт хватать, находится примерно около 150 000 строк кода. Около 300 000 строк среда становится по-настоящему сложной — повседневное состояние начинает рассыпаться, и всё ломается само по себе. Речь идёт о программном обеспечении, построенном на ООП, со сложными логическими условиями и частями, связанными через механизмы сообщений/событий и подобные приёмы. В таком коде связь между вызовом и его обработкой не всегда очевидна, и ИИ с этой частью справляется довольно плохо — весьма вероятно, что он не обнаружит весь код, связанный с данным методом.

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

Казалось бы, это должен решить проверяющий агент, задача которого — убедиться, что всё сделано согласно спецификации. Но что на самом деле означает «проверить»? Если другой ИИ оценивает задачу так же, как она была обработана, вы получаете лишь подтверждение того же суждения, а не независимую проверку. Лишь при использовании для проверки другой и более сильной LLM шанс поймать ошибку действительно возрастает — но это выбор, который кто-то должен сделать осознанно, а не автоматический итог того, что «проверка состоялась».

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

Для более простых вещей — скажем, веб-формы с редактированием, валидацией после заполнения и сохранением данных через бизнес-логику — это обычно нетрудно, и вероятность успеха близка к 99 %. Для более сложных структур можно действительно оказаться в состоянии, когда структура кода начинает рассыпаться, а за одним багом следует другой. Многократный запуск тестов и e2e-тестов может постепенно это исправить, но в по-настоящему сложной системе это может занять много попыток — и каждая чего-то стоит.

Ответ, обещанный в начале

Вернёмся к вопросу из начала: как узнать, что результат действительно верен, а не просто выглядит завершённым? Только по prompt и последующей проверке надёжно этого не определить. Мы видели почему: ограниченный контекст, галлюцинации, распространяющиеся между субагентами, проверка, которая в худшем случае лишь подтверждает ту же ошибку, и исправление по журналу, которое не способно отличить настоящий баг от побочного эффекта.

Это методы, которыми программисты широко пользуются сегодня, и для простых изменений они работают хорошо. Следующий уровень — оркестрация с помощью ИИ: вы готовите определённые данные о системе и поддерживаете их актуальными, чтобы передавать ИИ более качественную информацию и тем самым сужать его возможность сделать что-то иное, чем вы просили. Именно для этого создан AITM — AI Task Manager: прежде чем агент, пишущий код, вообще доберётся до запроса, система подтягивает контракты (документированное поведение), карту DOM и бизнес-логику для данной области — и только затем, обладая этими знаниями, формирует Task. Она опирается не на одного агента напрямую, а на целый Pipeline и другие методы, которые AITM использует для получения лучших результатов.

В следующие дни будет показано, как именно это выглядит в AITM на конкретных prompt, агентах и шагах Pipeline — и почему это иной способ работы с ИИ, чем тот, к которому программисты привыкли в обычной консоли.