# NVIDIA 上跑本地大模型:一张 3090 Ti 跑 27B 免审模型(附下载地址与实测对照) > 一张 3090 Ti 跑 27B 免审模型:改写/翻译类比原双卡快 2.2 倍,日常对话快 32%。代价是量化从 8 位降到 4 位,且质量尚未验证。 上一篇讲的是 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**。选它的三个理由: 1. **零预处理** —— 别的包下回来还得自己跑几个脚本把词表头转成 8 位、再生成一份"小抄词表",得几十分钟还可能出错。这个包作者已经做完了。 2. **自带投机解码所需的部件**(MTP 头 + 40,960 词的草稿词表)—— 这是它比同类快的原因,也是别的包缺的东西。 3. **免审血统和你 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` 自己的下载模块在这条链路上有问题。 **解法两条一起上:** 1. **换国内源**(官方源在墙内被代理拖到 0.1 MB/s,国内镜像直连): ```bash # 实测速度:阿里云 14.16 MB/s、中科大 2.65、腾讯 2.25、清华 1.58、官方 0.10 -i https://mirrors.aliyun.com/pypi/simple/ ``` 2. **换装包工具,用 `uv` 代替 `pip`**(Rust 写的,并行下载 + 重试强): ```bash uv pip install --index-url https://mirrors.aliyun.com/pypi/simple/ vllm==0.29.0 ... ``` **效果:6 分钟装完**(venv 从 0 到 6.4 GB)。`pip` 折腾 40 分钟连三分之一都没到。 ### 完整的安装命令 ```bash # 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` 文件**,照抄即可,一个字都别改。 ```bash # 关键:先设这个,否则 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 ``` 起来后: ```bash 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 -`** ```bash 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 页面也会生成一个小文件,看起来"文件存在"。正确校验: 1. 字节数**精确等于**官方公布的 2. `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` 里有条绕开的路: ```bash 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 目标文件 ""` | | 装依赖 | `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=; 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 实测。* --- **分类**:模型 **标签**:https · 模型 · 实测 **作者**:子龙 **链接**:https://octohz.com/p/2170