70 токенов в секунду в qwen3.8–27b на RTX 3090

На текущий момент qwen3.8-27b, без сомнений, лучшая модель для программирования, которую можно запускать на потребительских видеокартах. К сожалению, прямой путь - скачать модель с официального аккаунта qwen на huggingface -> запустить в своем любимом инференс-движке может не привести к хорошему результату, поэтому я решил написать эту статью.
План действий такой:
Установить необходимые пакеты для сборки llamAmpere (https://github.com/JakeATX/llamAmpere) - это форк llama.cpp, оптимизированный для запуска на поколении графических адаптеров Ampere.
Скомпилировать llamAmpere.
Установить huggingface client.
Скачать модель и отдельно исправленный chat template.
Запустить инференс-движок с нашей моделью.
Настроить агент (покажу на примере claude-code).
Подготовка зависимостей
Для начала нужна cuda. В README к llamAmpere указано, что они тестировали на cuda версии 12.4; у меня стоит 13.1, и тоже всё работает. Так что просто установите самый полный набор для разработки средствами вашего дистрибутива.
Далее нужны cmake и gcc не слишком высокой версии, крайне желательно не выше 14. В Fedora 44 нужно поставить дополнительно к системному gcc версии 16 пакеты gcc15 и gcc15-c++.
Фиксим заголовочный файл из cuda для gcc-15
Необходимо пропатчить файл /usr/local/cuda-13.1/targets/x86_64-linux/include/crt/math_functions.h. Вот патч: math_functions.patch
И еще текстом, на всякий случай:
--- math_functions.h.orig 2026-10-08 16:54:22.188939419 +0300
+++ math_functions.h 2026-10-08 16:25:45.772064018 +0300
@@ -626,7 +626,7 @@ extern __DEVICE_FUNCTIONS_DECL__ __devic
*
* \note_accuracy_double
*/
-extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ double rsqrt(double x);
+extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ double rsqrt(double x) noexcept(true);
/**
* \ingroup CUDA_MATH_SINGLE
@@ -650,7 +650,7 @@ extern __DEVICE_FUNCTIONS_DECL__ __devic
*
* \note_accuracy_single
*/
-extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ float rsqrtf(float x);
+extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ float rsqrtf(float x) noexcept(true);
#if defined(__QNX__) && !defined(_LIBCPP_VERSION)
namespace std {
@@ -6043,7 +6043,7 @@ inline __device__ void *__nv_aligned_dev
#endif /* _WIN32 */
-__func__(double rsqrt(double a));
+__func__(double rsqrt(double a) noexcept(true));
__func__(double rcbrt(double a));
@@ -6069,7 +6069,7 @@ __func__(double normcdf(double a));
__func__(double erfcx(double a));
-__func__(float rsqrtf(float a));
+__func__(float rsqrtf(float a) noexcept(true));
__func__(float rcbrtf(float a));
Сборка llamAmpere
Компилируем таким образом:
export NVCC_CCBIN='g++-15' # Только для fedora-44!
git clone https://github.com/JakeATX/llamAmpere.git
cd llamAmpere
cmake -S . -B build-sm86 -DCMAKE_BUILD_TYPE=Release -DGGML_CUDA=ON -DCMAKE_CUDA_ARCHITECTURES=86
cmake --build build-sm86 -j8 --target llama-serverЕсли всё прошло успешно то нужный исполняемый файл будет build-sm86/bin/llama-server.
Установка клиента huggingface
Ничего нестандартного тут не могу сказать, команда hf нам нужна только для того, чтобы скачать модель, можно ставить любым способом. Либо через pip:
pip install -U "huggingface_hub[cli]"Либо через uv:
uv tool install huggingface_hubЛибо установочным скриптом:
curl -LsSf https://hf.co/cli/install.sh | shДалее для более высокой скорости скачивания нужно зарегистрироваться на huggingface, сделать там себе токен и записать его в переменную окружения:
export HF_TOKEN=XXXXXXСкачиваем файлы
Для начала модель, она занимает 15 Гбайт:
hf download jakeatx/Qwen3.8-27B-ATX-IQ4_XS-M-GGUF --local-dir $HOME/models/qwen3.8-27b-gguf/С дефолтным chat_template из модели у меня claude-code не захотел работать, вот тут есть исправленные - https://huggingface.co/froggeric/Qwen-Fixed-Chat-Templates. Нам нужно скачать вот этот файл: https://huggingface.co/froggeric/Qwen-Fixed-Chat-Templates/resolve/main/chat_template.jinja
Запускаем
./build-sm86/bin/llama-server \
--ctx-size 245760 \
--batch-size 4096 \
--ubatch-size 1024 \
--threads 8 \
--threads-batch 8 \
--n-gpu-layers 99 \
--flash-attn on \
--cache-type-k turbo5 \
--cache-type-v turbo4 \
--parallel 1 \
--jinja \
--spec-type draft-mtp \
--spec-draft-n-max 4 \
--spec-draft-p-min 0 \
--spec-draft-vocab-map auto \
--model $HOME/models/qwen3.8-27b-gguf/Qwen3.8-27B-ATX-4-XS.gguf \
--chat-template-file $HOME/models/chat_template.jinja \
--host 0.0.0.0 \
--port 8089 \
--alias qwen3.8 \
--reasoning-format deepseekЕсли будете использовать только локально надо убрать параметр --host 0.0.0.0. Также можно немного поменять размер контекста, вместо 245760 поставить чуть больше, если изображение у вас выводится через отдельную видеокарту, либо чуть меньше, если хотите оставить больше видеопамяти для приложений. В указанном варианте потребляется 20834 Мбайт.
Настройка claude-code
Вот мой скрипт для запуска claude-code:
#!/bin/bash
CLAUDE_CODE_CONTEXT_LIMIT=245760 \
AI_LOG_ENDPOINT="" \
ANTHROPIC_BASE_URL="http://localhost:8089/" \
ANTHROPIC_AUTH_TOKEN="default" \
ANTHROPIC_CUSTOM_HEADERS="Plugin-Type: claude-code" \
API_TIMEOUT_MS=600000 \
ANTHROPIC_MODEL="qwen3.8" \
ANTHROPIC_SMALL_FAST_MODEL="qwen3.8" \
CLAUDE_CODE_SUBAGENT_MODEL="qwen3.8" \
ANTHROPIC_DEFAULT_SONNET_MODEL="qwen3.8" \
ANTHROPIC_DEFAULT_OPUS_MODEL="qwen3.8" \
ANTHROPIC_DEFAULT_HAIKU_MODEL="qwen3.8" \
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 \
CLAUDE_CODE_LOG_LEVEL=debug \
ENABLE_LSP_TOOL=1 \
command claude "$@"Если что-то меняли в строке запуска llamAmpere, то тут надо поправить соответственно размер контекста, адрес сервера или имя модели.
Тестирование
Для проверки скорости использовал самописный скрипт, который проверяет скорость с коротким промптом в 35 токенов и с длинным в 100000 токенов. Вот этот скрипт.
Сравнил с оригинальной llama.cpp, в ней нет типов turbo5 и turbo4, так что для kv-кеша использовал q8_0 и q4_0.
Числа указаны в токенах/с, время изменялось с момента отправки запроса, e2e.
35 токенов | 100K токенов | |
llamAmpere | 68.8 | 58.9 |
llama.cpp | 58.3 | 47.0 |
Полный отчет о тестировании
llamAmpere
Модель: qwen3.8 | runs=3 | max_tokens=2048 | temperature=0.0
Base URL: http://localhost:8089/v1
Long-промпт: ~100,480 токенов на запрос; на весь прогон (warmup + 3 runs) уйдёт ~401,920 входных токенов — учтите стоимость и лимит контекста модели.
=== Промпт: short (вход ~35 токенов, ~161 симв., max_tokens=2048) ===
warmup (не учитывается)...
# | TTFT, с | всего, с | токены | tok/s дек | tok/s e2e
1 | 2.72 | 20.40 | 1401 | 79.2 | 68.7
2 | 2.63 | 20.34 | 1401 | 79.1 | 68.9
3 | 2.63 | 20.39 | 1401 | 78.9 | 68.7
среднее: TTFT 2.66 с | всего 20.37 с | декод 79.1 tok/s | e2e 68.8 tok/s
медиана: TTFT 2.63 с | декод 79.1 tok/s
=== Промпт: long (вход ~100,480 токенов, ~512,089 симв., max_tokens=2048) ===
warmup (не учитывается)...
# | TTFT, с | всего, с | токены | tok/s дек | tok/s e2e
1 | 4.98 | 30.28 | 1784 | 70.5 | 58.9
2 | 5.01 | 30.32 | 1784 | 70.5 | 58.8
3 | 5.01 | 30.30 | 1784 | 70.5 | 58.9
среднее: TTFT 5.00 с | всего 30.30 с | декод 70.5 tok/s | e2e 58.9 tok/s
медиана: TTFT 5.01 с | декод 70.5 tok/s
Сравнение: TTFT short 2.66 с vs long 5.00 с (разница — цена префилла ~100,480 токенов контекста; после warmup сервер может кэшировать префикс, тогда TTFT повторных запусков занижен); декодирование: 79.1 vs 70.5 tok/sllama.cpp
Модель: qwen3.8 | runs=3 | max_tokens=2048 | temperature=0.0
Base URL: http://localhost:8089/v1
Long-промпт: ~100,480 токенов на запрос; на весь прогон (warmup + 3 runs) уйдёт ~401,920 входных токенов — учтите стоимость и лимит контекста модели.
=== Промпт: short (вход ~35 токенов, ~161 симв., max_tokens=2048) ===
warmup (не учитывается)...
# | TTFT, с | всего, с | токены | tok/s дек | tok/s e2e
1 | 3.25 | 23.82 | 1392 | 67.7 | 58.4
2 | 3.15 | 23.83 | 1392 | 67.3 | 58.4
3 | 3.19 | 23.94 | 1392 | 67.1 | 58.2
среднее: TTFT 3.20 с | всего 23.86 с | декод 67.4 tok/s | e2e 58.3 tok/s
медиана: TTFT 3.19 с | декод 67.3 tok/s
=== Промпт: long (вход ~100,480 токенов, ~512,089 симв., max_tokens=2048) ===
warmup (не учитывается)...
# | TTFT, с | всего, с | токены | tok/s дек | tok/s e2e
1 | 6.63 | 40.29 | 1584 | 47.1 | 39.3
2 | 6.65 | 40.32 | 1584 | 47.0 | 39.3
3 | 6.67 | 40.38 | 1584 | 47.0 | 39.2
среднее: TTFT 6.65 с | всего 40.33 с | декод 47.0 tok/s | e2e 39.3 tok/s
медиана: TTFT 6.65 с | декод 47.0 tok/s
Сравнение: TTFT short 3.20 с vs long 6.65 с (разница — цена префилла ~100,480 токенов контекста; после warmup сервер может кэшировать префикс, тогда TTFT повторных запусков занижен); декодирование: 67.4 vs 47.0 tok/sИтоги
В результате получаем полностью работающий claude-code, который вполне достойно анализирует и пишет код, вызывает инструменты и может работать в автономном режиме долгое время без каких-либо зависаний и ошибок. Да, он не такой умный, как Opus, но можно сначала сгенерировать план работы более умной моделью, а реализацию и отладку доверить этому джуну.
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.