…Еще играясь с 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

mlx-community/Qwen3.8-27B-bf16

8-bit

mlx-community/Qwen3.8-27B-8bit

4-bit

mlx-community/Qwen3.8-27B-4bit

Чтобы сравнение было честным, у всех трёх моделей были одинаковые условия:

  • один 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 компилируется через swiftc; hidden tests проверяют логику, а judge — наличие реального View, List, .searchable, Picker, Form, TextField, Button и .disabled.

В C# ответ должен был содержать только требуемый класс: без namespace, Main, доступа к файлам, сети и процессам. В SwiftUI недостаточно было красиво описать логику — нужно было вернуть компилируемый экран с нужными элементами.

Это важное различие. В реальной разработке ответ «в целом правильный, но не выполнил контракт» — это не почти готовый результат. Это работа, которую нужно переделать руками.

Тут стоит отметить, почему именно этот набор тестов и почему я не взял готовые бенчмарки. Еще играясь с Qwen3.6 я дал ей стандартную handoff задачу по проекту SwiftUI и QWEN cli ее так и не решил. Просто ушел в постоянные размышления. В итоге я его просто закрыл и сделал вывод, что Qwen3.6 не может решать такие задачи. И как оказалось я поспешил.

Готовые бенчмарки не взял по двум причинам: они бы обрабатывались слишком долго и… не нашел подходящего открытого benchmark suite для моего сценария для SwiftUI. Если у вы знаете такие - буду очень благодарен за ссылки в комментариях. А вторая причина - это время. На больших benchmark suite я не знаю когда бы закончился тест.

Для задач разработки использовались три режима:

Профиль

Настройка

xhigh

максимальное усилие, server default budget

medium

thinking_budget=2048

low

thinking_budget=1024

У 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

xhigh

4 / 5 · 4 / 5 · 1 / 5

1 / 2 · 1 / 2 · 0 / 2

medium / 2048

5 / 5 · 5 / 5 · 5 / 5

1 / 2 · 2 / 2 · 2 / 2

low / 1024

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.

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

  1. xhigh генерирует слишком длинную внутреннюю цепочку и оставляет меньше шансов на аккуратный финальный ответ.

  2. Квантизация меняет траекторию генерации; при длинном reasoning небольшое отклонение может накапливаться до момента, когда модель уже не возвращается к контракту задачи.

  3. В API-цепочке oMLX reasoning иногда попадал туда, где бенчмарк ожидал только код. Для автоматизации это не «особенность формата», а реальная ошибка интеграции.

Первый и третий пункты напрямую наблюдались в результатах. Второй — разумная гипотеза, которую ещё нужно проверять повторными прогонами, а не установленный факт.

Именно поэтому настройку нельзя выбирать по шкале «больше — лучше». Нужно выбирать по задаче.

Сценарий

Текущая практическая настройка

C# и SwiftUI с жёстким контрактом

4-bit или 8-bit + DFlash2 + medium / 2048

Быстрые детерминированные C#-задачи

можно начать с low / 1024, но проверять код тестами

Длинный анализ или особенно критичная задача

BF16 остаётся контрольной версией; результат стоит перепроверить отдельно

Нужен максимум скорости в интерактивной работе

4-bit + DFlash2, но не включать xhigh автоматически

Вердикт: качество нашлось не там, где его искали

Мы начали с понятной логики: 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 уже стала не экспериментом, а рабочим стандартом.