
上一篇讲的是 Mac(Apple 芯片)。这篇讲英伟达。
同样一句话先给结论:
一张 24G 的 3090 Ti 跑 27B 免审模型:改写/翻译类任务比原来的双卡方案快 2.2 倍,日常对话快 32%。 代价是量化从 8 位降到 4 位 —— 值不值,第六节算了细账。
而且——另一张卡完全空着,还能同时跑图像生成。
一、为什么?先看一个比喻
大模型像一本书。正文可以压缩(这就是"量化"),压得越狠,占地方越小、读得越快,但会损失一点点理解力。
常见的压缩档位:
| 档位 | 好比 | 27B 模型占多大 |
|---|---|---|
| 原始精度(BF16) | 精装大开本 | 约 55 GB |
| FP8(8 位) | 普通平装 | 约 29 GB |
| int4(4 位) | 口袋本 | 约 15 GB |
关键在这里:29 GB 装不进一张 24 GB 的卡,所以必须两张卡分摊(叫 TP=2)——卡之间来回传数据,本身就慢。而 15 GB 塞进一张卡绰绰有余,另一张卡空出来能干别的。
所以"用 4 位"不是省钱的将就,而是让单卡跑得动的必要条件。
二、这次用的免审模型(含地址)
HuggingFace 上叫 Qwen3.8-27B 的 4 位模型有十几个,我挑的这个是唯一一个装完就能跑的:
https://huggingface.co/Ar4ikov/Qwen3.8-27B-Uncensored-AWQ-W4A16-ASYM-HyperQwen
体积 16.9 GB。选它的三个理由:
- 零预处理 —— 别的包下回来还得自己跑几个脚本把词表头转成 8 位、再生成一份"小抄词表",得几十分钟还可能出错。这个包作者已经做完了。
- 自带投机解码所需的部件(MTP 头 + 40,960 词的草稿词表)—— 这是它比同类快的原因,也是别的包缺的东西。
- 免审血统和你 Mac 上那个一致 —— Mac 上跑的
orcarouter/Qwen3.8-27B-Uncensored,这个包就是从同一份权重转过来的。两台机器"性格"一致,不会出现"换了台机器像换了个人"。
这个模型是 4 位混合精度,不是全都压成 4 位:
| 部分 | 精度 |
|---|---|
| 主体线性层(411 个模块) | 4 位(非对称 AWQ,group 128) |
| 输出词表头 / 输入词表 / 投机头 / 草稿词表 | 8 位 |
| 视觉塔 / 部分门控投影 / 归一化层 | 保持 16 位不动 |
所以它其实是"哪儿该压、哪儿不能压"分开处理的,这也解释了为什么它比粗暴全压成 4 位的好用。
三、引擎:HyperQwen
模型只是"书",还得有"读书的人"(推理引擎)。这次用的引擎:
https://github.com/syv-ai/HyperQwen ← 引擎本体(★1652)
https://github.com/Ar4ikov/vllm-hyprfastQwen ← 上面那个模型作者的配套仓库,有现成配置
它做了什么?简单说:vLLM(主流推理引擎)+ 42 个补丁,专门为"一张 24G 卡跑 27B"调优。核心是投机解码——
打个比方:模型正常是"一个字一个字往外蹦"。投机解码是先猜 7~15 个字,再一次性验证猜得对不对。猜对了就一次性吐出来,所以快。
猜得准不准,取决于任务。这点后面实测会看到,差别非常大。
四、安装:这里有个大坑,先说
坑:这台机器上 pip 基本不可用
装引擎要下 3~4 GB 的 Python 依赖。用 pip 装?实测 0.08 MB/s,要 10 小时。
奇怪的是同一个下载地址,用 curl 测是 11.93 MB/s —— 差 140 倍。说明不是网络问题,是 pip 自己的下载模块在这条链路上有问题。
解法两条一起上:
- 换国内源(官方源在墙内被代理拖到 0.1 MB/s,国内镜像直连):
# 实测速度:阿里云 14.16 MB/s、中科大 2.65、腾讯 2.25、清华 1.58、官方 0.10
-i https://mirrors.aliyun.com/pypi/simple/
- 换装包工具,用
uv代替pip(Rust 写的,并行下载 + 重试强):
uv pip install --index-url https://mirrors.aliyun.com/pypi/simple/ vllm==0.29.0 ...
效果:6 分钟装完(venv 从 0 到 6.4 GB)。pip 折腾 40 分钟连三分之一都没到。
完整的安装命令
# 1. 取引擎(用上游 main,不要用作者的分支——上游已经正式收录了这个包,且新 23 个提交)
git clone https://github.com/syv-ai/HyperQwen ~/qwen-serving
cd ~/qwen-serving
# 2. 建环境(用 uv + 阿里云,见上)
python3 -m venv venv
venv/bin/uv pip install --python venv/bin/python \
--index-url https://mirrors.aliyun.com/pypi/simple/ \
vllm==0.29.0 huggingface_hub ninja pandas
# 3. 打补丁(42 个,必须全打)
sed -e 's/#.*//' -e 's/^[[:space:]]*//;s/[[:space:]]*$//' -e '/^$/d' patches/series |
while IFS= read -r name; do
case "$name" in
dflash2-backport.patch) continue ;; # 0.28 起已是原生,跳过
esac
patch -p1 -d venv/lib/python3.12/site-packages/vllm < "patches/$name"
done
# 4. 下模型(用 curl,不要用 hf download,原因见第六节坑 1)
curl -L -C - --retry 5 --retry-all-errors \
-o qwen38-uncensored-asym/model.safetensors \
"https://huggingface.co/Ar4ikov/Qwen3.8-27B-Uncensored-AWQ-W4A16-ASYM-HyperQwen/resolve/main/model.safetensors"
# 5. 自检(官方脚本,8 项检查)
MODEL=$PWD/models/qwen38-uncensored-asym bash verify.sh --no-server
# → 期望输出末尾:verify: OK (0 failures)
五、启动:照抄作者的配置文件,不要自己拼参数
这一步我连错三次,全部记录在第六节。结论写在前面:
作者的配套仓库 Ar4ikov/vllm-hyprfastQwen 里有个 configs/ 目录,每个档位存成了一个 .env 文件,照抄即可,一个字都别改。
# 关键:先设这个,否则 FlashInfer 编译内核时报 assert cuda_home is not None
export CUDA_HOME=/usr/local/cuda-13.0 # 换成你机器上 nvcc 13.0 的位置
export PATH=$CUDA_HOME/bin:$PATH
# 单会话默认档(configs/single-dflash2.env)
MODEL=/path/to/qwen38-uncensored-asym \
SPEC=dflash2 CTX=fast PREFIX_CACHE=1 VISION=1 \
KV_MEM=4300000000 DFLASH_MAX_LEN=49152 \
bash single-user/start_qwen.sh
起来后:
curl http://localhost:18020/v1/models \
-H "Authorization: Bearer $(cat api_key.txt)"
curl -X POST http://localhost:18020/v1/chat/completions \
-H "Authorization: Bearer $(cat api_key.txt)" \
-H "Content-Type: application/json" \
-d '{"model": "qwen3.8-27b",
"messages": [{"role": "user", "content": "你好"}],
"chat_template_kwargs": {"enable_thinking": false}}'
⚠️ 服务默认绑
0.0.0.0且不鉴权,一定要先生成密钥:openssl rand -hex 24 > api_key.txt
六、实测数据
硬件:2 × RTX 3090 Ti 24GB(显存带宽 1008 GB/s,功耗上限 450W) 采样参数:T 1.0 / top-p 0.95 / top-k 20(模型默认)
三个档位,速度差别很大
| 档位 | 单流 C1 | 4 并发 | 8 并发 | 64 并发 | 引用型 |
|---|---|---|---|---|---|
| D(单会话默认) | 102.3 | 240.8 | 208.3 | — | 266.2 |
| P(改写优化) | 95.9 | 169.2 | 173.0 | — | 315.7 |
| B(batch 后端) | 48.3 | — | — | 1,243.6 | — |
| 原来那套(双卡 FP8,8 位) | 77.4 | 279.9 | 做不到 | — | 121.3 |
单位 tok/s。「引用型」指要求模型逐字改写/翻译/引用给定文本的任务。
怎么读这张表
① 单流赢了,而且赢在关键处
原来开放生成是 77.4,现在是 102.3 —— 快 32%。而"引用型"从 121.3 涨到 266.2 —— 快 2.2 倍。
为什么引用型快这么多?回到那个比喻:投机解码先猜后验。当任务要求"把这段文字改写成正式风格"时,答案大量照抄原文,猜起来几乎不会错 —— 实测"平均每次验证能通过 6.26 个 token"(普通开放式写作只有 1.88)。
这正是 agent 场景的典型任务:改代码、翻译、整理文档、RAG 引用资料。
② 并发还是原来那套强
4 并发以上,原来那套(双卡分摊)反而更快(279.9 vs 240.8)。因为新方案为了换速度牺牲了请求槽位。
你要是一两个人用,这个差距吃不到。要是给多个系统提供 API,就得切 batch 档。
③ batch 档的 64 并发 = 1,243.6 tok/s
作者公布的是 1,169,我们实测反超了。但代价极大:单流掉到 48.3(从 102.3 掉一半多)。因为 batch 档把投机解码整个关了 —— 猜字省的是延迟,在大批量下反而拖累总吞吐。
一个人用不上,别开。
⚠️ 代价:量化从 8 位降到了 4 位
上面全是"赚",这一节说"花"。
原来那套是 FP8(8 位),新方案是 int4(4 位,混合精度)。虽然 4 位主体之外,词表头和视觉塔都保留在 8 位 / 16 位没动,但主体权重确实降了一档。
这笔质量损失目前还没有实测数据:
- 官方只公布了基础版的精度(IFBench 78.3,比未量化的 79.5 低 1.2 分;困惑度 8.09)
- 我们用这个是免审版,去审查的处理和官方测的基础版不是同一条技术路线,官方没测过
- 我们自己也还没做质量对比(拒答探针、能力抽检都没跑)
所以现在:速度账算清了,质量账还是空的。
| 你的用途 | 建议 |
|---|---|
| 大量改写 / 翻译 / 改代码 / 查资料问答 | 快 2.2 倍,值得(但建议先补质量验证) |
| 主要是聊天、写作 | 只快 32%,要掂量 8 位换 4 位的代价 |
| 要给多个系统提供 API | 原来那套并发更强(279.9 对 240.8),留原来的 |
| 需要腾一张卡同时跑图像生成 | 原来那套两张卡都占了,新方案只占一张 |
功耗
跑满时 GPU 吃 446W(上限 450W),利用率 100%。另一张卡 24W、完全空闲。
七、踩的坑
坑 1:hf download 已经不续传了(这个最坑)
大模型下到一半断了,重新跑同一条命令 —— 它从头开始。
我实测验证过:下到 80MB 时强杀,重跑,目录里出现两个分片:
旧的:80 MB 尾缀 51f288c6 inode 18886365 ← 原地不动,废了
新的:从 0 长到 180MB 尾缀 92caa2be inode 18886366
同一个文件本该是同一个 inode 继续变大。
原因:huggingface_hub 从 v1.18.0(2026-06-05) 起把跨进程续传删掉了(上游 PR#4306,为修缓存损坏)。上游 issue #4196 就叫《No resuming of downloads》,至今未修。
注意别被官方文档误导:文档说"失败下载会默认续传",那指的是同一个进程内的重试,不包括"杀掉重跑命令"。
解法:改用 curl -L -C -
curl -L -C - --retry 5 --retry-delay 10 --retry-all-errors --max-time 5400 \
-H "Authorization: Bearer $(cat ~/.hf_token)" \
-o model.safetensors "<模型的 resolve 地址>"
HF 的下载地址实测支持断点续传(响应头有 accept-ranges: bytes)。外面套一层循环,每次先看文件大小对不对、不对就再 curl 一次。
想要 hf download 也能续传:把 huggingface_hub 钉回 1.17.0 或更低(单独建个小环境专门下载,别动引擎那个环境)。
坑 2:装完必须自检,别信"下完了"
HF 的 404 页面也会生成一个小文件,看起来"文件存在"。正确校验:
- 字节数精确等于官方公布的
safetensors头部能解析,且"张量数据末端"等于文件实际大小
我们下完的校验结果:
大小:16195402152 字节 ← 与官方一字不差
张量数:2388
数据末端:16195402152 ← 等于文件大小,说明没截断、没空洞
坑 3:PREFIX_CACHE=1 不能漏
这个参数让多个请求共享同一段前缀的缓存。如果你的请求都带同一段系统提示(agent 场景基本都是),漏了它每次都要重算一遍前缀。
作者的实测:64 个请求共享 5,800 token 的系统提示,不开 222 秒,开了 17 秒。
坑 4:FlashInfer 要现场编译内核
某些档位(batch 模式、CTX=long)第一次启动会现场编译一个 GPU 内核。报错长这样:
AssertionError: cuda_home is not None
或者 Ninja build failed。
解法:设好 CUDA_HOME 指向 nvcc,且 nvcc 版本必须与 CUDA 头文件的 CUDART_VERSION 完全相等(大一点小一点都不行)。
如果实在编不过(比如 batch 档的 fp8 KV 内核),batch/start_qwen.sh 里有条绕开的路:
KV=int4pth # 改用 Triton 后端,只要 C 编译器,不要 nvcc
我们就是这样把 batch 档跑起来的(代价:上下文换成 262k、解码慢约 1.5 倍,但我们实测 64 并发仍有 1,243.6)。
坑 5:别自己拼参数(我连错三次)
第 1 次:漏传 KV_MEM → 引擎自动开池到 49,059 token
→ 15-token 验证块在 CUDA graph 捕获阶段显存不够
第 2 次:我以为"池子太大",把 KV_MEM 从 4.3e9 砍到 3.3e9
→ 报错:3.9 GiB KV cache is needed, which is larger than 3.06 GiB
← 方向完全反了,是太小不是太大
第 3 次:漏了 PREFIX_CACHE / DFLASH_TOKENS / INT8_ACT
→ 引用型只有 160 tok/s 而不是 315.7
正解:作者从不动 KV_MEM —— 两个档位的 KV_MEM 都是 4300000000,优化档只是把 DFLASH_MAX_LEN 从 49152 降到 36864。
照抄之后,池子读数(D 档 49,662 token、P 档 37,834 token)与作者文档逐字一致 —— 这就是配置对了的证据。
通用教训:配任何第三方项目,先去它的仓库找有没有
configs/*.env、profiles/*.env之类的现成配置。有就照抄。只有确认没有时,才自己拼参数 —— 而且拼之前先读它的启动脚本和相关docs/。
坑 6:别用 launchctl submit 调度"延迟重启"
这条跟模型无关,但差点把整台开发环境搞崩。
我为了"延迟重启一次服务",用 launchctl submit 建了个任务。结果 launchd 会反复重跑这个任务,而任务内容是"杀掉并重启 DSH" —— 于是变成每 15 秒自杀一次的死循环,服务永远站不稳,日志还干净得没有任何报错。
正确做法:用 nohup ... & disown,别用 launchd 调度这类一次性动作。万一建了 launchd 任务,跑完立刻 launchctl bootout。
八、速查表
| 你要做什么 | 命令 / 地址 |
|---|---|
| 下模型 | curl -L -C - --retry 5 --retry-all-errors -o 目标文件 "<resolve 地址>" |
| 装依赖 | uv pip install --index-url https://mirrors.aliyun.com/pypi/simple/ ... |
| 打补丁 | patches/series 按行 patch -p1 -d venv/.../vllm < patches/<名字> |
| 自检 | MODEL=<模型目录> bash verify.sh --no-server → 期望 OK (0 failures) |
| 设编译环境 | export CUDA_HOME=<nvcc 13.0 目录>; export PATH=$CUDA_HOME/bin:$PATH |
| 启动(单会话) | SPEC=dflash2 CTX=fast PREFIX_CACHE=1 VISION=1 KV_MEM=4300000000 DFLASH_MAX_LEN=49152 bash single-user/start_qwen.sh |
| 启动(batch) | VISION=1 KV=int4pth bash batch/start_qwen.sh |
| 关思维链 | 请求体加 "chat_template_kwargs": {"enable_thinking": false} |
关键地址
| 东西 | 地址 |
|---|---|
| 免审模型 | https://huggingface.co/Ar4ikov/Qwen3.8-27B-Uncensored-AWQ-W4A16-ASYM-HyperQwen |
| 引擎 | https://github.com/syv-ai/HyperQwen |
| 作者配套(含现成配置) | https://github.com/Ar4ikov/vllm-hyprfastQwen |
| 现成配置目录 | 上面仓库的 configs/ |
最后一句
Mac 那篇的结论是"稠密选小、MoE 选大";这篇的结论是"选对档位,比选对硬件更重要"。
同一个模型、同一张卡,配置对与不对,引用型任务能差 2 倍(160 vs 315.7)。而这个配置作者早就写好放在仓库里了 —— 我花了五次重启才想到去抄。
测试环境:2 × RTX 3090 Ti 24GB(1008 GB/s,450W),Ubuntu 24.04,vLLM 0.29.0 + HyperQwen 42 补丁,2026-09-23 实测。
暂无评论
