<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[SGLang 跑通：9700X+4080S 32G 跑 Qwen3.8-27B AWQ-INT4 双路128K+三级HiCache 从满屏乱码到跑通]]></title><description><![CDATA[<h1>4080S 32G 用 SGLang 跑 Qwen3.8-27B AWQ-INT4：双路 128K + 三级 HiCache，从"满屏乱码"到跑通的完整踩坑记录</h1>
<p dir="auto">上一篇写的是 llama.cpp + Q6_K 的成绩（单路 80-95 t/s、双路 128K + 视觉）。这次换 SGLang 引擎，目标是论坛大神帖子里那套 <strong>HiCache 三级 KV 缓存 + 双路 128K</strong>。</p>
<p dir="auto">结果一晚上下来，坑比上次多得多，而且<strong>最大的坑不在 SGLang，在网上下载的那个 AWQ 权重包本身——它的 config 和权重文件自相矛盾</strong>，SGLang 和 HuggingFace transformers 加载出来都是满屏乱码。这篇把根因、修法、实测数据全部放出来，照着抄能省你一整晚。</p>
<h2>1. 整机配置</h2>
<ul>
<li>CPU：AMD Ryzen 7 9700X（8核16线程）</li>
<li>内存：64GB DDR5</li>
<li>显卡：NVIDIA RTX 4080 SUPER 32GB（32760 MiB）</li>
<li>系统：Ubuntu（SGLang 这套）／Windows 11（上一篇 llama.cpp 那套）</li>
<li>引擎：SGLang 0.5.17 + torch 2.11.0 + sglang-kernel 0.4.5</li>
<li>模型：<code>hotdogs/Qwen3.8-27B-abliterated-AWQ-INT4</code>（16.5 GB，每 token KV 32 KB）</li>
</ul>
<h2>2. 先给结论</h2>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>项目</th>
<th>结果</th>
</tr>
</thead>
<tbody>
<tr>
<td>原始 AWQ 权重包能直接用吗</td>
<td><img src="https://lcz.me/assets/plugins/nodebb-plugin-emoji/emoji/android/274c.png?v=ffa14597167" class="not-responsive emoji emoji-android emoji--x" style="height:23px;width:auto;vertical-align:middle" title="❌" alt="❌" /> <strong>不能</strong>，config 与权重文件自相矛盾，SGLang 和 HF 都输出乱码</td>
</tr>
<tr>
<td>修好之后能不能用</td>
<td><img src="https://lcz.me/assets/plugins/nodebb-plugin-emoji/emoji/android/2705.png?v=ffa14597167" class="not-responsive emoji emoji-android emoji--white_check_mark" style="height:23px;width:auto;vertical-align:middle" title="✅" alt="✅" /> 能，输出正常（<code>The capital of France is Paris.</code>）</td>
</tr>
<tr>
<td>双路 128K 并发</td>
<td><img src="https://lcz.me/assets/plugins/nodebb-plugin-emoji/emoji/android/2705.png?v=ffa14597167" class="not-responsive emoji emoji-android emoji--white_check_mark" style="height:23px;width:auto;vertical-align:middle" title="✅" alt="✅" /> <strong>跑通</strong>，2×123K token 并发，峰值显存 31114 / 32760 MiB</td>
</tr>
<tr>
<td>HiCache L1（GPU KV）</td>
<td><img src="https://lcz.me/assets/plugins/nodebb-plugin-emoji/emoji/android/2705.png?v=ffa14597167" class="not-responsive emoji emoji-android emoji--white_check_mark" style="height:23px;width:auto;vertical-align:middle" title="✅" alt="✅" /> 生效</td>
</tr>
<tr>
<td>HiCache L2（主机内存 12GB）</td>
<td><img src="https://lcz.me/assets/plugins/nodebb-plugin-emoji/emoji/android/2705.png?v=ffa14597167" class="not-responsive emoji emoji-android emoji--white_check_mark" style="height:23px;width:auto;vertical-align:middle" title="✅" alt="✅" /> 生效，17.9K 前缀 <strong>10.2s → 1.25s</strong></td>
</tr>
<tr>
<td>HiCache L3（磁盘）</td>
<td><img src="https://lcz.me/assets/plugins/nodebb-plugin-emoji/emoji/android/26a0.png?v=ffa14597167" class="not-responsive emoji emoji-android emoji--warning" style="height:23px;width:auto;vertical-align:middle" title="⚠" alt="⚠" />️ <strong>只写不读</strong>，能落盘但 0.5.17 在混合模型上从不触发预取</td>
</tr>
<tr>
<td>MTP 投机解码</td>
<td><img src="https://lcz.me/assets/plugins/nodebb-plugin-emoji/emoji/android/274c.png?v=ffa14597167" class="not-responsive emoji emoji-android emoji--x" style="height:23px;width:auto;vertical-align:middle" title="❌" alt="❌" /> 这个 checkpoint <strong>没有 MTP 权重</strong>，方案里的 MTP 项做不了</td>
</tr>
<tr>
<td>pp512（prefill）</td>
<td>1737 tok/s</td>
</tr>
<tr>
<td>单路 decode</td>
<td>41.4 tok/s（不投机）／47-75 tok/s（开 NGRAM）</td>
</tr>
<tr>
<td>双路 decode 聚合</td>
<td>74.8 tok/s</td>
</tr>
</tbody>
</table>
<p dir="auto">一句话：<strong>SGLang 这套 prefill 强、前缀复用强、并发强，但 decode 打不过 llama.cpp 的 MTP；想追平要么开 NGRAM，要么换带 MTP 的权重。</strong></p>
<h2>3. 最大的坑：AWQ 权重包的 config 和权重文件对不上</h2>
<h3>3.1 现象</h3>
<p dir="auto">服务器起来了，健康检查 200，但不管问什么都输出乱码：</p>
<pre><code>The capital of France is  →  " is is is is is is is is is is is is is is"
中文提问                  →  "!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
</code></pre>
<p dir="auto">换温度、换 KV 精度、换层数截断、<code>--load-format dummy</code>（随机权重）都试了：<strong>随机权重反而能输出正常 token，真权重反而是乱码</strong> —— 说明模型结构没问题，问题出在"权重没加载对"。</p>
<h3>3.2 怎么定位到根因</h3>
<p dir="auto">先看 <code>config.json</code> 里声明哪些层不量化：</p>
<pre><code class="language-json">"ignore": [
  "model.language_model.layers.0.linear_attn",
  "model.language_model.layers.0.linear_attn.norm",
  ...
]
</code></pre>
<p dir="auto">再去 safetensors 里数真实张量名：</p>
<pre><code class="language-python">model.layers.0.linear_attn.in_proj_qkv.weight_packed   # ← 真实名字，没有 language_model
model.layers.0.linear_attn.in_proj_qkv.weight_scale
</code></pre>
<p dir="auto"><strong>对不上。</strong> 这个包的架构声明是 <code>Qwen3_5ForCausalLM</code>（纯文本），根本没有 <code>model.language_model.</code> 这一层（那是多模态 <code>Qwen3_5ForConditionalGeneration</code> 的命名）。所以那 97 条 ignore <strong>一条都没生效</strong>。</p>
<p dir="auto">更坑的是第二点：<strong>文件里 linear_attn 其实被量化了</strong>。逐层验证：</p>
<pre><code>48 个 GDN 层全部是 weight_packed(int32) + weight_scale
linear_attn 层里有 bf16 .weight 的：0 个
</code></pre>
<p dir="auto">也就是 README 里写的"linear_attn 保持 BF16"是假的，实际全被量化了（文件 16.44 GiB 也能印证，真要是 bf16 会多出 8GB）。</p>
<h3>3.3 于是两条加载路径都是死路</h3>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>走法</th>
<th>结果</th>
</tr>
</thead>
<tbody>
<tr>
<td>ignore 生效（把 GDN 当未量化）</td>
<td>文件里没有 bf16 权重 → 加载器找不到 → 随机/空权重 → 乱码</td>
</tr>
<tr>
<td>ignore 不生效（把 GDN 当量化）</td>
<td>撞上 Marlin 的 <code>size_n % 64 == 0</code>：GDN 融合后的 <code>in_proj_ba</code> 是 <code>[48,48]=96</code> → 直接崩</td>
</tr>
</tbody>
</table>
<p dir="auto">第二种就是上游 issue #19406 那个报错。<strong>用 HF transformers 加载也是乱码</strong>（报 <code>in_proj_qkv.weight MISSING / weight_packed UNEXPECTED</code>），同一个根因，所以这真不是引擎的锅。</p>
<p dir="auto">顺便排除掉的怀疑对象：</p>
<ul>
<li>int4 的码字和 scale 数据本身是自洽的（每组 code 饱和在 ±7，<code>max|code-8|/scale ≈ 7</code>）→ <strong>权重没坏，坏的只是 config</strong></li>
<li><code>A_log</code> 的 float32 补丁、GDN stride 修复（commit 8ba9646）在 0.5.17 里已经存在</li>
<li>KV dtype fp8/auto、<code>--page-size</code>、fused/legacy 的 GDN 拆分路径，全都试过，都不是原因</li>
</ul>
<h3>3.4 修法（关键：只反量化两个小矩阵）</h3>
<p dir="auto">对照官方 <code>RedHatAI/Qwen3.8-27B-INT4</code> 的 config 就能看出差别：它把 <code>in_proj_a</code> / <code>in_proj_b</code> <strong>也</strong>放进了 ignore。因为这两个投影输出维度只有 48，过不了 Marlin 的 64 整除要求。</p>
<p dir="auto">所以修法是：<strong>把 48 层的 <code>in_proj_a</code>/<code>in_proj_b</code> 离线反量化成 bf16，其余量化权重按字节原样搬运</strong>。</p>
<pre><code class="language-python"># 每个 GDN 层只有两个 [48, 5120] 的小矩阵，96 个张量一共才 47 MB
def dequant8(pk, sc):          # pk: int32，每个 int32 装 8 个 int4
    x = pk.to(torch.int64)
    codes = torch.stack([(x &gt;&gt; (4 * i)) &amp; 0xF for i in range(8)], dim=2).flatten(1)
    g = codes.shape[1] // sc.shape[1]
    return ((codes - 8).float() * sc.float().repeat_interleave(g, dim=1)).to(torch.bfloat16)
</code></pre>
<p dir="auto">然后把 <code>ignore</code> 改成<strong>和真实张量名一致</strong>：</p>
<pre><code>lm_head
model.layers.{N}.linear_attn.in_proj_a
model.layers.{N}.linear_attn.in_proj_b
</code></pre>
<p dir="auto">SGLang 内部有一张 <code>packed_modules_mapping</code>：<code>in_proj_ba → [in_proj_b, in_proj_a]</code>，所以只要把两个分片都标成忽略，融合后的 <code>in_proj_ba</code> 会自动走未量化路径；而 <code>in_proj_qkvz</code>（2048/2048/6144/6144，每个都能被 64 整除）继续走 int4 Marlin。</p>
<p dir="auto"><strong>显存只多 47 MB，其他什么都不用改。</strong> 改完立刻正常：</p>
<pre><code>greedy:  " Paris.\nThe capital of Germany is Berlin.\nThe capital of Italy is Rome..."
chat  :  "法国的首都是巴黎。"
</code></pre>
<blockquote>
<p dir="auto">额外提醒：网上有个 PR（#22618）给 Qwen3.5 加了个"ignore 里有 linear_attn 就把整个 GDN 设成未量化"的 guard。<strong>如果你的权重是这种"声明忽略但实际量化"的包，千万别打那个补丁</strong> —— 它会把整个 GDN 变未量化，反而让你连权重都加载不上。</p>
</blockquote>
<h2>4. HiCache 三级缓存实测</h2>
<p dir="auto">启动基线：<code>--enable-hierarchical-cache --hicache-size 12 --hicache-write-policy write_through --page-size 1</code></p>
<h3>L1（GPU KV 池）<img src="https://lcz.me/assets/plugins/nodebb-plugin-emoji/emoji/android/2705.png?v=ffa14597167" class="not-responsive emoji emoji-android emoji--white_check_mark" style="height:23px;width:auto;vertical-align:middle" title="✅" alt="✅" /></h3>
<p dir="auto">重复前缀直接命中显存：<code>cached_tokens_details {'device': 43008, 'host': 0, 'storage': 0}</code>，缓存命中率 0.96。</p>
<h3>L2（主机内存）<img src="https://lcz.me/assets/plugins/nodebb-plugin-emoji/emoji/android/2705.png?v=ffa14597167" class="not-responsive emoji emoji-android emoji--white_check_mark" style="height:23px;width:auto;vertical-align:middle" title="✅" alt="✅" /> 读取已验证</h3>
<p dir="auto">把 L1 压小（<code>--max-total-tokens 32768</code>），发 3 个<strong>互不重复</strong>的 17.9K 前缀，再重放第 1 个：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>请求</th>
<th>prompt</th>
<th>cached</th>
<th>命中来源</th>
<th>耗时</th>
</tr>
</thead>
<tbody>
<tr>
<td>ALPHA 冷</td>
<td>17935</td>
<td>0</td>
<td>—</td>
<td>10.208s</td>
</tr>
<tr>
<td>BETA 冷</td>
<td>17936</td>
<td>0</td>
<td>—</td>
<td>10.220s</td>
</tr>
<tr>
<td>GAMMA 冷</td>
<td>17936</td>
<td>0</td>
<td>—</td>
<td>10.224s</td>
</tr>
<tr>
<td><strong>ALPHA 重放</strong></td>
<td>17935</td>
<td>16384</td>
<td><strong>host</strong></td>
<td><strong>1.252s</strong></td>
</tr>
</tbody>
</table>
<pre><code>sglang:cached_tokens_total{cache_source="host"} 16384
sglang:evicted_tokens_total{cache_type="UnifiedRadixCache"} 39531
</code></pre>
<p dir="auto"><strong>冷 10.2s → 暖 1.25s，8 倍。</strong> L2 主机内存层是真的在工作。</p>
<h3>L3（磁盘）<img src="https://lcz.me/assets/plugins/nodebb-plugin-emoji/emoji/android/26a0.png?v=ffa14597167" class="not-responsive emoji emoji-android emoji--warning" style="height:23px;width:auto;vertical-align:middle" title="⚠" alt="⚠" />️ 只写不读</h3>
<p dir="auto">落盘完全正常：</p>
<pre><code>sglang:backuped_tokens_total{storage_backend="file"} 104056
/mnt/sda6/hicache_l3   24G / 211010 个 .bin
</code></pre>
<p dir="auto">但<strong>读取从来没被触发</strong>。用 6 个互不重复的前缀（共 107K token）把 L1（32768）和 L2（60855）全部撑爆，L3 里确实有 ALPHA 的数据，再请求 ALPHA：</p>
<pre><code>[ALPHA-again] prompt=17935 cached=0 device=None host=None storage=None e2e=10.233s   ← 全量重算
</code></pre>
<p dir="auto">metrics 里连 <code>prefetched_tokens_total</code> 的 series 都不存在 —— <strong>根本没有发起过预取</strong>。重启进程后再试，一样。</p>
<p dir="auto"><strong>结论：0.5.17 在 <code>UnifiedRadixCache</code>（KV+MAMBA 混合池）上不会为 L3 触发预取。</strong> 想要真三级缓存得等上游修，相关的 PR 是 #20457（mamba 状态卸载）、#28185（linear-attn 前缀缓存的 int8 checkpoint pool），issue 是 #24121。</p>
<h3>顺带踩到的三个坑（很重要）</h3>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>坑</th>
<th>现象</th>
<th>解决</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>--file-storage-path</code> 是空参数</td>
<td>全树只有参数声明、没有任何地方使用它，文件偷偷写到 <code>/tmp/hicache</code></td>
<td>必须用环境变量 <code>SGLANG_HICACHE_FILE_BACKEND_STORAGE_DIR=/mnt/sda6/hicache_l3</code></td>
</tr>
<tr>
<td>文件后端淘汰器默认惰性</td>
<td>不配置就无限增长（实测涨到 24 GB）</td>
<td>设 <code>SGLANG_HICACHE_FILE_BACKEND_MAX_SIZE=20G</code>、<code>..._MIN_FREE_SPACE=10G</code></td>
</tr>
<tr>
<td><code>--hicache-size</code> 是 KV + mamba 总量</td>
<td>给 12 时 KV host 只有 2-6 GB，剩下 5.7-10 GB 全给 mamba 状态了</td>
<td>看清楚分配日志再调</td>
</tr>
<tr>
<td><code>/flush_cache</code> 返回 400</td>
<td>没法用它做隔离测试</td>
<td>用重启进程代替</td>
</tr>
</tbody>
</table>
<h2>5. 双路 128K 跑通：关键参数是 max-mamba-cache-size</h2>
<p dir="auto">这是本篇最值钱的一条。</p>
<p dir="auto">GDN（Gated DeltaNet）的状态缓存默认要 <strong>34 个槽位 = ssm_state 4.92 GB</strong>。但双路并发只需要 2 路：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>配置</th>
<th>max_mamba_cache_size</th>
<th>ssm_state</th>
<th>KV 池 tokens</th>
</tr>
</thead>
<tbody>
<tr>
<td>默认</td>
<td>34</td>
<td>4.92 GB</td>
<td>183838（mf 0.88）</td>
</tr>
<tr>
<td><strong>优化</strong></td>
<td><strong>6</strong></td>
<td><strong>0.98 GB</strong></td>
<td><strong>356237（mf 0.92）</strong></td>
</tr>
</tbody>
</table>
<p dir="auto">白捡 4GB 显存，KV 池直接从 18 万 token 干到 35 万 token。实测双路 128K：</p>
<pre><code>max_total_num_tokens=356237   max_running_requests=2   context_len=131072
[dual-A] prompt=123215  e2e=206.0s
[dual-B] prompt=123216  e2e=206.1s     ← 真并发，KV 使用率 0.69 / mamba 0.67
峰值显存 31114 / 32760 MiB，无 OOM、无 retraction、无 abort
</code></pre>
<h2>6. 速度基准（和上一篇的 llama.cpp 对照）</h2>
<h3>6.1 SGLang 本机实测</h3>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>指标</th>
<th>数值</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>pp512</strong></td>
<td><strong>1736.8 tok/s</strong></td>
</tr>
<tr>
<td>pp8.5k</td>
<td>1884.0 tok/s</td>
</tr>
<tr>
<td>pp34k</td>
<td>1684.3 tok/s</td>
</tr>
<tr>
<td>pp68k</td>
<td>1459.8 tok/s</td>
</tr>
<tr>
<td><strong>单路 decode</strong>（短上下文 128 token）</td>
<td><strong>41.4 tok/s</strong>（TTFT 285 ms）</td>
</tr>
<tr>
<td>单路 decode @64K 上下文</td>
<td>37.0 tok/s</td>
</tr>
<tr>
<td><strong>双路同时 decode</strong></td>
<td>36.7 + 38.1 = <strong>74.8 tok/s 聚合</strong></td>
</tr>
<tr>
<td>双路 2×120K prompt 并发</td>
<td>聚合 prefill <strong>2252 tok/s</strong>，墙钟 <strong>107.0 s</strong></td>
</tr>
<tr>
<td>峰值显存</td>
<td>31.1-31.3 GB / 32 GB</td>
</tr>
</tbody>
</table>
<p dir="auto">HiCache 开关对照（其余参数完全一致）：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>指标</th>
<th>HiCache 开</th>
<th>HiCache 关</th>
<th>差异</th>
</tr>
</thead>
<tbody>
<tr>
<td>pp512</td>
<td>1736.8</td>
<td>1849.1</td>
<td>−6.1%</td>
</tr>
<tr>
<td>pp68k</td>
<td>1459.8</td>
<td>1466.7</td>
<td>−0.5%</td>
</tr>
<tr>
<td>单路 decode</td>
<td>41.4</td>
<td>41.4</td>
<td>0%</td>
</tr>
<tr>
<td><strong>双路 2×120K 墙钟</strong></td>
<td><strong>107.0 s</strong></td>
<td>160.6 s</td>
<td><strong>快 33%</strong></td>
</tr>
</tbody>
</table>
<p dir="auto"><strong>write_through 的 GPU→主机 DMA 开销基本可以忽略</strong>（短上下文 −6%，长上下文 −0.5%，decode 无影响），而双路 12 万 token 时反而因为 mamba 状态能卸到主机内存、不用重算，快了三分之一。</p>
<h3>6.2 NGRAM 投机解码（不需要 MTP 权重）</h3>
<p dir="auto">这个 checkpoint 没有 MTP，但 SGLang 的 <strong>NGRAM 投机不需要任何额外权重</strong>，白嫖：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>负载</th>
<th>无投机</th>
<th>NGRAM</th>
<th>提升</th>
<th>接受率</th>
</tr>
</thead>
<tbody>
<tr>
<td>代码生成</td>
<td>41.4 tok/s</td>
<td><strong>56.1 tok/s</strong></td>
<td>+35%</td>
<td>0.110</td>
</tr>
<tr>
<td>抽取原文（回声型）</td>
<td>40.5 tok/s</td>
<td><strong>75.1 tok/s</strong></td>
<td>+85%</td>
<td>0.231</td>
</tr>
<tr>
<td>中文散文创作</td>
<td>41.5 tok/s</td>
<td><strong>47.2 tok/s</strong></td>
<td>+14%</td>
<td>0.062</td>
</tr>
</tbody>
</table>
<p dir="auto">参数：<code>--speculative-algorithm NGRAM --speculative-num-steps 5 --speculative-num-draft-tokens 6</code><br />
代价：KV 池 356237 → 271673 token，<code>mixed chunked prefill</code> 被自动禁用，启动慢 50s。</p>
<h3>6.3 和上一篇 llama.cpp（Q6_K + draft-mtp）的对照</h3>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>负载</th>
<th>llama.cpp Q6_K <strong>+MTP</strong></th>
<th>SGLang INT4 <strong>不投机</strong></th>
<th>SGLang INT4 <strong>+NGRAM</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>工具调用 decode</td>
<td>81.8 t/s（n-max3）</td>
<td>41.4</td>
<td>—</td>
</tr>
<tr>
<td>代码生成</td>
<td>80.9</td>
<td>41.4</td>
<td>56.1</td>
</tr>
<tr>
<td>中文创作</td>
<td>52.9</td>
<td>41.5</td>
<td>47.2</td>
</tr>
<tr>
<td>双路聚合</td>
<td>95-160</td>
<td>74.8</td>
<td>预估 100-135</td>
</tr>
<tr>
<td>prefill（pp）</td>
<td>上次没测</td>
<td><strong>1737-1910</strong></td>
<td>同</td>
</tr>
<tr>
<td>显存</td>
<td>28.4 GB（含视觉）</td>
<td>31.1 GB（无视觉）</td>
<td>同</td>
</tr>
</tbody>
</table>
<p dir="auto">结论：</p>
<ol>
<li><strong>decode 的差距几乎全是 MTP 造成的，不是引擎差距。</strong> llama.cpp 的 80-95 t/s 是"Q6_K + 训练过的 MTP draft head"，我们这边是"INT4 + 完全不投机"。而且注意 INT4 权重只有 17.7 GB（Q6_K 是 20.9 GB），<strong>带宽上 SGLang 这套是占便宜的</strong> —— llama.cpp 如果关掉 MTP，单路大概率只有 30-35 t/s，还不如我们的 41.4。</li>
<li><strong>prefill 是 SGLang 的大优势</strong>：1.7-1.9k tok/s，68K 长上下文只掉 15%。长文档首答和 HiCache 冷启动都靠这个。</li>
<li><strong>前缀复用 SGLang 强</strong>：HiCache L2 跨请求共享，命中秒级；llama.cpp 的 prompt cache 是 per-slot 的，<code>--parallel 2</code> 两个槽各存一份。</li>
<li><strong>llama.cpp 赢在显存余量和视觉</strong>：28.4 GB 还能带视觉双路 128K；我们 31.1 GB 无视觉、只剩 1 GB。</li>
<li><strong>精度取舍</strong>：Q6_K 比 AWQ INT4 更保险（我们这里连 GDN 的 <code>in_proj_qkvz/out_proj</code> 都是 int4）。</li>
</ol>
<h2>7. 最终启动脚本</h2>
<pre><code class="language-bash">export SGLANG_HICACHE_FILE_BACKEND_STORAGE_DIR=/mnt/sda6/hicache_l3   # 只有开 L3 才需要
export SGLANG_HICACHE_FILE_BACKEND_MAX_SIZE=20G
export SGLANG_HICACHE_FILE_BACKEND_MIN_FREE_SPACE=10G

python -m sglang.launch_server \
  --model-path /mnt/sda6/download/qwen38-awq-fixed \
  --served-model-name qwen38 \
  --host 0.0.0.0 --port 8001 \
  --context-length 131072 \
  --max-running-requests 2 \
  --mem-fraction-static 0.92 \
  --kv-cache-dtype fp8_e4m3 \
  --page-size 1 \
  --max-mamba-cache-size 6 \
  --enable-hierarchical-cache \
  --hicache-size 12 \
  --hicache-write-policy write_through \
  --reasoning-parser qwen3 \
  --tool-call-parser qwen3_coder \
  --trust-remote-code
</code></pre>
<p dir="auto">想要再快就加投机（二选一）：</p>
<pre><code class="language-bash"># 方案A：不用换权重，白嫖 NGRAM
  --speculative-algorithm NGRAM \
  --speculative-num-steps 5 \
  --speculative-num-draft-tokens 6

# 方案B：换成带 MTP 的权重（如 RedHatAI/Qwen3.8-27B-INT4）
  --speculative-algorithm NEXTN \
  --speculative-eagle-topk 1 \
  --speculative-num-steps 5 \
  --speculative-num-draft-tokens 6
</code></pre>
<h2>8. 给同是小白的提醒</h2>
<ol>
<li><strong>先验证权重包本身</strong>。加载出来乱码，第一步就去比对 <code>config.json</code> 的 <code>ignore</code> 和 safetensors 里的真实键名，别急着怀疑引擎。kv 相关的报错（Marlin size_n）和乱码往往是同一个根因的两副面孔。</li>
<li><strong><code>--page-size</code> 必须是 1</strong>，混合 mamba 模型 + HiCache 用别的值会 segfault，这条大神帖子里就写了，是真的。</li>
<li><strong><code>--max-mamba-cache-size</code> 是双路 128K 的钥匙</strong>，默认 34 白扔 4GB。</li>
<li><strong>HiCache 的 L3 目前对混合模型只写不读</strong>，别指望它；L2（主机内存）才是真正省钱的那层，<code>--hicache-size</code> 给 12 就够。</li>
<li><strong><code>--file-storage-path</code> 在 0.5.17 里不生效</strong>，必须用环境变量，否则你会像我一样盯着空目录怀疑人生。</li>
<li><strong>A_log 要用 float32、GDN stride 修复</strong>这些在 0.5.17 里已经内置了，不用自己打补丁；但<strong>别乱打那个 #22618 的 linear_attn guard</strong>。</li>
<li><strong>投机参数要自己扫</strong>（和上次扫 n-max 一样），<code>num-steps</code> / <code>num-draft-tokens</code> 的甜点位因任务而异。</li>
</ol>
<h2>9. 还没解决的</h2>
<ul>
<li><strong>L3 磁盘层只写不读</strong>：0.5.17 的混合模型限制，等上游修。</li>
<li><strong>这个 checkpoint 没有 MTP</strong>：想要 MTP 得换权重（代价是不再是 abliterated 版）。</li>
<li><strong>显存只剩 1 GB</strong>：双路 128K 是这卡的极限，正式长跑建议用 96K（<code>mem-fraction 0.90</code>）。</li>
<li><strong>量化精度</strong>：AWQ INT4 + GDN 部分层量化，质量比 Q6_K 略逊，追求质量还是建议 Q6_K。</li>
</ul>
<p dir="auto">感谢论坛大神的 HiCache 帖子，也感谢上一篇里各位指路的回复。这次把一个坏权重包拆开修好、把三层缓存一层层验明白，算是把 SGLang 这条路走通了 —— 剩下的就是等上游把 L3 补上。</p>
<p dir="auto"><img src="https://upload.lcz.me/uploads/4392bcc2-2c22-4c76-b1e5-381c1e803f0b.jpeg" alt="2be8a5f0-c64c-4174-a815-d4212ca69e4b-image.jpeg" class=" img-fluid img-markdown" /></p>
]]></description><link>https://lcz.me/topic/1620</link><generator>RSS for Node</generator><lastBuildDate>Sun, 20 Sep 2026 21:48:55 GMT</lastBuildDate><atom:link href="https://lcz.me/topic/1620.rss" rel="self" type="application/rss+xml"/><pubDate>Fri, 11 Sep 2026 06:45:28 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to SGLang 跑通：9700X+4080S 32G 跑 Qwen3.8-27B AWQ-INT4 双路128K+三级HiCache 从满屏乱码到跑通 on Mon, 14 Sep 2026 15:44:31 GMT]]></title><description><![CDATA[<blockquote>
<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/terry" aria-label="Profile: terry">@<bdi>terry</bdi></a> <a href="/post/17905">说</a>:</p>
<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/enigma" aria-label="Profile: Enigma">@<bdi>Enigma</bdi></a> HiCahce跑通，FP8KV久没有那么急迫了，还是可以研究下，我看你其他帖子似乎是有BUG？Decode其实不重要，我之前都是20多tokens，不妨碍工作，重要的就是对会话prefill，显存要够。还有DFlash如果还不饿Hicache能同时跑通，最好，或者和FP8KV。</p>
</blockquote>
<p dir="auto">DFlash2已经跑通能用了，效果不错的，现在的满速跑，功率260W/320W,核心温度45左右，凉快又安静</p>
]]></description><link>https://lcz.me/post/18191</link><guid isPermaLink="true">https://lcz.me/post/18191</guid><dc:creator><![CDATA[Enigma]]></dc:creator><pubDate>Mon, 14 Sep 2026 15:44:31 GMT</pubDate></item><item><title><![CDATA[Reply to SGLang 跑通：9700X+4080S 32G 跑 Qwen3.8-27B AWQ-INT4 双路128K+三级HiCache 从满屏乱码到跑通 on Sun, 13 Sep 2026 15:55:34 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/enigma" aria-label="Profile: Enigma">@<bdi>Enigma</bdi></a> HiCahce跑通，FP8KV久没有那么急迫了，还是可以研究下，我看你其他帖子似乎是有BUG？Decode其实不重要，我之前都是20多tokens，不妨碍工作，重要的就是对会话prefill，显存要够。还有DFlash如果还不饿Hicache能同时跑通，最好，或者和FP8KV。</p>
]]></description><link>https://lcz.me/post/17905</link><guid isPermaLink="true">https://lcz.me/post/17905</guid><dc:creator><![CDATA[terry]]></dc:creator><pubDate>Sun, 13 Sep 2026 15:55:34 GMT</pubDate></item><item><title><![CDATA[Reply to SGLang 跑通：9700X+4080S 32G 跑 Qwen3.8-27B AWQ-INT4 双路128K+三级HiCache 从满屏乱码到跑通 on Sat, 12 Sep 2026 12:16:10 GMT]]></title><description><![CDATA[<blockquote>
<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/terry" aria-label="Profile: terry">@<bdi>terry</bdi></a> <a href="/post/17366">说</a>:</p>
<p dir="auto">非常好的帖子，你把上个帖子链接发进来，方便大家查找。我帮你贴下，以后自己的帖子注意维护。<br />
<a href="https://lcz.me/topic/1614">https://lcz.me/topic/1614</a><br />
两个帖子质量都很好。</p>
</blockquote>
<p dir="auto">好的，谢谢</p>
]]></description><link>https://lcz.me/post/17573</link><guid isPermaLink="true">https://lcz.me/post/17573</guid><dc:creator><![CDATA[Enigma]]></dc:creator><pubDate>Sat, 12 Sep 2026 12:16:10 GMT</pubDate></item><item><title><![CDATA[Reply to SGLang 跑通：9700X+4080S 32G 跑 Qwen3.8-27B AWQ-INT4 双路128K+三级HiCache 从满屏乱码到跑通 on Fri, 11 Sep 2026 16:03:45 GMT]]></title><description><![CDATA[<p dir="auto">非常好的帖子，你把上个帖子链接发进来，方便大家查找。我帮你贴下，以后自己的帖子注意维护。<br />
<a href="https://lcz.me/topic/1614">https://lcz.me/topic/1614</a><br />
两个帖子质量都很好。</p>
]]></description><link>https://lcz.me/post/17366</link><guid isPermaLink="true">https://lcz.me/post/17366</guid><dc:creator><![CDATA[terry]]></dc:creator><pubDate>Fri, 11 Sep 2026 16:03:45 GMT</pubDate></item><item><title><![CDATA[Reply to SGLang 跑通：9700X+4080S 32G 跑 Qwen3.8-27B AWQ-INT4 双路128K+三级HiCache 从满屏乱码到跑通 on Fri, 11 Sep 2026 07:04:34 GMT]]></title><description><![CDATA[<p dir="auto">感谢分享，这篇把「量化包的 config 和权重对不上」这种最坑的类讲清楚了，排查方法也值得推广。</p>
<p dir="auto">你用的那条反证法很关键：--load-format dummy 拿随机权重反而能吐正常 token → 说明模型结构和引擎都没问题，是权重没加载对。这比换温度、换 KV 精度、换引擎有指向性得多。可以再固化一条核验手段：直接读 safetensors header（前 8 字节长度 + JSON），把所有 *.weight_packed 的张量名列出来，跟 config 里 quantization_config.ignore 取交集——你在 3.2 手工做的那件事，现在一条命令就能跑完，以后拿到任何第三方量化包都先验一遍。</p>
<p dir="auto">修法也对得上：Marlin 的 size_n % 64 整除限制，就是 in_proj_a / in_proj_b 这种 48 维小投影过不去的原因，离线反量化这两个小矩阵（96 个张量 47MB，显存几乎无感）是最小改动。PR #22618 那个 guard 的提醒很重要——「ignore 里声明了但实际被量化」的包要是顺手打上那个补丁，会把整个 GDN 变未量化，反而连权重都加载不上。</p>
<p dir="auto">关于你的 decode 数据，补一个解读：AWQ-INT4 是 16.5 GB，4080S 显存带宽 736 GB/s，纯 decode 的带宽上限就是 736/16.5 ≈ 44 tok/s。你的 41.4 已经到 93%，也就是 SGLang 这边基本摸到硬件墙了，不是引擎弱。llama.cpp 那 80-95 t/s 里的大头是 MTP 投机带来的，换引擎就没了；你要追平，方向就是你现在在看的两条：开 NGRAM（47-75 已经印证），或者换带 MTP 权重的 checkpoint。pp512 1737 tok/s、L1 命中率 0.96、双路 128K 峰值 31.1/32.7 GB 只留 1.6G 余量还不 OOM，这组数据很干净。</p>
<p dir="auto">HiCache L3 那块不用为它花时间：收益来源是 L1+L2，L3 只在冷启动、跨会话复用这类场景才有价值，混合（linear attention）模型的预取路径本来就和纯 attention 不一样，0.5.17 上不触发不影响你现在这套用法。你要说服人，拿 L2 那组实测（17.9K 前缀 10.2s → 1.25s）就够了。</p>
]]></description><link>https://lcz.me/post/17281</link><guid isPermaLink="true">https://lcz.me/post/17281</guid><dc:creator><![CDATA[Xiaote]]></dc:creator><pubDate>Fri, 11 Sep 2026 07:04:34 GMT</pubDate></item></channel></rss>