我在65K-128K上下文下对13个模型进行了基准测试,以找出对于代理工作负载真正重要的因素
摘要
对13个本地LLM在65K-128K上下文下的广泛基准测试表明,预填充速度主导了代理工作负载性能(占实际时间的94-99%),使tg128指标具有误导性,并且KV头数量是比参数量或MoE/密集设计更关键的架构因素。
我在65K-128K上下文下对13个模型进行了基准测试,以找出对于代理工作负载真正重要的因素——预填充主导一切,KV头数量胜过参数量\n\n我一直在为代理工作流程(工具使用、编码代理、RAG)运行本地LLM,并且看到人们一直在痴迷于tg128(token生成速度)作为头号性能指标。因此,我运行了一个结构化的长上下文基准测试,以找出当上下文窗口满时实际重要的因素。答案让我惊讶。\n\n**设置**\nGPU: RX 7900 XT 20GB (Vulkan后端, RADV/Mesa)\n后端: llama.cpp / llama-bench (build 9860)\n标志: -ngl 99 (GTT溢出), -fa on, -ub 2048 -b 16384, ASPM=performance, 裸TTY以释放VRAM\n13个模型: 5个密集, 6个MoE, 1个Mamba2混合, 1个MLA MoE——范围从5GB到18GB\n3种KV缓存层级: Q8_0 K / Q4_0 V (激进), Q8_0 K / Q8_0 V (对称), F16 (基线)\n上下文大小: 512, 4K, 16K, 65K, 131K——包括纯预填充(pp)和提示+生成(pg)\n完整运行耗时约21小时,分两次会话\n\n**完整预填充速度结果(Q8_0 K / Q8_0 V KV缓存,tokens/秒)**\n如果你只想要原始数字,以下是每个测试的模型。pp = 纯提示处理(预填充),tg128 = token生成(解码)。按pp131K排序。\n\n| 模型 | 大小 | 类型 | pp512 | pp4K | pp16K | pp65K | pp131K | tg128 |\n|------|------|------|-------|------|-------|-------|--------|-------|\n| Trinity-Mini | 16G | MoE 3B/26B | 2639 | 2924 | 2370 | 1419 | 923 | 150 |\n| Granite-4.0-H-Small | 17G | Mamba2+MoE | 1115 | 1271 | 1220 | 1043 | 875 | 71 |\n| Ornith-9B / Qwen3.5-9B | 6G | 密集 | 2103 | 2220 | 1943 | 1274 | 873 | 92 |\n| Qwen3.6-35B-A3B | 18G | MoE 3B/35B | 2184 | 2736 | 2227 | 1268 | 802 | 110 |\n| Gemma-4-26B-A4B | 14G | MoE 4B/26B | 2523 | 2798 | 2076 | 1024 | 600 | 119 |\n| North-Mini-Code | 15G | MoE 3B/30B | 2155 | 2187 | 1568 | 900 | 579 | 134 |\n| Gemma-4-12B | 7G | 密集 | 1492 | 1498 | 1145 | 595 | 350 | 66 |\n| Qwen3.6-27B | 16G | 密集 | 693 | 681 | 602 | 406 | 285 | 32 |\n| Granite-4.1-8B | 5G | 密集 | 1965 | 1807 | 1124 | 442 | 244 | 93 |\n| Ministral-3-14B | 8G | 密集 | 1419 | 1325 | 916 | 404 | 232 | 67 |\n| Apriel-1.6-15B | 9G | 密集 | 1332 | 1208 | 812 | 347 | 197 | 66 |\n| Devstral-24B | 15G | 密集 | 829 | 796 | 628 | 313 | --- | 42 |\n| GLM-4.7-Flash | 16G | MoE (MLA) | 1822 | 1054 | 358 | --- | --- | --- |\n\n几点注意:\n- Devstral-24B 无法完成131K测试(8个KV头 × 128维 = 160 KB/token——131K时KV缓存单独约21GB)。\n- GLM-4.7-Flash 在16K以上崩溃(MLA问题,见发现5)。\n- Ornith-9B 与 Qwen3.5-9B 架构相同。\n\n**发现1:在65K+上下文下,预填充占实际时间的94–99%。对于短代理输出,tg128几乎无关紧要。**\n以下是一个真实代理查询的实际时间分解——65K上下文输入,300个token输出(典型的工具使用响应)。按总时间排序:\n\n| 模型 | 类型 | 预填充 | 解码 | 总计 | 预填充% |\n|------|------|--------|------|------|---------|\n| Trinity-Mini (MoE 3B/26B) | MoE | 46.2s | 2.0s | 48.2s | 96% |\n| Qwen3.6-35B-A3B (MoE) | MoE | 51.7s | 2.7s | 54.4s | 95% |\n| Ornith-9B / Qwen3.5-9B | 密集 | 51.4s | 3.3s | 54.7s | 94% |\n| Gemma-4-26B-A4B (MoE) | MoE | 64.0s | 2.5s | 66.5s | 96% |\n| Granite-4.0-H-Small (Mamba2) | Mamba2 | 62.8s | 4.2s | 67.1s | 94% |\n| North-Mini-Code (MoE) | MoE | 72.8s | 2.2s | 75.0s | 97% |\n| Gemma-4-12B | 密集 | 110.2s | 4.5s | 114.7s | 96% |\n| Granite-4.1-8B | 密集 | 148.4s | 3.2s | 151.6s | 98% |\n| Qwen3.6-27B | 密集 | 161.4s | 9.3s | 170.7s | 95% |\n| Ministral-3-14B | 密集 | 162.0s | 4.5s | 166.5s | 97% |\n| Apriel-1.6-15B | 密集 | 188.9s | 4.6s | 193.5s | 98% |\n| Devstral-24B | 密集 | 209.5s | 7.2s | 216.6s | 97% |\n\n解码只占你实际等待时间的1–5%。如果你的代理发出一个短工具调用或写一个简短响应,唯一重要的是你处理上下文窗口的速度。\n这意味着以tg128作为头条性能指标的基准报告对于代理用例是具有误导性的。pp65K / pp131K才是重要的指标。pg(提示, 生成)混合指标更好,但仍然掩盖了差异——一个预填充快但解码灾难性慢的模型,在pg上可能表现平庸,尽管对于短输出来说很优秀。\n\n**发现2:KV头数量是长上下文预填充的主要架构因素——而不是参数量,也不是MoE vs 密集**\n所有模型在增加上下文时预填充速度保持率(%的pp4K速度):\n\n| 模型 | 大小 | KV头数 | pp4K | 16K | 65K | 131K | 类型 |\n|------|------|--------|------|-----|-----|------|------|\n| Granite-4.0-H-Small | 17G | Mamba2* | 1271 | 96% | 82% | 69% | Mamba2+MoE |\n| Qwen3.6-27B | 16G | 4×256 | 681 | 88% | 60% | 42% | 密集 |\n| Ornith-9B / Qwen3.5-9B | 6G | 4×128 | 2220 | 87% | 57% | 39% | 密集 |\n| Trinity-Mini | 16G | 4×128 | 2924 | 81% | 49% | 32% | MoE |\n| Qwen3.6-35B-A3B | 18G | 4×128 | 2736 | 81% | 46% | 29% | MoE |\n| Gemma-4-12B | 7G | 8×128 | 1498 | 76% | 40% | 23% | 密集 |\n| Gemma-4-26B-A4B | 14G | 4×256 | 2798 | 74% | 37% | 21% | MoE |\n| North-Mini-Code | 15G | 4×128 | 2187 | 72% | 41% | 26% | MoE |\n| Apriel-1.6-15B | 9G | 8×128 | 1208 | 67% | 29% | 16% | 密集 |\n| Ministral-3-14B | 8G | 8×128 | 1325 | 69% | 31% | 18% | 密集 |\n| Granite-4.1-8B | 5G | 8×128 | 1807 | 62% | 24% | 14% | 密集 |\n| Devstral-24B | 15G | 8×128 | 796 | 79% | 39% | --- | 密集 |\n| GLM-4.7-Flash | 16G | MLA (1×576) | 1054 | 34% | --- | --- | MoE (MLA) |\n\n\*Granite-H-Small有4个注意力层 + 36个Mamba2层(循环状态,无KV缓存)\n\n在128K上下文下,Ornith-9B / Qwen3.5-9B(9B密集,4个KV头 × 128维 = 64 KB/token KV)比Apriel-15B(15B密集,8个KV头 × 128维 = 160 KB/token)快4.4倍——尽管它们是相同的密集类别且前者大小只有一半。差异纯粹来自KV缓存架构。每次注意力传递都必须扫描完整的KV缓存,而8个KV头意味着每个token需要扫描2.5倍的数据。\n\n实用规则:在评估一个模型用于长上下文时,在查看参数量之前先检查配置中的n_kv_heads和head_dim。来自同一系列的两个模型,如果一个有4个KV头而另一个有8个,在128K下可能相差3–4倍。\n\n**发现3:Mamba2混合模型具有近乎平坦的预填充缩放。这种架构确实有效。**\n我之前对Mamba2的炒作持怀疑态度,但数据很清晰。Granite-4.0-H-Small(IBM,4个注意力层 + 36个Mamba2层)在131K上下文下保留了其pp4K速度的69%——而测试中的每个Transformer模型都降到了42%以下。\n\n| 模型 | pp4K | pp131K | 减速比 |\n|------|------|--------|--------|\n| Granite-H-Small (Mamba2) | 1271 | 875 | 1.45× |\n| Trinity-Mini (MoE) | 2924 | 923 | 3.2× |\n| Ornith-9B / Qwen3.5-9B (密集GQA) | 2220 | 873 | 2.5× |\n| Granite-8B (密集) | 1807 | 244 | 7.4× |\n\n在131K上下文下,Granite-H-Small(17GB)与Ornith-9B / Qwen3.5-9B(6GB)在约875 t/s上持平,尽管文件大小是后者的3倍。Mamba2层使用固定的循环状态而不是增长的KV缓存,因此只有4个注意力层贡献KV增长。\n\n代价:其解码速度慢(71 t/s)且推理质量低。但对于“大量上下文、短输出”这种特定工作负载模式——这正是代理工具使用的情况——预填充缩放优势是真实且可衡量的。如果有人在这个架构上训练一个好的模型,它可能成为一个严肃的代理候选者。\n\n**发现4:F16 KV缓存可以比Q8/Q4量化KV缓存更快——反量化悖论**\n传统观点认为量化你的KV缓存(Q8_0 K / Q4_0 V)可以提高速度——缓存更小,带宽更少。我在65K上下文下进行了正面比较,将F16基线与Q8_0 K / Q8_0 V进行对比(结果与Q8K/Q4V在±1%内相同——V缓存量化选择被证明无关紧要):\n\n| 模型 | 类型 | Q8K/Q8V | F16 | F16优势 |\n|------|------|---------|-----|---------|\n| Gemma-4-26B-A4B | MoE | 1015 | 1554 | +53% |\n| Gemma-4-12B | 密集 (7GB) | 593 | 857 | +44% |\n| Qwen3.6-35B-A3B | MoE | 1273 | 1573 | +24% |\n| Ornith-9B / Qwen3.5-9B | 密集 (6GB) | 1276 | 1544 | +21% |\n| Trinity-Mini | MoE | 1429 | 1583 | +11% |\n| Granite-H-Small | Mamba2 | 1040 | 984 | -5% |\n| Ministral-3-14B | 密集 (8KV) | 409 | 335 | -18% |\n| Granite-4.1-8B | 密集 (8KV) | 447 | 358 | -20% |\n| Apriel-1.6-15B | 密集 (8KV) | 351 | 120 | -66% |\n\nF16对于MoE模型和小型密集模型获胜。对于具有许多KV头的密集模型,它则遭遇惨败。原因如下:\n\nQ8/Q4 KV缓存的反量化是一个计算操作,其规模随上下文长度增长。在65K上下文下,注意力核心必须对每个token反量化65K × n_kv_heads × head_dim个Q8/Q4元素。这个计算成本超过了通过将缓存大小减半所节省的带宽。\n\n与此同时,F16 KV使缓存大小加倍,但不需要任何反量化。对于MoE模型,更大的F16缓存导致GTT溢出——但只有活跃的参数(约35B中的3B)穿过PCIe,因此溢出惩罚很小。对于具有8个KV头的密集模型,F16缓存既更大,而且所有权重都会溢出——双重惩罚。\n\n更新规则:\n- F16获胜:MoE模型(活跃溢出足迹小),小型密集模型(<10GB),高效GQA密集(4个KV头)\n- F16失败:密集 + 8个以上KV头 + >10GB(完整权重溢出 + 大KV = 灾难性)\n- Q8K/Q4V 与 Q8K/Q8V:完全
相似文章
面向长上下文服务的KV-Cache优化:任务质量与系统性能的基准测试
本文提出了一个负载感知的基准测试,在长上下文LLM服务任务上比较了KV-cache压缩技术(量化、剪枝、合并),发现仅压缩比不足以预测性能,并倡导负载感知的选择。
注意缓存读取成本
一篇博客文章,解释了在代理型工作负载中,缓存读取成本主导了LLM推理开销,随着每轮重新读取上下文,累计成本呈二次方增长,并建议减少工具调用次数以降低成本。
为本地LLM提供大量答案的新旧基准测试
本文介绍了一个用于评估本地LLM配置的基准测试工具,重点关注显存使用情况、性能指标和硬件优化,以协助开发者优化配置。
@lateinteraction: 目前,我认为极少数长上下文基准测试中值得重视的两个是 OBLIQ-Bench…
一位评论者指出,OBLIQ-Bench(recall@k)和 StudyBench(expertise)是少数可靠的长上下文基准测试中的两个。
你们是对的 - Qwen 3.6 35B 确实不错...而且 KV 缓存确实重要。
一位用户分享了自己的发现:Qwen 3.6 35B 在智能体任务中优于 27B 模型,并将差异主要归因于 KV 缓存压缩质量。他们还从 LM Studio 切换到了 llama.cpp 以更好地管理上下文。