Что именно показал запуск M5 Ultra 96 GB: короткий ответ
На базовом Mac с чипом M5 Ultra (96 ГБ Unified Memory, 64-ядерный GPU) запустили Qwen 3.8 FN в смешанном квантовании: 4 бита для части слоёв, 8 бит для остальных, плюс MTP. Сервером выступила кастомная сборка mlx-serve с continuous batching, рассчитанная на 4 параллельных потока.
Под 4-поточной нагрузкой агрегированный prefill держался около 3,2k tok/s, декодирование шло на уровне примерно 170 tok/s. Медиана на поток: 828,2 tok/s на prefill и 42,7 tok/s на decode. За сессию прошло 112 млн токенов, из которых 3 млн сгенерировано, а 109 млн это prompt fills. Кэш промптов дал 97 млн попаданий, то есть 89%.
Контекст выставили на 4 x 128k (512k суммарно) с 8-битным KV-кэшем и примерно 90 ГБ RAM, закоммиченными под VRAM. Оркестратор на ПК вызвал сабагента на Mac около 1 700 раз, медианная глубина контекста на запрос составила 64,4k токенов, около 200 тяжёлых запросов превысили 100k.
Это отчёт одного пользователя на одной задаче разработки, а не контролируемый бенчмарк. Автор отдельно предупредил, что часть цифр и деталей кастомного сервера подготовлены с помощью AI, а нестабильность отдельных потоков сабагентов ему приходилось разбирать по ходу. Полная публикация с таблицами распределения по потокам опубликована в r/LocalLLaMA.
Ключевые цифры одним взглядом
- Агрегированный prefill при 4 потоках: около 3 200 - 3 313 tok/s.
- Агрегированный decode: около 170,8 tok/s.
- Медиана prefill на поток: 828,2 tok/s (среднее 917,6, p10 530,5, p90 1 374,9).
- Медиана decode на поток: 42,7 tok/s (среднее 48,9, p10 34,2, p90 71,5).
- Максимум на одном потоке: 3 328 tok/s prefill и 152 tok/s decode.
- Токенов за сессию: 112 млн, из них 109 млн prompt fills и 3 млн сгенерировано.
- Попаданий в кэш промптов: 97 млн, что даёт 89% hit rate.
- Вызовов сабагента от оркестратора: около 1 700.
- Медианная глубина контекста: 64,4k токенов, около 200 запросов тяжелее 100k.
Все значения получены в одной сессии на одном стенде, независимого воспроизведения нет.
Конфигурация стенда: M5 Ultra, Qwen 3.8 FN и mlx-serve
Железо: базовый M5 Ultra, 96 ГБ памяти, 64-ядерный GPU. Модель: Qwen 3.8 FN в смешанном 4-бит/8-битном квантовании с MTP. Контекст: 4 x 128k, суммарно 512k, 8-битный KV-кэш, около 90 ГБ RAM закоммичено под VRAM. Сервер: кастомная сборка mlx-serve с continuous batching и 4-поточной конкурентностью.
Публичной эту сборку назвать нельзя. Идеи автор нашёл в strix halo lab, портировал их сначала на CUDA для своего ПК, а затем на MLX-serve для flash next. Собирал он её с помощью AI и прямо пишет, что не понимает до конца, как всё работает внутри, хотя логика кажется ему разумной.
Нагрузка тоже не похожа на синтетику: это разработка по одному из проектов автора, где планирование, red teaming, верификацию, тесты и коммиты выполняли параллельные воркеры flash next. Проверял и пробовал бота он удалённо с мобильного через Hermes, пока находился в офисе. Такой профиль объясняет, почему в цифрах доминируют длинные промпты и малое число сгенерированных токенов.
Почему 4 x 128k и 8-битный KV-кэш - важная часть сетапа
4 x 128k нужны не ради красивого числа в конфиге. Четыре потока, каждый со своим длинным промптом, требуют держать в KV-кэше до 512k токенов одновременно. 8-битный KV-кэш снижает объём по сравнению с FP16, но даже с ним под VRAM ушло около 90 ГБ RAM.
Медианная глубина контекста 64,4k и примерно 200 запросов свыше 100k объясняют, откуда берётся такой запас. Если памяти меньше, первым делом придётся уменьшать число параллельных потоков или максимальную длину контекста, и агентский сценарий начнёт упираться в отказы по длине промпта или в пересчёт контекста заново.
Что такое MTP и как он влияет на decode
MTP (multi-token prediction) заставляет модель за один шаг предсказывать несколько токенов вместо одного. Работает это на этапе decode, то есть на генерации ответа, где обычная схема вынуждена выдавать токены строго последовательно. Чем больше токенов принимается за шаг, тем выше итоговая скорость генерации при той же пропускной способности памяти.
В этом отчёте нет замеров «без MTP», поэтому конкретный вклад механизма именно здесь неизвестен. Для ориентира: в разборе openPangu-2.0-Flash MTP ускоряет генерацию примерно в 1,5-2 раза, но это данные другой модели и другого стека, переносить их один в один нельзя.
Prefill, decode и агрегация: как читать цифры 3,2k tok/s и 170 tok/s
Prefill это обработка промпта, decode это генерация ответа. Первое хорошо параллелится по токенам промпта, второе идёт шаг за шагом, и здесь параллелизм упирается в пропускную способность памяти. Разница между prefill и decode подробно разобрана на примере Qwen3.8-Next на M5 Air: без её учёта любые замеры tok/s читаются неверно.
Агрегированный prefill около 3 200 tok/s на четырёх потоках почти совпадает с медианой 828,2 tok/s на поток, умноженной на четыре (3 313). Масштабирование близко к линейному: каждый поток получает свою долю и не мешает остальным.
С decode картина другая. Агрегат 170,8 tok/s совпадает с 4 x 42,7 tok/s, то есть каждый поток остаётся на своей медиане, а суммарная скорость растёт только за счёт числа потоков. Максимум на одном потоке, 152 tok/s, почти дотягивает до агрегата всех четырёх. Это намекает на упор в общую пропускную способность памяти, а не в свободные слоты конкурентности, но замеров загрузки GPU в источнике нет, так что перед нами трактовка цифр, а не измеренный факт.
Почему prefill масштабируется почти линейно, а decode - нет
Prefill обрабатывает весь промпт сразу: 64,4k токенов медианы раскладываются на матричные операции, которые GPU загружают плотно. Четыре таких потока занимают разные вычислительные блоки и дают почти четырёхкратный прирост.
Decode на каждом шаге генерирует по одному токену на поток и читает веса модели заново. Здесь потоки конкурируют за одну и ту же память, поэтому агрегат не выходит далеко за пределы одного быстрого потока. Схожий эффект виден и на других рантаймах: в сравнении GLM-5.3-Flash на TensorSharp и llama.cpp разрыв возникает именно на decode, а на prefill результаты почти сходятся.
Что означают медиана 828 tok/s и максимум 3 328 tok/s на поток
Медиана описывает типичный запрос, максимум показывает лучший случай. Разрыв почти в четыре раза говорит о неоднородной нагрузке: короткие промпты и попадания в кэш дают высокие значения, длинные и холодные промпты требуют больше работы.
Разброс подтверждают перцентили. На prefill p10 равен 530,5 tok/s, а p90 равен 1 374,9 tok/s. На decode p10 равен 34,2, p90 равен 71,5 tok/s. Для планирования агентского пайплайна ориентироваться стоит на медиану или на p10, а не на пиковые значения из таблицы.
112 млн токенов за сессию: что это говорит об агентской нагрузке
Соотношение 109 млн prompt fills к 3 млн сгенерированных токенов это примерно 36:1. Типичная картина для агентской работы: модель много читает контекст, файлы, логи и результаты предыдущих шагов, а пишет относительно немного. Нагрузка на prefill оказывается на порядок важнее скорости генерации.
Оркестратор на ПК (qwen 27b) вызвал сабагента на Mac около 1 700 раз за сессию. Медианная глубина контекста на запрос составила 64,4k токенов, около 200 тяжёлых запросов превысили 100k. Эти два числа важнее любой строчки с tok/s: они показывают, что система работала в режиме частых вызовов с длинными промптами, а не в режиме генерации больших текстов. Исходные данные сессии приведены в отчёте автора.
89% cache hit: почему это важнее пиковых tok/s
97 млн из 109 млн prompt fills пришли из кэша. Это значит, что большинство промптов не пересчитывались с нуля, а переиспользовали уже обработанные префиксы. Для агентского цикла, где каждый шаг дописывает к промпту небольшой фрагмент, такой hit rate снимает основную часть нагрузки с prefill.
Без кэша большая часть из 109 млн токенов шла бы через полный prefill, и 3,2k tok/s перестали бы выглядеть достаточными. Как именно устроен кэш промптов внутри mlx-serve, в источнике не описано, поэтому конкретные механизмы переиспользования и вытеснения остаются неизвестными.
Медиана 64,4k и запросы >100k: что это значит для памяти
При медианной глубине 64,4k токенов на запрос и пиках свыше 100k, да ещё на четырёх параллельных потоках, запас по KV-кэшу перестаёт быть избыточным. Отсюда и 8-битный KV-кэш, и около 90 ГБ RAM под VRAM, и конфигурация 4 x 128k.
Если у вас меньше памяти, порядок действий предсказуем: сначала снижается число параллельных потоков, затем максимальная длина контекста. Оба шага напрямую бьют именно по агентским сценариям с длинными промптами.
Что ускоряли в кастомной сборке mlx-serve
Четыре доработки из отчёта объясняют, откуда взялись цифры prefill и decode. Две из них касаются рекуррентного состояния и нормализации, две работают с разреженностью MoE. Важная оговорка: это детали конкретной кастомной сборки, подготовленные с помощью AI, и в публичном mlx-serve их может не быть.
Fused 4-Stream HyperConnection + RMSNorm объединяет смешивание четырёх параллельных residual-потоков модели и последующую Gated RMSNorm в один проход Metal threadgroup. Вместо двух проходов по памяти получается один.
Tiled GDN Recurrence: зачем держать состояние в регистрах
Рекуррентная матрица состояния 128 x 128 должна обновляться на каждом шаге генерации. Если писать её обратно в системную память после каждого шага, обмен с RAM начинает тормозить весь процесс, особенно на Apple Silicon, где Unified Memory делится между CPU и GPU.
Tiled Gated Delta-Net (GDN) Recurrence удерживает эту матрицу прямо в регистрах GPU на чанках по 16 токенов. Состояние не покидает быструю память до конца чанка, и обмен с системной памятью происходит заметно реже.
Sparse MoE Compaction: 98,3% padding-плиток в мусор
MoE-модель активирует лишь часть экспертов, но при пакетной обработке токенов образуются плитки, заполненные нулями. В этой сборке отбрасывается 98,3% таких незаполненных padding-плиток, а активные токены динамически упаковываются в плотные матричные операции через mx.gather_mm с последующим однопроходным fused scatter-reduction.
Эффект сильнее всего проявляется на prefill, где батч большой и доля пустых плиток растёт. Это один из факторов, почему агрегированный prefill дотянулся до 3,2k tok/s при четырёх потоках, хотя без замеров «до и после» вклад каждой доработки по отдельности неизвестен.
Temporal Expert Dequantization Cache: 960 МБ под топ-64 эксперта
При генерации текста маршрутизация экспертов повторяется: одни и те же эксперты выбираются снова и снова. Кэш Temporal Expert Dequantization держит топ-64 часто выбираемых экспертов в FP16-кэше Unified Memory объёмом около 960 МБ. Повторная деквантизация при этом не выполняется.
Это работает скорее на decode, где каждый шаг заново обращается к весам. Кэш такого размера дёшев на фоне 90 ГБ, занятых под VRAM, и объясняет, почему медиана decode на поток держится на 42,7 tok/s при смешанном 4-бит/8-битном квантовании. Описания всех четырёх доработок даны в том же отчёте.
Ограничения и риски: что важно знать до того, как повторять
Главное ограничение сформулировал сам автор: часть цифр и деталей кастомного сервера подготовлены с помощью AI. Дальше по значимости идут нестабильность части потоков сабагентов, отсутствие публичной сборки и то, что все данные получены в одной сессии на одной задаче.
AI-assisted цифры: как это читать
Пометка «AI assisted» не означает, что числа выдуманы. Она означает, что проверить их независимо нельзя: нет ни скриптов бенчмарка, ни повторных прогонов, ни второго стенда. Воспринимать такие значения стоит как отчёт одного пользователя, полезный для оценки порядка величин и для понимания профиля нагрузки.
Из этого следует практический вывод. Строить на этих числах аргументы вида «платформа X быстрее платформы Y» нельзя, а вот использовать их как ориентир при планировании собственного агентского пайплайна можно, если держать в голове погрешность.
Нестабильность потоков сабагентов и роль оркестратора
Автор зафиксировал, что некоторые потоки сабагентов «уходили не туда», и исправляла это оркестрирующая модель qwen 27b. Разбор проблемы он отложил на потом. Это указывает на то, что агентский пайплайн с четырьмя параллельными воркерами требует внешнего контроля и не работает автономно.
Частоту сбоев, их причины и логи в источнике не приводят. Оценивать надёжность схемы по одному упоминанию нельзя, но и игнорировать сигнал не стоит: четыре параллельных потока плюс длинный контекст это ещё и дополнительные точки отказа.
Отдельно про железо: все замеры относятся к базовой конфигурации M5 Ultra с 64-ядерным GPU. Более дорогая версия линейки в этом отчёте не участвовала, а сроки её поставок автор описывает как предположительные. Переносить цифры на другие конфигурации чипа без проверки не получится.
Как применить этот кейс на своём железе
Отправная точка для повторения: Mac с большим объёмом Unified Memory, 8-битный KV-кэш, запас под контекст 4 x 128k и сервер с continuous batching. Публичный mlx-serve подойдёт как база, но часть доработок из отчёта в нём может отсутствовать, а собирать кастомную версию автору помогал AI, причём сам он не до конца понимает её внутреннее устройство.
Минимальные требования, если ориентироваться на этот кейс
В кейсе 96 ГБ памяти, около 90 ГБ закоммичено под VRAM, 8-битный KV-кэш и 4 x 128k контекста. Точных порогов «сколько хватит» источник не даёт, поэтому честный ориентир такой: чем меньше памяти, тем меньше параллельных потоков и короче контекст.
Полезно сравнить с противоположным концом спектра. Запуск Qwen3.8-Flash-Next в квантовании IQ3_XXS на 12 ГБ VRAM даёт 14-15 токенов/с и контекст 128K. Это рабочий вариант, но агентский цикл на 1 700 вызовов с медианой 64,4k он не выдержит: другой класс задач и другой класс железа.
Когда стоит смотреть в сторону других стеков
Если нужна максимальная совместимость с CUDA-экосистемой или готовые публичные сборки vLLM и llama.cpp, этот кейс служит ориентиром, а не рецептом. Поддерживать кастомный сервер придётся самому, вместе с риском, что обновление модели или фреймворка сломает доработки.
На стороне CUDA тоже есть отчёты с оговорками, которые стоит учитывать. Замеры DeepSeek V4.1 Flash на восьми NVIDIA A40 показывают 40,3-40,7 tok/s в Q2_K и 31-32,5 tok/s в Q4_K_M, и там действуют свои ограничения по выводам. Путь автора отчёта не односторонний: идеи из strix halo lab он сначала портировал на CUDA, потом на MLX-serve для flash next.
Что в итоге: кому подходит такая конфигурация
Конфигурация M5 Ultra 96 GB плюс Qwen 3.8 FN в смешанном квантовании плюс кастомный mlx-serve показала агрегированный prefill около 3,2k tok/s и decode около 170 tok/s при четырёх потоках. За сессию прошло 112 млн токенов, 89% из них попали в кэш промптов, медианная глубина контекста составила 64,4k токенов. Это профиль агентского пайплайна с длинным контекстом и частыми вызовами, а не стенда для массовой генерации текста.
Кому подходит такой сетап
- Владельцам Mac с большим объёмом Unified Memory, готовым выставить 8-битный KV-кэш и закоммитить большую часть памяти под VRAM.
- Разработчикам агентских систем, где модель чаще читает, чем пишет, и где важен стабильный prefill и высокий cache hit.
- Тем, кто готов возиться с кастомными сборками и портировать идеи между CUDA и MLX.
Для этой группы решающими оказываются кэш промптов и предсказуемая медиана, а не пиковые 3 328 tok/s.
Кому этот кейс не подойдёт
- Тем, кто ищет решение «из коробки» без сборки сервера из исходников и ручных доработок.
- Тем, кто работает преимущественно в CUDA-стеке и не планирует переносить код на MLX.
- Тем, кому нужна массовая генерация текста, а не агентские циклы с контекстом по 64k и выше.
- Тем, кому важна независимо проверенная методика: здесь цифры пришли от одного пользователя и частично подготовлены с помощью AI.
Если ваш сценарий совпадает с описанным, начните с проверки объёма Unified Memory и профиля промптов: длинные повторяющиеся префиксы дадут основной выигрыш от кэша. Если нет, смотрите на публичные рантаймы и на железе с меньшим объёмом памяти, там свои компромиссы, но и порог входа ниже.