Qwen3.8 27B, 单卡也可以跑191 tok/s : 一套优化到极致的部署与实测
-
测试平台 尔英12700H DDR4 64G 技嘉3090 24G



.me/uploads/9cf793af-b18b-4eb8-bdb4-ec1a8fe535a9.png)


-
也部署了这个仓库:vLLM vs llama.cpp 同条件 A/B(3090 单卡,128K 上下文)
楼主好,也部署了这个仓库(vLLM 0.28 + W4A16 AutoRound-fast + DFlash2),同样是单卡 3090 24G。但我的用法和楼主不太一样:我是拿它给 agent 长会话(DSH)当后端,每步平均上下文约 79K token,比仓库标准测速的 ~190 token 深得多。所以顺手做了 vLLM 和 llama.cpp 的同条件 A/B 对比,数据放出来供参考。
部署配置
项 vLLM 侧 llama.cpp 侧 硬件 RTX 3090 24G 独占(功耗墙 280W),另有 3070 8G 未参与 同左 环境 Windows 10 + WSL2 (Ubuntu),vLLM 0.28.0 原生 venv llama.cpp,Windows 原生 模型 Qwen3.8-27B-W4A16-AutoRound-fast(项目自带,与楼主同款)Qwen3.8-27B-Uncensored-Q4_K_M.ggufKV 精度 int8( int8_per_token_head,CTX=long)q8_0 上下文上限 131072 131072 投机解码 DFlash2,7 草稿 draft-mtp,3 草稿 视觉塔 启用 启用(mmproj F16) 环境备注:Docker 路线放弃了——NVIDIA Container Toolkit 的 nvidia.github.io 源国内实测 0~1 KB/s,清华/中科大/阿里云镜像全 404/403。改走 WSL2 原生 venv + 离线 wheel(torch/vllm/triton/flashinfer 共 180 个 wheel 离线备好),装完不需要 toolkit。
测试口径(保证可比性的 5 条)
- decode = completion_tokens / (total − ttft),严格剔除预填,绝不把 prefill 平均进去
- 用真实提示词(仓库文档 + vLLM 源码,约 3.2 MB),不用随机 token——投机解码接受率完全取决于草稿能否猜中,随机 token 跑分没有意义
- 每个提示词加盐,避免被前缀缓存服务,测到的才是「冷」预填
- 先预热再测,丢弃首轮(含 JIT 编译,读数偏低 30~50%)
- 两侧都关思考(
enable_thinking: false)——否则思考 token 会把max_tokens预算吃光,两边不可比(实测:不关时 16 token 全被思考占掉,content为空)
实测数据
冷预填
上下文 vLLM llama ~1K 1141 t/s(0.90s) 977 t/s(1.05s) ~3.8K 1141 t/s(3.37s) 1083 t/s(3.54s) ~15.7K 936 t/s(16.78s) 1070 t/s(14.68s) ~44K 645 t/s(67.44s) 936 t/s(47.08s) vLLM 预填随上下文衰减明显(1141→645),llama 平稳得多(977→936),15.7K 起反超,44K 处快 45%。
★ 深上下文 decode(核心发现)
上下文 vLLM llama 胜负 ~1.9K 96.4 t/s 48.7 t/s vLLM 2.0× ~7.6K 72.1 t/s 50.7 t/s vLLM 1.4× ~23K 40.7 t/s 44.9 t/s llama 1.1× ~44K 29.2 t/s 42.4 t/s llama 1.45× ~75K 18.2 t/s 42.0 t/s llama 2.3× 差距不在绝对速度,在衰减曲线的形状:
vLLM : 96.4 → 18.2 t/s 掉 −81% ← 断崖式衰减 llama: 48.7 → 42.0 t/s 掉 −14% ← 几乎平坦交叉点在 20K 附近:浅上下文 vLLM 快一倍,深上下文 llama 反超且差距持续拉大。
前缀缓存(对 agent 场景价值最大的一项)
冷 TTFT 热 TTFT 加速 命中率 vLLM 39.38s 2.17s 18.2× 96% llama 31.65s 0.21s 147.6× 100% agent 场景反复发送同一前缀(工具定义 + 历史消息),llama 热启动几乎瞬时,这项差异直接体现在每一轮的响应延迟上。
根因分析
vLLM 为什么深上下文崩得快:
- 投机解码验证开销随上下文线性增长:DFlash2 每步要对 7 个草稿 token 做一次多查询验证注意力,上下文越长这一步的 KV 读取越贵。DFlash2 接受率 48.0%、tokens/step 4.36——这是它浅上下文快 2 倍的直接原因,但这个优势随上下文增长迅速蒸发
- int8 KV 反量化开销:CTX=long 用
int8_per_token_head配 Triton attention 反量化,llama 的 q8_0 KV 有更成熟的 dequant 路径 - CUDA graph 捕获尺寸限制:为了不 OOM,
max_cudagraph_capture_size被压到 32,深上下文的部分 shape 落到 eager 路径
llama 为什么能保持平坦:
draft-mtp是模型自带的 MTP 头(非独立草稿模型),验证成本远低于 DFlash2 的 7 草稿 + 路径选择器,GGML 的 KV 管理也更直接。代价是浅上下文只有 vLLM 的一半——MTP 接受率不如 DFlash2。结论与建议
场景 推荐 理由 agent 长会话(20K+ 上下文) llama.cpp 75K 处快 2.3×;热启动 0.21s 短问答 / 单轮任务 vLLM 1.9K 处快 2.0× 需要视觉 两者都支持 都加载了视觉塔 我的当前决策:日常主力切回 llama.cpp,vLLM 方案完整保留作备选。
给楼主和各位两个提示:
- 仓库标准测速(8 条真实聊天 prompt,~190 token)覆盖的是 vLLM 占优的浅上下文区间;如果拿来做 agent 长会话,建议补一组深上下文 decode 测试(23K/44K/75K),否则断崖要等真实使用才会暴露
- 「128K prefill 1200t/s」应该是前缀缓存开启 + 固定 prompt 的口径;我们的「冷预填」(加盐防前缀缓存命中)在 44K 是 645 t/s 且还在衰减。两个数字都对,口径不同
顺带:无审查版也测了
leminkozey/Qwen3.8-27B-Uncensored-W4A16-AutoRound(同 AutoRound W4A16 配方,abliterated 无审查版):DFlash2 接受率 52.2%(略高于官方版 48.0%)、tokens/step 4.66,浅上下文 ~100 tok/s,245K 上下文。深上下文衰减曲线与官方版一致——瓶颈在 vLLM/DFlash2 侧,不在模型侧。一个 Qwen3.8 的坑(与部署无关但很影响体验)
Qwen3.8 官方
chat_template.jinja默认reasoning_effort=xhigh,思考 token 会把输出预算烧光导致content为空(实测同问题 xhigh=373 token / low=136 /enable_thinking=false=28,答案质量无差异)。vLLM 侧用请求参数{"chat_template_kwargs": {"enable_thinking": false}}即可覆盖,不用换模板。 -
也部署了这个仓库:vLLM vs llama.cpp 同条件 A/B(3090 单卡,128K 上下文)
楼主好,也部署了这个仓库(vLLM 0.28 + W4A16 AutoRound-fast + DFlash2),同样是单卡 3090 24G。但我的用法和楼主不太一样:我是拿它给 agent 长会话(DSH)当后端,每步平均上下文约 79K token,比仓库标准测速的 ~190 token 深得多。所以顺手做了 vLLM 和 llama.cpp 的同条件 A/B 对比,数据放出来供参考。
部署配置
项 vLLM 侧 llama.cpp 侧 硬件 RTX 3090 24G 独占(功耗墙 280W),另有 3070 8G 未参与 同左 环境 Windows 10 + WSL2 (Ubuntu),vLLM 0.28.0 原生 venv llama.cpp,Windows 原生 模型 Qwen3.8-27B-W4A16-AutoRound-fast(项目自带,与楼主同款)Qwen3.8-27B-Uncensored-Q4_K_M.ggufKV 精度 int8( int8_per_token_head,CTX=long)q8_0 上下文上限 131072 131072 投机解码 DFlash2,7 草稿 draft-mtp,3 草稿 视觉塔 启用 启用(mmproj F16) 环境备注:Docker 路线放弃了——NVIDIA Container Toolkit 的 nvidia.github.io 源国内实测 0~1 KB/s,清华/中科大/阿里云镜像全 404/403。改走 WSL2 原生 venv + 离线 wheel(torch/vllm/triton/flashinfer 共 180 个 wheel 离线备好),装完不需要 toolkit。
测试口径(保证可比性的 5 条)
- decode = completion_tokens / (total − ttft),严格剔除预填,绝不把 prefill 平均进去
- 用真实提示词(仓库文档 + vLLM 源码,约 3.2 MB),不用随机 token——投机解码接受率完全取决于草稿能否猜中,随机 token 跑分没有意义
- 每个提示词加盐,避免被前缀缓存服务,测到的才是「冷」预填
- 先预热再测,丢弃首轮(含 JIT 编译,读数偏低 30~50%)
- 两侧都关思考(
enable_thinking: false)——否则思考 token 会把max_tokens预算吃光,两边不可比(实测:不关时 16 token 全被思考占掉,content为空)
实测数据
冷预填
上下文 vLLM llama ~1K 1141 t/s(0.90s) 977 t/s(1.05s) ~3.8K 1141 t/s(3.37s) 1083 t/s(3.54s) ~15.7K 936 t/s(16.78s) 1070 t/s(14.68s) ~44K 645 t/s(67.44s) 936 t/s(47.08s) vLLM 预填随上下文衰减明显(1141→645),llama 平稳得多(977→936),15.7K 起反超,44K 处快 45%。
★ 深上下文 decode(核心发现)
上下文 vLLM llama 胜负 ~1.9K 96.4 t/s 48.7 t/s vLLM 2.0× ~7.6K 72.1 t/s 50.7 t/s vLLM 1.4× ~23K 40.7 t/s 44.9 t/s llama 1.1× ~44K 29.2 t/s 42.4 t/s llama 1.45× ~75K 18.2 t/s 42.0 t/s llama 2.3× 差距不在绝对速度,在衰减曲线的形状:
vLLM : 96.4 → 18.2 t/s 掉 −81% ← 断崖式衰减 llama: 48.7 → 42.0 t/s 掉 −14% ← 几乎平坦交叉点在 20K 附近:浅上下文 vLLM 快一倍,深上下文 llama 反超且差距持续拉大。
前缀缓存(对 agent 场景价值最大的一项)
冷 TTFT 热 TTFT 加速 命中率 vLLM 39.38s 2.17s 18.2× 96% llama 31.65s 0.21s 147.6× 100% agent 场景反复发送同一前缀(工具定义 + 历史消息),llama 热启动几乎瞬时,这项差异直接体现在每一轮的响应延迟上。
根因分析
vLLM 为什么深上下文崩得快:
- 投机解码验证开销随上下文线性增长:DFlash2 每步要对 7 个草稿 token 做一次多查询验证注意力,上下文越长这一步的 KV 读取越贵。DFlash2 接受率 48.0%、tokens/step 4.36——这是它浅上下文快 2 倍的直接原因,但这个优势随上下文增长迅速蒸发
- int8 KV 反量化开销:CTX=long 用
int8_per_token_head配 Triton attention 反量化,llama 的 q8_0 KV 有更成熟的 dequant 路径 - CUDA graph 捕获尺寸限制:为了不 OOM,
max_cudagraph_capture_size被压到 32,深上下文的部分 shape 落到 eager 路径
llama 为什么能保持平坦:
draft-mtp是模型自带的 MTP 头(非独立草稿模型),验证成本远低于 DFlash2 的 7 草稿 + 路径选择器,GGML 的 KV 管理也更直接。代价是浅上下文只有 vLLM 的一半——MTP 接受率不如 DFlash2。结论与建议
场景 推荐 理由 agent 长会话(20K+ 上下文) llama.cpp 75K 处快 2.3×;热启动 0.21s 短问答 / 单轮任务 vLLM 1.9K 处快 2.0× 需要视觉 两者都支持 都加载了视觉塔 我的当前决策:日常主力切回 llama.cpp,vLLM 方案完整保留作备选。
给楼主和各位两个提示:
- 仓库标准测速(8 条真实聊天 prompt,~190 token)覆盖的是 vLLM 占优的浅上下文区间;如果拿来做 agent 长会话,建议补一组深上下文 decode 测试(23K/44K/75K),否则断崖要等真实使用才会暴露
- 「128K prefill 1200t/s」应该是前缀缓存开启 + 固定 prompt 的口径;我们的「冷预填」(加盐防前缀缓存命中)在 44K 是 645 t/s 且还在衰减。两个数字都对,口径不同
顺带:无审查版也测了
leminkozey/Qwen3.8-27B-Uncensored-W4A16-AutoRound(同 AutoRound W4A16 配方,abliterated 无审查版):DFlash2 接受率 52.2%(略高于官方版 48.0%)、tokens/step 4.66,浅上下文 ~100 tok/s,245K 上下文。深上下文衰减曲线与官方版一致——瓶颈在 vLLM/DFlash2 侧,不在模型侧。一个 Qwen3.8 的坑(与部署无关但很影响体验)
Qwen3.8 官方
chat_template.jinja默认reasoning_effort=xhigh,思考 token 会把输出预算烧光导致content为空(实测同问题 xhigh=373 token / low=136 /enable_thinking=false=28,答案质量无差异)。vLLM 侧用请求参数{"chat_template_kwargs": {"enable_thinking": false}}即可覆盖,不用换模板。 -
测试平台 尔英12700H DDR4 64G 技嘉3090 24G



.me/uploads/9cf793af-b18b-4eb8-bdb4-ec1a8fe535a9.png)


-
-
3090 单卡开启 Qwen3.8-27B 图像理解实测:VISION=1 即可,文本/DFlash2 全保留,附可证伪验证
跟着楼主这套
syv-ai/qwen38-27b-rtx3090部署的,环境完全一致:RTX 3090 24G、SPEC=dflash2、CTX=long(131072)、PREFIX_CACHE=1、vLLM 0.28.0。原帖主要讲文本速度,补充一下 图像理解(vision)这条路径 的开启经历,给后来人参考。结论先说:只需要在
.env加一行VISION=1,docker compose --profile single up -d重建即可。 不用换模型、不用动量化、不用牺牲 DFlash2 和上下文长度。1. 模型本来就带完整视觉塔
部署用的
Qwen3.8-27B-W4A16-AutoRound不是纯文本模型,config.json架构是Qwen3_5ForConditionalGeneration,处理器是Qwen3VLProcessor(图像+视频处理器都在)。关键点:量化时model.visual.*视觉塔权重被特意排除在 int4 之外、保持 BF16,约 0.85 GiB 。默认启动参数里的--language-model-only只是把这座塔"摘掉不加载"。2. 实际改了什么
Bash
运行
1
2# /root/qwen38-27b-rtx3090/.env 末尾追加 VISION=1启动后命令行变化(PID 1 实测):
- 移除:
--language-model-only - 新增:
--limit-mm-per-prompt {"image":{"count":1}} - 新增:
--mm-processor-kwargs {"size":{"shortest_edge":65536,"longest_edge":2097152}}
即每轮对话 1 张图、像素上限约 2048 个图像 token(截图/文档照/画面分析足够)。
3. 24G 显存是怎么塞下的:视觉塔 CPU offload
这个是项目自带的私有补丁(
vision-tower-cpu-offload.patch),VISION_OFFLOAD默认就是 1:视觉塔 0.85 GiB 权重常驻 锁页主机内存 ,只在图片编码时把对应模块短暂拷上 GPU,编码完即释放。启动日志可见:1
2Total CPU offloaded parameters: 0.85 GPU KV cache size: 136,429 tokensREADME 里作者也写明了:24G 上
SPEC=dflash2 + VISION=1不开 offload 会在 graph capture 阶段 OOM (960MB 的 split-KV verify buffer 分配不出来),开 offload 后 KV 池不缩水,编码输出与常驻显存逐 bit 一致。单图编码代价约 296→333ms(8192-patch,PCIe 4.0),实测中几乎无感。4. 实测数据(2026-09-27)
启动后 stable healthy,
/health返回 200。显存 22.8/24 GiB,与纯文本模式基本持平。测试 结果 纯文本回归(中文问答) 正常,0.9s,思考链完整 红底+蓝圆+黄方块,问背景/图形/颜色 "背景是红色;图中有一个蓝色的圆形和一个黄色的正方形。" 全对,image tokens=256 白底黑字 OCR(VISION-OK-2026) 逐字符准确读出,image tokens=100
特意用了可证伪的合成图而不是"描述一下这张图"——返回里
usage.prompt_tokens_details.multimodal_tokens.image有计数,能证明图真的进了模型,而不是被静默忽略后瞎编。5. 几个坑/边界,供参考
- 每轮限 1 张图 ,发第 2 张服务端直接 HTTP 400(
At most 1 image(s)),不会 OOM、不影响服务。 - 像素超限只缩放不报错,超大图细节会被压掉。
- 视频理解引擎层支持 (qwen3_5 注册了 image+video 双模态,cv2 解码依赖镜像里自带),但项目只验证过单图路径;而且 vLLM 启动是按最坏情况预留显存的,视频要开必须显式调帧数/分辨率限额,能不能过启动 profiling 是第一道关,目前没开。
- 容器重启策略是
no,开机要手动起。 - 回滚:删掉
VISION=1重建即可(建议先备份.env)。
整体感受:楼主这套方案视觉这块属于"功能都在、默认关掉、留了一个官方开关"的状态,开启成本比预想低很多,24G 单卡图文混合用完全可行.
- 移除:
-
3090 单卡开启 Qwen3.8-27B 图像理解实测:VISION=1 即可,文本/DFlash2 全保留,附可证伪验证
跟着楼主这套
syv-ai/qwen38-27b-rtx3090部署的,环境完全一致:RTX 3090 24G、SPEC=dflash2、CTX=long(131072)、PREFIX_CACHE=1、vLLM 0.28.0。原帖主要讲文本速度,补充一下 图像理解(vision)这条路径 的开启经历,给后来人参考。结论先说:只需要在
.env加一行VISION=1,docker compose --profile single up -d重建即可。 不用换模型、不用动量化、不用牺牲 DFlash2 和上下文长度。1. 模型本来就带完整视觉塔
部署用的
Qwen3.8-27B-W4A16-AutoRound不是纯文本模型,config.json架构是Qwen3_5ForConditionalGeneration,处理器是Qwen3VLProcessor(图像+视频处理器都在)。关键点:量化时model.visual.*视觉塔权重被特意排除在 int4 之外、保持 BF16,约 0.85 GiB 。默认启动参数里的--language-model-only只是把这座塔"摘掉不加载"。2. 实际改了什么
Bash
运行
1
2# /root/qwen38-27b-rtx3090/.env 末尾追加 VISION=1启动后命令行变化(PID 1 实测):
- 移除:
--language-model-only - 新增:
--limit-mm-per-prompt {"image":{"count":1}} - 新增:
--mm-processor-kwargs {"size":{"shortest_edge":65536,"longest_edge":2097152}}
即每轮对话 1 张图、像素上限约 2048 个图像 token(截图/文档照/画面分析足够)。
3. 24G 显存是怎么塞下的:视觉塔 CPU offload
这个是项目自带的私有补丁(
vision-tower-cpu-offload.patch),VISION_OFFLOAD默认就是 1:视觉塔 0.85 GiB 权重常驻 锁页主机内存 ,只在图片编码时把对应模块短暂拷上 GPU,编码完即释放。启动日志可见:1
2Total CPU offloaded parameters: 0.85 GPU KV cache size: 136,429 tokensREADME 里作者也写明了:24G 上
SPEC=dflash2 + VISION=1不开 offload 会在 graph capture 阶段 OOM (960MB 的 split-KV verify buffer 分配不出来),开 offload 后 KV 池不缩水,编码输出与常驻显存逐 bit 一致。单图编码代价约 296→333ms(8192-patch,PCIe 4.0),实测中几乎无感。4. 实测数据(2026-09-27)
启动后 stable healthy,
/health返回 200。显存 22.8/24 GiB,与纯文本模式基本持平。测试 结果 纯文本回归(中文问答) 正常,0.9s,思考链完整 红底+蓝圆+黄方块,问背景/图形/颜色 "背景是红色;图中有一个蓝色的圆形和一个黄色的正方形。" 全对,image tokens=256 白底黑字 OCR(VISION-OK-2026) 逐字符准确读出,image tokens=100
特意用了可证伪的合成图而不是"描述一下这张图"——返回里
usage.prompt_tokens_details.multimodal_tokens.image有计数,能证明图真的进了模型,而不是被静默忽略后瞎编。5. 几个坑/边界,供参考
- 每轮限 1 张图 ,发第 2 张服务端直接 HTTP 400(
At most 1 image(s)),不会 OOM、不影响服务。 - 像素超限只缩放不报错,超大图细节会被压掉。
- 视频理解引擎层支持 (qwen3_5 注册了 image+video 双模态,cv2 解码依赖镜像里自带),但项目只验证过单图路径;而且 vLLM 启动是按最坏情况预留显存的,视频要开必须显式调帧数/分辨率限额,能不能过启动 profiling 是第一道关,目前没开。
- 容器重启策略是
no,开机要手动起。 - 回滚:删掉
VISION=1重建即可(建议先备份.env)。
整体感受:楼主这套方案视觉这块属于"功能都在、默认关掉、留了一个官方开关"的状态,开启成本比预想低很多,24G 单卡图文混合用完全可行.
- 移除:
-
-
-
-
@johnnybegood 您好贴主,可否分享一下双卡3090的实测速度结果和方案呢,目前单卡的上下文拉不到256k,我正在考虑要不要在买一张3090组双卡,采用这个方案可否实现256k上下文并且速度不知道可以增加多少,跪求测试数据了,感谢!!!!
本帖参与讨论人数已达 15+,入选热议,作者 +3 积分奖励,感谢分享!