…Еще играясь с Qwen3.6 я дал ей стандартную handoff задачу от своей AI команды по проекту SwiftUI и QWEN cli ее так и не решил. Просто ушел в постоянные размышления. В итоге я его просто закрыл и сделал вывод, что Qwen3.6 не может решать такие задачи. И как оказалось я поспешил…
В предыдущем расследовании https://habr.com/ru/articles/1075706 мы искали скорость локальной Qwen3.8-27B на Mac Studio. Вывод был довольно жёстким: для интерактивной работы радикально ускорить 27-миллиардную модель можно прежде всего уменьшив объём её весов, то есть квантизацией. В связке с DFlash2 версия 8-bit дошла до 38 токенов в секунду.
Но это был только первый вопрос.
Быстро отвечать и хорошо работать — не одно и то же. Особенно когда модель должна не пересказать текст, а разобрать инцидент, соблюдать строгий формат, написать и отладить код.
Я хотел найти не самую быструю версию Qwen3.8-27B, а модель, которую можно реально использовать каждый день: чтобы не ждать ответ по минуте и не получать взамен очень убедительную чепуху.
Казалось, что план очевиден. BF16 берём как эталон качества. 8-bit и 4-bit сравниваем с ним. А чтобы квантизованные версии точно не потеряли в сложных задачах, включаем им максимальный уровень рассуждений — reasoning_effort=xhigh.
Это была вполне логичная гипотеза.
И она оказалась неверной.
Коротко о стенде
Тесты выполнялись на Mac Studio (2025), Mac15,14: Apple M3 Ultra, 32-ядерный CPU, 80-ядерный GPU, 512 ГБ объединённой памяти и SSD 2 ТБ.
Почему BF16 на такой машине не превращается в молнию, как устроены ограничения decode и почему DFlash2 помогает, уже разобрано отдельно в статье: https://habr.com/ru/articles/1075706. Здесь это лишь входное условие: после поиска скорости в эксперимент вошли три target-модели.
Метка | Модель |
|---|---|
BF16 |
|
8-bit |
|
4-bit |
|
Чтобы сравнение было честным, у всех трёх моделей были одинаковые условия:
один draft —
incoai/Qwen3.8-27B-DFlash2;Draft Window = 2048,Draft Sink = 0,Verify Mode = adaptive;draft-модель без квантизации;
включённый L1 in-memory cache;
проверка в логе, что
DFlashEngineдействительно загружен и завершил генерацию.
DFlash2 здесь не самостоятельная модель, а помощник для speculative decoding: он предлагает блок будущих токенов, а target-модель их проверяет. Авторы DFlash2 описывают его именно как block-diffusion draft-модель, а не замену основной Qwen (model card).
То есть в тесте менялась квантизация target-модели, а не весь остальной конвейер.
Что считать качеством, а не впечатлением
Попросить другую LLM оценить ответы — плохой бенчмарк. Мы тогда просто заменяем одно вероятностное суждение другим и с серьёзным лицом называем это измерением.
Поэтому я написал Python-бенчмарк для локального API oMLX. В нём 28 quality-запросов на каждую модель.
Семь задач проверяли reasoning, следование инструкции и анализ:
инвентарь, расписание и надёжность с повторной попыткой;
строгий JSON и заданный русский формат;
анализ инцидента и расчёт TCO поставщика.
Ещё 21 запрос — разработка: семь задач, каждая в трёх профилях reasoning.
Направление | Задачи | Как проверялось |
|---|---|---|
C# | longest window, compress ranges, строгий парсер TCP-порта, LRU cache, детерминированный build order с обнаружением циклов | Модельный код компилируется .NET SDK и запускается с hidden tests. Проверяются overflow, граничные случаи, порядок, дубликаты и контракт API. |
SwiftUI | список задач с поиском и фильтрами; форма бюджета с валидацией | Swift компилируется через |
В C# ответ должен был содержать только требуемый класс: без namespace, Main, доступа к файлам, сети и процессам. В SwiftUI недостаточно было красиво описать логику — нужно было вернуть компилируемый экран с нужными элементами.
Это важное различие. В реальной разработке ответ «в целом правильный, но не выполнил контракт» — это не почти готовый результат. Это работа, которую нужно переделать руками.
Тут стоит отметить, почему именно этот набор тестов и почему я не взял готовые бенчмарки. Еще играясь с Qwen3.6 я дал ей стандартную handoff задачу по проекту SwiftUI и QWEN cli ее так и не решил. Просто ушел в постоянные размышления. В итоге я его просто закрыл и сделал вывод, что Qwen3.6 не может решать такие задачи. И как оказалось я поспешил.
Готовые бенчмарки не взял по двум причинам: они бы обрабатывались слишком долго и… не нашел подходящего открытого benchmark suite для моего сценария для SwiftUI. Если у вы знаете такие - буду очень благодарен за ссылки в комментариях. А вторая причина - это время. На больших benchmark suite я не знаю когда бы закончился тест.
Для задач разработки использовались три режима:
Профиль | Настройка |
|---|---|
| максимальное усилие, server default budget |
|
|
|
|
У Qwen3.8 thinking mode включён по умолчанию, а глубину рассуждений можно управлять через reasoning_effort (документация Qwen). Именно поэтому этот параметр был не мелкой настройкой, а одним из главных объектов расследования.
Сначала общий результат: скорость нашли, качество не потеряли
В полном прогоне было 84 quality-запроса и 45 speed-запросов: три модели и пять повторов каждого из трёх speed-сценариев. Перед измерениями для каждой модели выполнялся warm-up.
Модель | Формальный quality score | Полностью пройдено заданий | Медианный end-to-end wall time |
|---|---|---|---|
BF16 | 85,3% | 24 / 28 | 38,91 с |
8-bit | 83,3% | 23 / 28 | 21,39 с |
4-bit | 82,7% | 20 / 28 | 17,77 с |
oMLX в этой версии не вернул API-метрики TG/PP/TTFT, поэтому это не «чистая» скорость decode, а end-to-end время запроса; в отдельных переключениях оно включает и загрузку модели. Для практического сравнения направление выигрыша достаточно ясно, но точный профайлинг нужно делать отдельно.
4-bit оказалась примерно в 2,2 раза быстрее BF16, 8-bit — примерно в 1,8 раза. На отдельных сценариях 4-bit ускорила обычную генерацию в 3,6 раза, генерацию C# — в 2,7 раза, а длинный prefill — только в 1,2 раза. Это ожидаемо: квантизация сильнее помогает в decode, где веса читаются снова и снова, чем в обработке длинного входного prompt.
И вот здесь первый важный результат: 4-bit не развалилась на простых рабочих задачах. Отставание от BF16 в формальном score составило 2,6 п.п., а у 8-bit — 2 п.п.
Это ещё не право объявить модели равными. Один прогон — не статистическая гарантия. Но это уже достаточная причина перестать исходить из предположения «4-bit обязательно непригодна для серьёзной работы».
Тем более что часть разрыва оказалась артефактом проверки. В анализе инцидента обе квантизованные модели правильно определили причину, регион и оба времени, но выбрали доказательства E1, E5, E6, а judge принимал только E2, E5, E6. Первый набор тоже логичен: он связывает проблему с выкладкой, подтверждает механизм и показывает восстановление.
Если judge принимать оба обоснованных набора, счёт меняется так:
Модель | Исходный score | Score после исправления judge |
|---|---|---|
BF16 | 85,3% | 85,3% |
8-bit | 83,3% | 85,3% |
4-bit | 82,7% | 84,7% |
То есть пока корректный вывод такой: на этом наборе не обнаружено заметной деградации от 8-bit и 4-bit. Дальше нужны повторные прогоны и больше независимых задач.
Но самая интересная улика была не в этой таблице.
Улика № 3: xhigh оказался плохим руководителем разработки
Изначальная гипотеза звучала разумно: чем сильнее квантизация, тем аккуратнее модель надо заставлять думать. Значит 4-bit стоит дать xhigh, а возможно — даже сделать его дефолтом.
Фактический результат оказался почти обратным.
Режим reasoning | C#, BF16 / 8-bit / 4-bit | SwiftUI, BF16 / 8-bit / 4-bit |
|---|---|---|
| 4 / 5 · 4 / 5 · 1 / 5 | 1 / 2 · 1 / 2 · 0 / 2 |
| 5 / 5 · 5 / 5 · 5 / 5 | 1 / 2 · 2 / 2 · 2 / 2 |
| 5 / 5 · 5 / 5 · 5 / 5 | 2 / 2 · 1 / 2 · 1 / 2 |
На xhigh хуже стало всем. Но сильнее всего провалилась именно 4-bit: одна из пяти C#-задач и ни одной из двух SwiftUI.
На medium / 2048 4-bit и 8-bit прошли все 7 из 7 задач разработки. В C#-задаче с LRU cache 4-bit была ещё и быстрее: 19,94 с против 25,21 с у 8-bit и 57,53 с у BF16.
Это и есть центральный результат расследования.
Чтобы компенсировать квантизацию, маленькой версии модели не нужно давать больше времени на размышления. В этом стеке ей нужно дать меньше свободы уйти в бесконечные размышления и быстрее потребовать финальный код.
Что именно ломал xhigh
Проблема была не в том, что модель выбирала неправильный алгоритм. В нескольких случаях она вообще не доходила до результата.
Самый наглядный пример — строгий парсер TCP-порта. Это не самая сложная задача в наборе: нужно корректно обработать null, пустую строку, пробелы, +80, Unicode-цифры, переполнение, диапазон 1...65535 и вернуть строго заданный C#-класс.
В xhigh BF16 и 8-bit ушли в длинное рассуждение, но не выдали итоговый Solution. Код не дошёл до компилятора — проверять там было уже нечего.
После переключения на medium / 2048 и low / 1024 обе модели прошли все 13 из 13 hidden tests этой задачи. В полном наборе все три модели, включая 4-bit, решили все пять C#-задач и в medium, и в low.
Со SwiftUI история похожая. Некоторые xhigh-провалы были не ошибками в фильтрации или валидации, а нарушением контракта вывода: модель не отдала import SwiftUI, добавила запрещённый импорт или не дошла до финального View.
У 4-bit в xhigh была и одна настоящая compile-ошибка: System.StringBuilder вместо System.Text.StringBuilder. Но это не объясняет всю разницу. Основная проблема — чрезмерное reasoning съедало токены и разрушало переход от анализа к финальному коду.
Парадокс в том, что xhigh выглядел как настройка «сделай тщательнее», а фактически стал плохим руководителем разработки. Он заставлял модель слишком долго перепроверять крайние случаи, но не контролировал простой и главный deliverable: верни компилируемый исходник с нужным API.
Меньше бит — меньше думать? Да, но в правильной формулировке
Соблазнительный вывод звучит так: «чем меньше модель, тем меньше ей надо думать». По этому эксперименту он действительно хорошо описывает практическую настройку 4-bit.
Так ли это, покажет уже ведущаяся разработка моей AI-командой на Qwen3.8.
Почему это происходит, вероятно, складывается из нескольких причин:
xhighгенерирует слишком длинную внутреннюю цепочку и оставляет меньше шансов на аккуратный финальный ответ.Квантизация меняет траекторию генерации; при длинном reasoning небольшое отклонение может накапливаться до момента, когда модель уже не возвращается к контракту задачи.
В API-цепочке oMLX reasoning иногда попадал туда, где бенчмарк ожидал только код. Для автоматизации это не «особенность формата», а реальная ошибка интеграции.
Первый и третий пункты напрямую наблюдались в результатах. Второй — разумная гипотеза, которую ещё нужно проверять повторными прогонами, а не установленный факт.
Именно поэтому настройку нельзя выбирать по шкале «больше — лучше». Нужно выбирать по задаче.
Сценарий | Текущая практическая настройка |
|---|---|
C# и SwiftUI с жёстким контрактом | 4-bit или 8-bit + DFlash2 + |
Быстрые детерминированные C#-задачи | можно начать с |
Длинный анализ или особенно критичная задача | BF16 остаётся контрольной версией; результат стоит перепроверить отдельно |
Нужен максимум скорости в интерактивной работе | 4-bit + DFlash2, но не включать |
Вердикт: качество нашлось не там, где его искали
Мы начали с понятной логики: BF16 — максимум качества, 8-bit — компромисс, 4-bit — почти наверняка плата качеством за скорость. А если плата окажется слишком велика, нужно добавить reasoning.
Эксперимент показал более интересную картину.
Квантизация до 8-bit и 4-bit дала огромный выигрыш по скорости и не показала катастрофической деградации на выбранном наборе задач.
Качество нельзя измерять только внешним впечатлением от текста: код должен компилироваться, а ответ — соблюдать контракт.
Максимальное reasoning не стало страховкой для квантизованных моделей. В программировании оно оказалось одной из причин сбоев.
Для 4-bit лучшим режимом стал не
xhigh, аmedium / 2048: все 7 из 7 задач разработки при минимальном времени среди трёх моделей.
Моя текущая рабочая конфигурация для разработки — Qwen3.8-27B-4bit + DFlash2 + reasoning_effort=medium + thinking_budget=2048. BF16 я не списываю со счетов: она остаётся контрольной моделью и резервом для задач, где ошибка особенно дорога.
Главный вывод здесь не про 4 бита. Он про то, как мы привыкли настраивать LLM.
Больше thinking не означает больше качества. Особенно если задача требует не красивого рассуждения, а конкретного артефакта: валидного JSON, работающего класса, компилируемого экрана, точного API-вызова.
Модель должна не просто долго думать. Она должна вовремя закончить думать и начать делать.
Что проверять дальше
Дело ещё не закрыто. Следующий этап — увеличить доказательную базу:
исправить judge инцидента, чтобы он принимал оба обоснованных набора доказательств;
повторить набор несколько раз и добавить независимые задачи;
проверить реальные задачи из рабочих проектов в изолированном harness;
отделить чистые TG/PP/TTFT от end-to-end wall time и запускать speed-прогоны блоками по моделям;
отдельно проверить длинный контекст, tool use и задачи, где ошибка особенно дорога.
Только после этого можно будет уверенно сказать, где BF16 действительно окупает свою медлительность, а где 4-bit уже стала не экспериментом, а рабочим стандартом.