ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

部署踩坑实录:vLLM 吞吐高 3 倍却判不准,llama.cpp 反而更稳?

部署踩坑实录:vLLM 吞吐高 3 倍却判不准,llama.cpp 反而更稳? 部署踩坑实录vLLM 吞吐高 3 倍却判不准llama.cpp 反而更稳【免费下载链接】SemIf-OpenJevSemantic ifs from open models, on a 3090 at home. Independent; not affiliated with Jev or TypeSafe.项目地址: https://gitcode.com/gh_mirrors/op/SemIf-OpenJev同样的 Qwen3.5-4B同样的 4-bit 量化在 RTX 3090 上vLLMAWQ吞吐高出 3–5 倍、单条延迟低约 5 倍却在 18 条边界样本上只判对 16 条llama.cppGGUF跑得慢却 18/18 全对。这不是玄学而是量化方案在注意力头与线性层上的精度取舍被摊到了明面上。本文以社区实测为线索结合 SemIf-OpenJev 仓库中一份「同模型、同状态、同 21 个判据」的受控对照实验拆解吞吐与判准在路由场景里到底该怎么选。一、先把账算清吞吐和准确率分别差在哪社区里那篇 3090 上的对比实验控制条件是严格的单字母判别任务A/B、上下文 8192、4-bit 量化、禁用思考模式。结论也很干脆——vLLM 吞吐高 3–5 倍单条延迟低约 5 倍但 llama.cpp 在 18 条刻意构造的边界样本上全部命中vLLM 漏了 2 条且差异恰好集中在在读生这类需要严格证据边界的识别上。这类数字单独看没有任何问题AWQ 走 GPU 批处理连续请求的流水线效率天然高于 llama.cpp 单上下文串行解码。问题在于吞吐的赢法和判准的输法是同一个原因——量化策略。AWQ 的核心思路是保留对激活值影响最大的少量权重通道把误差集中在不重要的通道上GGUF 的 K-quant如 Q4_K_M则把更多比特预算留给注意力头等敏感层并在块级做更细的缩放。对生成式对话这个差异可能只表现为流畅度对语义判别任务边界句的判断往往就悬在几个 logit 的零点几差距上量化误差直接改变 argmax。仓库里恰好有一组能印证边界决定成败的受控数据。在 results/raw/decision-vs-compact-array.json 记录的实验中冻结同一个 Qwen3.5-4B、同一份 21 条判据的共享状态跑了两条路径直接读取选项 logits与让模型生成一段紧凑的 yes/no 数组输出路径耗时中位数输出 token结果直接读取 typed logits1.023 s021 组概率对自回归生成紧凑 JSON 数组5.332 s11121 项合法数组生成路径的首 token 只要 0.489 s但把数组写完比直接读取慢了5.21 倍。更关键的细节是两组输出的 argmax 在 21 条判据上只一致了18/21——同一个模型、同一个状态仅仅因为读取方式不同就翻掉了 3 条边界决策。这跟社区对比里 18 vs 16 的差异是同一类现象决策任务对数值路径的敏感度远高于对话任务。二、仓库里的完整对照快路径到底牺牲了什么把对照再推进一步docs/RESULTS.md 给出了 37 个状态 × 21 条判据、共 777 个决策的完整实测RTX 3090执行路径Decisions/s777 决策总耗时相对 fresh 的 argmax 漂移fresh 直接读取batch 12.33333.1 s基准串行前缀复用10.7572.3 s5/777并行共享状态后缀20.0338.8 s6/777快路径前缀缓存 分支并行把吞吐拉高了近 9 倍代价是 777 个决策里有 5–6 个 argmax 发生了变化——而且每次变化都涉及某个执行形态下 0.5/0.5 的平局。也就是说这些快路径不是数值上逐位等价的优化而是在多数决策上等价、在平局决策上可能翻转的近似。它改变的不是 777 条里哪些一定对而是哪些本就在边界上。这正是语义路由场景最忌讳的吞吐优化的对象恰恰是批量的、可预测的决策而判准最需要的恰恰是边界上那几条。两条需求在量化与并行优化上互相拉扯。三、量化策略差异AWQ 与 GGUF 在注意力头上的精度取舍社区对比把差异归因于量化差异集中在注意力头与线性层精度保留策略仓库的 MLX 量化实验给出了直接证据链。在 docs/MLX.md 描述的流程里从同一个 BF16 固定 checkpoint 出发做 group-size 64 的仿射量化results/mlx/README.md 记录了 252 条质量用例的完整对比精度Authored144 平衡准确率Perturbations108 平衡准确率改变的决策authored / perturbations最大概率移动BF1681.32%77.99%0 / 0—Q881.85%76.58%2 / 40.1761Q478.92%79.89%14 / 60.6776两行数字讲清楚了取舍Q8 只动 6/252 个决策、最大概率移动 0.176Q4 动了 20/252 个决策、最大概率移动高达 0.678——接近一次从确定是 A到确定是 B的翻转。更值得警惕的是生成路径两个量化模型在三次紧凑数组生成里都只给出 20/21 个答案全部被记为失败完成证据而不是更快的结果而直接读取路径每次都返回全部 21 个决策。这也解释了为什么仓库为 CPU 部署保留 llama.cpp 后端时如此谨慎。src/semif_phase1/llamacpp_backend.py 里GGUF 权重加载后不是直接开跑而是先做三层校验GGUF 词汇表必须与参考 tokenizer 逐 token 一致每个答案槽位必须是独立的单 tokenLETTERS的 A–P完整 prompt 的prompt_sha256必须与 Torch 后端逐行一致。也就是说llama.cpp 在仓库里被定位成用 CPU 和 GGUF 换取可对照的判定而不是更快的服务——它的n_gpu_layers 0src/semif_phase1/llamacpp_backend.py 的_cpu_model_params推理结果被显式标注为基于量化权重的条件选项分数未经校准。这张回放海报demo/index.html 的配套资源直观展示了同一冻结 4B 模型下两条路径的形态差异typed 决策在 t0 对齐后整体出现生成路径则逐 token 流动——延迟优势与判准风险都藏在这张图里。四、结论路由场景该为吞吐买单还是为准入买单回到最初的问题。如果你在 3090 上只部署一个 4B 判别模型做路由社区对比和仓库数据给出的答案是一致的吞吐优先时vLLM/AWQ 是对的。3–5 倍的吞吐差在批量请求下是实打实的成本节省且 AWQ 的精度损失在多数常规样本上无感。代价是边界样本的漏判率升高——如果你能接受 18 条里漏 2 条并走人工兜底这是最经济的选择。判准优先时llama.cpp/GGUF 更稳。它慢但精度保留策略更贴合注意力头敏感的任务仓库的 Q4_K_Mmanifests/models.json 记录的 3.01 GB 浏览器产物在同级量化里保持了相对稳定的决策一致性。对在读生识别这类证据边界强相关的判据这一点直接决定线上是否误放。不要用对话模型的标准衡量决策模型。仓库的核心基线src/semif_phase1/direct.py证明一次前向、读选项 token 的 logits、不生成任何 token21 条判据 1.023 s 出齐——这比任何让模型说话再解析的方案都快且可审计。吞吐焦虑在很多场景下其实是在错误的地方生成 token造成的。量化必须按决策负载单独评估。BF16 是仓库默认精度src/semif_phase1/cli.py 的--dtype bfloat16任何--mlx-bits 4或 GGUF Q4 都要先跑一遍 252 条质量用例数一数 changed choices——而不是看 ECE 或困惑度。边界句的 0.6 概率移动在路由准入里就是一条误放。最后给一个务实的工程配方把吞吐敏感的常规决策和边界敏感的准入决策拆成两条路径前者走 vLLM 批量服务后者走 llama.cpp 这类低吞吐高判准路径并保留完整的prompt_sha256、模型 revision、GGUF 校验和记录src/semif_phase1/llamacpp_backend.py 的gguf_record就是这么设计的。这样你既拿到了 3–5 倍的吞吐也不用为 18 条里那 2 条漏判买单——前提是你得先知道自己的负载里藏着多少条边界样本。【免费下载链接】SemIf-OpenJevSemantic ifs from open models, on a 3090 at home. Independent; not affiliated with Jev or TypeSafe.项目地址: https://gitcode.com/gh_mirrors/op/SemIf-OpenJev创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进