Qwen3.8 27B 与 170HX--本地部署大模型(4)

2026年10月13日 · 2829 字 · 6 分钟

第三篇的结尾,故障的 2080 Ti 退役,破解后的 CMP 170HX 上机(解锁过程见第一篇)。40GB 显存第一次让 27B 模型可以单卡完整容纳——Q6_K_XL 权重 23.6GB,还能留下充裕的 KV 空间。这一篇记录这张卡上 27B 部署的一步步演进:从 llama.cpp 的 24 t/s,到 DFlash2 加持下的 95+ t/s(greedy 采样下短上下文可到 145 t/s,两种口径的区别后文会讲清楚)。

平台没有变化,仍是第一篇介绍的那台主机:华南金牌 X99-TF、Xeon E5-2696 v3、128GB 四通道 DDR3。唯一的新变量是显卡本身——以及它那条 Gen2 x4 的 PCIe。

起点:llama.cpp 与 ftllm

170HX 上机后的第一版沿用 llama.cpp(sm_75+sm_80 双架构编译)。单卡 Q6_K_XL 的成绩平平:prefill 约 110 t/s,decode 24.4 t/s。换用 FastLLM(自带 sm_80 kernel)后略有起色:150W 功耗墙下 decode 约 25 t/s,放宽到 200W 后约 30 t/s。

真正的第一个台阶来自官方 MTP 投机头。开 --mtp 3 后,同样的 10K 输入 + 5K 输出长测,端到端从 29.8 t/s 提升到 40.9 t/s(+37%),纯 decode 在 43~47 t/s;短上下文下实测可达 53~60 t/s,波动主要来自 MTP 接受率本身。

另外两个当时定下的结论:

  • KV 缓存首选 fp16:40GB 显存足够宽裕,零精度损失且 prefill 最快;llama.cpp 下可用 q8_0;唯独不要 fp8_e4m3——GA100 没有 FP8 硬件单元,只能走模拟路径,prefill 慢约 40% 且 decode 无收益;
  • Vulkan 不可用:170HX 设备可枚举但计算不执行(破解不含图形通道),这条路线对它关上了门。

散热的前提

插一句题外话:上述 200W 长测能成立,是因为第一篇里那套暴力风扇 + ESP32 温控。装扇之前,150W 持续 4 分钟显存就冲到 82°C(上限 95°C),长负载必须挂温度看门狗兜底;装扇之后 200W 满载,GPU 61°C、显存 71°C 进入平台期,限制解除。

终点:vLLM + W4A16 + DFlash2

最后的演进来自社区的启发。参考 syv-ai 的单卡 3090 配方与日本社区的 170HX 实测(vLLM + DFlash2 单流 177 t/s),于 9 月 11 日部署了完整配方并复现成功:vLLM 0.28.0 + syv-ai 补丁栈全部 30 个补丁 + 模型 lm_head/embed/MTP 重量化(int8/int4)+ DFlash2 草稿(lookup 增强起草)+ FlashAttention bf16 KV + 前缀缓存。配方的思路是把 decode 路径上每一层"税"挨个砍掉:每步少读字节(W4A16 权重从 24GB 压到约 15GB,Marlin kernel 带宽利用率高),每步多产 token(DFlash2 一次前向并行提出 7 个候选,而非自回归逐个猜)。

顺带交代一下量化格式的切换:此前的 Q6_K_XL 是冲着质量选的——6-bit 量化几乎无损。但 W4A16 的速度优势太大:同是无投机,8K 下 55.2 t/s 对 llama.cpp Q6 的 24.4 t/s,已经差了一倍多;叠加 DFlash2 后差距接近四倍。40GB 显存装 15GB 的 W4A16 权重绰绰有余,质量上的那点损失在这样的速度差面前不再重要,最终定案 W4A16。

KV 缓存的精度选择是这套配方里一个容易被忽略的细节:fp16/bf16 KV 比任何量化 KV 都快得多。原因有二:其一,GA100 没有 FP8 硬件单元,fp8 KV 只能靠读入时反量化模拟,省显存但加开销;其二更关键——配方中那枚拆分 KV 的专用验证注意力 kernel 只支持 bf16,一旦 KV 改为 fp8/int8,验证步就要退回通用 kernel,decode 明显变慢。40GB 显存让容量不成问题,量化 KV 在这张卡上也就彻底失去了吸引力。

同条件对照(早期消融实验:默认采样 T=1.0、固定块大小 8、64K 配置,单流):

上下文无投机MTP k=2DFlash2
8K55.2 t/s71.5 t/s86.4 t/s(+57%)
16K约 54 t/s63.4 t/s90.2 t/s(+67%)
32K51.5 t/s47.6 t/s63.9 t/s(+24%)
64K48.0 t/s32.6 t/s42.5 t/s(-11%)

DFlash2 的平均接受长度 2.8~3.9,明显优于 MTP 的 2.2~2.3;但 64K 以上块验证的开销开始超过收益。生产配置(256K 上下文、视觉保留、qwen38-vllm.service 开机自启)在日常默认采样下的日志实测:短上下文 decode 95~99 t/s,prefix cache 命中率 85% 以上。显存账本也很干净:40GB 中权重占 16.5 GiB(主模型 14.7 + 草稿 1.2),KV 缓存 19.3 GiB,按 98% 利用率预占。

服务上线后也接进了 opencode(终端里的 AI 编程 agent):在它的配置里加一个指向 http://127.0.0.1:8123/v1 的自定义 provider 即可,API key 支持 "{file:/path/to/api_key.txt}" 的文件引用写法,不必明文写进配置文件。opencode 的完整配置示例在下一篇。

拉满 256K

40GB 显存相对 3090 的 24GB 多出来的部分,全部换成了上下文:最终配置把上下文拉满到模型原生上限 256K(262,144 tokens),KV 池实测 274,818 tokens——刚好 1.05 倍,严丝合缝。视觉输入也一并验证通过(测试图正确识别,64 个 image tokens;限制为单张)。

256K 配置下的实测速度(greedy 采样,最终调优配置——注意与上一张表的默认采样条件不同,greedy 下草稿与目标输出完全一致、接受率更高,数字不能直接横比):

上下文prefilldecode
0.5K1817 t/s145 t/s
8K2024 t/s131 t/s
64K1619 t/s113 t/s
128K1301 t/s(TTFT 101s)78 t/s

这里展开解释一下 greedy(贪心)采样:每步直接取概率最高的 token,给定相同输入,输出完全确定、可复现。与之相对的默认采样(T=1.0)按概率分布随机抽取,同样的问题每次回答都可能不同。

greedy 的优势很实在:输出确定、可复现,调试、评测和抽取类任务(JSON、格式化、翻译)都需要这种稳定性;在投机解码里它还能把速度推到上限——草稿模型"猜中"即被接受,分布拟合得越好接受率越高,表二的数字就是这么来的。

局限也同样明显。一是长文本容易陷入重复循环,几句话来回说;二是总取最高概率的 token,回答会偏向"最安全"的那个,多样性差——创意写作、头脑风暴这类场景,greedy 的输出往往死板。而默认采样虽然每次回答可能不同,在投机解码里却要按拒绝采样规则逐位校验:即使草稿分布完全准确,也会有一定比例的候选被随机性拒之门外,速度自然低一截。

这就是两张表数字差距的来源:日常聊天多为默认采样,表一的 86~90 t/s 更接近真实体验;表二的 145 t/s 展示的是这套配置在理想条件下的上限。

这张表里两个值得一提的数字:128K 下 decode 仍有 78 t/s,对比原版 vLLM 0.29 的 41 t/s 接近翻倍。换回日常默认采样口径看,256K 配置的短上下文 decode 是 95~99 t/s,与之前 64K 配置的 86~90 t/s 基本持平——等于白赚了 4 倍上下文和视觉。

从 24.4 到 95+(默认采样口径;greedy 下短上下文可到 145),同一张卡、同一个模型,四倍差距全部来自软件栈:量化格式、推理引擎、投机解码,每一层都值得单独折腾。

这条路的边界

这套方案并非没有短板。其一,KV 池只有 1.05 倍余量,长上下文场景实质上是单用户——并发起码捉襟见肘;其二,128K 的 prefill 要 100 秒(好在开了前缀缓存,同一文档第二轮起只要 1 秒);其三,上下文继续加深时 decode 仍会明显衰减:生产日志里 KV 占用接近九成(约 26 万 tokens)时,decode 降到 50~80 t/s,比短上下文少了近一半。

因此它的最终定位是备用与对照:只占 170HX 一张卡,自带视觉,服务文件保留可一键回切。而日常主力已经换成了另一个思路更激进的方案——那是下一篇的内容。