Статья · Личный эксперимент

Как я ускорил локальную Qwen 27B на Mac с M4 Max — и что получилось на самом деле

355,48 токена в секунду на длинном входе, работа с кэшем и ограничения качества. Подробный эксперимент с Kapitsa, замерами и набором для воспроизведения.

Скачать материалы эксперимента

Актуальный ИИ-промптai-prompt.md · Markdown (.md) Минимальный набор для воспроизведенияqwen27b-minimal.zip · Архив (.zip)

Я хотел использовать локальную модель для работы с кодом: открывать проект, передавать ей десятки тысяч токенов исходников, задавать вопросы и продолжать диалог без ожидания по несколько минут после каждого прочитанного файла. Компьютер — Mac с M4 Max, 32 ядрами GPU и 36 ГБ общей памяти.

Сначала задача казалась простой: модель класса 27B в Q4, длинный контекст до 128k, prefill около 300 токенов в секунду и генерация не ниже 30 токенов в секунду. Чуть позже я согласился на 255 токенов в секунду как нижнюю границу скорости prefill. И, конечно, хотелось ускориться без заметной потери качества.

Вместе с ИИ-помощником мы построили рабочую связку на базе Qwen3.8-27B и доработанного Kapitsa. В одном холодном тесте на 144 585 входных токенах она обработала запрос со скоростью 355,48 токена в секунду. В другом тесте на длинном контексте генерация кода достигла 48,25 токена в секунду. Но русскоязычный ответ на другом запросе шёл примерно 22,11 токена в секунду. Короткие добавления к длинному контексту тоже могли обрабатываться заметно медленнее 255 токенов в секунду.

Это экспериментальные результаты конкретных запросов, а не гарантия минимума на любом контексте. Главное ограничение: ради скорости мы изменили вычисления attention на этапе prefill. Все входные токены сохраняются, но ответ модели не обязан совпадать с ответом при полном attention. На контексте около 256k был зафиксирован тест с ошибкой качества; подтвердить общую потерю качества не более 1–2% не удалось.

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

С чего начинали и чего добились

До доработок большие запросы обрабатывались у меня со скоростью prefill примерно 135–200 токенов в секунду; на длинном контексте ориентиром были около 135 ток/с. После настройки в одном холодном тесте на 144 585 токенах мы получили 355,48 ток/с. Если сравнить эти конкретные цифры, получается примерно в 2,6 раза быстрее — то есть практический прирост порядка 2,5 раза относительно моего исходного наблюдения.

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

Если таблица не помещается, прокрутите её по горизонтали.

Показатель Контроль: полный prefill Наш ускоренный prefill Разница в этом замере
Вход 131 266 токенов 131 268 токенов Почти одинаковый объём
Prefill 179,14 ток/с 342,01 ток/с В 1,91 раза быстрее
Время до первого токена 733,54 с 384,17 с На 349 с меньше
Генерация по потоку 32,09 ток/с 40,82 ток/с Примерно на 27% быстрее

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

При этом ускорение не означает, что мы доказали полное отсутствие потерь качества. На выбранных шести заданиях LongBench v2 и четырёх вопросах к контексту около 50k ответы полного и ускоренного профилей совпали. Для проверенных случаев результат хороший, но выборка мала, а приближённый prefill меняет вычисления. Поэтому вывод точнее формулировать так: мы получили заметный прирост скорости и не обнаружили различий в этих парных проверках, но не установили, что качество сохраняется на всех задачах.

Что именно я хотел ускорить

Для начала разделим работу модели на два этапа. Иначе в цифрах легко запутаться.

Prefill — чтение входа. Модель обрабатывает системные инструкции, историю диалога, код, файлы и результаты инструментов до начала ответа. Если в запросе 50 000 токенов и система обрабатывает их со средней скоростью 200 токенов в секунду, одно чтение займёт примерно четыре минуты.

Генерация, или decode, — создание ответа после чтения входа. Например, 30 токенов в секунду означают, что ответ длиной 900 токенов займёт примерно 30 секунд после начала генерации. Сравнивать эту скорость по ответу из одного или двух токенов бессмысленно: такой результат слишком мал и зависит от накладных расходов.

Есть и третья важная величина — повторное использование кэша. Когда я спрашиваю модель о проекте второй раз, клиент обычно снова отправляет предыдущую историю. Если начало истории совпадает с уже обработанным, сервер может восстановить сохранённое состояние и обработать только новый хвост. Ускорение за счёт кэша означает меньший объём повторной работы; само по себе оно не означает, что вычисление каждого нового токена стало быстрее.

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

Из чего состоит связка

В качестве основной модели мы использовали Youssofal/Qwen3.8-27B-MTPLX-Bare-Speed — сборку весов Qwen3.8-27B с квантованием Q4. Воспроизводимая ревизия модели закреплена в прилагаемом наборе. Три файла её основных весов и токенизатор на моей машине совпали по SHA256 с этой ревизией.

Сервером стал Kapitsa. Это отдельный нативный движок для Apple Silicon, работающий с Metal и использующий Neural Engine для части вычислений. Он умеет читать совместимые веса, но сам не является интерфейсом MTPLX. Подробности архитектуры есть в документации Kapitsa.

Мы взяли конкретный коммит Kapitsa и немного его доработали: добавили приблизительный prefill, изменения работы с кэшем и мониторинг. Поэтому обычная установка Kapitsa или запуск тех же весов в MTPLX не включат автоматически все описанные здесь изменения.

Для ускорения генерации добавили отдельную черновую модель incoai/Qwen3.8-27B-DFlash2. Она предлагает несколько следующих токенов, а основная модель проверяет предложения. Мы использовали исходные BF16-веса черновика и включили его загрузку в Q4 внутри движка. Это DFlash2, не MTP. Черновик помогает генерации; не стоит приписывать ему измеренное ускорение холодного prefill.

Ещё мы включили Q8 для KV-кэша — сохранённых данных, используемых attention при следующих вычислениях. Это ещё одно приближение по сравнению с хранением KV в более высокой точности. У него своя роль: уменьшить расход памяти на длинном контексте и сделать выбранную вместимость практической на машине с 36 ГБ.

Если таблица не помещается, прокрутите её по горизонтали.

Компонент Роль в нашем профиле
Qwen3.8-27B, Q4 Основная модель и её квантованные веса
Kapitsa + патч Локальный сервер, вычисления на GPU/Neural Engine, кэш и монитор
Приближённый prefill attention Меньше вычислений на длинном входе с изменением математической схемы
Q8 KV-кэш Снижение расхода памяти на данные attention
DFlash2, загрузка в Q4 Черновые предложения для ускорения генерации
Контрольные точки кэша Меньше лишнего пересчёта при изменениях истории

Neural Engine в этой схеме действительно используется для части prefill. Параметр NI_ANE_UNITS=30 в нашем профиле — это доля работы, выраженная движком в блоках по 512 каналов, а не утверждение, что в чипе 30 ядер Neural Engine. Оптимальное значение для другого Mac нужно измерять заново.

Откуда взялся быстрый prefill

При полном attention каждая новая позиция учитывает доступные ей предыдущие позиции. По мере роста контекста объём этой части работы увеличивается. Мы выбрали экспериментальную политику, которая для значительной части входа ограничивает область attention: сохраняет глобальную часть в начале и недавнее окно.

В нашем конкретном профиле использовались:

  • первые 8192 позиции как глобальная область;
  • последние 8192 позиции относительно рассматриваемого токена как недавнее окно;
  • плотный attention для последних 2048 входных позиций при холодном запросе;
  • плотный хвост 128 позиций в выбранном режиме продолжения.

Отдельные участки восстановленного хвоста могут пересчитываться плотным attention в зависимости от того, какая контрольная точка кэша найдена. Во время генерации применяется плотный attention к доступному кэшу.

Здесь важно не потерять оговорку. Мы не удаляем входные токены, однако на этапе prefill многие их представления вычисляются с ограниченной областью внимания. Поэтому позднейший плотный decode обращается к уже приближённо вычисленным состояниям. Он не превращает предшествующую обработку в полное attention. Кроме того, при продолжении используются сохранённые состояния прежних эпох вычисления: результат может зависеть от истории диалога и отличаться от нового холодного прохода по той же полной истории.

Скорость здесь досталась не бесплатно: мы сознательно изменили вычисления и приняли риск для качества. Для задач, где нужно строго учитывать связи между всеми частями длинного документа, такой профиль необходимо проверять особенно внимательно.

Почему кэш иногда «обнулялся»

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

Мы обнаружили случаи, когда совпадал большой кусок истории, но ближайшая доступная точка восстановления находилась далеко позади. Модель повторно считала тысячи уже известных токенов. Со стороны это выглядело так, будто кэш обнулился: сменил тему — и снова ждёшь.

Мы добавили несколько защищённых контрольных точек: на границе входа, перед ходом пользователя, рядом с заголовком ответа и в отдельных местах генерации. При восстановлении проверяются совпадение префикса, принадлежность состояния текущему контексту и совместимость политики attention. Незавершённое состояние после частичного prefill нельзя просто объявить готовым кэшем. При некоторых отменах движок возвращается к ранее подтверждённой точке; когда подходящей точки нет, он пересчитывает больше или начинает заново.

Один из контрольных случаев выглядел так:

Если таблица не помещается, прокрутите её по горизонтали.

Смена вопроса на входе около 147k До После
Лишние повторно обработанные токены 2017 3
Время prefill 21,200 с 1,829 с

В другом отдельном тесте изменение внутри длинного ответа привело к следующему результату:

Если таблица не помещается, прокрутите её по горизонтали.

Вход после изменения: 65 023 токена До архива С архивом
Лишний повторный расчёт 4498 токенов 398 токенов
Всего обработано с учётом нового хвоста 8465 токенов 4365 токенов
Время prefill 38,809 с 18,229 с

В последнем случае обязательный новый хвост оставался примерно 3967 токенов в обоих вариантах. Выигрыш получен за счёт сокращения повторной обработки, а не за счёт удаления нового текста. В обеих контрольных парах все восемь проверенных ответов до и после совпали. Но это отдельные сценарии, а не гарантия, что кэш больше никогда не будет сброшен.

Но точек восстановления не бесконечно много. Например, при изменении ранней системной инструкции, списка инструментов, переходе к другому диалогу или изменении текста раньше доступной точки пересчёт по-прежнему может быть большим. Дополнительная архивная точка в нашем случае занимала около 189,6 МиБ.

Что показали замеры

Для основного сравнения использовались итоговые счётчики движка, а не только меняющаяся во время работы цифра в мониторе. Скорость prefill рассчитывалась по действительно обработанным токенам, включая необходимый replay, а не по полному объёму истории, уже взятому из кэша.

Следующая таблица относится к исторической проверенной сборке E2 e2dcb749f9b5…, а не к отдельному повторному бенчмарку каждой последующей доработки:

Если таблица не помещается, прокрутите её по горизонтали.

Сценарий Полный вход Обработано в этом запросе Prefill Генерация
Холодная загрузка 144 585 144 585 355,48 ток/с Короткое подтверждение из 6 токенов; не оценивается
Продолжение с задачей на код 144 766 176 78,15 ток/с 1744 токена при 48,25 ток/с
Продолжение с русским текстом 146 935 2169 99,74 ток/с 1337 токенов при 22,11 ток/с

Вот почему заголовок «теперь prefill всегда 355 токенов в секунду» выглядел бы красиво, но был бы неправдой. Большой холодный запрос и короткое дополнение к длинному кэшу ведут себя по-разному. У второго могут быть другие накладные расходы и больше работы с уже накопленным состоянием. Скорость генерации также зависит от самого задания и поведения спекулятивного декодирования.

Позже мы отдельно проверили адаптивный путь packedR4 для работы с Q8 KV. В одной паре одинаковых русских заданий на 146 935 входных токенах скорость генерации выросла с 21,858 до 24,366 токена в секунду. В проверенных ответах этой серии результат совпал с контролем, но 30 токенов в секунду для этого русского задания всё равно не получилось. Этот результат относится к отдельной сборке и отдельному сравнению, а не к таблице E2 выше.

Чтобы перевести скорость в более знакомые минуты: если бы средняя скорость на протяжении всего запроса составила те же 355,48 токена в секунду, обработка 131 072 токенов заняла бы около 369 секунд, или 6 минут 9 секунд. Реальная скорость может меняться с длиной, состоянием памяти и профилем. Поэтому клиент с ограничением ожидания 300 секунд может отменить такой запрос ещё до ответа. Таймаут на стороне клиента и таймаут серверного шлюза — разные настройки.

В интерфейсе мы сделали отдельный монитор на /monitor. Он показывает активные и последние завершённые запросы, рассчитанный и взятый из кэша объём, prefill, генерацию и время до первого токена. Во время работы скорость может быть предварительной; для сравнения лучше брать окончательные данные завершённого запроса. Время подготовки запроса, токенизации и передачи данных может отличаться от чистого времени вычисления prefill.

А качество не потерялось?

Мы сравнивали варианты на реальном WordPress-проекте: 10 вопросов по исходникам и 6 небольших задач на PHP/JavaScript. Были заранее зафиксированы входы и проверки, а затем выполнен replay из 51 запроса с контекстами до 157 202 токенов. Ответы испытуемой версии не подставлялись как будущие входы: это позволяло сравнивать зафиксированные запросы.

В трёх проверенных вариантах результаты для 16 задач совпали:

  • первоначальный строгий протокол: 9 из 16;
  • отдельный разбор фактов в JSON: 10 из 10;
  • отдельный набор проверок кода с дополненным DOM-тестом: 5 из 6.

Эти показатели нельзя просто сложить или заменить ими исходные 9/16: они получены по разным правилам проверки. Одна из ошибок встречалась и у контроля с полным attention: валидатор месяца принимал строку с завершающим переводом строки. После явной подсказки в отдельном диалоге исправленная версия прошла 13 из 13 тестов, но это уже результат с подсказкой, а не успех первой попытки.

При этом один исторический тест long_config_witness на входе 255 747 токенов не прошёл проверку качества. Мы сохранили этот результат и после последующих исправлений кэша. Небольшая выборка успешных задач не доказывает потерю качества в пределах 1–2%, а наличие выделенного окна 262 144 не доказывает одинаковое качество на всём его протяжении.

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

Обновление от 30 октября 2026: проверяем память, кэш и реальные вопросы

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

Все результаты ниже получены на том же Mac с M4 Max и 36 ГБ памяти. Один замер — это не гарантия скорости на другом Mac или даже на каждом запросе на этом же компьютере. В наших проверках у основного профиля были Q4-веса, Q8 KV-кэш и приближённый prefill, описанный выше. Изменения в рабочем сервере после неудачных экспериментов мы откатили.

Скорость и поиск фактов в длинном тексте

Мы подготовили собственный тест в духе needle-in-a-haystack: вставили в текст 15 случайных кодов, по три в пяти областях документа, и попросили модель вернуть все коды в одном ответе. Области находились примерно на 1,5%, 25%, 50%, 75% и 98,5% длины текста по символам, а не точно по токенам. Для каждой метки проверялось совпадение именно её кода.

Если таблица не помещается, прокрутите её по горизонтали.

Холодный вход Время до первого токена Вход / время Найдено Скорость ответа
30 215 токенов 77,81 с 388 ток/с 15 из 15 около 67 ток/с, ответ 324 токена
131 636 токенов 371,28 с 355 ток/с 15 из 15 около 51 ток/с, ответ 793 токена

Скорость ответа здесь оценивалась по потоку между первым и последним содержательным фрагментом. Это два конкретных ответа, а не обещание 51 токен в секунду для русского текста, кода или любого запроса с 128k. В замере на 131 636 токенов до начала ответа пришлось ждать около шести минут. Можно успеть за чаем — но лучше всё же учитывать это в настройках клиента.

Важно: 15 из 15 — результат одного запроса с несколькими фактами, а не полноценная сетка независимых запросов на каждой глубине. Этот тест показывает, что в данном материале модель нашла нужные строки. Он не доказывает, что она надёжно понимает связи между документами или напишет правильный код.

Открытые тесты RULER и LongBench v2

Чтобы проверить не только поиск отдельной строки, мы использовали RULER от NVIDIA. Официальным генератором подготовили два примера одного типа — отслеживание цепочки переменных с четырьмя переходами. Генератор использовал токенизатор нашей модели и seed 42; API насчитал примерно 32,6 тысячи входных токенов на пример. В обоих примерах модель нашла все пять искомых переменных: 10 из 10, около 389 ток/с на каждом запросе. Оценка следовала правилу RULER для этого задания: доля ожидаемых имён, встречающихся в ответе.

Это не результат полного RULER. Мы проверили два примера одной категории, а не все задачи и все длины контекста. По ним нельзя утверждать, что модель на 100% справляется с длинной памятью.

Для более реалистичных вопросов мы взяли шесть примеров из LongBench v2: по одному из каждой категории — документ, несколько документов, история диалога, репозиторий кода, структурированные данные и обучение по контексту. Это первые подходящие примеры с длиной документа от 40 до 180 тысяч символов, а не случайная репрезентативная выборка. Полные запросы заняли примерно от 13 до 50 тысяч токенов, документы не обрезались.

Здесь модель встретилась с довольно прозаичной проблемой: форматом ответа. С опубликованным шаблоном прямого ответа и лимитом 128 выходных токенов модель во всех шести случаях начала подробное объяснение и исчерпала лимит, не выдав финальную букву. Формально правило извлечения ответа дало 0 из 6, но это не означает, что модель неправильно решила все шесть задач: готового ответа в этих запусках просто не было. Мы явно отключили режим thinking; обычный текст ответа при этом всё равно оказался слишком многословным для заданного лимита.

Затем мы повторили те же шесть заданий с дополнительной системной инструкцией сразу дать краткий ответ. Все шесть ответов завершились; 2 из 6 совпали с эталоном — задания по истории диалога и по репозиторию. Это адаптированный тест, а не официальный результат LongBench v2. Шесть примеров слишком малы для надёжной общей оценки модели, но они хорошо показывают разницу между поиском факта и более сложным анализом.

Проверка кэша в разговоре

Отдельно мы отправили большой контекст проекта и задали четыре последовательных вопроса. Время ниже — от отправки очередного запроса до начала ответа:

Если таблица не помещается, прокрутите её по горизонтали.

Ход Вход Использовано из кэша Время до ответа Ответ
Первый, холодный 50 145 токенов 0 134,57 с верно
Второй 50 267 50 190 0,78 с верно
Третий 50 514 50 339 1,39 с неверно
Четвёртый 50 616 50 530 0,85 с неверно

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

Мы проверили и такой случай: в отдельном контексте около 12 тысяч токенов заменили код в начале документа. Сервер повторно обработал вход и вернул новое значение, а не старое. В этом конкретном случае использованных из кэша токенов было ноль; это правильное поведение, хотя повторный prefill занял около 26 секунд. Одна проверка не гарантирует корректность всех клиентов и всех способов изменения истории.

Эксперимент со SpecPrefill: быстрее первый запрос, но хуже продолжение

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

При сохранении 20% в одном тесте на примерно 100 тысяч исходных токенов мы получили 649 исходных ток/с до первого токена, включая отбор. Это эффективная скорость относительно полного исходного текста, а не скорость, с которой большая модель физически обработала каждый исходный токен. На четырёх простых контрольных фактах ответ совпал с эталоном, но такая проверка не устанавливает общего качества.

На другом наборе с контекстом около 132 тысяч токенов сохранение 30% дало 443 исходных ток/с и 4 полностью правильных ответа из 6; наше старое решение дало 362 ток/с и 3 из 6. Два следующих набора на том же искусственном проекте закончились одинаково для обоих решений: 2 из 4 и 4 из 4. Движки и профили различались, поэтому по этим небольшим выборкам нельзя приписать разницу одному отбору или заявить общую потерю качества в процентах.

Самое интересное обнаружилось на продолжениях. В тестовом oMLX с включённым дисковым кэшем оценщик восстановил 49 152 токена и повторил отбор примерно за секунду. Но основная модель при каждом новом сообщении снова обрабатывала около 15 тысяч выбранных токенов. В беседе с начальным контекстом около 50 тысяч токенов время до второго ответа составило 75,35 с, а у нашего старого профиля — 0,84 с, при повторном использовании более 50 тысяч токенов основного кэша.

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

Мы пробовали ускорить и старый профиль, сохраняя его кэш. Уменьшение глобальной части attention с 8192 до 6144 позиций подняло результат одного запроса примерно с 372 до 384 ток/с, но на одном контрольном вопросе новый вариант ошибся там, где исходный ответил правильно. Другая GPU-операция не дала измеримого выигрыша на полном запросе. В короткой выборке нельзя уверенно установить причину расхождения ответов, но и оснований включать такие изменения мы не получили. 500 ток/с на полном холодном входе в нашем старом профиле пока не подтверждены.

Сравнение с обычным запуском в MTPLX

Мне хотелось понять, что дают доработки движка в сравнении с обычным запуском. Поэтому мы отдельно сравнили нашу сборку с запуском тех же Q4-весов Qwen3.8-27B в MTPLX 2.12.2 на том же M4 Max с 36 ГБ. Для проверки MTPLX использовали профиль stable, обычную авторегрессионную генерацию без MTP и отключённый SSD-кэш сессий. Квантование KV в этом запуске MTPLX было выключено; в нашей сборке использовался Q8 KV, приблизительный prefill и спекулятивное декодирование. Таким образом, сравниваются две рабочие конфигурации, а не одна изолированная настройка.

На одинаковом коротком входе из 3459 токенов с четырьмя вопросами по проекту оба решения вернули правильные итоговые ответы: 4 из 4. Совпал и итоговый JSON с ответами, хотя формулировки ответов различались. На конкретном задании результаты совпали. Но это ещё не доказательство одинакового качества на длинных контекстах или других вопросах.

В отдельном первом запуске MTPLX на этом входе первый токен появился через 29,72 секунды — около 116 входных токенов в секунду, если делить длину входа на время ожидания. У нашей сборки на том же входе первый токен появился через 7,18 секунды, или около 482 входных токенов в секунду по тому же способу расчёта. Эти числа приведены как наблюдения, а не как точная оценка превосходства: лимит ответа и конфигурации в этих двух замерах различались. Кроме того, это расчёт по времени до первого токена, включающий накладные расходы, а не показания одного и того же счётчика prefill. Повторный запуск MTPLX с лимитом ответа 4096 токенов уже использовал кэш, поэтому его время нельзя подставлять в таблицу холодных запросов.

Длинные запросы LongBench v2 на 13 270 и 19 537 токенов в этой конфигурации MTPLX не были выполнены: защита памяти отклонила их до вычисления. Поэтому мы не получили сопоставимых результатов MTPLX на этих длинных заданиях. Это ограничение конкретного запуска с заданным бюджетом памяти, а не утверждение, что MTPLX в принципе не поддерживает такие контексты.

Сколько качества меняет наш prefill?

Чтобы сравнение было прямее, мы проверили два режима одного и того же Kapitsa: основной профиль с приближённым prefill и контроль с полным attention при prefill. Оба использовали одинаковые Q4-веса и Q8 KV-кэш. Это позволяет проверить влияние нашей маски attention, но не отделяет влияние Q4 и Q8 и не является сравнением с моделью в полной точности.

Если таблица не помещается, прокрутите её по горизонтали.

Проверка Полный attention Наш профиль
Шесть выбранных заданий LongBench v2 2 из 6 2 из 6
Четыре вопроса по одному контексту из 50 359 токенов 2 из 4 2 из 4
Холодный вход из 50 359 токенов: время до первого токена 162,89 с 138,34 с
Тот же вход / время до первого токена 309 ток/с 364 ток/с

На шести заданиях ответы двух режимов совпали по каждому вопросу. В проверке на 50 тысячах токенов полный ответ тоже совпал побайтно. В одной этой паре наш профиль сократил время ожидания примерно на 15%, а расчётная скорость по полному входу выросла примерно на 18%. Это один замер: не среднее по большому набору и не обещание такого выигрыша на каждом запросе.

Шесть вопросов LongBench — небольшая неслучайная выборка; для ограничения длины ответа использовалась дополнительная инструкция, поэтому полученный результат не является официальным общим баллом LongBench v2. Совпадение результатов в этой проверке означает лишь, что мы не наблюдали разницы на выбранных заданиях. Оно не доказывает, что приближённый prefill нигде не снижает качество или что потеря укладывается в 1–2%. Поэтому ускоренный профиль стоит проверить на собственных задачах: сравнить его с полным attention и заранее подготовленными ответами.

Как читателю проверить результаты

Прежде чем радоваться числу на графике, проверьте свой рабочий сценарий:

  1. Зафиксируйте модель и квантование, размеры памяти, настройки движка, используемую маску prefill, формат KV-кэша и параметры генерации.
  2. Для холодного запроса сохраните количество входных токенов и время до первого содержательного токена. Делите полный вход на время только при пустом кэше; отдельно отмечайте токенизацию и загрузку модели.
  3. Отправьте несколько продолжений в той же беседе. Запишите cached_tokens, время до ответа и качество; затем измените ранний фрагмент и проверьте, что модель не использует устаревшее значение.
  4. Для поиска фактов заранее подготовьте разные случайные значения в разных местах текста и сравнивайте каждый ответ с собственной таблицей. Повторите тест на разных документах и длинах.
  5. Для внешней проверки используйте инструкции RULER и датасет и методику LongBench v2. Укажите число реально выполненных задач, выборку, шаблон и лимит ответа. Небольшую выборку не называйте полным результатом бенчмарка.

HumanEval в этой серии мы не запускали, поэтому его результата у нас нет. Минимальный архив установки не содержит датасет LongBench размером около 443 МиБ или полные результаты бенчмарков; их нужно скачать и выполнить отдельно по инструкциям авторов.

Как повторить установку

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

Для настройки нужна отдельная папка на Mac, Python 3.10 или новее, Xcode Command Line Tools, интернет и свободное место на SSD. Практический ориентир — 30–40 ГБ под модели, сборку и временные файлы. Исходный эксперимент проводился на M4 Max с 36 ГБ; на другой конфигурации размер окна, бюджет памяти и скорость могут отличаться.

После распаковки откройте терминал в папке набора. Команды ниже создают отдельное Python-окружение, собирают нужную версию Kapitsa и скачивают веса:

python3 -m venv .venv
.venv/bin/python -m pip install 'cmake>=3.24,<5' 'huggingface_hub>=0.34,<2'
git clone --no-checkout --filter=blob:none https://github.com/nace-ai/kapitsa.git upstream
git -C upstream checkout --detach 6bcac82bed6986c1f1b0227c0234aa42e93c895b
git -C upstream apply --check "$PWD/source.patch"
git -C upstream apply "$PWD/source.patch"
.venv/bin/cmake -S upstream -B build -DCMAKE_BUILD_TYPE=Release
.venv/bin/cmake --build build --target kapitsa --parallel 2
cp build/kapitsa runtime/kapitsa
.venv/bin/python download_models.py
.venv/bin/python run.py --dry-run

Если нужные веса уже загружены через MTPLX, вместо скачивания второй копии целевой модели используйте путь к своей папке:

.venv/bin/python download_models.py --model-dir "$HOME/.mtplx/models/Youssofal--Qwen3.8-27B-MTPLX-Bare-Speed"

Скрипт проверит контрольные суммы трёх основных файлов модели и токенизатора и скачает отдельный DFlash2. Если сухая проверка показывает ready: true, можно запускать сервер. Перед запуском: launcher автоматически останавливает проверенный простаивающий MTPLX на порту 8000 и сообщает об этом. При выходе он пытается восстановить MTPLX, но после аварийного завершения восстановление не гарантировано. Сохраните текущую работу и убедитесь, что такое поведение вам подходит:

.venv/bin/python run.py

Оставьте этот терминал открытым. Монитор появится по адресу http://127.0.0.1:8010/monitor, локальный OpenAI-compatible API — http://127.0.0.1:8008/v1. Для идентификатора модели откройте http://127.0.0.1:8008/v1/models. Остановка — Ctrl+C в терминале запуска; кнопка в мониторе перезагружает модель и сбрасывает её кэш.

Профиль в наборе по умолчанию задаёт окно 262 144 токена суммарно на вход и ответ, бюджет памяти 30 ГБ, Q4 для основной и черновой моделей, Q8 KV и описанное приближённое внимание. Это параметры эксперимента, а не утверждение, что на любом Mac все 262k будут помещаться и давать хорошее качество. Перед запуском убедитесь, что порты свободны: если обнаружен определённый простаивающий MTPLX на порту 8000, launcher может временно остановить его и попытаться восстановить при выходе.

Для собственного холодного замера подготовьте UTF-8 файл и выполните:

.venv/bin/python measure.py --file /путь/к/контексту.txt --fresh --max-tokens 512 --show-answer

Скрипт обращается к локальному серверу и выводит фактические токены, кэш, prefill, примерную скорость генерации по потоку и хеш файла. Количество символов не равно количеству токенов — это разные счётчики. Для проверки кэша повторяйте историю в клиенте без --fresh; для проверки интеллекта сравнивайте ответы с заранее подготовленными правильными результатами. Не публикуйте ответы, содержащие частные данные вашего проекта.

Для дополнительного контроля можно остановить свой сервер, сохранить копию config.json, установить в нём approximation.enabled: false и повторить те же запросы после запуска. Так вы отключите экспериментальную маску prefill; Q4-веса и Q8 KV останутся, поэтому это сравнение не является эталоном полностью неквантованной модели. Полный prefill может потребовать больше времени и ресурсов. После проверки верните исходный конфиг.

По умолчанию сервер и монитор слушают только localhost. Доступ с другого устройства требует отдельной настройки доверенной домашней сети и ключа. Шлюз использует HTTP без шифрования; открывать его в Интернет или публиковать ключ не нужно.

Если что-то пошло не так

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

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

Клиент отменяет большой запрос. Увеличьте его собственный timeout ожидания потока или ответа. Например, при средней скорости около 355 токенов в секунду один prefill на 128 × 1024 токенах уже превышает пять минут. Само по себе изменение серверного timeout клиентское ограничение не исправляет.

Ответ пустой при маленьком лимите. Режим рассуждений может израсходовать доступные токены до появления обычного текста. Увеличьте лимит ответа либо для короткой проверки явно отключите рассуждения, если клиент поддерживает chat_template_kwargs: {"enable_thinking": false}. В прилагаемом measure.py короткий тест использует этот параметр.

Монитор не открылся. Проверьте, готов ли локальный сервер и свободен ли порт 8010. Прямой API использует порт 8008. Если порт занят, сначала определите приложение-владельца: бездумное завершение чужого процесса может прервать работу.

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

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

Промпт для настройки с ИИ-помощником

Скопируйте текст ниже и приложите к чату архив qwen27b-minimal.zip из этой статьи. Помощнику нужны доступ к терминалу Mac, Интернету и разрешение изменять файлы в отдельной папке настройки. Если инструмент видит только текст чата, он сможет лишь подготовить команды.

Актуальный текст также можно скачать отдельным файлом ИИ-промпта. В минимальный архив промпт не включён — скачайте его отдельно или скопируйте со страницы.

Ты помогаешь настроить локальную Qwen3.8-27B на моём Mac. У меня есть архив
qwen27b-minimal.zip и статья с описанием эксперимента. Выполни настройку,
не ограничиваясь советами. Сначала прочитай README.md и конфигурацию из архива.

Архив содержит патч, скрипты и локальный монитор; весов и готового бинарника
в нём нет, их нужно скачать и собрать отдельно. После распаковки проверены
контрольные суммы и сухой запуск без модели; полноценная установка с нуля и
длинный тест именно этого минимального архива пока не подтверждены. Сначала
проверь SHA256SUMS.txt, затем отдельно зафиксируй результаты своих проверок.
По умолчанию API и монитор доступны только на этом Mac. Скрипт run.py может
временно остановить простаивающий MTPLX на порту 8000 после проверок и затем
попытаться восстановить его; сообщи мне об этом заранее и не останавливай
занятые или неподтверждённые процессы.

Цель: воспроизвести описанную сборку Kapitsa и протестировать её на моём Mac.
Исходный эксперимент сделан на M4 Max с 36 ГБ RAM. Зафиксируй мой чип, RAM,
macOS, доступное место на диске и установленные инструменты. Если компьютер
существенно отличается, не обещай ту же скорость и предложи подходящее окно и
лимит памяти, объяснив отличия. Если данных достаточно, решения принимай сам.

Собери движок из конкретного коммита Kapitsa и source.patch из архива. Скачай
закреплённые Qwen3.8-27B-MTPLX-Bare-Speed Q4 и incoai/Qwen3.8-27B-DFlash2
скриптом download_models.py; если совместимая модель уже есть на диске,
используй --model-dir и сначала проверь хеши. Веса скачиваются отдельно;
не заменяй модель или патч другой версией без объяснения. Пакет допускает
использование собственных уже установленных весов без их перезаписи.

Выполни сухую проверку, запусти сервер и подключи локальный OpenAI-совместимый
клиент. Перед остановкой или перезапуском любого работающего сервера сообщи мне
заранее; не завершай чужие или занятые процессы. Если порт занят, выясни кем и
остановись, если нельзя безопасно использовать требуемые порты. Данные, проекты
и настройки существующих приложений не удаляй. Не печатай и не передавай API-ключи,
содержимое моих файлов или журналов третьим лицам. Для замеров файлов моего
проекта обрабатывай их локально и не меняй их.

Проверь короткий запрос, монитор, а затем сделай холодный и повторный замеры
на контекстах подходящего размера. Для каждого сообщи реальные входные токены,
сколько взято из кэша, сколько пересчитано, время prefill и генерации. Не
оценивай скорость генерации по ответу из 1–2 токенов. Сравни одинаковые входы
и параметры, отличай нативный ток/с от приблизительного значения в окне.
Проверь работу с несколькими ходами, вызовами инструментов и отменой. Если
клиент меняет начало истории, объясни неизбежный пересчёт.

Используй профиль статьи как экспериментальный: Q4-веса, Q8 KV-кэш,
приближённый prefill и DFlash2. Все токены сохраняются, но ограниченная маска
attention меняет вычисления; плотный decode не делает этот prefill точным.
У прежнего эксперимента есть длинный тест с ошибкой и нет доказанной границы
потери качества 1–2%. Не объявляй 255/30 ток/с гарантией. Сравни качество с
подходящим контрольным профилем на моих проверочных задачах, сохрани ошибки и
результаты отдельно; не называй совпадение на паре задач общей гарантией.

Проверь поиск нескольких случайных фактов на разных глубинах и нескольких
длинах контекста; укажи, как измерены глубины и сколько было отдельных запросов.
При желании проверь RULER и LongBench v2 по инструкциям их авторов: записывай
выборку, шаблон, лимит ответа, метод оценки и результаты каждого задания. Не
выдавай частичную или адаптированную проверку за полный официальный результат.
Не запускай сгенерированный код без подходящей изоляции и ограничения ресурсов.

Для кэша отдельно проверь холодный запрос, продолжение, добавление новых данных
и изменение ранней части контекста. Фиксируй время до первого токена и объём
совпавшего кэша; проверь, что после изменения модель не выдаёт старое значение.
Если экспериментируешь со SpecPrefill, отдельно измеряй время отбора и повторное
использование кэша основной модели. Не называй отобранные фрагменты полным KV.

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

Источники и материалы

  • Kapitsa: исходники и описание движка, базовый коммит эксперимента 6bcac82bed6986c1f1b0227c0234aa42e93c895b.
  • Qwen3.8-27B-MTPLX-Bare-Speed, ревизия b59d7002368575f08a58ba0d26686b53a9c162d6.
  • Qwen3.8-27B-DFlash2, ревизия 015e795645c74b1a0eeef3b570031fb62e769bc5.
  • Документация MTPLX — если веса уже установлены через это приложение.
  • NVIDIA RULER — генератор и методика задач на длинный контекст.
  • LongBench v2 и набор данных — вопросы по длинным документам и кодовым базам.
  • Минимальный архив включает SHA256SUMS.txt для проверки собственных файлов. Исходные запросы, результаты бенчмарков, данные моего проекта и веса моделей в него не включены.

Патч и вспомогательные файлы распространяются вместе с лицензией и уведомлениями из набора. Лицензии моделей проверяйте отдельно на страницах их авторов.

Скачать материалы эксперимента

Актуальный ИИ-промптai-prompt.md · Markdown (.md) Минимальный набор для воспроизведенияqwen27b-minimal.zip · Архив (.zip)