<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>KV Cache on Leon Li · 李梁</title><link>https://notes.liliang.me/tags/kv-cache/</link><description>Recent content in KV Cache on Leon Li · 李梁</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Thu, 01 Oct 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://notes.liliang.me/tags/kv-cache/index.xml" rel="self" type="application/rss+xml"/><item><title>给 Qwen3.8-Flash-Next 配内存 KV 缓存</title><link>https://notes.liliang.me/posts/2026-10-01-qwen38-flash-next-ram-kv-cache/</link><pubDate>Thu, 01 Oct 2026 00:00:00 +0000</pubDate><guid>https://notes.liliang.me/posts/2026-10-01-qwen38-flash-next-ram-kv-cache/</guid><description>&lt;p&gt;上一篇讲了怎么用 4 张 V100 跑 &lt;a href="https://huggingface.co/Qwen/Qwen3.8-Flash-Next"&gt;Qwen3.8-Flash-Next&lt;/a&gt;。这台机器主要给我的 Agent 用，会话动不动就是几十万 token。显存里能放约 110 万 token 的 KV 缓存，可会话一多，或者某个会话闲置一阵，它的缓存就会被挤出显存，下次再问只能从头重算。几十万 token 从头算，要好几分钟。&lt;/p&gt;&#10;&lt;p&gt;所以又加了一层主机内存缓存：显存放不下的 KV 先存到内存里，用到时再搬回显存。这篇记一下怎么设置，以及踩过的坑。&lt;/p&gt;&#10;&lt;h2 id="怎么设置"&gt;怎么设置&lt;/h2&gt;&#10;&lt;p&gt;引擎还是 &lt;a href="https://github.com/1CatAI/1Cat-vLLM"&gt;1Cat-vLLM&lt;/a&gt;，用它自带的 &lt;code&gt;OffloadingConnector&lt;/code&gt;：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--enable-prefix-caching --mamba-cache-mode align --prefix-cache-retention-interval &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--kv-transfer-config &lt;span style="color:#e6db74"&gt;&amp;#39;{&amp;#34;kv_connector&amp;#34;: &amp;#34;OffloadingConnector&amp;#34;, &amp;#34;kv_role&amp;#34;: &amp;#34;kv_both&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; &amp;#34;kv_connector_extra_config&amp;#34;: {&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; &amp;#34;spec_name&amp;#34;: &amp;#34;TieringOffloadingSpec&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; &amp;#34;cpu_bytes_to_use&amp;#34;: 68719476736,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; &amp;#34;eviction_policy&amp;#34;: &amp;#34;lru&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; &amp;#34;demote_superseded_states&amp;#34;: true,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; &amp;#34;mamba_state_slots_reference_tokens&amp;#34;: 65536}}&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中三个参数最关键：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;cpu_bytes_to_use&lt;/code&gt; 决定给缓存多少内存，我给了 64GB。容器总共 160GiB 内存，跑起来以后还剩 15GB 左右。别给得太满，系统和多模态预处理也要用内存。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;demote_superseded_states&lt;/code&gt; 让已经用完的旧状态优先被淘汰。不开的话，闲置的长会话很容易丢缓存（&lt;a href="https://github.com/1CatAI/1Cat-vLLM/pull/738"&gt;#738&lt;/a&gt;）。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;mamba_state_slots_reference_tokens&lt;/code&gt; 决定内存怎么分配，最需要按场景调，下面细说。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="为什么要分两种槽"&gt;为什么要分两种槽&lt;/h2&gt;&#10;&lt;p&gt;Flash-Next 是混合模型：一部分层是普通注意力，一部分是线性注意力（GDN）。普通注意力的缓存逐个 token 存；线性注意力存的是一份“状态”，而且只在请求结尾处才有。&lt;/p&gt;&#10;&lt;p&gt;要从内存里恢复一个会话，两样都得有。只有 token 缓存、没有对应位置的状态，前面存的东西就全用不上，还是得从头算。所以内存被分成了两块：token 槽存普通注意力的 KV，很便宜；状态槽存线性注意力的状态，一个就顶好几个 token 槽，数量少得多。&lt;/p&gt;</description></item></channel></rss>