Что я понял, пока пытался заставить локальные модели писать приложения
Путь от простых промптов к собственной инженерной среде: 9B, 35B, агенты, scaffolds и контекст как валюта.
Я довольно долго проверял одну простую мысль: можно ли сделать локальную LLM полезной для разработки личных проектов. Не в формате разового чата, где модель пишет функцию или объясняет ошибку, а в более интересном режиме: у меня есть идея приложения, модель помогает разложить её на шаги, пишет код, проверяет себя, чинит ошибки и постепенно доводит проект до состояния, где им уже можно пользоваться.
Сначала я пытался понять сами модели. Потом генераторы. Потом агентные обвязки. Потом свои workflow с пакетами, слайсами, ревью, субагентами и полуавтоматической разработкой. В какой-то момент стало ясно, что я проверяю уже не одну модель, а всю маленькую инженерную среду вокруг неё.
Короткая карта экспериментов
| Этап | Что я пробовал | Что стало понятно |
|---|---|---|
| Синтетические задачи | Тексты, сайты, ограничения, промпты вместе с ChatGPT | Модель легко заполняет пустоты и звучит уверенно там, где у неё нет опоры |
| Генераторы и scaffolds | Быстрый старт Vue/Express, конфиги, шаблоны, первые заготовки | Без каркаса модель быстро уходит в случайные решения |
| 9B + агенты | Qwen 9B, OpenCode, Pi.dev, Aider, первые роли planner/implementer/reviewer | Маленькие задачи работают, длинная автономность быстро трещит |
| Субагенты и поиск | Websearch, codesearch, explore/review-подзадачи | Субагенты помогают, но легко раздувают контекст |
| Full-auto workflow | bootstrap, choose-task, implement, stabilize, finish, repair | Полная автоматика хрупкая, зато stabilize оказался очень полезным |
| Scaffolds как лаборатория | 10-ideal, Vue 3, Express 5, TS, ESLint, Prettier, API layer | Хорошая стартовая форма важнее длинных инструкций |
| 35B локально | Qwen3.6 35B A3B, длинный контекст, llama.cpp/Vulkan | Впервые появилось ощущение рабочего локального исполнителя |
| Текущий подход | Templates, small slices, checks, review packets, внешний reviewer по делу | Модель лучше всего работает внутри подготовленного коридора |
Сначала были синтетические эксперименты
Начиналось всё довольно мирно. Я гонял синтетические задачи, часто вместе с ChatGPT. Мы придумывали промпты, проверяли, как модель держит ограничения, как пишет тексты, как реагирует на задачу без готового материала.
Например, был заход про личный сайт разработчика-энтузиаста. Условия были специально неприятные: нельзя выдумывать репозитории, статьи, проекты, клиенты и достижения, но красивый сайт всё равно очень хочется. Хотелось понять, сможет ли модель сделать что-то убедительное без фейковой биографии.
Там быстро всплыла первая привычка моделей: они заполняют пустоты. Просишь не использовать портфолио, а модель всё равно тянется к привычным блокам: проекты, кейсы, статьи, достижения. Просишь живой текст, а получаешь гладкую, но пластиковую подачу. Приходится вычищать пафос, пустые обобщения, канцелярит и нейросетевую драму.
Уже на этом уровне стало видно, что хороший результат редко рождается из одного волшебного промпта. Нужны маленькие правила, которые возвращают модель к реальности.
Первые правила были почти литературные:
• не выдумывать факты
• не прятать пустоту за красивыми словами
• не делать вид, что у автора уже есть портфолио
• писать проще
• оставлять только то, за что можно отвечать
Позже оказалось, что ровно такой же принцип работает и в коде. Только вместо красивых фраз модель начинает выдумывать архитектуру, правила, папки, конфиги и смысл там, где лучше было бы сделать маленький понятный шаг.
Потом пошли генераторы и первые scaffolds
После текстов захотелось большего: быстро поднимать основу приложения. Не просто попросить модель написать компонент, а дать ей задачу вроде: создай минимальный Vue + Express проект, настрой TypeScript, ESLint, Prettier, Tailwind, добавь пару команд, сделай так, чтобы всё запускалось.
И тут началась настоящая разработческая часть эксперимента.
Модель может впечатляюще быстро создать package.json, конфиги, папки, минимальный фронт и бэк. На маленьком демо это выглядит почти магически. Но стоит попросить свежую связку инструментов, и уверенность модели начинает мешать. Она помнит старые конфиги, путает новые версии, иногда чинит проблему таким способом, который через два шага создаёт новую.
Был совсем простой пример. Я просил сделать последний Vue с последним ESLint, только package.json, eslint.config.mjs, tsconfig.json и .gitignore. Без приложения. Всё на npm. В конце npm run lint должен запускаться. Казалось бы, задача маленькая. Но агент сразу полез в websearch за версиями и конфигами.
И тут нет простого ответа. Поиск правда нужен, потому что фронтенд-инструменты меняются быстро. Но бесконтрольный поиск быстро превращается в пожирателя контекста. Для локальной модели контекст стоит дорого. Его приходится беречь почти как оперативку.
| Идея | Ожидание | Как вышло в работе |
|---|---|---|
| Дать модели свежий frontend setup | Она быстро соберёт актуальные конфиги | Модель либо тащит старые знания, либо начинает много искать |
| Попросить только несколько файлов | Контекст останется маленьким | Даже маленькая задача может увести в websearch |
| Использовать генератор как старт | Получится быстрый чистый проект | Без правил рядом появляются странные решения |
| Сразу сделать идеальный scaffold | Один раз настроить, потом жить спокойно | Scaffold сам стал отдельной лабораторией |
В этот момент я впервые начал думать не только о модели, а о форме задачи. Чем меньше модель придумывает вокруг, тем лучше. Чем понятнее границы, тем меньше мусора в результате.
9B: быстрые надежды и узкий коридор
Дальше я много экспериментировал с Qwen 9B. Она была заманчивой: легче, быстрее, проще помещается в память, не создаёт ощущения, что каждый запуск превращает компьютер в отдельную инфраструктуру. Для первых агентных экспериментов такой размер выглядел разумным.
9B может быть полезной. Если дать ей маленький, понятный кусок, она способна исправить файл, дописать простой компонент, пройтись по очевидной ошибке, собрать небольшой пакет изменений. Но как только задача требует удерживать архитектуру, свежие конфиги, длинную цепочку действий или несколько слоёв проекта, начинаются потери.
Она может сделать рабочий код, а рядом положить странную структуру. Может починить одно и сломать другое. Может уверенно править конфиг, который сама до конца не понимает.
| Модель / режим | Как ощущалось | Где годилось | Где быстро начинались проблемы |
|---|---|---|---|
| Qwen 9B | Лёгкая, удобная для быстрых попыток | Маленькие правки, простые компоненты, эксперименты | Архитектура, длинные задачи, свежие конфиги |
| Qwen 9B как implementer | Нормально, если дать короткий packet | Локальная реализация маленького slice | Начинает терять края, если пакет слишком широкий |
| Qwen 9B + remote planner/reviewer | Уже похоже на workflow | План снаружи, маленькая реализация локально | Передача контекста и repair packets требуют дисциплины |
| Qwen 9B + full-auto идея | Заманчиво на бумаге | Учебные и полуавтоматические прогоны | Полная автономность быстро становится хрупкой |
Поэтому следующим шагом стали не новые промпты, а обвязки. Хотелось, чтобы модель работала не как один чат, а как участник процесса.
OpenCode, Pi.dev, Aider и идея ролей
Я пробовал разные инструменты и схемы: OpenCode, Pi.dev, Aider, Codex, локальные и удалённые модели, разные роли. Постепенно появилась схема с разделением обязанностей:
Сначала это выглядело громоздко. Потом стало понятно, что в такой громоздкости есть смысл. Локальной модели трудно дать большую задачу целиком. Ей лучше передавать маленький кусок с понятными границами и конкретной проверкой.
Параллельно возникла идея локального оркестратора. Основной OpenCode-чат на локальной Qwen управляет субагентами: remote slice planner, local implementer, remote reviewer, local repairer. В идеале основной агент держит состояние, а подзадачи делают грязную работу. Реальность оказалась менее гладкой, но направление было полезным.
Мои workflow быстро начали обрастать бюрократией
После готовых инструментов я начал делать свои заготовки. Появились команды вроде bootstrap-project, choose-task, implement-slice, finish-packet, revert-packet. Потом start-packet, work-packet, stabilize-packet, inspect, abort-packet. Идея была понятная: каждая команда запускается в новой сессии, получает минимум нужного контекста, делает один этап и пишет артефакты.
Выглядело почти как маленькая фабрика приложений. На практике фабрика быстро начала требовать ухода.
Документы повторяли друг друга. README оказывался бесполезным. AGENTS.md разрастался и становился хуже. Модель путала workflow-файлы с продуктом. Внутренние папки вроде .workflow и .pi приходилось отдельно защищать от восприятия как части проекта. Команды с аргументами оказались не так уж полезны, потому что bootstrap и inspect всё равно сами задавали вопросы. Некоторые ограничения, которые сначала казались защитой, только мешали полуавтоматическому эксперименту.
| Что я добавлял в workflow | Почему казалось хорошей идеей | Что выяснилось |
|---|---|---|
| Много docs на старте | Модель будет лучше понимать проект | Документы начинают повторяться и стареть |
| Длинный AGENTS.md | Больше правил, меньше ошибок | Длинные правила хуже читаются и хуже соблюдаются |
| Команды с аргументами | Можно запускать всё точнее | В реальности команды часто сами спрашивают нужное |
| Bootstrap всего проекта | У модели будет полная картина | Полная картина быстро превращается в лишний контекст |
| Subagents для проверок | Основной поток останется чистым | Субагенты тоже могут сжечь много контекста |
| Stabilize pass | Финальная уборка | Один из самых полезных этапов всего процесса |
Самым полезным этапом оказался stabilize. Когда модель уже что-то сделала, ей проще посмотреть на конкретный результат, найти грубые ошибки и привести проект в порядок. Полная автономная разработка из одной идеи оставалась хрупкой, а цикл сделал кусок, проверил, стабилизировал, закоммитил выглядел намного ближе к реальной пользе.
Субагенты: хорошая идея, если они не съедают весь дом
Отдельно я много думал про субагентов. Хотелось разгрузить главный контекст. Пусть отдельный агент сходит в websearch, codesearch, explore, review, соберёт информацию и вернёт короткий вывод. Основной поток тогда не будет забит поиском, логами и промежуточным мусором.
В теории звучит отлично.
На практике я видел, как субагент набирал около 59 тысяч токенов контекста, делал несколько поисков, работал около двенадцати минут, а потом возникал неприятный вопрос: насколько всё это правда разгрузило основной процесс? Даже если технически подзадача завершается отдельно, её итоговый отчёт легко становится слишком длинным. А если отчёт длинный, основной контекст снова пухнет.
С websearch и codesearch похожая история. Я добавлял их в Pi agent, обсуждал, как этим может пользоваться OpenSpec, думал, стоит ли разрешать свободный поиск. В итоге свободный режим оказался опасным. Модель любит искать, потому что поиск похож на работу. Лучше работает лимит: сходить в интернет пару раз, когда правда нужны свежие версии, документация или реальные примеры. Для остального хватает локального контекста проекта, короткого пакета задачи и проверок.
Первые живые приложения и неприятные мелочи
Параллельно с workflow я пробовал реальные приложения. Иногда результат уже начинал радовать. Например, были автосгенерированные прототипы с dark liquid-glass UI, вкладками Active / Pinned / Trash, модальным редактором, confirm dialog, SQLite-сессиями, backup/restore-скриптами и LAN-friendly dev.
В какой-то момент локальная 35B смогла сгенерировать широкий рабочий прототип, потом сама же починить длинную TypeScript-проблему и вызвать explore-субагента. Это был важный сдвиг. До этого агентные схемы часто выглядели как борьба с инструментами. Тут впервые появилось ощущение, что локальная модель может быть исполнителем для реального личного проекта.
Но мелкие аварии никуда не делись.
В одном редакторе модель пыталась добавить атрибуты, чтобы отключить автокоррекцию на мобильной клавиатуре. Идея была нормальная: конкретный редактор сходил с ума от автозамены и начинал печатать справа куски слов. Но локальная модель перепутала скобки, и приложение упало на синтаксической ошибке в собранном JS. Фикс оказался простым, однако сам эпизод хорошо показывает уровень риска: модель может понимать замысел, делать почти правильную правку и всё равно ломать приложение одной тупой скобкой.
Другой пример был с Sovka. После редизайна под dark liquid glass интерфейс стал заметно лучше, но модель создала второй элемент с id=“app” внутри AppShell. Корневой app уже был в index.html, и второй такой id ломал приложение. Потом пришлось переименовывать внутренний shell в app-shell и добавлять guardrail: не создавать второй #app, внутренний контейнер должен называться #app-shell или классом.
Такие вещи трудно поймать красивым системным промптом. Они лучше превращаются в короткие правила, выросшие из настоящих аварий.
10-ideal: scaffold как лаборатория
Важным этапом стал 10-ideal. Я не воспринимал его как финальный notes app. Это была лаборатория для Qwen, Pi и OpenCode: pnpm workspace, Vue 3 + Vite + TypeScript на фронте, Express 5 + TypeScript на бэке, строгий TypeScript, ESLint, Prettier, Tailwind v4, Vue Router, API client layer, позже идеи Pinia, Zod, OpenAPI, SQLite, auth, тестов и CI.
Там постепенно появился важный вывод: локальной модели нужна хорошая стартовая среда. Не огромная архитектурная энциклопедия, а аккуратный scaffold с понятными папками, командами проверки и несколькими короткими правилами.
Я стал больше склоняться к type-first структуре, а не к feature-first. Для фронта что-то вроде:
src/api
src/stores
src/router
src/layouts
src/views
src/components/ui
src/components/<domain>
src/styles
Для бэка:
src/routes
src/services
src/repositories
src/validation
src/middleware
src/config
src/db
src/types
Модель лучше работает, когда ей не нужно каждый раз заново придумывать форму проекта. В пустой папке она фантазирует. В хорошем scaffold она чаще продолжает существующую мысль.
На базе такого подхода стали появляться живые вещи. Один из примеров — лёгкий аналог pi-web для LAN/self-use: управление project folders, создание новых папок, список Pi-сессий через SDK, reader view, SSE events, session creation, guard от второго prompt в running session, статус running/idle через finally. Там ещё оставалось много работы, но ощущение было другим. Модель уже не лепила случайный Vue-компонент. Она работала внутри формы, которую можно продолжать.
Проверки, ревью и неожиданный урок про внешние модели
У меня был интересный эпизод с review-collect и внешним ревью. Локальная модель прошла задачу по notes scaffold, а внешний reviewer ошибочно отметил blocker на POST /api/notes, потому что не увидел express.json() в wiring context. После этого стало понятно, что diff-audit полезен, но пакет для ревью должен включать не только diff, а ещё важные куски wiring и untracked files.
Интересно, что локальная Qwen в том случае дала более полезное ревью, чем внешняя модель. Это не значит, что внешние модели бесполезны. Скорее они очень зависят от пакета, который им дали. Если пакет неполный, reviewer начинает уверенно ругаться на то, чего в проекте на самом деле нет.
После этого я стал больше ценить не саму модель-ревьюера, а качество пакета. Хороший packet иногда важнее, чем разница между моделями.
Переход к 35B
В какой-то момент стало ясно, что 9B для главной роли тесновата. Я пробовал разные варианты: Qwen Coder 30B, Qwen 27B, Qwen2.5 Coder 14B, разные кванты. Некоторые запускались, но были слишком медленными для нормального цикла. Qwen3 Coder 30B A3B Q3_K_L технически работала, но один audit-agent занимал около 700 секунд. Qwen3.5 27B на полном прогоне доходила до десятков минут. Модель могла быть умнее 9B, но реальный workflow убивает не только глупость, а ещё задержка.
Настоящий сдвиг произошёл с Qwen3.6 35B A3B в GGUF, особенно с UD-Q4_K_M. На моём сетапе с Ryzen 7 5700X, 32 GB RAM и видеокартой с 16 GB VRAM она стала первой большой локальной моделью, которую можно всерьёз встроить в разработку.
В хорошей конфигурации я видел примерно 22–25 токенов в секунду на генерации и около 280–318 токенов в секунду на обработке промпта. Иногда длинный prompt eval был ниже, но всё равно терпимо. При этом память сразу стала частью workflow: видеопамять может быть около 14 из 16 GB, оперативка около 22 из 32 GB, и каждый лишний браузер, VS Code, Docker или вторая сессия уже чувствуется.
С 35B изменился потолок. Модель лучше держит задачу, лучше понимает архитектурные замечания, спокойнее работает с большим проектом, увереннее чинит свои ошибки. Но старые проблемы не исчезли. Длинный контекст дорогой. Полный репроцессинг ощущается болезненно. Если агент начинает много читать, много искать и много писать в чат, скорость падает, а сессия становится тяжёлой.
Я думал, что буду выбирать модели. В итоге начал обсуждать batch, ubatch, KV cache, prompt cache, контекст на 65k или 81k, сколько RAM можно отжать у браузера, как не убить систему, что делать с Docker Desktop, сколько оставить под VS Code. Где-то на этом этапе локальная LLM-разработка перестала быть только про промпты.
Контекст оказался отдельной валютой
Длинный контекст был для меня принципиальной темой. Без него агентная разработка быстро разваливается: модель забывает документы, теряет текущий packet, не видит архитектуру, повторяет старые решения. Но большой контекст нельзя использовать как свалку.
Чем больше я экспериментировал, тем сильнее хотелось выносить подробности в файлы и артефакты, а в основной поток давать короткий пакет. Если модель пишет огромный отчёт в чат, она вредит следующему шагу. Если reviewer делает короткий repair packet, его можно передать локальному исполнителю без лишнего шума.
Контекст, память и скорость постепенно стали частью одной системы. На бумаге можно сказать: просто возьми модель умнее. В работе приходится спрашивать иначе: сколько она ест, сколько генерирует, сколько держит, как часто можно запускать проверки, насколько больно перезапускать сессию, можно ли параллельно держать браузер и VS Code.
Где удалённые модели всё ещё полезны
После перехода к 35B удалённые модели не исчезли. Скорее их роль стала спокойнее. Бесплатная Laguna и другие OpenRouter-модели полезны как внешний планировщик, критик или reviewer. Особенно когда нужно посмотреть на решение со стороны.
Но отдавать им весь проект каждый раз неудобно. Лучше работает одноразовый внешний обзор: собрать review packet, отдать модели, получить конкретные замечания, вернуть локальному исполнителю короткий repair packet.
В итоге внешний reviewer стал не главным мозгом, а дополнительной парой глаз. Основная работа всё равно упирается в форму задачи.
Что поменялось в ожиданиях
Если смотреть назад, ожидания менялись несколько раз.
Сначала казалось, что нужен правильный промпт. Потом казалось, что нужен правильный агент. Потом правильный workflow. Потом стало понятно, что нужна среда: шаблоны, проверки, маленькие пакеты, понятные команды, короткие правила, нормальный способ переносить состояние между сессиями.
Мои текущие правила для локальной LLM-разработки
Что сейчас выглядит самым рабочим:
• маленький slice вместо большой задачи
• хороший scaffold вместо пустой папки
• короткий AGENTS.md вместо энциклопедии
• проверки после каждого шага
• stabilize pass перед следующим этапом
• websearch только по делу
• review packet вместо огромного dump
• форматирование только затронутых файлов
• детали в артефакты, не в чат
• один локальный тяжёлый исполнитель за раз
Ещё один вывод: шаблоны нужны разные. Один scaffold для Vue + Express приложения. Отдельный для полустатичного личного сайта. Отдельный для CLI. Возможно, отдельный для маленького backend-only сервиса. В каждом должны быть рабочие команды проверки, понятная структура, минимальные docs и несколько правил, родившихся из настоящих поломок.
Что в итоге
Самое приятное во всём этом опыте: прогресс правда есть. Ранние эксперименты часто выглядели как борьба с красивой болтовнёй. Потом началась борьба с конфигами, памятью, агентами, permission prompts, раздутыми документами и сессиями на десятки тысяч токенов. Сейчас локальная 35B уже может за несколько часов сделать кусок реального приложения на хорошем scaffold. С багами, с ревью, с человеческим надзором, но это уже рабочий материал.
Главный навык оказался не в том, чтобы написать идеальный промпт. Гораздо важнее научиться строить вокруг модели среду, где ей трудно делать глупости и легко делать полезную работу.
Локальная LLM в таком формате похожа на работника в личной мастерской. Ей нужны инструменты, верстак, понятные заготовки, короткая задача и проверка результата. Если бросить ей идею целиком, она легко устроит беспорядок. Если дать хороший scaffold, маленький slice и нормальный набор checks, она начинает приносить пользу.
Для меня это и стало главным выводом. Локальная модель уже может быть частью разработки. Но ценность появляется не от одной модели, а от всего вокруг: шаблонов, пакетов, ревью, проверок, ограниченного поиска, аккуратного контекста и честного отношения к её слабым местам.