☰
Janas 拆解:48GB 模型塞进 32GB 内存的笔记本,SSD 流式专家凭什么比 llama.cpp 快 8 倍
2026/10/14 5:41:43 网站建设 项目流程

十月九日到十一日,一台普通笔记本上跑完了一组违反直觉的对比测试。

机器是 32GB 内存的轻薄本,模型文件是 48.4GB 的 Qwen3-Next-80B。

模型比整机内存还大出一半,按常理它根本不该在这台机器上跑起来。

它不仅跑起来了,还以每秒 24 个词元的速度往外写回答。

同一台机器、同一份权重,llama.cpp 的写出速度是每秒 2.8 个。

八倍多的差距,来自一个叫 Janas 的新推理引擎。

它做的事一句话能说清:权重留在硬盘上,专家用谁读谁。

测试的机器配置很普通,英特尔的移动处理器加核显。

内存 32GB,硬盘是一块读速 5.7GB 每秒的 NVMe。

系统是最新的 Debian,内核 6.12,编译器 GCC 14。

这不是一台为跑大模型准备的机器,而这正是看点。

这篇文章把这笔账算细,看它快在哪里,又贵在哪里。

Janas 是什么

Janas 是一个用纯 C 写的人工智能工具家族,不依赖 C 库之外的任何东西。

它的第一个组件叫 Janas-LLM,专门在普通电脑上跑混合专家大模型。

作者是意大利的 Maurizio Cammalleri,项目以 GPLv3 开源。

项目目前由作者一人维护,他最想要的外部贡献是基准报告。

作者在页面开头就写明,这是实验品,不是产品。

接口和命令行每周都可能变,稳定性未经验证。

唯一给出承诺的是模型文件格式,.jns 第二版会被以后所有版本读取。

引擎之外,家族里还有天气、地震、地图等一串小服务。

但让这些服务成立的地基,是这个本地推理引擎。

这种先把丑话说在前面的写法,贯穿了整个项目的文档。

核心机制:专家留在 SSD 上

混合专家模型的关键特性,是每个词元只激活一小部分专家。

路由器给每个词元从数百个专家里点亮十来个,其余原地待命。

Qwen3-Next-80B 有八百多亿参数,每个词元实际用到的约三十亿。

八百亿激活三十亿,激活率不到百分之四。

也就是说,任何一个时刻,九成以上的权重都在闲着。

激活哪些专家由词元内容决定,单步看来事先无法预测。

但统计上,专家被点名的频率极不均匀。

少数热门专家承担大部分激活,这正是缓存能赢的原因。

Janas 的选择是,闲着的权重不占内存,全部留在 NVMe SSD 上。

轮到某个专家干活,才把它从盘里读出来。

反复被激活的热门专家,留在内存缓存里不再重复读盘。

在那台 32GB 的笔记本上,这个缓存稳定在 19GB 上下。

19GB 大约装下全部权重的四成,钉住的恰是最热的那批。

读盘用 O_DIRECT 直通模式,绕过操作系统页缓存,全速拉数据。

页缓存在这里是负资产,它会把内存浪费在只读一次的冷专家上。

冷专家冲刷页缓存,还会拖累系统里其他程序。

主动管理内存,是 Janas 和被动 mmap 路线的根本分歧。

为什么缓存命中率是生死线

SSD 路线成立的前提,是专家激活高度不均。

如果专家们被均匀激活,39% 的驻留缓存只能挡掉四成读盘。

真实模型的路由远比这偏心,热门专家被反复点名。

我用一个 Zipf 热度分布做了量级估算,脚本和输出如下。

N=128; k=4 cache_ratio=19.0/48.4 # 缓存驻留权重比例 c=int(N*cache_ratio) # 驻留专家数 = 50 s=1.1 # Zipf 热度参数 w=[1/(i**s) for i in range(1,N+1)] p=[x/sum(w) for x in w] hit=sum(p[:c]) # 激活落在缓存里的概率 miss_per_tok=k*(1-hit) read_mb=miss_per_tok*(48400/N) print(f"hit={hit*100:.1f}% miss/tok={miss_per_tok:.2f} read={read_mb:.0f}MB") print(f"ceiling={5700/read_mb:.1f} tok/s")

在本机真跑的输出是,命中率 86.4%,每词元期望读盘 206MB。

按这块 NVMe 实测 5.7GB/s 的顺序读速度,理论上限是 27.7 tok/s。

Janas 实测写出 24 tok/s,已经把理论上限吃掉了八成七。

同样的脚本按均匀激活重算,上限立刻掉到 6.2 tok/s。

llama.cpp 在这台机器上的 2.8 tok/s,甚至比均匀假设还差。

把两个上限和实测放在一起看,信息量很大。

实测 24 贴着 Zipf 上限 27.7,说明缓存策略接近最优。

这也侧面印证,这个模型的专家激活确实高度不均。

还要分清,提示词和回答是两个节奏完全不同的环节。

读提示词可以几百个词元一起并行,矩阵乘法铺满核显。

写回答必须一个词元一个词元串行,每步都要等专家到位。

所以 SSD 路线的瓶颈,永远先暴露在写出阶段。

这正是被动页缓存的代价,下一节看它具体卡在哪。

llama.cpp 为什么只有 2.8

先说清楚,llama.cpp 的常规配置在这台机器上直接内存溢出。

即使把专家留在 CPU 侧,只要核显参与计算,内存就会被吃光。

根因有两层,都藏在内存复制里。

第一层,llama.cpp 的 CPU 后端会把权重复制一份重新打包。

重新打包本来是给速度做的优化,小模型上这份复制是免费的。

48.4GB 的文件面前,复制打包就意味着内存里要再长出几十GB。

第二层,Vulkan 后端给留在 CPU 的部分也分配了系统回收不了的缓冲。

这个分配策略同样假设资源宽裕,48GB 面前假设失效。

两份复制叠在一起,32GB 的机器当场弹尽粮绝。

想跑起来,得专门编一个关掉重打包的版本。

再加上两个非默认参数,让专家留在文件里走页缓存读取。

这套抢救组合的最终成绩,是读提示词每秒 16 个词元。

写出回答只能靠 CPU,每秒 2.8 个,核显帮忙反而更慢。

页缓存是被动机制,内核不知道该预读哪个专家。

每个词元都在等磁盘随机读,速度自然被钉死在个位数。

llama.cpp 自己的 CPU 后端在这台机器上表现更差。

Qwen3-4B 用 CPU 后端 20 线程读提示词,每秒只有 70 个。

这不是 llama.cpp 的耻辱,它的设计目标从来不是这种场景。

把为装进内存设计的引擎,塞进装不进内存的场景,结果早已注定。

对比的方法学有多扎实

性能对比最容易造假的地方,是测量条件。

这组对比难得地把条件钉死了。

两边跑在同一台机器、同一份转换后的模型文件上。

测试集中在十月九日到十一日三天内完成。

llama.cpp 用的是九月十八日的构建,Vulkan 后端火力全开。

关键型号的数字来自三轮取均值,不是挑最快的一轮。

Janas 自己的基准表更狠,所有数字都是三轮均值。

每轮配置由引擎自己选定,模拟真实聊天负载。

提示词 256 个词元,然后写 64 个,交替顺序执行。

交替是为了让机器预热和缓存填充,平等地压在每个配置上。

两边写出数字都不带草稿预测,这是刻意的公平。

两种工具的测量口径其实略有差异,作者也主动交代。

llama.cpp 的基准在空提示后写出,Janas 在 1024 词元后写出。

这个差异对写出速度影响很小,但作者选择写在明处。

作者还明说,第一次跑会偏慢,因为缓存还没填满。

预期几次运行之间有几个百分点的浮动,这是实话。

引擎会自己测量机器

Janas 最不像玩具的地方,是它的自适应策略。

每个环节该用几个线程,引擎不靠猜,靠现场测。

每类环节的第一次运行,会逐个尝试每个核心。

性能核逐个单线程试,再试性能核的全部线程组合。

谁最快就用谁,之后还会偶尔重试其他选项。

机器热起来之后,允许推翻之前的结论。

在那台轻薄本上,读提示词和单词元写出都选定 12 线程。

12 正好是六个性能核的超线程数。

多词元并行的环节,才启用性能核加能效核的全部可用核心。

两个低功耗核心始终被排除在外。

换一台 i9-14900HX,每个线程的速度不到性能核 16 线程方案的一半。

同一套测量逻辑,在两台机器上得出完全不同的线程策略。

这种自适应在工程上的意义,是配置不再有银弹。

网上抄来的线程数参数,换台机器可能就是错的。

测量结论记在本机缓存里,换一台机器就重新校准。

基准工具还会把结果写成报告,方便用户回传给作者。

作者明说他最想要的贡献不是代码,是新机器上的报告。

这就是作者说的,选择从测量中来,这部分本来就该带走。

那张表里的全部数字

把同机对比的核心数字抽出来,是下面这张表。

模型读提示词 Janasllama.cpp写回答 Janasllama.cpp
Qwen3-Next-80B (48.4GB)6216242.8
Qwen3-30B-A3B1351223215
Qwen3.5-2B4413235228
Qwen3-0.6B93967013045

单位都是词元每秒,读提示词按 1024 个词元计。

从 0.6B 到 80B,Janas 在表里的每一行都更快。

小模型也快,说明优势不只来自 SSD 路线。

整个前向计算的工程实现,本身就更省时间。

表中唯一例外,是一个三位量化的 30B 模型读提示词略慢。

112 对 100,原因是那档量化权重还没接入核显的快速通道。

但它的写出速度仍然是 llama.cpp 的三倍,36 对 11。

投机解码的诚实样本

Janas 还支持草稿预测,小草稿先猜,大模型核验。

猜对多少,直接决定这个特性值多少。

作者的数字是,英文日常问题下草稿存活率 74% 到 89%。

换成意大利语散文,存活率掉到三分之一,几乎白猜。

存活率的方差提醒我们,文本分布本身也是变量。

同一个模型写代码和写散文,草稿的价值完全不同。

基准数字离开文本分布,本身就是一种误导。

多数项目到这里只会留下前一组数字。

这个项目还多做了一步,公开了自己算错的历史。

九月二十六日之前,草稿那一列的数字一直是错的。

当时测量用的是一段自我重复的文本,模型照抄就能猜对。

Qwen3.5-2B 因此虚报出每秒 107 个词元的好成绩。

发现之后,作者改了测量方法,并在更新日志里写清错因。

今天的表里,同一型号在草稿辅助下是 67,数字缩了水但可信。

dense 模型与 Windows 也快

SSD 流式专家是 MoE 的玩法,dense 模型怎么办。

dense 模型整个进核显,块整体送上去算。

在 Windows 11 下,Qwen3-4B 读提示词达到每秒 346 个词元。

比 Linux 下同模型的 193 还快,功臣是英特尔自己的 Windows 驱动。

同一台机器双系统,这个数字排除了硬件差异。

不用核显也行,环境变量关掉 GPU,Qwen3-4B 读 85 写 27。

纯 CPU 路线的写出几乎不掉,因为写出本来就主要靠 CPU 和盘。

Janas 的模型文件可以从 Hugging Face 直接下转换好的版本。

想自己转,仓库里有 GGUF 到 .jns 的转换工具。

转换只写新文件,不动原始模型,这是它的数据纪律。

整个工具只往两个地方写,缓存目录和用户指定的输出位置。

代码补全场景的账

引擎附带一个 HTTP 服务,能给编辑器做代码补全。

这里有一笔容易被忽视的账,窗口不能跟着光标滑。

每次按键都重读整个上下文,一次提案要 17 秒。

把发送窗口固定住,每次只读改动的部分。

同一个补全,延迟降到 1.5 到 2.2 秒。

七倍的差距不来自模型,来自上下文管理。

这个 HTTP 服务兼容 OpenAI 的接口形状。

编辑器插件不用认识 Janas,认识接口就够了。

同一引擎还能把模型挂成 MCP 工具服务。

Claude Code 这类客户端可以直接调用它。

这也是整个项目的缩影,省的都是不必要的数据搬运。

风险与边界必须说清楚

这套引擎对机器并不温柔。

打开模型时,专家缓存会吃掉当时所有空闲内存。

回答期间,磁盘被直通模式拉到全速。

内存余量不足的机器,桌面可能被挤进交换区卡死。

作者记录过一次 GPU 驱动重置,把整个桌面一起带走。

所以官方建议先在空闲机器上试,再谈日常使用。

想限制内存占用,有硬性参数可以封顶。

所有这些数字还有一个更大的限定词,一台机器。

整套引擎至今只在这台轻薄本上完整测过。

其他处理器、独立显卡、更慢的盘,全部未测。

模型权重本身的许可,归各自的作者所有。

Janas 只负责引擎,不重分发任何带限制的权重。

转换后的 .jns 文件被视为模型的衍生品。

转发转换文件前,要先核对模型原本的许可。

这笔账意味着什么

Janas 证明的不是某个具体速度,而是一个不等式。

当模型按稀疏方式激活,NVMe 带宽可以部分替代内存容量。

这台笔记本的盘每秒读 5.7GB,这是它的新显存。

llama.cpp 的 2.8 不是耻辱,它是为通用场景设计的默认值。

Janas 的 24 也不是魔法,是把一种访问模式压榨到理论上限的八成七。

同赛道里还有其他引擎在探索同一条路线。

Colibri 和 Strata 都在做 SSD 流式专家,侧重各不相同。

这个方向突然拥挤,说明内存墙是真痛点。

显卡内存容量这几年涨得远比模型尺寸慢。

当模型继续变大而显存不涨,盘和内存的层级就会被重排。

Janas 给出的答案是引擎主动管理,而不是依赖操作系统。

这个答案对不对,要看更多机器上的回报。

对想在本地跑大模型的人,最该抄的作业是测量方法。

同机同文件、三轮均值、交替顺序、公开错因,一个都不能少。

48GB 模型跑进 32GB 内存,靠的不是突破物理,而是尊重物理。

尊重的含义是,先量清楚自己的机器,再决定权重放在哪里。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询