Перейти к содержанию
Публикация AiManual

Qwen 27B на AMD RX 7900 XTX: 40 токенов/с, контекст 240K и агентный кодинг через llama.cpp

Разбираем реальную конфигурацию запуска Qwen 27B в Q4_K_M на AMD RX 7900 XTX через llama.cpp и Vulkan: параметры llama-server, 40 токенов/с декодирования, префи

Коротко

Что будет в материале

  1. 01

    Что именно удалось запустить: конфигурация и результаты

  2. 02

    Почему Vulkan, а не ROCm: выбор бэкенда для AMD

  3. 03

    Параметры запуска llama-server: разбор конфигурации

  4. 04

    Контекст 240K: как это работает и чего стоит

Qwen 27B в квантизации Q4_K_M запущена на одной AMD RX 7900 XTX через llama.cpp с бэкендом Vulkan. Автор сборки сообщает о скорости декодирования около 40 токенов/с и префилле порядка 900 токенов/с при контексте 240128 токенов. Этого хватило, чтобы ставить модели агентные задачи по кодингу и возвращаться за готовым результатом, а не сидеть над чатом.

Источник цифр - пост в r/LocalLLaMA. Это личный отчёт, а не независимый бенчмарк: значения округлены самим автором (в тексте он пишет «40ish» и «900ish»), а замеры сняты на живой задаче глубокого кодинга, не в синтетическом тесте. Ниже разобрана сама конфигурация: железо, параметры llama-server, работа с длинным контекстом и слабые места схемы.

Что именно удалось запустить: конфигурация и результаты

Работа идёт не через десктопный чат-клиент, а через сервер. llama-server слушает 0.0.0.0:8081, модель целиком лежит на GPU, vision-часть вынесена на отдельную карту, а клиент живёт на другом устройстве в сети.

Железо и софт: что понадобилось

КомпонентРоль в сборке
Intel 9700CPU, на него приходятся потоки обработки батчей
32 ГБ DDR2400Системная память, включая кэш промптов и сохранённые слоты
AMD RX 7900 XTXОсновная GPU: все слои модели, устройство Vulkan0
NVIDIA RTX 2060Vision-проектор и второй экземпляр сервера, устройство Vulkan1
БП 850 ВтПитание обеих карт и платформы
UbuntuОС, под которой работает llama.cpp
Hermes на Raspberry PiКлиент: постановка задач и получение результатов

Платформа выглядит скромно для локального инференса: старый четырёхъядерный Intel 9700 и 32 ГБ памяти DDR2400. Вся вычислительная нагрузка ложится на видеокарту, а CPU обслуживает подготовку батчей. Память здесь не запасной ресурс: слоты сохраняются в /dev/shm, а это тот же системный RAM, поэтому 32 ГБ стоит держать в голове при планировании параллельных запросов.

Файл модели в сообщении назван так: Qwen3.8-27B-TurboFCFusion-735-882-Here-Uncen-NEO-CODER-MAX-MTP-Q4_K_M.gguf. Суффикс MTP в имени совпадает с включённым режимом спекулятивного декодирования --spec-type draft-mtp. Точная версия модели за пределами имени файла не раскрыта, поэтому переносить конфигурацию на другой чекпойнт нужно с поправкой на это.

Замеры: 40 токенов/с декодирования и 900 токенов/с префилла

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

При 240K контекста именно префилл становится узким местом. Простая арифметика: чтобы заполнить 240 128 токенов на скорости около 900 токенов/с, нужно примерно 4,5 минуты только на чтение промпта. На практике KV-кэш почти никогда не строится с нуля, если включено переиспользование, но первый запрос с большим контекстом всё равно требует времени.

Скорость декодирования 40 токенов/с для 27B-модели в 4-битной квантизации на потребительской AMD-карте - рабочий уровень для агентных сценариев, где модель вызывает инструменты, читает файлы и правит код. Отчёт про 40 токенов/с получен на живой задаче глубокого кодинга, что важнее синтетического замера: в реальном агенте генерация чередуется с длинными промптами и паузами на выполнение инструментов.

Почему Vulkan, а не ROCm: выбор бэкенда для AMD

llama.cpp умеет работать с GPU через несколько бэкендов: CUDA, HIP/ROCm, Metal, Vulkan. ROCm - нативный вычислительный стек AMD, Vulkan - кросс-платформенный графический API, который llama.cpp использует и для вычислений. Оба варианта дают доступ к видеокарте, но по-разному ведут себя в зависимости от модели GPU, версии драйвера и дистрибутива.

В описанной сборке выбран Vulkan, и это не означает, что Vulkan быстрее ROCm. В исходном сообщении нет ни слова о сравнении бэкендов, поэтому делать вывод о превосходстве одного над другим не из чего. Практический смысл выбора в другом: Vulkan не требует установки ROCm-стека и его зависимостей, а на Ubuntu такой запуск проще поднять.

Vulkan и ROCm: что выбрать на практике

Бэкенд определяет, какие параметры вообще доступны и как стабильно ведёт себя сервер под нагрузкой. Стратегия проверки простая: собрать llama.cpp с нужным бэкендом, прогнать короткий промпт и длинный контекст, посмотреть на потребление VRAM и отсутствие ошибок в логе. Если на вашей карте и версии драйвера один вариант даёт сбои, второй стоит проверить, не меняя остальные параметры.

Для владельцев нескольких карт Radeon отдельный вопрос - как они видны системе и как распределяется память. Разбор двух 7900 XT/XTX на платах X570/X870, PCIe-линий и питания есть в материале про сборку на двух Radeon 7900 XT/XTX.

Параметры запуска llama-server: разбор конфигурации

Ниже команда, восстановленная из параметров, перечисленных автором. Путь к файлу модели подставьте свой.

llama-server -m /path/to/Qwen3.8-27B-...-MTP-Q4_K_M.gguf \
  --device Vulkan0,Vulkan1 --split-mode layer --tensor-split 1,0 \
  --n-gpu-layers 99 --flash-attn on \
  --cache-type-k iq4_nl --cache-type-v iq4_nl \
  --cache-ram 5631 --cache-reuse 256 \
  -c 240128 --batch-size 2048 --ubatch-size 512 \
  --threads 6 --threads-batch 6 --n-predict 32000 --cont-batching \
  --spec-type draft-mtp --spec-draft-n-max 2 --spec-draft-p-min 0 \
  --reasoning on --reasoning-format deepseek --reasoning-budget -1 --reasoning-preserve \
  --jinja --chat-template-file /dev/shm/llama_qwen38/qwen3.8-safe-v2.jinja \
  --chat-template-kwargs '{"reasoning_effort":"xhigh","preserve_thinking":true,"max_tool_response_chars":9000}' \
  --mmproj /home/admin/models/mmproj-F16.gguf --image-min-tokens 1024 --mmproj-device Vulkan1 \
  --slot-save-path /dev/shm/llama_qwen38/slots \
  --log-file /dev/shm/llama_qwen38/telemetry/engine_debug.log \
  --metrics --no-warmup --host 0.0.0.0 --port 8081

Сплит слоёв и tensor-split: как распределяется нагрузка

Пара --device Vulkan0,Vulkan1 перечисляет устройства, а --split-mode layer говорит llama.cpp раскладывать слои модели по ним. Пропорция задаётся через --tensor-split 1,0: единица достаётся первой карте, ноль второй. Вместе с --n-gpu-layers 99 это значит, что все слои уходят на Vulkan0, то есть на RX 7900 XTX, а RTX 2060 в инференсе основной модели не участвует.

Решение выглядит осознанным. Как только слои делятся между картами, активации начинают ходить по шине между устройствами на каждом токене, и выигрыш от второй карты легко съедается накладными расходами на передачу. Здесь вторая карта отдана под задачи, которые не мешают основному потоку: vision-проектор и второй экземпляр сервера.

Flash-attention и квантование KV-кэша

--flash-attn on включает оптимизированное внимание. Оно снижает расход памяти на промежуточные матрицы внимания и помогает на длинном контексте, где стандартный путь требует заметно больше VRAM.

Ключевые для 240K контекста параметры - --cache-type-k iq4_nl и --cache-type-v iq4_nl. KV-кэш хранит ключи и значения для всех обработанных токенов, и его объём растёт линейно с длиной контекста и числом слоёв. Квантизация кэша до 4 бит сокращает эту статью расходов, иначе длинный контекст просто не поместился бы в память карты вместе с весами модели. Точный объём сэкономленной памяти в сообщении не приводится, поэтому конкретные гигабайты лучше измерять самому.

Значения --cache-ram 5631 и --cache-reuse 256 относятся к переиспользованию уже обработанного контекста: llama.cpp может подхватить совпадающий префикс промпта вместо повторной обработки. В исходном отчёте детали этого механизма не раскрыты, но логика та же, что и в других сборках на llama.cpp: повторные запросы с общим началом промпта обрабатываются быстрее. Практический пример такой конфигурации с разбором speculative decoding и KV-кэша есть в гайде по локальному стеку для Qwen 3.8 27B на Debian.

Батчи, потоки и предсказание

--batch-size 2048 и --ubatch-size 512 задают логический и физический размер батча при обработке промпта. Логический батч определяет, сколько токенов обрабатывается за проход на уровне планировщика, физический - сколько помещается в одну вычислительную итерацию. Физический батч можно уменьшить, если не хватает VRAM, ценой скорости префилла.

--threads 6 и --threads-batch 6 - число потоков CPU на генерацию и на обработку батчей. Шесть потоков для Intel 9700 выглядят разумно: больше потоков не всегда быстрее, а лишние переключения контекста съедают прирост. --n-predict 32000 ограничивает длину генерации в одном запросе, что для агентных прогонов скорее страховка от бесконечной петли, чем ограничение по существу.

--cont-batching включает непрерывный батчинг: сервер может подмешивать новые запросы в текущий проход, не дожидаясь полного завершения предыдущего. --metrics открывает эндпоинт с метриками, --no-warmup пропускает прогрев модели при старте, что экономит время запуска, но первый реальный запрос будет чуть медленнее.

Контекст 240K: как это работает и чего стоит

Контекст задан параметром -c 240128, то есть около 240 тысяч токенов. Это настройка окна, а не гарантия, что модель одинаково качественно работает на всей длине: в отчёте нет тестов качества на заполненном до предела контексте. Для агентных задач такой запас полезен, потому что в промпт попадают системные инструкции, описания инструментов, история вызовов, содержимое файлов и результаты команд. Всё это накапливается быстро.

KV-кэш и VRAM: где проходит граница

Расход памяти на KV-кэш растёт линейно с длиной контекста. Увеличили окно вдвое - вдвое вырос и кэш, при том же числе слоёв. Именно поэтому здесь включена 4-битная квантизация ключей и значений: она позволяет держать длинный контекст на карте, не вынося слои в системную память. Побочный эффект - потеря точности в представлении кэша, и её влияние на качество ответов зависит от задачи.

Если VRAM не хватает, порядок действий обычно такой: снизить контекст, ещё сильнее ужать KV-кэш, уменьшить --ubatch-size. Обещаний по конкретному приросту тут дать нельзя, значения подбираются под карту.

Cache-reuse и сохранение слотов

Слоты сохраняются в /dev/shm/llama_qwen38/slots через --slot-save-path, туда же пишется лог движка в /dev/shm/llama_qwen38/telemetry/engine_debug.log. /dev/shm в Linux - это RAM-диск: запись не изнашивает SSD и работает быстро, но занимает оперативную память. На машине с 32 ГБ DDR2400 это реальное ограничение, которое стоит учитывать при долгих агентных сессиях.

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

Вынос vision на RTX 2060 и второй экземпляр сервера

Для обработки изображений подключён проектор mmproj-F16.gguf, а параметр --mmproj-device Vulkan1 направляет его на вторую карту. Дополнительно задан --image-min-tokens 1024: минимальное число токенов, которое отводится под изображение.

Зачем вообще выносить mmproj

mmproj - это проектор, превращающий изображение в эмбеддинги, которые модель подмешивает в контекст. Когда он считается на CPU, работу получает процессор и системная память. Перенос на отдельную GPU освобождает CPU, но сам по себе не ускоряет обработку картинок: по словам автора сборки, скорость с RTX 2060 примерно такая же, как при выгрузке на CPU. То есть выигрыш здесь не в скорости vision, а в разгрузке основной карты и процессора.

Второй экземпляр сервера: зачем и как

Раз vision-проектор переехал на RTX 2060, эта карта перестала быть занятой постоянно, и автор поднял на ней второй экземпляр сервера. Разделение простое: одна карта обслуживает основную модель, вторая берёт на себя вспомогательные запросы. Параметры этого второго экземпляра в сообщении не раскрыты, поэтому повторять схему придётся по аналогии с основной командой, подбирая размер карты и модель под неё.

Для смешанной конфигурации из AMD и NVIDIA это аккуратное решение: карты не конкурируют за одну и ту же память, а драйверы не пересекаются. Если вместо второй карты в системе стоит один мощный Radeon, логика распределения ресурсов будет другой, и её стоит считать заранее, как в разборе сервера на двух Radeon AI PRO R9700.

Агентный кодинг: Hermes, reasoning и speculative decoding

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

Speculative decoding: draft-mtp и его параметры

Спекулятивное декодирование использует чернового предсказателя: он предлагает несколько токенов вперёд, а основная модель их проверяет пачкой. Здесь включён режим --spec-type draft-mtp, то есть ставка на MTP-модуль внутри самой модели. Лимит предложений задан через --spec-draft-n-max 2, а порог вероятности - через --spec-draft-p-min 0.

Значение 0 в пороге означает, что отбраковка по вероятности фактически отключена: черновик принимается к проверке независимо от уверенности. Лимит в два токена - осторожный режим. Прирост от спекулятивного декодирования зависит от того, насколько часто предложения черновика совпадают с ответом основной модели, поэтому на разных задачах эффект будет разным, и в отчёте отдельного замера вклада draft-mtp нет.

Reasoning и chat-template: как управлять поведением модели

Настройки рассуждений в этой конфигурации: --reasoning on, --reasoning-format deepseek, --reasoning-budget -1, --reasoning-preserve. Формат deepseek задаёт разметку блока размышлений, бюджет -1 снимает ограничение на длину цепочки, а preserve сохраняет рассуждения в истории. Для агентного кодинга неограниченный бюджет - палка о двух концах: модель может рассуждать дольше на сложных задачах, но на простых это только тратит токены и время.

Поверх этого подключён кастомный шаблон чата через --jinja и --chat-template-file /dev/shm/llama_qwen38/qwen3.8-safe-v2.jinja. В параметрах шаблона переданы reasoning_effort со значением xhigh, preserve_thinking true и max_tool_response_chars 9000. Последний параметр обрезает ответ инструмента до 9000 символов, и это важная деталь для 240K-контекста: без ограничения вывод длинных команд быстро съел бы окно. Содержимое самого jinja-файла в сообщении не раскрыто, так что готовый шаблон придётся собирать самостоятельно.

Hermes на Raspberry Pi как клиент

Клиентом выступает Hermes на Raspberry Pi: через него ставятся задачи и забираются результаты. Сервер слушает на 0.0.0.0:8081, поэтому доступен по сети, и клиент живёт на отдельном устройстве. Автор отдельно отмечает, что наконец смог отдать задачу и вернуться к результату позже, без постоянного контроля процесса.

Обратная сторона такого запуска - безопасность и доступность. Адрес 0.0.0.0 открывает сервер всем в локальной сети, у llama-server нет аутентификации, поэтому выставлять порт в интернет без обратного прокси и пароля не стоит. Что именно за задачи ставились через Hermes и как он связан с сервером по API, в отчёте не описано.

Отдельный результат этой сборки - панель управления inference-серверами, которую сгенерировала сама Qwen 27B. По словам автора, панель написана с нуля за неделю с приоритетом на скорость работы, а генерировалась моделью в варианте qwen3.8-27b davidau q4k_m max mtp. Какие функции вошли в панель и как она устроена внутри, не раскрыто. Сам факт показателен: 40 токенов/с и 240K контекста хватило, чтобы неделю вести итеративную разработку собственного инструмента.

Практические выводы: кому подходит и на что обратить внимание

Сборка закрывает конкретный сценарий: локальный сервер с одной потребительской AMD-картой, длинный контекст и агентные задачи по коду. Ключевые её элементы - RX 7900 XTX как основная GPU, Vulkan как бэкенд, квантование KV-кэша в iq4_nl, flash-attention и жёсткое разделение карт через tensor-split 1,0. Панель управления, сгенерированная моделью за неделю, показывает, что такой конфигурации хватает для реальной разработки, а не только для демонстраций.

Что можно улучшить или проверить

Первое, что стоит тюнинговать под своё железо, - размеры батчей. --batch-size 2048 и --ubatch-size 512 подобраны под конкретную карту, и на другой они могут упереться в VRAM или, наоборот, недобрать скорости префилла. Второе - число потоков CPU: --threads 6 привязано к Intel 9700, на другом процессоре оптимум будет другим. Третье - схема квантования KV-кэша: iq4_nl это компромисс между экономией памяти и точностью, и если качество на длинном контексте проседает, есть смысл проверить более щадящие варианты за счёт длины окна.

Если сборка не помещается в память, двигайтесь в таком порядке: уменьшить контекст, ужать KV-кэш, уменьшить ubatch. Конкретного прироста от этих шагов обещать нельзя, значения подбираются замерами на своей машине.

Ограничения и риски

Все цифры в материале - данные одного пользователя, полученные на одном наборе железа и софта. Независимых измерений нет, а сами значения приблизительные. Скорость на другой карте, процессоре или версии llama.cpp может отличаться заметно.

Отдельного внимания требует драйверная часть. На AMD связка бэкенда, версии драйвера и сборки llama.cpp определяет, запустится ли всё вообще и не упадёт ли под нагрузкой. Vulkan здесь выбран как рабочий вариант на Ubuntu, но это не универсальная рекомендация: на других конфигурациях имеет смысл проверить ROCm и сравнить поведение.

Квантизация Q4_K_M весов и iq4_nl для KV-кэша снижают точность по сравнению с более высокими разрядами. Это осознанная плата за то, чтобы 27B-модель с длинным контекстом уместилась на потребительской карте. Заявленные 240K контекста - настройка окна, а не подтверждённое качество работы на всей его длине.

Если задача ограничивается короткими чатами без кода, вся эта схема избыточна: спекулятивное декодирование и неограниченный бюджет рассуждений только замедлят ответы. Сборка имеет смысл там, где модель вызывается агентами, работает с файлами и удерживает большой контекст. Для альтернативного взгляда на бюджет локального инференса полезно посмотреть разбор домашнего сервера на четырёх Radeon V620 со 128 ГБ VRAM: там те же компромиссы видны уже на другом масштабе бюджета и энергопотребления.

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

Подписаться на канал