Qwen3.8-27B-DFlash2-EXL3-5.0bpw README

The project's README from github.com/MiaAI-Lab/Qwen3.8-27B-DFlash2-EXL3-5.0bpw. As one markdown file: README.md.

Qwen3.8-27B · EXL3 · DFlash2

by Mia'a AI Lab

Sponsor me on GitHub Follow Mia on X

Deployment kit for serving Qwen3.8-27B quantized to EXL3 3.5bpw with speculative decoding — MTP by default (draft head inside the checkpoint, best context per GB) or DFlash2 (EXL3 5.0bpw draft model, ~15% faster) — plus a ~4.5-bit KV cache lane (NVFP4 on Ada/Hopper/Blackwell, Hadamard-4 on Ampere) for maximum context per GB.

This repo contains the launcher, server and configuration. The model weights live on Hugging Face (see Model cards) and the inference engine is our exllamav3 fork (DFlash2/MTP drafting, NVFP4/FP8 KV, aarch64 GB10 + x86 CUDA).

What's in the box

file what
start.sh env-driven launcher for the OpenAI-compatible server
stop.sh stop the server (graceful shutdown, safe to re-run)
tools/serve_openai.py the server itself (chat completions, streaming, tool calling)
.env.example documented configuration knobs
model-cards/ model cards for the two HF weight sets

Quick start

# 1. configure and launch:
cp .env.example .env      # edit: context, GPU memory
./start.sh                # first run: builds .venv + installs the engine,
                          # downloads weights, serves http://localhost:8888/v1

start.sh is self-bootstrapping: on first run it creates .venv, installs GPU torch and pip-installs the exllamav3 engine from this fork (all of DFlash2/MTP drafting, NVFP4/FP8 KV and the aarch64 GB10 port are fork features). EXL3_REPO in .env overrides where the engine comes from — any git URL or a local path.

Running on a 24 GB GPU (RTX 3090/4090)? Jump to 24 GB config.

start.sh auto-creates .env from the example on first run, prefers .venv/bin/python when present, and downloads the target and draft weight sets from Hugging Face automatically on first launch (and resumes partial downloads) — no manual fetching. Set HF_TARGET_REPO / HF_DRAFT_REPO in .env to pull from a mirror instead.

Configuration highlights (.env)

Concurrency note: the server generates one request at a time (batch-1 speculative decoding); concurrent requests queue automatically. Measured on DGX Spark with DRAFT=dflash2: 8 concurrent requests ran fully sequentially (no batching benefit), aggregate throughput ~16.7 tok/s at that concurrency — plan capacity accordingly if your workload is concurrent rather than single-request.

Reasoning note: the server always reasons — there is currently no way to disable it. chat_template_kwargs.enable_thinking (the vLLM/SGLang convention) is silently ignored. The reasoning trace comes back in a separate reasoning_content field (both in the full response and in each streamed delta), but it is not a separate token budget: reasoning and visible content both draw from the same max_tokens. With a tight budget (e.g. max_tokens: 16 on a short-answer prompt) I got a response with no content at all, entirely consumed by the reasoning trace — clients expecting a quick, cheap warmup/probe call should budget generously rather than assuming a short max_tokens implies a short wait.

24 GB GPUs (RTX 3090 / 4090)

The kit targets DGX Spark (121 GB) by default. On a 24 GB card the recipe is the same weights, a tighter KV budget, and a ~4.5-bit KV format so the native 262k context still fits. The default drafter (MTP) is the right choice here.

KV format is GPU-dependent. This fork's nvfp4 / fp8 lanes are software packed caches (E2M1 + E4M3 scales, or raw E4M3) with Triton online dequant. Those kernels use fp8e4nv, which Triton only compiles on compute capability ≥ 8.9. They are not Blackwell tensor-core NVFP4 matmul.

GPU Arch CACHE_QUANT for 262k
RTX 4090, GB10, Hopper+ sm ≥ 8.9 nvfp4 (measured lossless at generation level)
RTX 3090 Ampere sm_86 4 (Hadamard int4; same ~4.5 bits/elem). nvfp4 and fp8 will fail to compile
# .env — 24 GB recipe (MTP, the default)
GPU_MEM_GB=22            # auto-detected when unset; explicit for clarity
CONTEXT_SIZE=262144      # full native context fits (see math below)
CACHE_QUANT=nvfp4        # 4090 / GB10 / Hopper+. On a 3090 use: CACHE_QUANT=4
# DRAFT=mtp is the default — no extra config, no draft download
# .env — alternative: DFlash2 at 24 GB
GPU_MEM_GB=22
CONTEXT_SIZE=200000
CACHE_QUANT=nvfp4        # 3090: CACHE_QUANT=4
DRAFT=dflash2
DRAFT_DIR=models/Qwen3.8-27B-DFlash2-EXL3-5.0bpw   # auto-downloaded
# CPU_CACHE_GB=16        # CPU spill tier: NOT YET ACTIVE (planned; see notes)

Memory math (GiB): target weights 14.2 + MTP head 0.05 → ~6.7 GB left for KV at a 22 GB budget; NVFP4 or Hadamard-4 KV costs ~18 KB/token for the target plus ~1.2 KB/token for the MTP head (only the 16 full-attention layers hold KV; fp16 is ~64 KB/token) → the full native 262k fits with ~1 GB to spare. With the DFlash2 draft instead: 15.6 GiB of weights + ~24 KB/token → ~220k–262k. CACHE_QUANT=8 (8.5 bits) needs 9.1 GB at 262k and will not leave that much headroom; fp16 (17 GB at 262k) does not fit. Past the resident limit the cache does not hold today; the CPU spill tier is planned but not yet implemented.

RTX-class notes (vs the DGX Spark the numbers above were measured on):

Tool calling

OpenAI-style tools / tool_choice work (referenced in the file table above but not otherwise documented here). Verified request/response shape:

curl http://localhost:8888/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "qwen3.8-27b-exl3-3.5bpw-wm",
    "messages": [{"role": "user", "content": "What is the weather in Lyon?"}],
    "tools": [{
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Get current weather",
        "parameters": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]}
      }
    }],
    "tool_choice": "auto",
    "max_tokens": 300
  }'

Returns a normal OpenAI tool_calls array (finish_reason: "tool_calls", message.content: null) alongside the usual reasoning_content. The model id in responses doesn't necessarily match HF_TARGET_REPO or MODEL_DIR verbatim (I saw qwen3.8-27b-exl3-3.5bpw-wm for MODEL_DIR=models/Qwen3.8-27B-EXL3-3.5bpw) — check /v1/models rather than assuming the id a client should send.

Model cards

Measured on DGX Spark (GB10): HumanEval-class decode 47.5 tok/s at T=0.6 with acceptance 4.43 tokens/step; tool-eval-bench hardmode @ T=1.0: 87–88 / 100.

License

Code in this repo: MIT. Model weights are Apache-2.0 derivatives (see model cards); exllamav3 is MIT.

Qwen3.8-27B-DFlash2-EXL3-5.0bpw (MiaAI-Lab/Qwen3.8-27B-DFlash2-EXL3-5.0bpw)

Searching Database…

这是什么?一套部署工具包,用于通过 OpenAI 兼容服务器提供 Qwen3.8-27B(量化为 EXL3 3.5bpw)服务,并利用投机解码加速生成。它捆绑了启动器、服务器和配置;模型权重托管在 Hugging Face 上,推理则在团队的 exllamav3 分支上运行。
这是模型本身,还是只有服务代码?只有服务代码。这个仓库包含 start.sh/stop.sh 启动器、tools/serve_openai.py 服务器和 .env 配置;实际权重托管在 Hugging Face(两张模型卡)上,GPU 推理引擎则是单独的 exllamav3 分支。
怎么让它跑起来?运行 start.sh——它是自举式的:首次运行时会创建 .venv、安装 GPU 版 torch、用 pip 安装 exllamav3 分支、根据示例写入 .env,并自动从 Hugging Face 下载目标与草稿权重(支持断点续传)。
运行它需要什么 GPU?一块支持 CUDA 的 Nvidia GPU;该工具包默认面向 DGX Spark(121 GB,GB10/aarch64),但也提供面向 RTX 3090/4090 的 24 GB 配置。NVFP4/FP8 KV 缓存路线需要计算能力 ≥8.9(Ada/Hopper/Blackwell);Ampere(3090,sm86)必须回退到 Hadamard-4 KV 格式。
它能同时处理多个请求吗?不能——服务器一次只生成一个请求(batch-1 投机解码);并发请求只能排队,因此吞吐量不会随并发数扩展(实测在 DGX Spark 上 8 个并发请求时合计约 16.7 tok/s)。
它在任何品牌的 GPU 上都能跑,还是仅限 Nvidia?仅限 Nvidia——它通过 exllamav3 分支基于 CUDA 构建,针对 Ada/Hopper/Blackwell 与 Ampere GPU 分别有专门的 Triton 内核路径,并为 DGX Spark 的 GB10 提供 aarch64 构建。
MTP 和 DFlash2 草稿模式有什么区别?MTP 使用内置于目标检查点的草稿头——无需额外下载,每 GB 可承载的上下文最长,在 DGX Spark 上约 30 tok/s。DFlash2 使用单独的 1.4 GB EXL3 5.0bpw 草稿模型,可达约 34.5 tok/s,但会占用额外的 KV 内存并压缩全量驻留上下文的余量。
它支持多大的上下文窗口?原生上限是 262,144 个 token。把 CONTEXTSIZE 设到 1M 也能工作,启动器会自动换用 YaRN 配置变体,但 262k 被描述为质量保真的上限。
我能关闭模型的推理输出吗?不能——服务器始终会推理,目前没有办法禁用;vLLM/SGLang 的 enable_thinking 标志会被静默忽略,而且推理轨迹与可见答案共用同一个 max_tokens 预算。
它支持工具调用吗?支持——它返回带 finish_reason: 'tool_calls' 的标准 OpenAI tool_calls 数组,经验证在完整响应和流式响应中都能与独立的 reasoning_content 字段共存。
Creator
MiaAI-Lab
Size
0.1 MB
Stars
232
Updated
CommitSep 01
Age
1mo
Commits · 90 Days