The qwen3.6-35b-a3b VL checkpoint is a single hybrid model with a per- request enable_thinking switch (Qwen3-style), defaulting thinking ON. Make the default non-thinking and add an opt-in reasoning variant, mirroring the existing glm-5.1 / glm-5.1-reasoning gateway split. - qwen36-vl compose: add --reasoning-parser qwen3 (model-matched) so the single :8007 endpoint splits <think> into reasoning_content when on and routes all output to content when off — serving both modes cleanly. - litellm gateway: base qwen3.6-35b-a3b pins chat_template_kwargs enable_thinking=false (non-thinking default); new qwen3.6-35b-a3b-thinking pins enable_thinking=true (opt-in reasoning). Same upstream checkpoint, no extra VRAM/container. Deployed + verified on ana-ml2 (vLLM recreated, healthy) and ana-docker (litellm reloaded): default returns a direct answer with no reasoning_content; -thinking returns cleanly-separated reasoning_content, no raw tag leak.
122 lines
5.2 KiB
YAML
122 lines
5.2 KiB
YAML
# qwen36-vl — Qwen3.6-35B-A3B vision-language MoE (official FP8) on ana-ml2.
|
|
#
|
|
# Replaces the qwen35-vl stack (Qwen3.5-9B) 2026-06-14. Co-located on GPU 1 with
|
|
# the granite summarizer + embed/rerank/reward trio (GPU 0 stays free for the
|
|
# llama-swap creative-writing hot-swap card). Serves on :8007.
|
|
#
|
|
# WHY official FP8 (not NVFP4): NVFP4 (nvidia/Qwen3.6-35B-A3B-NVFP4, ~21 GB) is the
|
|
# lighter fit but its vLLM ModelOpt-MoE loader is BROKEN as of 0.19.1/0.22.0
|
|
# (KeyError w2_input_scale / lm_head.input_scale — vLLM #44081). The official
|
|
# Qwen pre-quantized FP8 (~34 GB weights) loads clean on :latest and — unlike
|
|
# the old qwen35-vl — needs NO pinned nightly digest: that hack existed because
|
|
# vLLM DYNAMIC `--quantization fp8` quantized the vision tower to noise. This
|
|
# checkpoint is PRE-quantized, so we OMIT --quantization (vLLM auto-detects the
|
|
# checkpoint's own fp8) and the vision tower is preserved. Validated 2026-06-14
|
|
# on GPU 0: loads in 34.2 GiB, image test returns correct ("Blue"). Revisit
|
|
# NVFP4 (frees ~13 GB) once vLLM's loader is fixed.
|
|
#
|
|
# NAMING: served ONLY as its TRUE name `qwen3.6-35b-a3b`. A model is never aliased
|
|
# under a prior model's name — a caller asking for `qwen3.5-9b-fp8` (a 9B dense)
|
|
# must NOT be silently handed this 35B-A3B MoE; that's a downstream-confusion
|
|
# footgun. The legacy `qwen3.5-9b-fp8` name is RETIRED. Consumers (Arbo's vision
|
|
# hero-judge, stacks/arbo v0.11.3+) migrate to `qwen3.6-35b-a3b` — they 404 on the
|
|
# old name until they repoint, which is the correct loud signal (notified 2026-06-14).
|
|
#
|
|
# WHY util 0.42 / max-len 131072: hybrid attn (10 of 40 layers full-attn, ~10 KB/
|
|
# tok KV) → KV is cheap, so big context is nearly free; the 34 GB weights are the
|
|
# cost. 0.42 (~40 GB) = weights + graph + generous KV. Granite drops to 0.25/64K
|
|
# to make room (the FP8-vs-maxed-granite tradeoff, operator-approved 2026-06-14).
|
|
#
|
|
# THINKING TOGGLE: this is ONE hybrid checkpoint (not separate Instruct/Thinking
|
|
# downloads) with a Qwen3-style per-request `enable_thinking` switch. The chat
|
|
# template defaults thinking ON (`<think>\n`); passing
|
|
# `chat_template_kwargs={"enable_thinking":false}` emits the empty
|
|
# `<think>\n\n</think>\n\n` block (no reasoning). We run --reasoning-parser qwen3
|
|
# (model-matched — its vLLM docstring describes THIS checkpoint) so ONE endpoint
|
|
# serves BOTH modes cleanly: thinking-ON splits <think>…</think> into
|
|
# reasoning_content; thinking-OFF routes everything to content. The gateway
|
|
# selects the mode per model_name (stacks/litellm/conf/config.yaml):
|
|
# qwen3.6-35b-a3b → enable_thinking:false (non-thinking DEFAULT)
|
|
# qwen3.6-35b-a3b-thinking → enable_thinking:true (opt-in reasoning)
|
|
#
|
|
# All tunables live in .env — edit that, not this file.
|
|
|
|
name: qwen36-vl
|
|
|
|
services:
|
|
vllm-qwen36:
|
|
image: ${QWEN_IMAGE}
|
|
container_name: ${QWEN_CONTAINER_NAME}
|
|
restart: unless-stopped
|
|
ipc: host
|
|
ports:
|
|
- "${QWEN_PORT}:8000"
|
|
volumes:
|
|
- /tank/aimodels/huggingface:/hfcache
|
|
environment:
|
|
- HF_HOME=/hfcache
|
|
- HF_HUB_CACHE=/hfcache/hub
|
|
- HUGGING_FACE_HUB_TOKEN=${HF_TOKEN:-}
|
|
- VLLM_API_KEY=${API_KEY:-}
|
|
command:
|
|
- ${QWEN_MODEL}
|
|
# Pre-quantized FP8 checkpoint → NO --quantization (vLLM auto-detects; a
|
|
# forced flag would re-quantize the vision tower to noise, see header).
|
|
- --served-model-name
|
|
- qwen3.6-35b-a3b
|
|
- --host
|
|
- 0.0.0.0
|
|
- --port
|
|
- "8000"
|
|
- --gpu-memory-utilization
|
|
- ${QWEN_GPU_MEM_UTIL}
|
|
- --max-model-len
|
|
- ${QWEN_MAX_MODEL_LEN}
|
|
# Cap concurrency: vLLM warms the sampler with max_num_seqs dummy requests,
|
|
# and this model's 248K vocab makes that warmup tensor huge — the default
|
|
# 1024 OOMs on a shared GPU even though weights+KV fit. 32 is ample for a
|
|
# vision endpoint (the summarizer carries the concurrency, not this).
|
|
- --max-num-seqs
|
|
- ${QWEN_MAX_NUM_SEQS}
|
|
- --kv-cache-dtype
|
|
- fp8
|
|
- --trust-remote-code
|
|
- --dtype
|
|
- auto
|
|
- --enable-prefix-caching
|
|
# Model-matched reasoning parser for the hybrid thinking toggle (see header).
|
|
# Splits <think>…</think> into reasoning_content when thinking is ON; routes
|
|
# all output to content when the empty think-block signals thinking OFF — so
|
|
# this single :8007 endpoint serves both the non-thinking default and the
|
|
# qwen3.6-35b-a3b-thinking gateway variant.
|
|
- --reasoning-parser
|
|
- qwen3
|
|
deploy:
|
|
resources:
|
|
reservations:
|
|
devices:
|
|
- driver: nvidia
|
|
device_ids:
|
|
- "${QWEN_GPU_ID}"
|
|
capabilities:
|
|
- gpu
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 300s
|
|
networks:
|
|
- tnet
|
|
labels:
|
|
- homepage.group=AI Systems
|
|
- homepage.name=Qwen3.6-35B-A3B VL (FP8)
|
|
- homepage.icon=mdi-image-search
|
|
- homepage.description=Qwen3.6-35B-A3B vision-language MoE (FP8) via vLLM (ana-ml2)
|
|
- homepage.href=http://10.250.50.54:${QWEN_PORT}/docs
|
|
|
|
networks:
|
|
tnet:
|
|
name: traefik-net
|
|
external: true
|