Всем привет! Меня зовут Виктор, и более трёх лет я работаю с языковыми моделями – от проприетарных решений вроде ChatGPT до open-source систем, которые можно разворачивать локально и встраивать в собственные продукты. Я застал времена жутких галлюцинаций GPT-3.5 и ждал обещанного GPT-5 – того самого почти AGI, которое, казалось, вот-вот появится.

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

Но одно остаётся неизменным – AGI так и не случилось.

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

И это не плохо. Просто разработчикам, приходится учиться работать с тем, что есть, и извлекать максимум пользы из нынешних LLM.

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

На первый взгляд – ничего нового: это те же инженерные практики, которые мы применяем в обычном программировании.

Но в контексте LLM они начинают работать совсем иначе.

В этой статье я сосредотачиваюсь на задаче генерации кода – самой близкой и понятной разработчику.

Эта область особенно показательна: в ней сильнее всего проявляются ограничения моделей – трудности с контекстом, архитектурой и интеграцией кода.
Возможно, часть этих принципов уже частично реализована в инструментах вроде Cursor или GitHub Copilot, но большинство разработчиков по-прежнему работают напрямую – через GPT, DeepSeek, Qwen или локальные модели.
А с учётом ограничений по оплате и доступу к проприетарным сервисам такой способ взаимодействия, скорее всего, останется основным.
Поэтому все наблюдения, описанные ниже, относятся именно к «ручному» взаимодействию с LLM – когда разработчик сам строит диалог и управляет процессом генерации.

Принцип 1. Сначала архитектура системы – потом код

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

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

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

В научных работах этот эффект исследуется довольно активно. Подтверждено, что предоставление LLM информации об окружающей кодовой базе и её структуре заметно повышает качество результатов. Многие современные подходы основаны на поиске и систематизации нужных фрагментов из репозитория, а также на автоматическом подмешивании зависимых сигнатур в промпт [1–3].

Принцип 2. Спроектируй код – прежде чем генерировать

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

Если возникает желание попросить модель «сделать всё сразу», лучше не торопиться. Двигайтесь поэтапно – так проще контролировать качество, тестировать и корректировать код. К тому же модели гораздо сложнее испортить небольшой метод, чем целый модуль.

Хороший приём – сначала попросить модель написать короткий план, псевдокод или набор сигнатур функций, а уже потом переходить к их реализации. Такой способ снижает вероятность логических ошибок и делает результат более предсказуемым.

В научной литературе подход «plan-then-generate» считается одним из наиболее перспективных. Он особенно полезен в ситуациях, когда исходные требования сформулированы не полностью – что, по сути, и является нормой при общении с LLM [4–6].

Принцип 3. Придерживайся чистой архитектуры

Самое трудное для LLM – следить за эволюцией собственного кода при работе с большими контекстами. Когда в одном методе или классе сосредоточено слишком много задач, модель теряет нить. Она начинает смешивать уровни абстракции, добавляет ненужные зависимости и в итоге создаёт код, который трудно читать, тестировать и поддерживать.

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

Если этого не делать, модель склонна объединять всё подряд. В результате рождаются классы вроде DatabaseLoggerWithUIHandler, которые и пишут в базу, и обновляют интерфейс. На вид всё выглядит “умно”, но архитектурно это катастрофа.

Мне ближе всего принципы чистой и гексагональной архитектуры – «порты и адаптеры». Но, по сути, это неважно: можно использовать любую архитектуру, главное, чтобы модель придерживалась той же дисциплины. Всё, что обеспечивает структуру и управляемость кодовой базы, помогает LLM писать лучше. Эмпирические исследования подтверждают: нарушение архитектурной чистоты ведёт к деградации кода и накоплению технического долга [7, 8].

Принцип 4. Генерируй пошагово

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

Для LLM избыточный контекст – не благо, а источник ошибок. Чем больше кода подаётся на вход, тем выше риск, что модель начнёт путаться или повторяться. Короткие шаги позволяют контролировать процесс, вовремя уточнять требования и тестировать код сразу после генерации.

Это согласуется с тем, как обучались модели: они лучше справляются с локальными задачами, чем с крупными структурами. Исследования вроде ClassEval [9] показывают, что при переходе от функций к классам точность генерации падает в разы, а пошаговый подход помогает это компенсировать. Разработчики фреймворка FunCoder [10] подтверждают: деление задачи на функции и сборка решения по частям повышает стабильность и качество.

Принцип 5. Размер кода

Хорошо написанный код – это не только читаемость, но и управляемость. В классическом программировании давно существует понятие «хорошего тона»: избегать слишком длинных методов и перегруженных классов. Сегодня это уже не просто рекомендация, а есть статистика и эмпирические доказательства.

В исследовании [11] на выборке из 784 тысяч методов показано, что оптимальная длина метода составляет не более 24 строк. Разделение больших методов на меньшие существенно снижает затраты на поддержку. Другое исследование [12], охватившее 30 проектов и 395 релизов, показало: “всезнающие классы” и длинные методы чаще содержат ошибки и сложнее в сопровождении.

LLM идеально ложатся на эту идею, потому что обучались именно на коротких и локальных примерах кода. Для себя я сделал простое правило: класс не должен содержать больше десяти методов, а метод – больше двадцати строк. Если код разрастается, значит, пора пересмотреть архитектуру и вынести избыточное в отдельные компоненты.

Принцип 6. Пиши тесты как требования к генерации

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

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

Исследования подтверждают эффективность TDD в связке с LLM. Добавление тестов до генерации повышает точность выполнения задач на 15–18% для GPT-4, а у открытых моделей вроде Llama-3 – до 38% [13]. Фактически это позволяет сократить разрыв между проприетарными и open-source-моделями только за счёт правильной методики.

Принцип 7. Проси комментарии и докстринги

Модель может генерировать синтаксически правильный код, который логически не решает задачу. Чтобы избежать этого, стоит добавить в процесс генерации дополнительный уровень размышления – попросить LLM сопровождать код короткими объяснениями.

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

Исследование [14] подтверждает этот эффект: генерация комментариев повышает pass@k на бенчмарках MBPP и HumanEval, а в некоторых случаях даже превосходит традиционный подход chain-of-thought.


Без чёткого плана генерации почти всегда получается не то, что хотелось. Подход “сгенерируй что-нибудь рабочее” приводит к усложнению – не потому, что LLM «глупая», а потому, что она не знает ваших намерений. Механизмы уточнений и активной обратной связи только начинают появляться, поэтому пока самый надёжный способ – самому быть архитектором, аналитиком и заказчиком, а модель использовать как исполнителя, которому вы чётко ставите задачу.

Если тема кажется вам интересной, я продолжаю разбирать подобные вещи у себя в Telegram короткими постами, экспериментами и примерами из практики: «надо разобраться | заставляем LLM работать».

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

  1. Self-planning Code Generation with Large Language Models – самопланирование генерации кода с использованием LLM

  2. Sketch Then Generate: Providing Incremental User Feedback and Guiding LLM Code Generation through Language-Oriented Code Sketches – об эффективности подхода "сначала план - затем генерация"

  3. Planning In Natural Language Improves LLM Search For Code Generation – об эффективности генерации множества планов и выбора из них оптимального для кодогенерации.

  4. ????????: Repository-level Coding using LLMs and Planning – о кодировании с LLM на уровне репозитория, в том числе миграция кода на другие языки

  5. ChatCoder: Human-in-loop Refine Requirement Improves LLMs’ Code Generation – о планировании требований к коду в цикле "человек-LLM"

  6. Enhancing Repository-Level Code Generation with Integrated Contextual Information – о интеграции в промпт информации из больших репозиториев о связях на уровне типов/классов/интерфейсов/структур, показывающие, какие типы упоминаются и требуются другим типом или функцией.

  7. Design First, Code Later: The AI Era Mantra – о различных архитектурах в виде краткой справки.

  8. Evolution patterns of software-architecture smells: An empirical study of intra- and inter-version smells – это не про LLM, но принцип тот же. Работа о том, что нарушение принципов архитектурной чистоты ведет к деградации кодовой базы продукта, снижению качества самого продукта и наращиванию технического долга. Ровно то, что произойдет, если не требовать от LLM придерживаться принципов вашего проекта при генерации кода.

  9. Evaluating Large Language Models in Class-Level Code Generation – о разнице в эффективности между генерацией методов и классов, насколько падает производительность и метрики

  10. Divide-and-Conquer Meets Consensus: Unleashing the Power of Functions in Code Generation – фреймворк помогает модели вводить вспомогательные функции и писать решение по частям, а затем собирать итог.

  11. An Empirical Study on Maintainable Method Size in Java – исследования о том, что проектирование методов не более чем в 24 строки помогают снизить будущие расходы на сопровождение кода.

  12. On the diffuseness and the impact on maintainability of code smells: a large scale empirical investigation – масштабное исследование по 13 различным "запахам" кода и их влиянии на качество кода и последующее его обслуживание.

  13. Test-Driven Development for Code Generation – о влиянии практики TDD на генерацию кода.

  14. Comments as Natural Logic Pivots: Improve Code Generation via Comment Perspective – о влиянии генерации встроенных комментариев на эффективность генерации кода.

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


  1. qnquro
    06.11.2025 11:00

    использовал LLM для ускорения написания кода и методом проб и ошибок сам пришёл к таким же принципам. главная ошибка новичков, которые используют LLM для генерации кода, заключается в том, что они могут просить генерировать то в чём сами не разбираются и нормального ТЗ дать не могут, что приводит к ошибкам. и тут даже эти 7 принципов не помогут)


    1. victor_shev89 Автор
      06.11.2025 11:00

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


  1. kuza2000
    06.11.2025 11:00

    Ждать от LLM появление AGI - это примерно так же, как пытаться собрать автомобиль, имея только коробку передач)

    А статью спасибо! Вообще, я баловался генерацией кода в обычных LMM. Что-то получалась, но результат был так себе. Читал новости "у нас 70% кода пишет LLM" и не понимал, как такое может быть. А потом поставил Cursor и офигел от результата :) Там действительно решены проблемы контекста и многое другое. Теперь и у меня стало так) Помощь огромная.


    1. victor_shev89 Автор
      06.11.2025 11:00

      Да, cursor - это мощный инструмент, но имеет свои ограничения, из за которых многие или не могут или не готовы им пользоваться на постоянной основе. Как раз и хотелось поисследовать суть этой мощи. По хорошему, если заморочиться, можно подручными open source средствами собрать свой "домашний курсор".))