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

Расскажу, как я сделал свой первый шаг к большому проекту на ИИ. Он в значительной степени изобретён с нуля, а не скопирован.

Нейросети пока не могут работать с большими проектами. Даже лучшие их образцы начинают тупить, если кода больше 40-100 кб, и галлюцинировать после 10-60 итераций одного и того же проекта (1000 циклов - это пока что грубый маркетинг). Шестьдесят итераций - это много? Если речь об автономной ИИ-разработке, то очень мало. Если о man-in-the-loop, то более-менее уже потянет.

Я выбрал такие условия:

  • реально нужную задачу (причем тема для меня в новинку)

  • незнакомый язык (т.е. чистый вайб-кодинг)

  • отсутствие RAG (забегая вперёд: чтобы никоим образом не зависеть от истории)

  • невозможность или высокую трудность сделать приложение единым блоком

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

С нейронкой это приводит к тем же проблемам, но может, получится обходной маневр?..

Первый прототип был сгенерирован как один файл (я оставил его в проекте). Он работает, он очень похож на итоговый, но в нем нет и 10% итогового функционала. Уже на второй итерации нейронка стала галлюцинировать - по мелочам (упорно путая формат лога, неспособная исправить ошибки) и по крупному (перестав понимать, что от нее требуется, как-то по-своему формулируя задачу)

Решение увиделось в упоре на гранулярность. То есть, модули должны общаться между собой максимально просто и понятно (по соглашениям, пусть даже и неявным), тогда как внутри самого модуля допускается постоянный рефакторинг - иными словами, модуль отражает не код, а возложенную на него задачу.

Этакий черный ящик, но при этом самодокументирующийся.

Первым я выделил модуль работы с паролями. Чтобы не хранить их в файле, я взял библиотеку для работы с защищенными системными хранилищами - такое сейчас есть в каждой популярной ОС. Я также вынес в модуль кусок графического интерфейса, чтобы получить самотестирование в файле. Мне очень понравилось: не нужно устанавливать среду разработки, не нужно делать конвейер сборки и отдельные тесты. На настройку всего этого обычно уходит не один день, а тут у меня ушло всего 4 дня на целое приложение. Это, считаю, большой прорыв, поскольку сюда входит проектирование, прототипирование, тестирование в несколько этапов, с несколькими версиями, с полным пониманием всего, что происходит.

Следующим был выделен модуль выполнения скриптов. Ему добавилась задача уметь выполнять как на сервере, так и локально, а это две разных библиотеки, увы. К счастью, здесь сработал автоматизированный подход: нейросеть просто повторяла одну и ту же задачу раз десять, накапливая ошибки в логе, и в конце-концов нашелся хороший рабочий подход. Проблема была то в настройке логов, то в кодировках, то в чем-то еще. И да, работу с кодировками в ps1/bat/cmd пришлось вынести в отдельный экспериментальный файл с тестами. Мы вместе проработали несколько подходов, и самый лучший (но не идеальный) отправился в новое ТЗ, а не в код - так естественным образом образовался новый паттерн работы.

Далее я выделил модуль автоопределения типа скрипта, чтобы без лишних проблем выполнялся не только sh/bash, но и powershell, ansible/yml без хоста, python и js. Это может быть удобно и в перспективе делает программирующего агента, который я надеюсь тоже здесь опубликовать.

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

Во-первых, нейросети в общем виде не заточены на память контекста. Да, можно сохранить диалог и при необходимости поднять его - “вот тут мы поменяли интерфейс, поправь тип”. Но надо понимать, что в LLM всегда загружается вся история, плюс что-то там еще. А это - избыток токенов и, следовательно, всегда приводит к потере качества. Поэтому каждый диалог лучше начинать с текущей версии модуля и инструкций к нему, как будто работаешь с новым человеком. История - длинные чаты или RAG - оказалась ненужной. Есть только самодокиментированный (иногда даже без комментариев!) код и есть текущее задание по нему. Лаконично. Встроенных тестов должно быть досатточно для понимания нейронкой вашего интерфейса, или можно их описать отдельным файлом-примером, но даже такой подход со временем теряет актуальность, поэтому эволюционно у меня остались только модули с кодом, которые вполне самодостаточны.

Во-вторых, как выше писал, внутри себя модули постепенно превращаются в черные ящики. Они рефакторятся без вашего ведома, или с небольшим комментарием на эту тему. Количество багов при этом уменьшается, так как нейронка постепенно сводит всё к тому, что лучше всего понимает (о да, модуль обязан быть семантически устойчивым островом!). Git перестает быть пошаговым логированием мыслей разработчика и превращается в логирование стабильных интерфейсных срезов, ну что-ж, чем-то всегда приходится жертвовать.

Третье - стратегия предотвращения галлюцинаций. Нужно подбирать пары нейросетей с разной базой, разные под разные языки. Для питона у меня хорошо зашла схема: 90% кода делать на qwen-3.5-max, а оставшееся, когда Цюен начинает глючить, выполнять на gemma-4-it (это очень дешевые LLM, дорогие работают лучше). Есть много агрегаторов, в т.ч. российских, которые позволяют прозрачно переключаться между моделями. При подходе с короткими диалогами цена может быть очень небольшой, порядка 20-150р/день. Использование новой нейронки с рефактором обычно прерывает галлюцинации, потому что их природа - в самоусилении ошибки, а здесь мы как бы убираем сам источник ошибки, и осцилляции начинаются заново.

И, повторюсь, абсолютно критичным становится умение выделять блоки, чтобы общение между ними было сведено до минима и чтобы они могли тестироваться по отдельности.

Демонстрационный проект все же мелковат, а как перейти к действительно большому проекту? Пока что просто использую тот же самый подход - выцепляю по 2-30 файлов из своего проекта (но в этот раз с отдельными тестами), скармливаю их нейросетям в режиме JSON и сразу запускаю тесты. Возникает интерфейсный дрейф - выходные форматы могут случайно измениться, а входные - обрасти ненужными проверками, не влияющими на приложение, но ломающими тесты. Но с этим понятно как работать - использовать все более строгие описания интерфейсов.

Что для меня не взлетело: Cursor, Qwen studio, Copilot. Да, они работают, но не так быстро и не так точно, как хотелось бы. Возможно, их дизайн ограничен обратной совместимостью и ожиданиями пользователей. Но возможно, я слишком рано забросил их, и следует посмотреть, что там в обновлениях…

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

Подытожу принципы, сразу с их возможной эволюцией.

  1. Максимальная гранулярность. Это то, к чему всё идет - не личное мнение, а закон сложных систем. Еще Илья свет Пригожин вывел, что сложные системы стремятся от множества маленьких элементов к небольшому числу средних, с четкими протоколами взаимодействий. Его универсальный подход полностью оправдывает себя и в программировании, и тогда грануляция получает возможность эволюционировать.

  2. Самотестируемость модуля. Модуль должен содержать встроенные тесты или тестовый запуск прямо в своем файле. На период прототипа - прекрасно, но в дальнейшем, видимо, будет напрягать.

  3. Короткая память, отказ от хранения диалогов. Может, в будущем поменяется, но сейчас предпосылок нет.

  4. Ротация моделей. Применять при возникновении повторяющегося тупежа.

  5. Модуль как серый ящик. Это необходимо для работы п.1, а без него никак. Магический артефакт? Ну так к тому всё и идёт - поэтому важно совершенствовать управление артефактами.

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

Всем успехов, результат выложил здесь

Всем успехов, результат выложил здесь

Комментарии (7)


  1. ramil_trinion
    06.06.2026 20:03

    ИИ все прочнее входит в работу программиста

    Нейросети пока не могут работать с большими проектами. 

    Ни пруфов. Ни аналитики. Просто очередной пиар ИИ.

    Дальше читать не стал.


  1. Ra2007
    06.06.2026 20:03

    Гранулярность на уровне модулей: именно к этому пришёл сам после 200к строк с AI. Только у нас дополнительный слой: CLAUDE.md описывает границы каждого модуля явно, чтобы агент не «видел» соседей без необходимости. Получился примерно тот же принцип, каждый модуль самодостаточен и не требует контекста других. Интересно, у вас это получилось эволюционно или изначально закладывали?


    1. fathergorry Автор
      06.06.2026 20:03

      Я этими идеями грезил еще когда никаких LLM не было, а были индусы, которые ведут себя примерно также:)

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


      1. Ra2007
        06.06.2026 20:03

        «Дрейфующая гранулярность» точное название. Наблюдаем то же самое: код сначала монолит, потом сам вырисовывает границы через боль. У нас сигнал что граница проведена не там, когда CLAUDE.md одного модуля начинает ссылаться на детали соседнего. Про перекладывание разделения на ИИ интересно, пробовали? Мы пару раз просили Claude предложить разбивку, результат неплохой но требует ревью.


        1. fathergorry Автор
          06.06.2026 20:03

          Несколько запросов в одним и тем же промптом, и в какой-то момент получается хороший вариант. В общем, человек должен проверять.


  1. Ariless
    06.06.2026 20:03

    Интересно, что принцип "короткой памяти" здесь фактически заменяет историю диалога текущим состоянием системы. История чата накапливает не только полезный контекст, но и шум. Код в этом смысле выступает как источник истины о том, что система представляет собой сейчас.

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

    Для автономных модулей такой подход выглядит очень практичным. Для долгоживущих систем это наверное открытый вопрос - где хранить не только текущее состояние, но и reasoning, который к нему привёл.


    1. fathergorry Автор
      06.06.2026 20:03

      Рассуждения и есть тот самый лишний шум.
      В проекте храню shittrace.txt - резюме диалогов, которые регулярно приводили к ошибкам, вот он в принципе помогает. Т.е. не всю историю решений, а только краткую историю плохих решений.
      Это логично: нам нужна максимальная свобода, но не нужно повторять ошибки.