Если вайб-кодинг это гусеница, а харнесс это куколка, то что дальше? Я называю следующую стадию имаго-кодингом (имаго: взрослая бабочка).
Гусеница жадно жует все подряд: даешь промпт, опционально указываешь скилл, получаешь код и надеешься, что результат окажется тем, что тебе нужно. Куколка строит вокруг модели каркас из инструментов, тестов и циклов проверки, и полученный харнесс превращает модель в агента. А бабочка это модель, которая уже сама стала частью проекта: знает его данные, его конвенции и документацию и использует те же привычки в разработке.
Давайте посмотрим, как моя система разработки дошла до имаго.
Вначале я делал так же, как все: брал нейросеть и встраивал в существующие процессы разработки. Сначала это были чаты, затем плагины для IDE, затем собственный плагин под любимую IDE с MCP/SKILLS/TOOLS/AGENTS и локальной моделью, первые попытки написать харнесс, появление общедоступных харнессов и переход на них, дальнейшее улучшение харнесса плагинами.
Раз за разом я вносил разные изменения, которые скорее ускоряли, чем улучшали один и тот же этап, а сам процесс разработки, сложившийся еще на заре вайб-кодинга, оставался прежним.
В конечном итоге качество перестало расти, а скорость перестала быть целевой метрикой для улучшения. Тогда я понял, что для того, чтобы двигаться дальше, придется переосмыслить и поменять весь жизненный цикл разработки, от постановки задачи до сопровождения: этапы, их порядок и мою роль в них как человека. Так, от постоянных попыток улучшить старый процесс (вайб-кодинг/харнесс) я начал менять сам процесс разработки (имаго-кодинг).
Многочисленные исследования подтверждают то, к чему многие уже и так пришли: ИИ работает как усилитель, сильные процессы он ускоряет, а слабые делает заметнее вместе с их узкими местами. Скорость разработки растет, и вместе с ней растет технический долг, т.к. у разработчиков остается все меньше времени разбирать лапшу, которую написал ИИ.
Это в свою очередь бьет по безопасности поставки продукта, т.к. так же быстро и качественно принимать результат работы ИИ еще не научились, а обмазывание тестированием со всех сторон, конечно, полезно, но скорее маскирует проблему, чем исправляет ее.
Почему фронтирная модель не подходит
Проблема не в том, что большие модели глупые. Они отлично пишут типовой код и знают почти все. Проблема в другом: они не знают моего проекта. Не знают, что в этих логах время хранится в локальной зоне заказчика, что колонка в таблице после миграции означает другое, что мы договорились считать метрики только на временном отложенном срезе, что у нас есть свой слой абстракции со своими примитивами и бизнес-сущностями. Каждый раз я тратил большую часть промпта на объяснение контекста, а модель все равно срывалась на «среднепопулярное» решение.
В моем случае проблема стоит наиболее остро, потому что я ML-разработчик, и на задачах машинного обучения это особенно заметно. В 2024 году, когда вышел бенчмарк MLE-bench (75 соревнований Kaggle), сильная на тот момент модель в связке с харнессом AIDE получала хотя бы бронзовую медаль лишь примерно в 17% случаев.
За два года результат вырос: специализированные агентные системы сообщают уже о 65-70% (бронза означает попадание в top 40%). Но это публичные, хорошо описанные задачи с чистой постановкой, и высокий балл на них мало говорит о том, справится ли модель с закрытым проектом, где нет готовых решений и описанного контекста. Корень проблемы не в общей силе модели, а в том, что она не знает именно этот конкретный проект.
Есть и вторая причина, чисто правовая. Я работаю с данными предприятий, а там почти всегда есть либо коммерческая тайна, либо персональные данные, либо и то и другое. Отправлять такие данные в зарубежное облако уже чревато огромными штрафами. Моя система за одну задачу делает сотни запросов, и в каждом могут оказаться куски реальных данных. Проще устроить все так, чтобы данные вообще не покидали контур. Локальная модель это позволяет: код, схемы, логи и обучающие выборки остаются на моих машинах или в контуре заказчика.
Как я до этого дошел
Сначала имаго-кодинга не было вовсе, была обычная практика. Я заметил, что почти на каждом проекте дообученная модель в проде показывает результат лучше, чем такая же недообученная, даже если ей дать хороший промпт.
Это неудивительно: я занимаюсь относительно узкими задачами с одной и той же структурой данных, а именно такие задачи выигрывают от дообучения. Но дальше я задал себе простой вопрос: если дообучение помогает модели в проде, почему я не делаю то же самое с моделью, которая эти системы пишет?
К этому моменту у меня уже был индивидуальный RAG под каждый проект: харнесс собирал статьи и документацию, а модель их использовала. Но, в отличие от модели заказчика, полноценное обучение собственной модели для разработки под каждый проект не выглядело здравой идеей по затраченному времени. В одном из проектов я работал с диффузными моделями для генерации изображений из шума, где, помимо прочего, необходимо было создать адаптеры для генерации изображений в определенном стиле и с определенными элементами.
И тут меня накрыло озарение: LoRA изначально создавали для языковых моделей, но массовое распространение она получила в адаптации diffusers-архитектур, где сдвигает генерацию в нужную сторону. Так почему бы не вернуть ее в transformers и не создать адаптер для генерации кода, который будет смещать знания LLM в нужную проекту сторону?
Таким образом, LoRA стала следующим шагом. RAG стал приносить строителю (системе разработки) знания о проекте, а адаптер должен был принести привычки. Это два крыла имаго-кодинга, необходимые для полета: без RAG адаптеру не за что зацепиться, а без адаптера строитель каждый раз заново учится писать так, как принято в конкретном проекте или отрасли.
Почему все говорят о харнессе и RAG, но не об адаптации модели, ведь у многих разработчиков уже есть достаточные GPU-мощности для этого? Я считаю, что это еще одно когнитивное искажение, ведь рисовать картинки и генерировать слова внешне абсолютно разные действия и архитектуры, хотя внутри те же слои, нейроны и веса.
Меня уже спрашивали, не является ли имаго-кодинг вариантом spec-driven development, то есть разработки, ведомой спецификациями, которая сейчас набирает популярность вместе с харнессами. Это не так, главное отличие в том, что именно дорабатывается. SDD улучшает запрос: агент общего назначения получает подробное структурированное описание того, что нужно сделать. Имаго-кодинг улучшает исполнителя: меняется сама модель и ее представление о том, как в этой теме решают задачи.
Схема строителя: харнесс, RAG, LoRA
Первый слой это харнесс, который собирает знания. Он берет тему проекта, ходит на arXiv, скачивает свежие статьи, режет их на осмысленные куски и складывает в векторный индекс для следующего слоя. Туда же попадают документация проекта, схемы данных и история коммитов.
Второй слой это RAG. При его построении я использую контекстуальный чанкинг с векторными эмбеддингами, BM25 и RRF. Эту идею я подсмотрел у Anthropic.
Третий слой это LoRA/QLoRA. Веса модели-строителя класса 27-35B замораживаются, обучаются только небольшие добавки к матрицам. При таком подходе число обучаемых параметров можно сильно сократить на выбранном спектре задач, поэтому дообучение под каждый проект стало доступным индивидуальному разработчику без большого GPU-кластера (в моем случае достаточно 48GB). Обучающие пары я беру из истории самого проекта и родственных проектов, например из GitHub-репозиториев. Идею я заимствовал у разработчиков OctoCoder, которые придумали, как превращать историю публичных Git-репозиториев в источник размеченных учебных данных.
Раньше каждое правило проекта, которое я указывал в промпте, оплачивалось токенами в каждом запросе и съедало окно контекста. По аналогии с дистилляцией моделей я перешел на дистилляцию контекста: после дообучения модель ведет себя так, будто инструкция у нее перед глазами, а окно остается свободным для реальной работы.
Совместная работа этих слоев и есть имаго-кодинг. LoRA обучается не отдельно от RAG, а вместе с ним: примеры уже содержат найденные куски контекста. Так модель учится не только «писать как я», но и пользоваться найденным, в том числе игнорировать лишнее. Этот подход я взял из развития идеи RAFT, где модель обучали на вопросах вместе с релевантными и отвлекающими документами. К этой схеме я пришел далеко не сразу, перебрав и протестировав несколько десятков различных идей и методик.
Самое сложное в имаго-кодинге это правильный сбор датасета для модели-строителя, и здесь я напрыгался на граблях когнитивных искажений.
Первое большое искажение, на преодоление которого ушло огромное количество времени, касалось размера датасета. Оказалось, что больше не значит лучше. В первых версиях я собирал выборку по принципу «взять все, что есть»: вся история репозиториев, все статьи и ноутбуки, все сгенерированные примеры и т.д. Строитель от этого только ухудшался, а мне казалось, что данных просто недостаточно. Выяснилось, что небольшой набор хороших данных дает больше, чем большой набор усредненных.
С тех пор я вычищаю несколько вещей. Во-первых, примеры, которые учат фактам, а не привычкам (почему это важно, расскажу ниже). Если ответ опирается на знание, которого у модели нет, такой пример я либо убираю, либо перевожу в RAG. Во-вторых, код, который не прошел тесты или проверку на реальной версии языка. В-третьих, повторы: коммиты вида «поправил опечатку» и десять его копий слишком сильно учат одному и тому же. В-четвертых, старые решения, которые я сам уже считаю плохими: адаптер закрепит их с той же уверенностью, что и хорошие. В-пятых, утечку между обучением и проверкой: если задачи для проверки строителя пересекаются по времени с обучающими коммитами, я делю их по дате. И в-шестых, я обязательно слежу за балансом по типам задач. Если семьдесят процентов выборки это мелкие правки, строитель отлично правит мелочи и теряется, когда нужно спроектировать новый модуль. Поэтому я смотрю на состав выборки так же внимательно, как на ее размер.
Второе большое искажение было в понимании того, что LoRA умеет, а что нет. Я думал, что дообучение вкладывает знания в модель. Оказалось, что это не так: новые факты модель при дообучении усваивает медленно, а по мере усвоения растет склонность к галлюцинациям.
Что же тогда делает моя LoRA? Судя по моим наблюдениям и найденным исследованиям, она учит поведению. Примерно от 500 до 1000 аккуратно подобранных примеров хватает, чтобы задать модели стиль и формат ответов, потому что знания в основном закладываются на предобучении. Мне это и нужно: чтобы строитель писал код в структуре моего репозитория, используя существующую логику и интерфейсы, вызывал мои утилиты, соблюдал мои проверки и не изобретал свои. В итоге факты приносит RAG, а привычки дает LoRA.
Третье большое искажение: я слишком доверял научным статьям, препринтам на arXiv, а также прикладным работам по узким темам. Когда харнесс начал собирать статьи с arXiv, я столкнулся с тем, что примерно у половины статей, на выводы которых я мог бы опереться, нет кода, и проверить их заявления нельзя. А там, где код был и я запускал его на своих данных, результат обычно получался заметно хуже заявленного.
Оказалось, что об этом уже известно: по оценке различных исследований, у статей с открытым кодом и данными воспроизводится около 80% результатов, а у статей, где открыты только данные, около 33%. Чаще всего это проявляется на новых архитектурах и методах, поэтому их приходится проверять вручную, т.е. фокус работы смещается в R&D.
После дообучения строителя я столкнулся с небольшим проявлением эмерджентности модели. Она стала сама определять, какие решения из статей стоит брать из RAG-выборки, а какие нет. Я думаю, что это следствие смещения распределения. Адаптер обучен на примерах, где решения прошли тесты и проверку на отложенной выборке, и у модели складывается внутреннее представление о том, как в этой области выглядят решения, которые работают. Метод из статьи, который в это представление не укладывается, она воспринимает как малоправдоподобный и дает ему меньший вес. Это согласуется с тем, что LoRA учит поведению и предпочтениям, а не фактам: у модели появляется «вкус» по отбору решений, что также относится к поведению.
Теперь о том, ради чего вся эта конструкция затеяна. Имаго-кодинг смещает распределение знаний в модели, продавливая путь к решению. Модель общего назначения на любой вопрос держит в голове сотни подходов, и вероятность между ними распределена по тому, что чаще встречалось в ее обучающих данных. Для типовой задачи это отлично. Для узкой задачи проекта это плохо: правильный подход в общем распределении не самый вероятный, он один из многих, а рядом стоят десятки правдоподобных, но неподходящих.
Дообученная локальная модель с LoRA-адаптером становится специализированной в конкретной теме: вероятность перетекает к тому, что работало именно в этой теме, и путь к решению из одного из тысячи превращается в самый «протоптанный». Я не утверждаю, что такая модель умнее фронтира: в общем смысле фронтир гораздо умнее. Адаптер смещает не столько знания, сколько предпочтения по их выбору, и переставляет приоритеты между тем, что модель и так умеет. RAG дает факты (версии, схемы, статьи), а адаптер выбирает, что из этого важно и в каком порядке действовать.
Это помогает преодолеть распространенный сбой агентных систем в цикле разработки: тест падает, модель чинит, тест падает по-другому. Модель общего назначения в такой ситуации нередко ходит по кругу: предлагает исправление A, потом B, потом снова A с небольшой переделкой, потому что все три выглядят одинаково разумно. Или уходит в менее релевантные решения: переписывает то, что работает, вместо того чтобы искать причину там, где она в проектах такого типа обычно сидит. Адаптер, обученный на истории проектов, где такие задачи уже решались, смотрит сразу туда, где ответ обычно лежит. В итоге в своей узкой теме модель тратит меньше шагов на рабочее решение, меньше спотыкается и не ходит по кругу.
Смещение распределения также улучшает качество кода. Напомню, универсальная модель пишет усредненный код: он работает, но собран из того, что чаще встречалось в обучающих данных, а не из того, что актуально в конкретном проекте. Вместо существующего хелпера появляется новый, вместо бизнес-сущности проекта собственная структура, вместо вызова уже написанного сервиса копия его тела. Получается рабочая лапша, которую потом долго разбирает ревьюер (если вообще разбирает).
Это проблема всей отрасли. Отчет с аналитикой GitHub-репозиториев основан на 211 миллионах измененных строк за 2020-2024 годы. Он зафиксировал восьмикратный рост частоты повторяющихся блоков кода в 2024 году. Доля перемещенных строк (признак рефакторинга и повторного использования) упала с примерно 25% в 2021 году до менее 10% в 2024. По моему мнению, это следствие распространения ИИ-ассистентов с моделями общего назначения.
Имаго-модель пишет иначе. Если в проекте есть кодовая база, строитель пишет код так, как принято в ней: использует ее бизнес-сущности и абстракции, а не сходу изобретает свои. Если кодовой базы еще нет, он пишет так, как принято в этой отрасли, потому что привычки перенял через LoRA из родственных проектов и отобранных примеров из отрасли.
Ревью идет быстрее: ревьюер видит знакомую структуру, знакомые имена и небольшие диффы, а не десятки строк, которые нужно сверять с тем, что уже есть в проекте. Технического долга становится меньше: меньше дублирования, больше повторного использования, меньше расхождений с соглашениями. Есть и оборотная сторона: если в проекте уже накоплен долг, строитель, обученный на нем, будет воспроизводить и его, поэтому отбор данных, о котором я писал выше, здесь критичен.
Еще одно искажение, от которого я избавился после перехода на имаго-кодинг: я думал, что со временем потеряю навыки разработчика, ведь если код пишет модель, то разработчик деградирует. В имаго-кодинге я оказываюсь в петле получения знаний из-за устройства самого процесса. Чтобы собрать датасет для строителя, мне приходится постоянно заниматься R&D: читать статьи и разбираться в архитектурах, изучать код репозиториев проекта и родственных проектов, решать, какие решения включить в выборку, а какие выбросить и почему. Харнесс помогает: собирает, суммирует, ищет, но решение остается за мной, и принять его, не понимая сути, нельзя. Чтобы отличить хороший коммит от костыля, нужно понимать архитектуру глубже, чем требуется для того, чтобы просто принять сгенерированный код, а это, на мой взгляд, и есть ядро квалификации.
Возможно, на следующих уровнях развития систем разработки (пост-имаго) эта проблема вернется, т.к. модели разовьются настолько, что отбор данных и прием результата целиком отдадут харнессу, не читая. Вряд ли это вопрос ближайшей пары лет.
Соберу все в одну картину: изменился не только сам процесс разработки, изменилась роль разработчика в процессе: из напарника харнесса он стал архитектором модели-строителя. Также изменились затраты времени: центр тяжести сместился с разработки на данные и проверку, и сама разработка стала самым коротким этапом.
На практике срок создания проектов сократился, а качество при этом выросло. В среднем за месяц я делаю то, что команда из трех человек делает за три месяца. Конечно, здесь играют роль шестилетний опыт в ML и некая «насмотренность», позволяющая относительно быстро собирать датасеты, но и сам процесс не отстает. Модель-строитель уже знает проект, данные проверены до начала разработки, а проверка не пускает ошибки дальше, поэтому не приходится переделывать. По моим наблюдениям, то, что раньше всплывало на приемке, здесь часто ловится на первых этапах.
Важное для меня следствие: на такой результат обратили внимание B2B-интеграторы. Раньше я работал в основном напрямую с клиентами, а теперь все больше работы идет через субподряд и white label-решения для интеграторов. Они приходят с проектом, где сжатые сроки или сложная специфика. Я делаю ядро системы в виде модели или всю систему, а конечному заказчику она уходит под их брендом.
Изменилась и моя собственная роль. Я все меньше пишу код и все больше занимаюсь тем, что не делегируется: R&D, подготовкой данных для имаго (то есть для строителя), архитектурными решениями, контролем и проверкой результата.
Слабые места
-
Адаптер привязан к конкретной версии базовой модели, и при выходе новой базовой модели его приходится обучать заново. Фронтирные модели улучшаются каждые несколько месяцев, обучение адаптера занимает 1-2 дня. В большинстве проектов это не критично, и обновление адаптера можно делать примерно раз в год. Мне же приходится делать это на каждом новом проекте.
-
Обучаясь на истории существующего проекта, адаптер перенимает и старые баги, и устаревшие привычки. Поэтому в выборку идет только то, что прошло тесты, статический анализ и хотя бы поверхностное ревью, но полностью этот риск не снимается. То же относится к скиллам: они фиксируют соглашения проекта, включая устаревшие, поэтому их нужно пересматривать по мере рефакторинга.
-
Необходимо делать отдельный адаптер под каждого клиента: никаких общих обучающих выборок между проектами, максимум общие статьи с arXiv по одной отрасли. Адаптер, обученный на данных клиента А и попавший в проект Б, это не только утечка, но и ухудшение качества работы системы. За 21 год в ИТ-разработке и комплексной автоматизации предприятий я ни разу не видел два одинаковых проекта в одной и той же сфере.
-
Считать стоимость токенов в имаго-кодинге не нужно. Вместо этого нужно считать GPU, электричество и, главное, свое время на подготовку данных и обучение. CAPEX/OPEX тут со своими нюансами. Для больших проектов это окупается, для двухчасовой задачи проще взять модель без адаптации.
-
Модель, которая знает, что обычно работает, склонна недооценивать по-настоящему новое. Хорошая идея из статьи без кода или с непривычной формулировкой может получить мало веса. Поэтому в каждом проекте я просматриваю список отвергнутого вручную и запускаю на проверку некоторые перспективные, на мой взгляд, но отвергнутые идеи.
-
Перестройка процесса стоит времени сама по себе. Для команды, которая делает один короткий проект, это может не окупиться, и тогда лучше использовать ИИ-модель в харнессе как есть.
-
Вся схема держится на человеке, который понимает архитектуру и умеет судить, что подойдет в выборку, а что нет. Начинающему разработчику этот подход не заменит опыта.
-
Несмотря на то, что я использую имаго-кодинг с начала года, это все еще опыт одного разработчика на ML-проектах. Он показывает, что подход работает у меня, но это не значит, что он универсален.
Заключение
Встроить нейросеть и харнесс в процесс разработки сегодня означает ускорить один этап и упереться в остальные. Настоящий эффект дает смена самого процесса: появляются этапы, которых не было (настройка строителя и данные как отдельная работа), центр тяжести уходит с написания кода на данные и проверку.
Имаго-кодинг это мой способ так работать: строитель внутри харнесса сам становится частью проекта, у него два крыла: RAG приносит факты, LoRA приносит привычки, а по моим наблюдениям еще и вкус, то есть умение не верить статьям, которые проверить нельзя.
Главное, что дает такой строитель: он смещает распределение знаний в сторону темы проекта и продавливает путь к решению там, где универсальная модель ходила бы по кругу или предлагала бы менее подходящие варианты. Он пишет код проекта, с его бизнес-сущностями и абстракциями, а не усредненную лапшу. Поэтому такой код быстрее проходит ревью и создает меньше технического долга. А я сам, занимаясь R&D и отбором данных, не теряю квалификацию. При этом данные заказчика, включая коммерческую тайну и персональные данные, не покидают контур.
Главная сложность не в обучении, а в датасете: больше не значит лучше, и выборку для строителя приходится собирать и чистить как продукт, опираясь на собственный опыт. Модели заказчиков, от небольшой 9B до полноценной 35B, обучаются обычным способом, а имаго-кодинг отвечает за то, как быстро и аккуратно я эти модели строю.
На моих проектах это выглядит как один месяц вместо трех у команды из трех человек при более высоком качестве. Именно поэтому со мной стали работать интеграторы, а сам я все больше занят R&D, данными и контролем. Такой строитель не станет умнее фронтира вообще, но на узкой группе задач, где важно знать версию, схему данных и договоренности проекта, он может оказаться полезнее и не тратит окно контекста на объяснения. Это не разновидность разработки по спецификациям, а соседний прием: спецификация улучшает запрос, адаптер улучшает исполнителя, и вместе они, скорее всего, будут работать лучше, чем порознь, что я сейчас и проверяю.
Если ваша фронтир-модель постоянно спотыкается и выдает усредненное решение, несмотря на все усилия, попробуйте имаго-кодинг и решите сами, подходит ли вам такой код будущего. И не верьте на слово красивым метафорам, включая мою про бабочек.
ссылка на оригинал статьи https://habr.com/ru/articles/1086430/