Перейти к содержимому
ПереводыQwen, InternLM и другие

Документация Qwen, часть 2: запуск через vLLM, SGLang и Ollama

Пересказ разделов документации Qwen о развёртывании: OpenAI-совместимый сервер в vLLM и SGLang, переключение размышления, разбор рассуждений и вызовов функций, квантованные версии, YaRN, борьба с нехваткой памяти, а также локальный запуск через Ollama и llama.cpp.

В уроке 7.1.2 вы разобрали, как устроены движки инференса: непрерывный батчингнепрерывный батчингEN continuous batching (iteration-level scheduling)Состав батча пересматривается после каждого шага decode — закончившиеся запросы уходят, новые встают на их место. Идея системы Orca (2022), стандарт всех современных серверов., PagedAttentionPagedAttention (страничный KV-кэш)EN PagedAttentionKV-кэш хранится блоками фиксированного размера (например, по 16 токенов), а таблица блоков связывает логические позиции с физическими — как страницы виртуальной памяти в ОС. Основа vLLM., префикс-кэшпрефикс-кэш (кэширование префиксов)EN prefix cachingЕсли начало нового запроса совпадает с уже обработанным (системный промпт, история диалога), его KV-кэш берут готовым и prefill делают только для «хвоста».. Документация Qwen отвечает на практический вопрос: какими командами поднять конкретную модель так, чтобы к ней можно было обращаться кодом из урока 8.1.1, и какие подводные камни ждут именно у Qwen3 (режим размышления, разбор вызовов функций, длинный контекст).

Порядок разделов в оригинале: vLLM (рекомендуемый вариант) → SGLang → TGI, dstack, SkyPilot, OpenLLM (облачные и корпоративные варианты, для курса не нужны) → локальные: llama.cpp, Ollama, MLX-LM (только Mac), LM Studio.

Документация рекомендует vLLMvLLMEN vLLMОткрытый движок инференса LLM (UC Berkeley): PagedAttention, continuous batching, тензорный параллелизм, OpenAI-совместимый сервер (vllm serve, порт 8000). Стандарт для сервисов и генерации в RL. как основной путь: просто запустить, высокая пропускная способность, эффективное управление KV-кэшем через PagedAttention, непрерывный батчинг.

Окно терминала
pip install "vllm>=0.8.5" # документация советует ставить в чистое окружение

Предупреждение оригинала: готовые сборки vLLM жёстко привязаны к своей версии torch и CUDA. Если в окружении уже стоит другой PyTorch, установка его заменит — поэтому отдельное виртуальное окружение под vLLM обязательно.

Окно терминала
vllm serve Qwen/Qwen3-8B # сервер на http://localhost:8000
vllm serve Qwen/Qwen3-8B --tensor-parallel-size 4 # то же, модель разрезана на 4 GPU
export VLLM_USE_MODELSCOPE=true # качать веса с ModelScope, а не с Hugging Face

Если имя модели не указывает на локальную папку, vLLM скачает веса сам. Адрес и порт меняются флагами --host и --port.

Обращаться к серверу можно curl или OpenAI SDK — тем же кодом, что к облачному API:

from openai import OpenAI
# Ключ не проверяется, но SDK требует непустую строку
client = OpenAI(api_key="EMPTY", base_url="http://localhost:8000/v1")
resp = client.chat.completions.create(
model="Qwen/Qwen3-8B", # имя, под которым vLLM поднял модель
messages=[{"role": "user", "content": "Чем vLLM отличается от transformers? Два предложения."}],
max_tokens=4096,
temperature=0.6, top_p=0.95, # параметры режима размышления (см. часть 1)
extra_body={"top_k": 20}, # top_k нет в OpenAI SDK — передаём через extra_body
)
print(resp.choices[0].message.content)

Совет документации: vLLM по умолчанию берёт параметры выборки из generation_config.json модели, но лучше всегда передавать их явно в каждом запросе — и разные для режима с размышлением и без.

  • В запросе — поле chat_template_kwargs: extra_body={"chat_template_kwargs": {"enable_thinking": False}}. Это аргумент шаблона чата, его нет в спецификации OpenAI, и в другом движке он может называться иначе. Для режима без размышления документация советует temperature=0.7, top_p=0.8, top_k=20 и presence_penalty=1.5.
  • Мягко — /no_think в сообщении пользователя (модель слушается последней такой команды).
  • Насовсем — запустить сервер со своим шаблоном чата, который никогда не даёт модели думать: vllm serve Qwen/Qwen3-8B --chat-template ./qwen3_nonthinking.jinja. Файл шаблона лежит в репозитории (docs/source/assets/qwen3_nonthinking.jinja). С ним модель не думает, даже если пользователь напишет /think.

Модель выдаёт один сплошной текст: <think>…</think> и ответ, а вызовы функций — как <tool_call>{…}</tool_call>. Чтобы клиент получил всё это по полям, серверу нужны парсеры:

Окно терминала
# рассуждение уйдёт в отдельное поле message.reasoning_content (vLLM 0.9.0+)
vllm serve Qwen/Qwen3-8B --reasoning-parser qwen3
# вызовы функций — в стандартное поле message.tool_calls (формат Hermes)
vllm serve Qwen/Qwen3-8B --enable-auto-tool-choice --tool-call-parser hermes

Флаги можно сочетать в одной команде. Документация отмечает две тонкости:

  • поле reasoning_content — тоже не часть спецификации OpenAI, это соглашение vLLM, SGLang и DeepSeek API;
  • в vLLM 0.8.5 разбор рассуждений не сочетался с enable_thinking=False (тогда был флаг --enable-reasoning --reasoning-parser deepseek_r1); с версии 0.9.0 и парсера qwen3 это исправлено.

Подробный разбор вызова функций — на третьей странице путеводителя.

vLLM умеет ограничивать генерацию JSON-схемой (ограниченное декодированиеограниченное декодированиеEN constrained decoding / guided decodingНа каждом шаге сэмплирования запрещаются токены, нарушающие грамматику (например, JSON-схему), — их логиты заменяются на минус бесконечность, и после softmax вероятность таких токенов равна нулю.); параметры — в документации vLLM. Документация Qwen добавляет здравый совет: всё равно описывайте нужный формат в промпте — модели так проще.

Команда та же, меняется только имя: Qwen/Qwen3-8B-FP8 или Qwen/Qwen3-8B-AWQ.

  • FP8-версии Qwen3 квантованы поблочно. Как W8A8 (8-битные веса и активации) они идут на картах с архитектурой Ada Lovelace (RTX 40xx, в том числе ваши 4080), Hopper и новее; с vLLM 0.9.0 — и на Ampere (как W8A16).
  • Если при запуске FP8 на нескольких GPU вы видите ошибку вида «output_size … is not divisible by weight quantization block_n = 128», значит, при таком числе карт слой режется на куски, не кратные блоку квантования. Уменьшите --tensor-parallel-size или (для MoE) добавьте --enable-expert-parallel.

Что такое AWQ и FP8 и почему блоки — в уроке 7.2.1.

Qwen3 предобучали на последовательностях до 32 768 токенов. Для более длинного контекста документация предлагает YaRNYaRNEN YaRN (Yet another RoPE extensioN)NTK-by-parts (каждая пара частот масштабируется по числу оборотов за обучающую длину) плюс температура внимания 0.1·ln s + 1. Используется в DeepSeek-V3 и Qwen. — масштабирование RoPE (урок 5.5.1):

Окно терминала
vllm serve Qwen/Qwen3-8B \
--rope-scaling '{"rope_type":"yarn","factor":4.0,"original_max_position_embeddings":32768}' \
--max-model-len 131072

Что здесь написано: «растяни позиции в factor = 4 раза относительно исходных 32 768» — получается 4×32 768=131 0724 \times 32\,768 = 131\,072 токенов.

Три предупреждения документации:

  1. В vLLM YaRN статический: множитель один и тот же для любых входов, поэтому на коротких текстах качество может немного упасть. Включайте YaRN, только когда длинный контекст действительно нужен.
  2. Подбирайте factor под задачу: если типичная длина 65 536, достаточно factor = 2.
  3. По умолчанию max_position_embeddings в config.json равен 40 960 = 32 768 под ответ + 8 192 под промпт. Если ваши тексты короче 32 тыс. токенов, YaRN не нужен вовсе.

Без сервера vLLM удобен для пакетной обработки (прогнать тысячу промптов разом):

from vllm import LLM, SamplingParams
llm = LLM(model="Qwen/Qwen3-8B") # загрузка модели и выделение KV-кэша
params = SamplingParams(temperature=0.6, top_p=0.95, top_k=20, max_tokens=4096)
conversations = [
[{"role": "user", "content": "Сколько будет 17 * 23?"}],
[{"role": "user", "content": "Назови три реки Китая."}],
]
# LLM.chat сам применит шаблон чата; enable_thinking передаётся так же, как в сервере (vLLM 0.9.0+)
outputs = llm.chat(conversations, params, chat_template_kwargs={"enable_thinking": False})
for out in outputs:
print(out.outputs[0].text)

В этом режиме нет разбора рассуждений и вызовов функций — их придётся выделять самим (код — в части 1).

Документация называет два главных рычага:

  • --max-model-len. По умолчанию 40 960 токенов, и vLLM резервирует память так, чтобы хоть один запрос такой длины поместился. Если вам хватит 8–16 тысяч, уменьшите — освободится место.
  • --gpu-memory-utilization (по умолчанию 0,9): доля памяти GPU, которую vLLM занимает заранее — поэтому сервер «съедает» почти всю карту. Если включены CUDA-графы (по умолчанию да), им нужна память сверх этой доли, и тогда долю надо уменьшать. Не помогло — --enforce-eager (без CUDA-графов, медленнее) или меньший --max-model-len.

SGLangSGLangEN SGLangДвижок инференса от LMSYS: RadixAttention (переиспользование общего префикса запросов), быстрый структурированный вывод, ранняя поддержка новых DeepSeek и Qwen; OpenAI-совместимый сервер на порту 30000. — второй рекомендованный движок. Всё устроено так же, отличаются команды и флаги:

ЧтоvLLMSGLang
установкаpip install "vllm>=0.8.5"pip install "sglang[all]>=0.4.6.post1"
запускvllm serve Qwen/Qwen3-8Bpython -m sglang.launch_server --model-path Qwen/Qwen3-8B
порт по умолчанию800030000
4 GPU--tensor-parallel-size 4--tensor-parallel-size 4 (или --tp 4)
ModelScopeVLLM_USE_MODELSCOPE=trueSGLANG_USE_MODELSCOPE=true
разбор рассуждений--reasoning-parser qwen3--reasoning-parser qwen3
разбор вызовов функций--enable-auto-tool-choice --tool-call-parser hermes--tool-call-parser qwen25
YaRN--rope-scaling '{…}' --max-model-len 131072--json-model-override-args '{"rope_scaling":{…}}' --context-length 131072

Клиентский код тот же, меняется только base_url="http://localhost:30000/v1". Предупреждения про enable_thinking=False вместе с разбором рассуждений и про статический YaRN в SGLang те же, что в vLLM.

OllamaOllamaEN OllamaПрограмма для запуска LLM одной командой (ollama run qwen3:8b): своя библиотека моделей в формате GGUF, работа на CPU и GPU, OpenAI-совместимый API на порту 11434. — самый простой способ запустить модель на своём компьютере: одна команда, готовые квантованные GGUFGGUF (формат файлов llama.cpp)EN GGUFОдин файл с весами (обычно квантованными), токенизатором, шаблоном чата и метаданными. Типы квантования — Q8_0, Q6_K, Q4_K_M и др. Используют llama.cpp, Ollama, LM Studio.-файлы.

Честное замечание: страница Ollama в документации Qwen на январь 2026 года всё ещё помечена «будет обновлено для Qwen3» и описывает Qwen2.5 (ollama run qwen2.5:7b и т. д.). Принцип не изменился, а команды для Qwen3 — те же, что в уроках курса:

11434/v1
ollama run qwen3:8b # скачает квантованную модель и откроет чат в терминале
ollama pull qwen3:0.6b # только скачать

Две полезные вещи со страницы:

  • В Ollama нет базовых моделей: даже если в теге нет слова instruct, это чат-модель.
  • Свой GGUF-файл подключается через Modelfile: строка FROM путь/к/файлу.gguf, параметры (PARAMETER temperature 0.7, PARAMETER top_p 0.8, PARAMETER top_k 20, PARAMETER repeat_penalty 1.05), шаблон чата TEMPLATE """…""" на языке шаблонов Go (в оригинале приведён полный шаблон ChatML с поддержкой инструментов) и системное сообщение SYSTEM """…""". Затем ollama create имя -f Modelfile и ollama run имя.

Страница о llama.cpp — самая подробная в разделе «локально». Ключевые мысли:

  • llama.cpp — библиотека на C/C++ без внешних зависимостей; Ollama и LM Studio построены поверх неё. Документация подчёркивает: «использовать llama.cpp» в смысле руководства — это запускать её готовые программы llama-cli (чат в терминале) и llama-server (OpenAI-совместимый сервер).
  • Поддерживает CPU (AVX/AVX2/AVX512), Apple Silicon, NVIDIA (CUDA), AMD, Intel, Ascend и другие ускорители и умеет гибридный режим CPU+GPU: часть слоёв на видеокарте, остальное в оперативной памяти — так запускают модели больше суммарной видеопамяти.
  • Qwen3 и Qwen3-MoE поддерживаются начиная со сборки b5092.
  • Порядок работы: получить программы (лучше собрать самому — получите оптимизации под свой процессор), скачать модель в формате GGUF, запустить.

Подробные команды сборки с CUDA и запуска llama-server для Qwen3-8B и Qwen3-30B-A3B с выгрузкой экспертов на CPU — в уроке 7.2.2.

ЗадачаКомандаКомментарий
чат-сервер на одну картуCUDA_VISIBLE_DEVICES=0 vllm serve Qwen/Qwen3-8B --max-model-len 16384 --reasoning-parser qwen3веса ≈16 ГБ, остальное под KV-кэш
большая плотная модельvllm serve Qwen/Qwen3-32B --tensor-parallel-size 4 --max-model-len 16384≈66 ГБ весов, по ≈16 ГБ на карту
быстрая MoEvllm serve Qwen/Qwen3-30B-A3B --tensor-parallel-size 2 --max-model-len 32768≈61 ГБ весов; активны 3 млрд параметров — генерация быстрая
сервер для агентаvllm serve Qwen/Qwen3-8B --enable-auto-tool-choice --tool-call-parser hermes --reasoning-parser qwen3для практики уроков 8.3
локально без Pythonollama run qwen3:8b4-битная модель, ≈5 ГБ

Карты GeForce связаны только по PCIe, поэтому тензорный параллелизм обходится дороже, чем на серверных GPU с NVLink. Если модель помещается на одну карту, четыре независимые копии (--data-parallel-size 4) часто дают больше запросов в секунду. Это опыт из урока 7.1.2 — проверьте сами.

  1. Поднимите vllm serve Qwen/Qwen3-0.6B --reasoning-parser qwen3 и задайте вопрос через OpenAI SDK. Напечатайте resp.choices[0].message.reasoning_content и content по отдельности.
  2. Повторите запрос с chat_template_kwargs={"enable_thinking": False}. Сравните число токенов в resp.usage.
  3. Запустите тот же код против Ollama (base_url="http://localhost:11434/v1", model="qwen3:0.6b") — убедитесь, что клиентский код не меняется.
  4. Специально вызовите нехватку памяти: --max-model-len 40960 --gpu-memory-utilization 0.3 на 8B-модели. Прочитайте ошибку и исправьте её рычагами из FAQ.
EnglishРусский
deploymentразвёртывание
OpenAI-compatible APIOpenAI-совместимый API
tensor parallelismтензорный параллелизм
reasoning parserпарсер рассуждений
tool call parserпарсер вызовов функций
structured outputструктурированный вывод
out of memory (OOM)нехватка памяти