Я работаю по ИП, поэтому не только пишу код, но и поддерживаю как DevOps свои проекты у заказчика. Эта история началась банально: я собирался в отпуск и хотел оптимизировать часть процессов, которые в повседневной жизни занимают время — чтобы не дёргать клиентов из-за вопросов по ошибкам, которые я мог не увидеть во время отдыха. Пусть локальная моделька сама разгребает типовое. Думал: запущу OpenClaw, подключу к локальной модели — и поеду спокойно
Через две недели — вместо отпуска — я сидел и обучал Qwen3 на Nvidia RTX 3090 24GB, потому что ни одно из существующих решений у меня не работало. Дальше расскажу, как до этого докатился — с цифрами, граблями и бенчмарками.
Точка входа: OpenClaw и боль с локальными моделями
Поставил OpenClaw — open-source агентный фреймворк. Если вы не знакомы с этим чудом, то простыми словами это прослойка между tool calling модели и скриптами (скиллами), которые может вызывать ваш ИИ. Плюс удобный планировщик типа cron — может по расписанию слать промт.
У меня несколько ПК, прокинул его на один с RTX 4080 16GB + 64GB DDR5 + Core i9. Задумка была такая: модель должна по расписанию через OpenClaw соединиться по SSH с удалённым сервером, пролистнуть docker ps, и если есть контейнеры, которые перезагружаются — взять оттуда логи, проанализировать и прислать в Телеграм с обоснованием «что это».
Я как и многие разрабы ведусь на хайп, читаю статьи, исследования. Это меня и подвело. В статьях — красивые цифры и «годнота», в реальности — мир влажных фантазий. Что произошло: я прогнал кучу моделей, начиная со старых gpt-oss до последнего qwen3.6, который мог себе позволить на ollama даже с очень низкой скоростью. И тут начало вылезать неприятное. Половина моих реальных кейсов локальные модели просто не вытягивали: tool calling через раз, галлюцинации в ответах, обрезанный output, путаница с аргументами функций.
В итоге картина простая: без серьёзных платных ИИ — а именно codex от OpenAI, который предлагается из коробки по oAuth, ну и Антропик (очень дорогой через консоль) — остальное мусор. Некая замануха: ты пробуешь локальные модельки для OpenClaw, обжигаешься, потом не страдаешь фигнёй и переезжаешь на платный. Что в свою очередь рождает массу сомнений — VPN (не только с нашей стороны), безопасность данных (а если я работаю с паспортными данными или ещё с чем). В итоге решил запилить сам.
Шаг 1: бенчмарк 16 локальных моделей
Слово «САМ» — оно очень смелое, потому что самому запилить с нуля модель типа Qwen — задача неподъёмная, поэтому я решил не придумывать велосипед, а взять готовый вариант и дообучить его до нужного состояния. Прежде чем пилить дообучение, надо понять, что вообще существует из локальных моделей и какая из них реально работает на моих задачах. Делаю бенчмарк из трёх реальных кейсов и замера скорости:
-
Code Review — даю заведомо багованный Java-код Jitsi-клиента (SQL injection, сравнение строк через
==, небезопасный Random, HTTP вместо HTTPS, ресурс-leak, пустой catch). Модель должна найти все баги и предложить fix. 0–10 баллов. -
Финансовая аналитика — план погашения кредитов методом лавины с помесячной разбивкой на 12 месяцев. Проверяет математику и следование инструкциям. 0–10 баллов.
-
HTML страница — генерация визуального таймлайна погашения 8 кредитов. Проверяет вёрстку, адаптивный дизайн, обработку данных. 0–10 баллов.
Бонус за скорость 0–5 баллов: ≥100 t/s = 5, ≥60 = 4, ≥30 = 3, ≥15 = 2, >0 = 1.
Стенд: RTX 4080 16GB, 64GB DDR5, Core i9, Ollama 0.20.7. Прогнал все актуальные модели, которые помещаются:
|
# |
Модель |
Код |
HTML |
Кредит |
Скорость |
ИТОГО |
t/s |
Tool calling |
|---|---|---|---|---|---|---|---|---|
|
1 |
🥇 gemma4:latest |
10 |
10 |
9 |
5 |
34 |
108 |
✅ |
|
2 |
🥈 phi4-mini:latest |
10 |
10 |
8 |
5 |
33 |
208 |
❌ |
|
3 |
🥉 deepseek-r1-tool-calling:14b |
10 |
10 |
9 |
4 |
33 |
61 |
❌ |
|
4 |
qwen3:8b |
9 |
10 |
8 |
5 |
32 |
102 |
✅ |
|
5 |
deepseek-r1:14b |
10 |
9 |
9 |
4 |
32 |
65 |
❌ |
|
6 |
phi4:latest |
8 |
10 |
9 |
4 |
31 |
67 |
❌ |
|
7 |
lfm2:latest |
8 |
10 |
9 |
4 |
31 |
70 |
❌ |
|
8 |
glm-4.7-flash:latest |
9 |
10 |
9 |
2 |
30 |
20 |
✅ |
|
9 |
devstral:latest |
8 |
10 |
9 |
1 |
28 |
14 |
✅ |
|
10 |
qwen3:30b-a3b |
9 |
9 |
7 |
2 |
27 |
25 |
✅ |
|
11 |
mistral-small:latest |
8 |
9 |
9 |
1 |
27 |
14 |
✅ |
|
12 |
nemotron-3-nano:latest |
8 |
10 |
7 |
2 |
27 |
21 |
✅ |
|
13 |
gpt-oss:latest |
9 |
10 |
2 |
5 |
26 |
123 |
✅ |
|
14 |
qwen3:32b |
timeout |
1 |
1 |
5 |
❌ |
||
Но не всё так гладко. Для агентной работы (а я хотел именно агента, не просто chat) обязательно нужен tool calling. Из 14 протестированных это умели только 7. И из них в категории «10/10 на коде + быстрая» — только gemma4.
Шаг 2: первая попытка дообучения, и почему 4080 16GB — мало
Решил: беру gemma4:latest как базу, дообучаю QLoRA-лорой на своих DevOps-кейсах, получаю свой домашний AI-ассистент.
На бумаге норм. На практике — не помещается в 16GB VRAM 4080. QLoRA с активациями + градиентами в 4-битном квантовании требует ~22–24 GB. Раздать на CPU offload — обучение шло бы неделями, с потерей всего смысла «локальное дообучение». Простыми словами: запустить уже обученную LLM — она отлично работает и помещается в 16GB, а вот дообучать и формировать адаптеры — места уже не хватает.
Опустился на qwen3:8b. 8B модель реально влезает в 4080, обучение проходит за ночь. Прогнал свой первый датасет (~1000 hand-crafted DevOps-трейсов), получил oni:v3. Запустил.
И вот тут второе расстройство: 8B мало для агентной работы. На простых задачах работает, на multi-step типа «отрефактори этот docker-compose с учётом всех 12 требований» — теряет нить. Не хватает параметров, чтобы держать контекст и принимать сложные решения.
Я мог:
-
Смириться с 8B и считать «лучше что есть».
-
Снять VM с большим объёмом памяти на GPU, дообучить нормальную модель, потом смержить и запустить на 4080, как я и хотел.
-
Купить ещё одну видеокарту.
Выбрал вариант 2.
Шаг 3: VM с RTX 3090 и обучение Qwen3-14B
Снял на ночь VM с RTX 3090 24GB. Снова сделал бенчмарк, добавив простой тест на создание файла на сервере. Тут уже выиграл ранее пропущенный мной Qwen3-14B. На 24 гигах помещается с QLoRA r=64 — хороший баланс «достаточно большая, чтобы тянуть агентные задачи» + «обучение проходит за разумное время».
Попросил Claude запилить сиды на дырявые моменты в шагах тестирования. Перетащил датасет, запустил обучение. Через ~6 часов получил oni:v6. Стало заметно лучше: tool calling стабильный, контекст держится, multi-step задачи решает.
Понимая, что OpenClaw уже может что-то типа «закинь мне с frontend-контейнера последние логи с ошибками за 3 часа», я решил отказаться от достойного по цене intelion.cloud VM (мы с ним прожили 4 дня за 44 рубля в час, дешевле и качественнее не нашёл) и купил себе домой с авито старенький Dell с 3090. Теперь обучение полностью дома, никаких VM, никаких облачных зависимостей. Точно соответствует моему изначальному принципу: ничего не должно зависеть от VPN или зарубежной инфраструктуры.
Шаг 4: качество датасета — главное, что я недооценивал
На oni:v6 я провёл сравнение head-to-head с базовым qwen3.6:27b (более крупная свежая модель из коробки) на конкретной задаче — multi-file scaffold TODO web app: backend Django REST, frontend Vue+Vite, docker-compose, README. Промт был такой: «Создай мне приложение: TODO на фронте Vue, бэк на Django, и подними мне на локалке в docker-compose».
Получилось интересно:
|
|
qwen3.6:27b (cloud) |
oni:v6 (local 4080) |
|---|---|---|
|
Время |
3 мин 54 с |
49 с |
|
Шагов агента |
21 (max=20, упёрся) |
19 |
|
Файлов создано |
15 (но docker-compose.yml ✗) |
14 (compose.yml ✓) |
|
Честность отчёта |
❌ сфабриковал docker-compose.yml |
✅ отчёт совпадает с диском |
И вот это уже серьёзно. qwen3.6:27b в финальном отчёте написал «успешно создал TODO web app» и привёл содержимое docker-compose.yml — красивый YAML, четыре строки описания сервисов, volumes, ports. А файла на диске нет. Вызова write_file в логе агента не было. Модель в финальном ответе сфабриковала результат, которого не существует.
Это так называемый «phantom final answer» — когда модель описывает то, чего не делала. В продакшене это убивает доверие: ты думаешь «всё готово», идёшь в папку, делаешь docker compose up — и получаешь «no such file». Если ошибку видно сразу — её можно починить. А если ассистент врёт, что её нет — починить нельзя.
Мой oni:v6 наоборот: знал Django хуже (забыл cors_headers, settings.py был куцый), но не врал про результаты. Что записал — про то и отчитался. Плюс в 4.8 раза быстрее на 4080, чем 27B на 3090 через тоннель.
Когда я давал тест, я не ждал от своей модели, что она запилит хоть что-то — мне просто нужен был честный ответ или решение на уровне песочницы. Я и до этого видел, как модельки на локалке при разработке простого приложения путаются в роутинг-файлах. То есть тест был не про «вот посмотрите, модель 14b побеждает 27b» — это бред — а про разницу в подходе. qwen3.6:27b в это сравнение попал как рекомендация от друга-ИИшника со словами «там tool-calling проработан лучше».
Так вот, для агента честность — главное. Для LLM-чата — наоборот, 27B будет полным, развёрнутым. Но для self-running агента, который реально выполняет задачи и должен честно отчитываться — фантюненный 14B работает лучше базового 27B.
Шаг 5: текущее состояние — base-7.v2
Ниже я вложил плод моих страданий. Повёлся на полный набор сидов от Magicoder, которые лежат на HF — там много обучающих датасетов, но они общие и ломают логику маленького агента. Поэтому следующую статью я хотел написать как раз про дистилляцию данных с общих ресурсов под агента — это отдельная тема.
За неделю мой датасет вырос:
-
180 hand-written seed templates в YAML (типовые DevOps-задачи)
-
14 generation templates (превращают seed → multi-turn agent trace)
-
45 hand-curated «эталонных» полных трейсов (для самых сложных паттернов: anti-pattern fix, honest failure, multi-file scaffold)
-
= ~1900 трейсов после paraphrase-вариаций
Текущий чемпион — oni:base-7.v2, обученный на этом датасете с 2 эпохами Unsloth QLoRA r=64 на RTX 3090. Метрики:
Stage 1 SSH (22 теста): 15/22 (68%)Realworld stepped (5 этапов): 4/5 (80%, честный fail на 5-м)Phase 3 multi-file scaffold: работаетСкорость inference: 25-30 t/s на 3090
Это не идеально. Multi-step SSH chains (port-forward, scp с проверкой, обратный туннель) проседают. Реальный nginx через SSH+sudo тоже тяжело. До production-ready ещё доводить — но базовый агент уже даёт пользу. Это значит, что не «два раза я сделал ничего», а «выполняю задачи, но говорю, если у меня не выходит» (уровень джуна: не получилось — сказал). Что я считаю прорывом!
Самый загадочный баг по дороге: Qwen3 thinking mode
Один баг сожрал у меня 3 ночи — расскажу подробно, потому что ловушка типичная для тех, кто фантюнит.
Модель обучилась хорошо (eval_loss 0.4), но в Ollama выдавала 2/22 на бенчмарке. Сижу, смотрю на вывод: модель пишет осмысленно, но не выполняет инструкции. Адаптер кривой? Шаблон чата сломан?
Оказалось — Qwen3 family по умолчанию пишет в thinking-поле, а не в response. То есть весь num_predict уходит в <think>...</think> блок, в response — пусто. Модель «думает», но не «отвечает».
Решение — TEMPLATE override в Modelfile с предзакрытым <think></think>:
TEMPLATE """{{- if .System }}<|im_start|>system{{ .System }}<|im_end|>{{ end }}{{- range .Messages }}<|im_start|>{{ .Role }}{{ .Content }}<|im_end|>{{ end }}<|im_start|>assistant<think></think>"""
Без этого: 2/22. С этим: 15/22. Один параметр в Modelfile = разница в 13 баллов на бенчмарке.
Если будете фантюнить Qwen3 family — обязательно проверьте этот Modelfile-фикс. Через Ollama API параметр называется think: false:
requests.post(f"{OLLAMA_URL}/api/generate", json={ "model": "oni:base-7.v2", "prompt": prompt, "stream": False, "think": False, # ← критично для Qwen3 family "options": {"num_ctx": 16384, "num_predict": 4000}})
Что выложил в open source
Весь датасет, скрипты, бенчмарки, методология — лежит на GitHub:
👉 github.com/makarsuperstar/oni-devops-traces
Что там:
-
data/own_anchors/train.jsonl— 1867 hand-crafted multi-turn agent трейсов в JSONL формате -
data/distilled_*— distilled subsets (распилка из Magicoder через локальный teacher gemma4:31b — об этом в следующей статье) -
scripts/distill.py— скрипт дистилляции (~250 строк, только requests + pyyaml) -
scripts/run_benchmark.py— composite scoring 8 метрик format compliance -
meta/few_shot_reference.jsonl— 5 эталонных трейсов для few-shot prompting -
meta/benchmark_results.md— полный отчёт teacher-бенчмарка -
DATASET_FORMAT.md— спецификация формата -
REPRODUCE.md— пошаговый гайд как пересобрать с нуля
Что я бы сделал иначе с самого начала
Сразу пошёл бы на 14B+ базу. Время, потраченное на qwen3:8b в попытках «уместить в 4080» — потеряно зря. Если задача агентная (multi-step + tool calling), 8B параметров просто мало. Лучше снять VM на ночь, чем месяц мучиться на маленькой модели.
Не начинал бы с HuggingFace mix raw. Это разрушило 3 итерации. Если фантюнишь агента — данные должны быть в формате агента (multi-turn). Иначе модель учится противоречию между single-turn и multi-turn.
TEMPLATE override в Modelfile — с первого дня. 3 ночи на диагностику «обучилось, но не работает» — этого можно было избежать одной строкой.
Сразу делал бы composite scoring. Я долго смотрел на loss + субъективную оценку. Когда добавил композитный 8-метричный scoring (json parses, has messages, tool call present, final answer present, verification before final и т.д.) — стало возможно сравнивать модели объективно.
Не игнорировал бы баланс датасета. Распределение трейсов по seed-ам у меня было от 1 до 30. Это означало 30× перекос. Из-за него base-8 начал hallucinate success на realworld step. Урок: кап на seed — обязателен.
Что дальше
-
Distillation pipeline — расширяем датасет через локальный teacher LLM (без облачных API), переоборудуем существующие открытые датасеты в наш agent-формат. Уже выложено
distilled_bash_pipes(243 трейса) иdistilled_django(199 трейсов). В очереди — express, microservices, ssh, docker_advanced, kubernetes, ci_cd, postgres. Подробнее в следующей статье. -
Train base-10 на сбалансированных + distilled данных. Цель — Stage 1 SSH 19+/22, realworld 5/5 honest.
-
Telegram-бот @oni_devops_bot для публичного demo (через 2–3 недели, когда модель станет «не стыдно показывать»). Free 10 запросов/день.
-
OpenClaw integration — ради чего всё начиналось. Конфиг + Modelfile в репо, любой может подключить свою oni к openclaw-серверу.
Если интересно следить
Я веду building-in-public канал с короткими заметками про процесс, грабли, числа.
Репо с данными и скриптами: github.com/makarsuperstar/oni-devops-traces
В следующей статье — детально про SeedBuilder pipeline (как мы локально дистиллируем существующие датасеты в agent format) и сравнение 4 кандидатов на teacher-модель: Qwen 2.5 Coder vs Qwen 3.6 vs Gemma 4 vs DeepSeek Coder V2.
Если делаете что-то похожее, или хотите помочь с PR (например, добавить distillation из своего домена — Terraform, Ansible, Kubernetes-specific) — буду рад. Или просто скачайте JSONL и расскажите как он повёл себя у вас в SFT — фидбек ценнее звёзд.
— makarsuperstar
ссылка на оригинал статьи https://habr.com/ru/articles/1033128/