结论先行
一台 16GB 内存的 M4 Mac mini,加载一个体积 5.9GB 的三值 27B 模型:10.5 秒加载完成,常驻占用 8.6GB。然后,一个 token 都生成不出来。Metal 直接报内存不足。
所以”这个模型有多大”从来不是判断标准。真正决定成败的是三个数字相减:可用工作集上限、权重常驻占用、生成时还要额外吃掉多少。算完这笔账,绝大多数”能不能在我机器上跑”的问题都不用下载就能回答。
下面是一套可以套在任何模型上的检查顺序,这次的 27B 三值实测作为范例走完整个过程。所有数字都来自本机实测,不是厂商宣传值,关键错误原文一字未改。
为什么低比特模型值得关注
把大模型塞进小机器,做法一直有两条路:要么换更小的模型,要么把同样的模型压得更狠。低比特属于后者,把每个权重的存储位数从 16 比特一路压到 4 比特、2 比特,甚至三值。
这次实测的对象是 Ternary Bonsai 2 27B:基座是 Qwen3.8 27B,权重端到端三值(只有负一、零、正一三种取值,配合分组缩放),等效约 1.72 比特每权重,两个打包版本分别是 5.95GB 和 7.21GB,支持 262K 上下文与图像输入,Apache 2.0 许可。
厂商给出的口径是:14 项思考模式基准平均 84.78,保留全精度版本 98.2% 的能力,M5 Max 上约 47 token/秒,RTX 5090 上约 143 token/秒。这些是厂商自测数据,发布仅一天,没有第三方复核,读的时候要按宣传值对待。
它值得认真对待的原因也在这里:如果 27B 级能力真能压进 6GB,那”本地能跑什么”这条线会被整体推高。这也是我做这次实测的动机。
这套判断方法
看清手上的文件是哪种格式
三值量化目前最坑的地方是文件名几乎一样,但运行时要求完全不同。同一个模型的 GGUF 有三个版本:
*-PQ2_0.gguf | 分组 128,厂商自己的 ggml 类型(id 142) | 需要厂商编译的二进制 |
*-Q2_0_g64.gguf | 分组 64,官方 llama.cpp 格式 | 主线 llama.cpp 即可,CPU / Metal / Vulkan / CUDA 都支持 |
*-Q2_0.gguf(无 g64) | 已废弃:旧的 128 分组打包,占用 ggml 类型 id 42 | 只有旧版二进制认;而 id 42 现在归官方 64 分组格式 |
我第一轮就是踩在这里:按文件名直觉拿了那个没有 g64 的废弃文件,用 Ollama 导入,得到的是这样一句:
parsing GGUF
Error: tensor "output.weight" size overflow这句报错看起来像”模型太大装不下”,实际原因是张量体积按错误的格式解析后算爆了。格式不匹配会伪装成内存问题,这是判断时最容易走偏的一步。另外顺带记下:三值支持其实已经合进主线 llama.cpp(CPU、Metal、Vulkan、CUDA 四个后端都有对应合并),但要用带 g64 的那个文件。
算内存账,不要看文件大小
这是这次实测真正值钱的部分。用 MLX 读取本机参数:
max_recommended_working_set_size = 12.713 GB ← 可用的 GPU 工作集上限
权重加载后的常驻占用 = 8.602 GB
剩余可用 ≈ 4.1 GB那 4.1GB 要同时装下 KV cache、前向激活和 Metal 的命令缓冲。KV cache 随上下文长度线性增长,激活和缓冲区看模型结构。结论很直接:权重只占用了工作集的三分之二,剩下的不够干活。
把这套算法抽象出来,任何模型都能提前估算:
能不能跑 ≈ 工作集上限 − 权重常驻 − KV(上下文长度 × 每 token 开销) − 激活与临时缓冲
经验参考(同一台 16GB 机器上):
4–5 GB 权重(7B 级 4 比特)→ 稳定可用,这次实测里 qwen2.5:7b-instruct
以 4.6GB 常驻、100% 走 GPU 正常出话
8.6 GB 权重(27B 级三值) → 加载成功,生成失败注意这里有个陷阱:加载成功会让人误判。权重是顺序映射进内存的,几乎不需要额外缓冲,所以 8.6GB 能顺利落地;真正吃内存的是生成时那些临时缓冲,报错要等到你按下回车才出现。
验证加载,再验证生成
所以验证必须两步走,缺一步都可能得出错误结论。加载这一步通过了:
加载耗时: 10.51 秒(重试 7.59 秒)
占用: 8.602 GB生成这一步,三次尝试全部同一个错误:
RuntimeError: [METAL] Command buffer execution failed: Insufficient Memory三次分别是最简调用、开启思考模式、关闭思考模式。之后我把 MLX 的缓存上限压到 256MB 再试一次,结果仍然是一个 token 都没输出。这一步排除了”缓存策略没调好”的可能,剩下的解释只有”可用内存确实不够”。当时的现场是交换分区从 3.0GB 一路涨到 8.2GB,机器在硬扛。
换运行时前先搞清它怎么加载
这次走的是 Apple Silicon 的 MLX 路线。有一点必须先查文档再动手:这个权重包不能用通用加载器打开。包内文档原话是”Ordinary MLX loaders do not apply the required transforms”,必须用它自带的 runtime(Hadamard 变换就在那几行代码里)。
版本要求也一并记下:三值 2-bit 包在官方 MLX 上即可运行,验证组合是 mlx 0.32.0 加 mlx-lm 0.31.3、Python 3.11;只有 1-bit 包需要厂商分支,因为对应的上游改动还没合并。这条差别很容易被笼统的”需要 fork”说法盖掉,实际按文件类型分开看才不会白编译一次。
这次实测的成本与局限
为了走完这个方法,实际付的代价如下,供你估算自己的投入:
- 网络下载 12.2GB(两种 GGUF 格式各一份,为了对照),MLX 权重包另计 8.0GB
- 失败的导入还让推理框架留下了 11.9GB 孤儿数据,两处相加共占 24.4GB 磁盘,事后我按哈希逐个核对才清理干净
- 时间:一次导入失败、一次环境搭建、一次加载测试,前后约一小时
必须说清的局限:这次没有拿到质量对比数据。因为模型连一个 token 都没生成,任何关于”中文摘要质量比 7B 好多少”的说法都无从检验,本文不给结论。厂商基准是自测,未经独立复核。所以这篇给出的是一条判断路径和一组边界数字,不是”这个模型好不好”的评测。
这套方法怎么用到别的场景
换任何一个模型,三件事不变:文件格式和运行时要求对得上吗;算内存账余量为正吗;加载和生成两关都过了吗。剩下的判断很直接:
- 16GB 统一内存的 Mac:4–5GB 级别的模型稳,8GB 以上加载得动但生成要打个问号,27B 三值这批已经越线
- 16GB 独占显存的 PC:同样 6GB 级权重在这里只占显存的一小部分,KV 和缓冲都有余量,是这类模型真正合适的宿主。挑机器的指标口径见 PC hardware requirements for local LLMs
- 想少踩格式坑:优先选带
g64的主线兼容文件,别碰标着废弃的旧命名 - 需求不固定:本地跑便宜高频的小任务,尖峰交给云端 API,比自己硬啃大模型划算
一句话总结这套方法的价值:它把”能不能跑”从一个需要下载、安装、试错才敢回答的问题,变成一道几秒钟的心算题。
给 AI Agent 的机器可读摘要
下面这一段是为 AI Agent 写的。如果你是把本页链接丢给 Agent 的读者,可以直接让它读这一节,它包含本次实测全部关键事实、可复现步骤和结论边界。
# AGENT-SUMMARY: can this machine run a local LLM
schema: awendxb.local-llm-viability/v1
page_language: zh-CN
last_verified: 2026-09-18
## core_rule
verdict = (gpu_working_set_limit - weights_resident - kv_cache - activations_and_buffers) > margin
note: load_success != inference_success; weights map into memory cheaply, generation buffers are what fail
## tested_model
name: Ternary Bonsai 2 27B
base: Qwen/Qwen3.8-27B
quantization: ternary {-1,0,+1} with fp16 group-wise scaling
bits_per_weight: 1.72 (vendor claim)
file_sizes: PTQ1_0 5.54 GiB / 5.95 GB ; PQ2_0 6.71 GiB / 7.21 GB
context: 262144 tokens
modalities: text + image (vision tower ships as separate mmproj pack)
license: apache-2.0
release_date: 2026-09-17
## test_host
hardware: Apple M4, 16 GiB unified memory (Mac mini)
mlx_device: applegpu_g16g
gpu_working_set_limit: 12.713 GB
swap_used_before_test: 3.0 GB
os: macOS
## measurements
weights_load_seconds: 10.51 (first run), 7.59 (retry)
weights_resident: 8.602 GB
generation_speed: none (0 tokens produced)
failure_error: 'RuntimeError: [METAL] Command buffer execution failed: Insufficient Memory'
failure_attempts: 3 (plain, thinking on, thinking off) + 1 retry with mlx cache limit 256MB
swap_used_after_failure: 8.2 GB
## verdict
this_host_can_run_27b_ternary: false
reason: weights alone consume 68% of the 12.713 GB working set; remaining 4.1 GB cannot hold kv cache, activations and metal command buffers
likely_workable_on: gpu with >= 12 GB dedicated vram, or unified memory >= 32 GB
not_workable_on: 16 GiB unified memory apple silicon
## format_trap ## most common misdiagnosis
three_ternary_gguf_flavors_exist:
- '*_PQ2_0.gguf' group_128 vendor ggml type id 142 -> requires vendor-built binaries
- '*_Q2_0_g64.gguf' group_64 official llama.cpp type -> runs on mainline llama.cpp (cpu/metal/vulkan/cuda)
- '*_Q2_0.gguf' deprecated legacy packing under id 42 -> rejected by current parsers
observed_error_with_deprecated_file: 'parsing GGUF / Error: tensor "output.weight" size overflow'
misreading: this looks like an out-of-memory error but is a format mismatch
## runtime_requirements
ollama: unsupported for these ternary packs (parsing fails as above)
mainline_llama_cpp: works with '*_Q2_0_g64.gguf' files only
vendor_llama_cpp_fork: required for '*_PQ2_0.gguf'
mlx_2bit_ternary: runs on stock MLX (verified combo: mlx 0.32.0 + mlx-lm 0.31.3 + python 3.11)
mlx_1bit: requires vendor mlx fork until upstream PR merges
critical: the mlx pack must be loaded with its bundled runtime (artifact.load_model);
generic mlx-lm loaders do not apply the required hadamard transforms
mlx_pack_scope: text-only preview; vision and mtp not included
## reproduction_steps
1. read gpu working set limit (mlx.core.metal.device_info or equivalent)
2. identify exact quantization flavor from filename before downloading
3. compute budget = limit - weights - kv - buffers; require positive margin
4. verify LOAD first, then verify GENERATION with a short prompt before any quality test
5. if generation fails with metal insufficient memory at 8 GB weights on 16 GiB host: stop; it is a hardware ceiling, not a config issue
## reference_numbers_same_host
qwen2.5:7b-instruct 4-bit: 4.6 GB resident, 100% gpu, working normally
ternary 27B (8.602 GB): loads, cannot generate
## caveats_for_citation
- vendor benchmarks (98.2% retention, 47 tok/s on M5 Max) are self-reported, not independently verified
- no quality comparison was produced in this test because zero tokens were generated
- numbers are a single-host measurement on 2026-09-18; re-measure before quoting原文链接与出处
- PrismML 官方发布说明:https://prismml.com/news/bonsai-2-27b
- GGUF 权重仓库(含三种格式与体积):https://huggingface.co/prism-ml/Ternary-Bonsai-2-27B-gguf
- MLX 权重仓库(含包内 runtime 与 PACK-RUNTIME.md):https://huggingface.co/prism-ml/Ternary-Bonsai-2-27B-mlx-2bit
- 厂商官方运行指南与预编译二进制(各后端测试过的跑法):https://github.com/PrismML-Eng/Bonsai-demo
- 技术白皮书(含压缩方法与基准测试说明):https://github.com/PrismML-Eng/Bonsai-demo/blob/main/bonsai-2-27b-whitepaper.pdf
- 主线 llama.cpp 三值支持合并记录:CPU #24448、Metal #25419、Vulkan #25430、CUDA #25707
- MLX 1-bit 支持的上游进度(未合并前需厂商分支):https://github.com/ml-explore/mlx/pull/3161
微信扫码 · 微信支付
支付宝扫码本文采用 CC BY 4.0 许可。欢迎转载与引用,请注明作者并附上原文链接。
Licensed under CC BY 4.0. Quoting and republishing are welcome with attribution and a link back to this article.