32G内存的迷你主机跑大模型这两年从“玩具”变成了“能干活的备机”。我手上这台按标题里的配置代称叫 Mac mini M632G 统一内存日常挂在桌上当本地推理节点用。前后折腾了小半年从最早的“能跑起来就开心”到后来盯着eval rate一行数字较劲中间踩的坑比写的代码多。这篇就把三件事讲透这台机器的算力真相到底在哪、真实 TPS 能到多少、以及什么事该留在本地、什么事该扔给云端。不管你是刚买机器想试试水的新手还是已经在评估端云混合方案的老手下面这些数字和方法都能直接抄。我先把结论摊开32G 统一内存的甜点区是 7B 到 14B 的 4bit 量化模型32B 能跑但上下文一长就喘70B 基本别想。速度的天花板不在算力单元数量而在内存带宽端云决策的分水岭也不是“快不快”而是“这件事的数据能不能出门”。这两句话后面会用实测数据一条条对上。1. 先搞清楚这台机器到底能跑什么很多人拿到机器第一件事就是下载最大的模型然后被一条out of memory或者疯狂 swap 教做人。我第一周也这么干过跑 70B Q4 的时候系统直接卡成幻灯片鼠标都要等两秒才动。所以第一步不是测速是把“可用内存”这件事算清楚。1.1 32G 统一内存的真实可用额度统一内存的好处是 CPU 和 GPU 共享一块物理内存模型权重不用在两边拷来拷去这也是这类机器跑推理效率还不错的根本原因。但“共享”不等于“随便用”系统本身、图形界面、后台常驻服务加起来会先吃掉 6 到 8G剩下给推理的大概 24G 出头。更关键的是 GPU 侧的 wired limit。默认情况下系统只允许一部分内存被 GPU 锁定占用超过就要走换页。你可以用一条命令查当前上限sysctl iogpu.wired_limit_mb如果返回 0意思是走系统默认策略通常是物理内存的三分之二左右。我这台 32G 的机器默认给到 21G 上下。想跑到 28G 附近可以手动调sudo sysctl iogpu.wired_limit_mb28672注意这个值是“上限”不是“预留”调太高不会立刻出事但一旦系统和推理同时要内存就会开始换页速度断崖式下跌比直接跑不动更难受。我建议留 4G 以上余量给系统别顶格。所以实际能喂给模型的是“模型权重 KV Cache 计算中间量 框架自身开销”四部分之和。很多人只算权重结果 8K 上下文一开就崩问题就出在后面三项。1.2 模型尺寸与量化档位的对应关系量化档位直接决定权重体积也直接决定速度这两件事是绑在一起的。下表是我实测的落地数据按 GGUF 格式的 Q4_K_M 和 Q8_0 两档统计单位是 GB模型规模Q4_K_M 权重Q8_0 权重32G 可否容纳含 8K 上下文7B / 8B约 4.1 至 4.7约 7.5 至 8.5轻松可开 32K14B约 8.9约 15.5舒适建议 16K 以内32B约 19.8约 34勉强上下文压到 4K70B约 42超出不可行Q4_K_M 是我最推荐的默认档原因不是“小”而是它在 4.5 bit 左右的实际位宽下困惑度损失通常只有几个百分点日常问答、写代码、做摘要几乎感知不到差异。Q8_0 提升有限但体积翻倍在 32G 这个容量段性价比不高除非你做的是对数值精度敏感的任务。有一个反直觉的点不是所有 4bit 都一样。同样是 Q4K-quant 系列Q4_K_M、Q4_K_S因为对部分张量做了混合精度处理质量明显好于老的 Q4_0。我在同一批测试题上对比过Q4_0 在长句复述任务里会开始出现丢词Q4_K_M 基本没有。这个差别在体积上只有几百 MB值。1.3 哪些模型“能跑”和“能好用”是两回事能加载进内存只是及格线。我给自己定了个“好用”的门槛首字延迟低于 1.5 秒、生成速度高于 8 token/s、连续对话 20 轮不崩。按这三条筛下来14B Q4 是这台机器的舒适区上限32B Q4 属于“能跑但别指望当生产力”。这里有个容易被忽略的细节上下文长度对体验的影响是非线性的。同样是 14B Q44K 上下文时生成速度大概 11 token/s开到 32K 会掉到 8 出头因为 KV Cache 变大之后注意力计算和内存访问都变重了。所以别一上来就把上下文拉满按实际任务给写代码给 16K 够用日常问答 4K 到 8K 足矣。2. 算力真相解码阶段的瓶颈不在算力标题里“算力真相”这四个字是我最想聊的部分。市面上很多评测喜欢比“多少核 GPU”“多少 TOPS”但真跑起大模型你会发现这些数字和你看到的 TPS 几乎不相关。原因在于大模型推理分两个阶段两个阶段的瓶颈完全不是一回事。2.1 从内存带宽反推理论 TPS先讲解码阶段也就是模型一个字一个字往外蹦的那个阶段。这个过程里每生成一个 token都要把整个模型的权重从内存里读一遍和当前 token 的向量做一次乘加。注意是“整个模型读一遍”不是读一部分。这就意味着解码速度的上限由内存带宽除以每 token 需要读取的字节数决定理论 TPS ≈ 内存带宽(GB/s) / 单 token 读取量(GB)单 token 读取量约等于模型权重大小。拿 7B Q4 举例权重 4.1GB如果这台机器的内存带宽按 150GB/s 估算这是基于同系列基础款逐年提升趋势的合理推断具体以实测为准理论 TPS 就是 150 / 4.1 ≈ 36。实际测出来是多少我这边稳定在 22 到 25 之间大约是理论值的 65%。这个折扣来自三部分内存访问不是完美的顺序流、注意力计算要额外读 KV Cache、框架层有调度开销。所以你可以把“理论值乘以 0.65”当成一个快速估算公式用来判断一个模型在你的机器上大概能跑多快不用每次都实测。按这个公式往下推14B Q4 权重 8.9GB理论 16.8实测 11 到 1232B Q4 权重 19.8GB理论 7.6实测 4.5 到 5.5。三个数字摆在一起规律非常清楚模型越大TPS 越低而且降幅基本和权重体积成正比。这也解释了一个常见困惑为什么这台机器的 GPU 核心数比某些独显方案少很多跑小模型却不算慢因为小模型的解码根本不吃算力吃的是带宽而统一内存架构在带宽利用上效率很高没有跨总线拷贝的损耗。2.2 Prefill 与 Decode 的两套账刚才说的是解码。另一个阶段叫 prefill也就是模型读你输入的提示词、建立 KV Cache 的过程。这个阶段是可以并行的所有 token 一起算所以它吃的是算力而不是带宽。这两个阶段的性能差异极大。同一台机器上prefill 速度经常是 decode 速度的十几倍甚至几十倍。我实测 14B Q4 处理一段 2000 token 的输入prefill 大概 0.9 秒折合 2000 多 token/s而生成阶段只有 11 token/s 左右。这个差异带来的直接后果是短提示词的交互你感受到的是“首字延迟”长文档处理你感受到的是“等它读完”。前者几秒内后者可能十几秒。所以如果你的场景是长文档摘要优化重点应该放在 prefill如果是多轮对话优化重点在 decode 和 KV Cache 复用。提示主流推理框架都会分别打印prompt eval time和eval time看性能时千万别只看后一个。很多“某模型跑出 XX token/s”的宣传说的是 prefill 速度拿它当生成速度会严重误判。还有一个实用技巧多轮对话时如果框架支持 prompt cachellama.cpp 系默认支持第二轮开始只处理新增部分prefill 开销会大幅下降。我测过一段 30 轮的连续对话不开缓存时每轮平均要 1.2 秒才出首字开了之后稳定在 0.3 秒以内体感差别非常明显。2.3 KV Cache被忽视的内存黑洞前面反复提到 KV Cache这里单独算一笔账因为它是 32G 这个容量段最容易翻车的地方。KV Cache 的大小可以这样估每 token 字节数 2 × 层数 × KV头数 × head_dim × 每元素字节数以 8B 级别模型为例32 层、8 个 KV 头GQA、head_dim 128、fp16 存储算下来每 token 是 2 × 32 × 8 × 128 × 2 131072 字节也就是 128KB。8K 上下文就是 1GB32K 就是 4GB。再看 32B 级别64 层、8 个 KV 头、head_dim 128每 token 256KB8K 上下文直接 2GB32K 就是 8GB。这时候权重 19.8G 加上 8G KV Cache再加上计算中间量32G 根本兜不住。这就是为什么我说 32B 在这台机器上“上下文必须压到 4K”。一旦超过框架要么报错要么退化成换页速度从 5 token/s 掉到 1 以下完全没法用。有两个应对办法。一是开 KV Cache 量化把 fp16 降到 q8_0体积直接减半质量损失很小我在 14B 上对比过几乎无感二是用 GQA 头数更少的模型同样参数量下 KV Cache 能省一半以上。选模型的时候顺手看一眼 config 里的num_key_value_heads这个数字比参数量更能决定你能开多长上下文。3. 真实 TPS 实测怎么测、测出什么性能数据这东西别人给的不如自己测的。因为同一台机器框架版本、线程数、量化格式、上下文长度任何一个变了结果都能差 30%。这一节把我用的方法、参数和数据完整摊开你可以直接复现。3.1 测试环境与统一口径为了让数字可比我固定了几个条件同一台 32G 机器、同一版推理框架、固定 4 线程、关闭其他重负载应用、接电源不降频。测试用的提示词统一为一段约 350 token 的中文技术说明输出上限 512 token温度 0跑三轮取中位数。要看的指标有三个prefill 速度处理提示词的速度、decode 速度生成速度、首字延迟从提交到第一个 token 出现的时间。这三者对应的体验分别是“读得快不快”“写得快不快”“反应快不快”。# llama.cpp 系通用测法关键看这两行输出 llama-cli -m model.gguf -p 你的提示词 -n 512 -t 4 --temp 0 # 输出中关注 # prompt eval time ... ms / ... tokens ( ... tokens per second) # eval time ... ms / ... tokens ( ... tokens per second)跑的时候记得看系统内存压力。我会另开一个终端盯vm_stat如果 swap 增长明显那这组数据就作废因为测的是磁盘不是内存。3.2 五组模型的实测数据下面这张表是我这半年攒下来的核心数据全部为 Q4_K_M 量化上下文分别给 4K 和 16K 两档模型档位权重上下文Prefill (token/s)Decode (token/s)首字延迟7B Q44.1G4K约 95023.50.4s7B Q44.1G16K约 90021.80.5s14B Q48.9G4K约 62011.60.7s14B Q48.9G16K约 5609.90.9s32B Q419.8G4K约 2405.11.9s几个值得说的观察。第一从 7B 到 14Bdecode 速度几乎正好对半砍和权重体积翻倍吻合验证了前面那个带宽公式。第二上下文从 4K 拉到 16K7B 只掉 7%14B 掉了 15%说明模型越大、KV Cache 占比越高长上下文的代价越明显。第三32B 那行看着还能跑但首字延迟接近 2 秒多轮对话时会明显感到“卡顿”这就是我把它归为“能跑不好用”的依据。再补一组 Q8_0 的对照只测 7B 和 14B7B Q8 权重 7.5Gdecode 13.214B Q8 权重 15.5Gdecode 6.8。基本也是随体积线性下降。所以在这台机器上Q4_K_M 是性价比最优解这件事用数据是站得住的。3.3 我的复现脚本与操作步骤如果你想在自己的机器上跑一遍按下面这几步走十分钟能出结果。第一步装框架。我习惯用编译版而不是打包版因为可以针对本机架构开优化git clone https://github.com/ggerganov/llama.cpp cd llama.cpp cmake -B build -DGGML_METALON cmake --build build --config Release -j第二步下模型。选 GGUF 格式的 Q4_K_M文件名里带这个后缀的就是# 以 14B 级别模型为例 ./build/bin/llama-cli -m ./models/model-14b-q4_k_m.gguf \ -p 解释一下什么是内存带宽瓶颈 -n 256 -t 4 --temp 0第三步记录。把prompt eval time和eval time两行的 tokens per second 抄下来多跑三次。第一次往往偏慢因为模型刚加载、页缓存还没热取后两次的均值更准。第四步加压力。把-c 16384加上再跑一遍对比速度落差。这个落差就是长上下文成本也是你决定“给多大上下文”的依据。注意测速时别开着浏览器几十个标签页。我第一次测的时候忘了关数据比后来低了近 20%还纳闷了两天。统一内存架构下任何吃内存的后台程序都会间接影响推理速度测试环境要干净。4. 端云决策什么活留给本地什么活交给云端测完这些数字很多人会得出一个简单结论本地慢那就全上云。我不这么看。端云决策从来不是单纯比速度它有五个维度而且这五个维度的权重在不同场景下完全不同。4.1 五个维度的打分框架我把决策要素拆成延迟、成本、隐私、能力上限、稳定性五项每项按 1 到 5 分打分分数越高越倾向本地。这个框架不完美但比拍脑袋强。维度本地方案表现云端方案表现倾向延迟首字 0.5 到 2 秒稳定可预期网络好时 0.8 秒起波动大本地略优成本一次性硬件投入用越多越划算按量计费高频使用成本上升快看频次隐私数据不出机器数据需出境传输本地完胜能力上限14B 封顶可调更大规模云端完胜稳定性断网可用但会降频依赖网络与服务可用性各有短板关键在于这五项不是加总求平均而是看你的场景里哪一项是“一票否决”。涉及内部文档、客户资料、未公开代码的处理隐私这一项就是否决项速度慢点也得本地跑。反过来如果是公开资料的翻译、通用知识问答隐私不敏感那能力上限就成了主导因素该上云就上云。4.2 三种典型场景的决策表我把日常遇到的活分成三类每类给一个明确结论免得每次都要重新纠结。第一类是“数据敏感 中等复杂度”比如整理内部会议记录、给私有代码写注释、检索自己的笔记库。这类任务我全部放本地用 7B 或 14B 的 Q4 模型。速度虽然只有 10 token/s 上下但一段 500 字的总结也就等 50 秒可以接受。关键是数据一步都没离开机器这个安心感值这个等待。第二类是“数据不敏感 高复杂度”比如啃一篇长论文、做多步推理的数学题、生成复杂代码结构。这类我用云端因为本地 14B 在这类任务上会明显吃力容易答一半跑偏。这里的判断标准很简单如果本地模型连续两次答非所问就别硬扛了。第三类是“高频轻量”比如每天几十次的短文本改写、翻译、格式转换。这类我倾向本地原因是延迟稳定且没有边际成本。云端方案每次几百毫秒的网络往返几十次累积起来很烦而且高频调用下按量计费的成本会比想象中高。4.3 混合架构的落地方式真正实用的不是二选一而是一个能自动分流的入口。我自己的做法是在本地起一个兼容 OpenAI 接口的服务然后在调用层加一层路由规则。# 本地起服务暴露标准接口 ./build/bin/llama-server -m ./models/model-14b-q4_k_m.gguf \ -c 8192 --host 127.0.0.1 --port 8080 -t 4路由规则按优先级排命中敏感词库或指定目录的请求走本地上下文超过 8K 的走云端本地队列积压超过 2 个请求时溢出到云端其余默认本地。这套规则写下来不到 50 行代码但能把本地的隐私优势和云端的能力优势都吃到。提示路由层一定要做失败兜底。本地服务偶尔会因为内存压力退出这时候如果没兜底整个流程就断了。我的做法是本地调用超时 30 秒自动转云端并且把这次失败记进日志方便后面调参。还有一点经验不要为了“全本地”而牺牲任务质量。我早期有过一段时间坚持什么都本地跑结果一份需要跨文档对比的分析报告14B 模型给出的结论有明显遗漏返工花的时间远超省下的那点调用费。后来想明白了本地节点的定位是“高频、敏感、轻量”重活该外包就外包。5. 踩坑与排查速查表这部分是我这半年攒下来的问题清单几乎每个都真实卡过我半天以上。按内存、速度、稳定性三类整理遇到问题可以直接对表。5.1 内存相关的坑最常见的报错是加载到一半退出提示分配失败。这时候先别怀疑模型坏了按顺序查三件事当前 wired limit 是多少、有没有别的进程占着内存、上下文是不是给太大了。现象可能原因处理方式加载到 80% 退出权重加 KV Cache 超限降量化档或减上下文能加载但一对话就崩上下文开太大从 4K 开始往上试系统整体变卡触发换页调低 wired limit 或关后台程序速度突然掉到 1 以下正在 swap立刻停掉减模型有一条经验值得单独说内存不够时的表现不是“报错”而是“变慢”。系统不会立刻告诉你撑不住了它会悄悄开始换页你以为模型在思考其实它在等磁盘。所以测速时一定要盯 swap这个指标比任何日志都诚实。5.2 速度相关的坑同样是 14B Q4有人测出 12 token/s有人只有 6差距往往不在硬件而在配置。第一个坑是线程数。这类机器的核心是大小核混合架构线程数开太大会把任务调度到小核上反而拖慢。我实测 4 线程最优开 8 线程反而慢 15%。这个参数没有通用答案得自己二分试。第二个坑是没开 Metal 加速。编译时如果漏了-DGGML_METALON跑的就是纯 CPU速度差三到五倍。判断方法很简单看启动日志里有没有 Metal 相关的初始化信息。第三个坑是电源管理。用电池供电时会降频decode 速度能掉三成。插电测和电池测数据要分开记别混在一起比。5.3 稳定性相关的坑长时间跑任务时最容易遇到的是“跑着跑着变慢”。这通常是热降频机器温度上来后频率被压下去。我的处理是给任务分批每批之间留十几秒间隙让温度回落比一直满载跑要稳。另一个是服务进程莫名退出。查日志十有八九是内存峰值超了尤其是处理超长输入的时候prefill 阶段的中间激活值会比平时大不少。解决办法是给输入做长度上限或者把长文档先切块再喂。最后一条也是我觉得最值的一条经验给本地节点定一个“能力边界”写进配置文件而不是靠记忆。比如我的是“上下文不超过 8K、单次输出不超过 1K、并发不超过 2”。有了这条线路由层可以自动判断该不该转走也不会出现某天心血来潮丢个超长文档进去把服务搞挂的情况。边界清晰了这套本地加云端的组合才真的能长期跑下去而不是折腾两天就吃灰。
阅读完成 · 觉得有帮助?