本地推理的讨论长期围绕一个数字转:模型有多大。量化到几比特、能不能塞进显存、值不值得换张卡。而 arXiv 上 9 月 15 日挂出的 JustFit,把注意力挪到了另一个数字上——执行状态有多大,并给出了一个相当激进的实测结果。
硬件是一台 24GiB 内存的 M4 Pro MacBook。模型是 Qwen3.8-27B 的 MXFP4 量化版。三次独立运行,每次都完整跑完 196608 个输入 token 与 16384 个输出 token。
单请求可用上下文容量从 mlx-vlm 基线的 30720 个位置,提升到 212992 个位置,倍率 6.93 倍。
一、把瓶颈重新定位
论文的核心判断是:在长上下文场景里,权重占用是常数,而 KV 缓存是线性增长的。
27B 模型量化到 MXFP4 之后,权重占用是确定的。但上下文推到 20 万 token 时,KV 状态本身就可能超过权重。如果并发两个请求,还要再乘一遍。于是在同一台 24GiB 的机器上,限制来自状态而不是参数。
这个视角切换带来一个直接结论:模型权重的量化方案和上下文容量的伸缩方案,应该被解耦处理。JustFit 明确声明它的机制独立于权重量化——这一点很重要,意味着你可以沿用任何已有的权重量化方案,只把状态管理这一层换掉。
它由三个机制组成:
| 机制 | 负责的维度 | 解决的问题 |
|---|---|---|
| KVExec | 状态大小 | 压缩 KV 的直接执行,规避解压峰值 |
| PhaseSwap | 占用时机 | 按执行阶段决定组件驻留与换出 |
| StateTrans | 生命周期 | 服务切换时保全状态,避免重建 |
二、KVExec:让压缩态直接参与计算
压缩 KV 缓存有个常被忽略的陷阱:解压本身的开销。
朴素流程是「压缩存储、取出时解压、再算注意力」。但解压会在一瞬间产生一个完整的、未压缩的 KV 张量——这个瞬时峰值可能比压缩省下来的空间还大。结果是内存账面上限没变好,只是把压力从「持续占用」变成了「峰值尖刺」。
KVExec 的做法是融合重构与计算:让压缩态直接参与运算路径,只在必要时即时物化(just-in-time materialization)所需的片段,并且同步即时释放不再需要的部分。这不是把压缩率推到极致,而是把「物化—使用—释放」这个生命周期管住。
💡 一句话理解:它不追求单个张量更小,而追求任何时刻同时存活的张量总量更小。
这个区别在长上下文下被放大:上下文越长,同一时刻理论上的存活的中间量越多,管住生命周期带来的收益就越大。
三、PhaseSwap:按阶段而不是按大小做调度
第二个机制处理的是时间维度的错峰。
推理过程不是一段均匀的旅程。预填充阶段主要消耗 KV 状态写入、注意力矩阵计算;解码阶段每个 token 只处理一行,但权重访问频繁;权重加载本身又是另一波内存需求。这些需求在时间上并不同步,但在朴素的实现里,所有组件都从头到尾保持在场。
PhaseSwap 按执行阶段划分:此刻必须有谁在场、谁可以换出。它和 KVExec 正交——KVExec 管「状态有多大」,PhaseSwap 管「什么时候真的需要它」。两层叠起来,峰值占用才被真正压下去。
论文报告的一个可验证指标是:在重复执行的 32768 加 6144 token 工作负载下,进程中位峰值占用为 16374 MiB。这个数字释放出的余量,正是上下文能继续往上推的空间。
四、StateTrans:切换时的状态保全
第三个机制解决的是服务切换。本地推理工具在长任务里经常需要换模型、换配置、或者在预填充与解码之间做运行时切换,而每次切换如果都要重建执行状态,代价就是几十秒甚至几分钟的等待,长上下文下尤其不能接受。
StateTrans 做的是保状态的切换:让状态跨切换存活,而不是丢弃重建。对交互式使用来说,这决定了「能不能在长会话中做调整」,而不只是「能不能跑起来」。
五、实测数字
论文在 13 页、4 图、9 表里给了相当完整的测量,整理如下:
硬件 24 GiB 统一内存 M4 Pro MacBook
模型 Qwen3.8-27B (MXFP4)
─────────────────────────────────────────────
容量测试 3 次独立运行,均完成
196,608 输入 + 16,384 输出 token
单请求上下文 30,720 (mlx-vlm 基线)
→ 212,992 (JustFit)
倍率 6.93x
双请求总量 229,376 positions
─────────────────────────────────────────────
性能探针 32K 输入 + 64 输出 → 19.11 tokens/s
峰值占用 重复 32K+6K 负载,中位 16,374 MiB
─────────────────────────────────────────────
AIME 2026 29 / 30 正确
最后一行值得单独看:AIME 2026 三十道题答对二十九道。这不是一个容量指标,而是「容量扩大之后模型还能不能正确思考」的指标。论文的表述是「支持扩展的生成式推理」——意思是长思考链不会被内存压力截断,能力的兑现没有被基础设施掐掉。
另外要注意双请求那一行:229376 个位置是总量,不是每个请求的容量。两个请求共享这个额度,这与单请求场景的账不一样。
六、该有的怀疑
第一,19.11 tokens/s 是探针数字,不是生产数字。 它对应 32K 输入加 64 输出的短解码场景。上下文真正拉到 20 万时,解码速度会显著下降,论文没有把这一档的吞吐作为卖点,读者也不应该替它假设。
第二,平台绑定。 整个运行时基于 MLX,面向 Apple Silicon 的统一内存架构。这个架构的特殊性(CPU 与 GPU 共享物理内存,无需拷贝)是这套方案能成立的前提之一。搬到独立显存的平台上,PhaseSwap 的很多设计假设会失效。
第三,容量测试是单请求口径。 高并发服务场景关注的是「多少请求共享多少 KV 预算」,而论文的 6.93 倍是单请求容量。把它当作并发容量的提升会严重误判。
第四,基线选择的敏感性。 6.93 倍是与 mlx-vlm 基线对比得到的。换一个不同的基线实现,倍率会变。看这类论文时,倍率永远要连着基线一起读。
结语
JustFit 的价值主要在提问方式上。它把「本地能跑多长的上下文」从一个关于显存的硬件问题,改写成了一个关于执行状态生命周期管理的系统问题。
这个改写带来的实际好处是:你不需要换更贵的硬件,也不需要接受更激进的权重量化损失,而是通过让「物化、使用、释放」这个循环更紧凑来换容量。
对于做本地长文档处理、离线代码库审查、或者单纯想在笔记本上跑完整推理链的人来说,这是一个值得跟进的工程方向——只要记住 6.93 倍是单请求容量口径,而 19.11 tokens/s 是短探针口径,两者不能混着用。