﻿---
title: "几十美元的小盒子，为什么跑得动大模型"
description: "一台一百多美元的树莓派，单用户能把一个 300 亿参数的模型跑到约 8 token/s。顺着这个反差往下追：单路生成到底卡在哪、小盒子的内存带宽比数据中心 GPU 贵多少、300 亿参数怎么塞进 16GB 还跑得动、GPU 真正的本事是什么、为什么同样一笔账在「租 GPU 转卖 API」那篇里是亏的、这里却不亏，以及一大片这样的小盒子连起来会呈现什么整体性质。"

pubDate: 2026-10-20
tags: ["大模型", "推理", "内存带宽", "边缘计算", "成本测算"]
hero: "./hero.svg"
refs:
  - id: geerling-pi
    title: "Benchmark Qwen3 30B quantized model on Pi 5 16GB（Issue #47）"
    url: https://github.com/geerlingguy/ai-benchmarks/issues/47
    site: geerlingguy/ai-benchmarks
    date: "2025"
    note: "单台树莓派 5（16GB）用 llama.cpp 跑 Qwen3-30B-A3B（Q4 量化），token 生成约 8 tok/s（llama-bench tg128 7.99 ± 0.03）。"
  - id: pi-cluster
    title: "Raspberry Pi 5 cluster runs Qwen3-30B-A3B at 15 tokens/s on CPU"
    url: https://linuxgizmos.com/raspberry-pi-5-cluster-runs-qwen3-30b-a3b-at-15-tokens-s-on-cpu/
    site: LinuxGizmos
    date: "2025"
    note: "四台 Pi 5 用改版 distributed-llama，仅用 CPU 跑出约 15.14 tok/s；对比未改版基线 13.15 tok/s。"
  - id: apxml-decode
    title: "Decode Phase: Memory Bandwidth"
    url: https://apxml.com/courses/designing-and-sizing-production-llm-infrastructure/chapter-3-inference-dynamics-attention/decode-phase-memory-bandwidth
    site: APXML
    note: "batch=1 的解码阶段算术强度约 1 FLOP/byte（16 位：每参数 2 字节、约 2 FLOP），受内存带宽绑定；批量把权重读摊给多个请求，才从 GEMV 转向 GEMM。"
  - id: roofline
    title: "Why LLM Decoding is Memory-Bound: Prefill vs Decode Roofline"
    url: https://dev.to/ji_ai/why-llm-decoding-is-memory-bound-prefill-vs-decode-roofline-223f
    site: DEV Community
    note: "70B FP16 模型在 H100 单路解码的理论上限约 24 tok/s；算术强度约 1 FLOP/byte，远低于脊点。"
  - id: spheron-roofline
    title: "The Roofline Model for LLM Inference: Are You Compute Bound?"
    url: https://www.spheron.network/blog/the-roofline-model-for-llm-inference-are-you-compute-bound-o/
    site: Spheron
    note: "BF16 下 H100 大约要 280 个并发序列才进入算力绑定区；注意力部分几乎不随批次改变，KV cache 会成为新的带宽瓶颈。"
  - id: pi-bw
    title: "Raspberry Pi 5 memory benchmarks（STREAM）"
    url: https://zbotic.in/raspberry-pi-5-benchmarks-real-performance-numbers-vs-pi-4/
    site: Zbotic
    note: "STREAM Triad 约 11.2 GB/s（Pi 4 约 5.76 GB/s）。LPDDR4X-4267 32 位理论峰值约 17 GB/s，实测通常低于此。"
  - id: h100-spec
    title: "NVIDIA H100 GPU Specs, VRAM, Price and AI Performance"
    url: https://www.runpod.io/blog/nvidia-h100-gpu-specs-vram-price-and-ai-performance
    site: RunPod
    note: "H100 SXM：80GB HBM3，约 3.35 TB/s 带宽。整卡购置价各渠道从约 2.7 万到 5 万美元不等。"
  - id: h100-used
    title: "NVIDIA H100 Price – Is It Worth the Investment?"
    url: https://www.trgdatacenters.com/resource/nvidia-h100-price
    site: TRG Datacenters
    date: 2026-07
    note: "新卡单颗约 2.7 万美元起；二手 SXM5 随 B200 铺开跌到约 1.5 万–2 万美元。"
  - id: m4-bw
    title: "Apple M4"
    url: https://en.wikipedia.org/wiki/Apple_M4
    site: Wikipedia
    note: "M4 基础版 LPDDR5X 统一内存带宽 120 GB/s；M4 Pro 273 GB/s、M4 Max 最高 546 GB/s。消费级双通道 DDR5-5600 约 90 GB/s。"
  - id: qwen3-moe
    title: "Qwen3-30B-A3B"
    url: https://apxml.com/models/qwen3-30b-a3b
    site: APXML
    note: "总参数 30.5B，每 token 激活约 3.3B；48 层，每层 128 个路由专家取 top-8。"
  - id: gptoss
    title: "GPT-OSS Models"
    url: https://docs.nvidia.com/nemo/microservices/25.9.0/fine-tune/models/gpt-oss.html
    site: NVIDIA NeMo
    note: "gpt-oss-20b 总 20.9B / 激活 3.6B（32 选 4）；gpt-oss-120b 总约 117B / 激活 5.1B，权重以 MXFP4 存储，约 61GB，单张 80GB 卡可放。"
  - id: deepseek-v3
    title: "DeepSeek-V3"
    url: https://ai.azure.com/catalog/models/DeepSeek-V3
    site: Azure AI
    note: "总参数 671B，每 token 激活约 37B（256 个路由专家 + 共享专家）。"
  - id: pi-power
    title: "Raspberry Pi 5 with 16GB RAM launched for $120"
    url: https://cnx-software.com/2025/01/10/raspberry-pi-5-with-16gb-ram-launched-for-120/
    site: CNX Software
    date: 2025-01
    note: "16GB 版 120 美元（8GB 80 美元、2GB 50 美元）。heise 实测满载功耗不到 9W。"
  - id: resale
    title: "租云 GPU 转卖大模型 API，能赚钱吗"
    url: https://twwy.net/blog/gpu-api-resale/
    site: twwy.net
    note: "同一站点早前的测算：按每卡时租金 / 可卖吞吐算 per-token 成本，再对市场最低价，多数情况下是负毛利。"
---

前阵子算过一笔账：租云上的 GPU、部署开源大模型、按 token 卖 API，到底能不能赚钱[^resale]。结论是大多数情况下亏钱——市场价压得太低，一张 H100 每小时几美元的租金，摊到能卖出去的 token 上就不够本。

但最近看到另一组数字，初看和上面那笔账是矛盾的：一台 16GB 的树莓派 5，硬件一百二十美元，用 `llama.cpp` 单机跑 Qwen3-30B-A3B——一个**三百亿参数**的模型——token 生成能到约 8 个每秒[^geerling-pi]。有人把四台拼成集群，也就到 15 个每秒[^pi-cluster]。

<figure class="dd dd-figure dt-figure">
<div class="dt-panel">
<div class="dt-title" id="t0-title">同一个 Qwen3-30B-A3B，两种硬件</div>
<div class="dt-scroll">
<table class="dt" aria-labelledby="t0-title">
<colgroup><col style="width:46%"><col><col></colgroup>
<thead>
<tr><th scope="col">硬件</th><th scope="col">单用户速度</th><th scope="col">大致价钱</th></tr>
</thead>
<tbody>
<tr><th scope="row">树莓派 5 · 16GB · 纯 CPU</th><td class="num">~8 tok/s</td><td class="num">$120</td></tr>
<tr><th scope="row">四台 Pi 5 拼集群</th><td class="num">~15 tok/s</td><td class="num">~$480</td></tr>
<tr><th scope="row">NVIDIA H100 · 单卡</th><td class="num c">—</td><td class="num">$27,000</td></tr>
</tbody>
</table>
</div>
</div>
<figcaption>表 0 · 三百亿参数的模型，一个一百多美元的小盒子单用户也跑得动；但四台拼起来只快了不到一倍</figcaption>
</figure>

8 token/s 大概是一个人正常读字的速度，单用户用起来不算难受。这里有两个说不通的地方：

1. 三百亿参数的模型，按常理是数据中心 GPU 的活。为什么一个几十到一百多美元、连独立显卡都没有的小盒子，也跑得动？
2. 既然能跑，为什么四台拼起来几乎不变快？多三倍的硬件，速度只涨了不到一倍。
3. 更要紧的是：如果小盒子跑大模型这么划算，前面那篇"转卖 GPU 亏钱"的账又该怎么理解？同样是算力和模型，怎么一个亏一个不亏？

本文就顺着这几个问题往下追。会发现关键只有一句话：**单用户、一个 token 一个 token 地生成，瓶颈根本不是算力，而是内存带宽**——而小盒子在"单位带宽的价钱"上，和数据中心的 GPU 其实是同一个量级。

## 一、单用户生成，到底卡在哪

### 现象：算力强得多的卡，单路也快不到哪去

先看一个反直觉的事实。一张 H100，纸面算力是树莓派的几千倍。可要是只有一个用户、让它一个 token 一个 token 地生成一个 70B 的模型，它的理论上限也只有每秒二十几个 token[^roofline]。算力碾压，单用户速度却没拉开几个数量级。算力显然没用在刀刃上。

### 原因：生成一个 token，主要时间花在"把权重搬一遍"

大模型生成是自回归的：要吐出下一个 token，得让当前的上下文从头到尾过一遍网络的每一层。这一步里，真正耗时的不是乘加运算本身，而是**把这一层的权重从内存搬进计算单元**。

关键在于 batch=1（只有一个请求）时的一个比例。每个权重是一个数，按 16 位存就是 2 个字节；用它算一个 token，大约只做 2 次浮点运算。也就是说，**每从内存搬 1 个字节，计算单元只需要做约 1 次运算**[^apxml-decode]。而现代 GPU 的算力和带宽之比（所谓"脊点"）动辄是几百比一——它期待你每搬 1 字节就喂给它几百次运算。单用户解码只喂来 1 次，于是计算单元绝大部分时间在**等内存**。

<figure class="dd dd-figure">
<div class="dd-scroll">
<svg class="dd-svg" viewBox="0 0 800 300" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="f1-title f1-desc">
<title id="f1-title">单路解码受内存带宽绑定</title>
<desc id="f1-desc">内存里存着每层权重；生成一个 token 要把权重通过一条带宽有限的通道搬进计算单元，计算单元因为每字节只算一次而大部分时间空闲。</desc>
<defs>
<marker id="f1-arrow" markerWidth="9" markerHeight="9" refX="7" refY="4.5" orient="auto"><path class="dd-head" d="M1 1 L7 4.5 L1 8"/></marker>
</defs>
<rect class="dd-frame" width="800" height="300" rx="10"/>
<rect class="dd-zone" x="16" y="16" width="300" height="268" rx="8"/>
<text class="t-zone" x="32" y="44">内存 · 存放全部权重</text>
<rect class="dd-card" x="36" y="60" width="124" height="30" rx="4"/><text class="t-mono" x="48" y="80">第 1 层 · W₁</text>
<rect class="dd-card" x="36" y="96" width="124" height="30" rx="4"/><text class="t-mono" x="48" y="116">第 2 层 · W₂</text>
<rect class="dd-card" x="36" y="132" width="124" height="30" rx="4"/><text class="t-mono" x="48" y="152">第 3 层 · W₃</text>
<text class="t-note" x="98" y="186" text-anchor="middle">⋮</text>
<rect class="dd-card" x="36" y="198" width="124" height="30" rx="4"/><text class="t-mono" x="48" y="218">第 N 层 · Wₙ</text>
<text class="t-say" x="176" y="118">每吐一个 token，</text>
<text class="t-say" x="176" y="140">要把这些权重</text>
<text class="t-say" x="176" y="162">完整搬一遍</text>
<line class="dd-edge-acc" x1="316" y1="150" x2="470" y2="150" marker-end="url(#f1-arrow)" stroke-width="2"/>
<rect class="dd-zone" x="336" y="120" width="120" height="60" rx="8"/>
<text class="t-zone t-acc" x="396" y="146" text-anchor="middle">内存带宽</text>
<text class="t-note" x="396" y="166" text-anchor="middle">一条窄通道</text>
<rect class="dd-zone" x="500" y="16" width="284" height="268" rx="8"/>
<text class="t-zone" x="516" y="44">计算单元</text>
<rect class="dd-derived" x="520" y="60" width="248" height="200" rx="8"/>
<text class="t-say" x="644" y="130" text-anchor="middle">每搬 1 字节，</text>
<text class="t-say" x="644" y="152" text-anchor="middle">只算约 1 次</text>
<text class="t-note" x="644" y="184" text-anchor="middle">大部分时间在等内存</text>
<text class="t-note" x="644" y="206" text-anchor="middle">（算力几乎闲置）</text>
</svg>
</div>
<figcaption>图 1 · 单用户生成一个 token ≈ 把权重从内存读一遍；决定速度的是这条"窄通道"的带宽，不是计算单元有多快</figcaption>
</figure>

于是单路解码的速度有一个干净的近似：

$$\text{每秒 token 数} \approx \frac{\text{内存带宽}}{\text{每个 token 要读的权重字节数}}$$

这条式子里压根没有"算力"。一台机器单用户跑得多快，几乎只由它的内存带宽、和模型每个 token 要读多少字节决定。**这就把问题从"小盒子算力够不够"，换成了"小盒子的内存带宽值多少钱"。**

既然决定速度的是带宽，那小盒子的带宽，到底比数据中心的 GPU 贵多少？

## 二、单位带宽的价钱，差得没那么多

### 现象：几万美元的卡，和一百多美元的盒子，摆在一起比

直觉上，H100 的内存带宽是 3.35 TB/s[^h100-spec]，树莓派是 11 GB/s 上下[^pi-bw]，差了三百倍，价钱也该差三百倍才对。但要比的不是"谁带宽大"，而是"**每单位带宽花了多少钱**"——因为单用户要的就是带宽这一样东西。把几种设备摆在一起算一下：

<figure class="dd dd-figure dt-figure">
<div class="dt-panel">
<div class="dt-title" id="t1-title">每单位内存带宽的价钱</div>
<div class="dt-scroll">
<table class="dt" aria-labelledby="t1-title">
<colgroup><col style="width:30%"><col><col><col class="hl"></colgroup>
<thead>
<tr><th scope="col">设备</th><th scope="col">内存带宽</th><th scope="col">大致价格</th><th scope="col">每 GB/s 成本</th></tr>
</thead>
<tbody>
<tr><th scope="row">树莓派 5 · 16GB</th><td class="num">~11 GB/s</td><td class="num">$120</td><td class="num">~$11</td></tr>
<tr><th scope="row">Mac mini M4 · 16GB</th><td class="num">120 GB/s</td><td class="num">$599</td><td class="num">~$5</td></tr>
<tr><th scope="row">H100 SXM · 80GB（二手）</th><td class="num">3,350 GB/s</td><td class="num">~$18,000</td><td class="num">~$5.4</td></tr>
<tr><th scope="row">H100 SXM · 80GB（新卡）</th><td class="num">3,350 GB/s</td><td class="num">~$27,000</td><td class="num">~$8</td></tr>
</tbody>
</table>
</div>
</div>
<figcaption>表 1 · 价钱差两百倍的设备，折算到"每单位带宽"后都落在每 GB/s 五到十一美元，同一个量级（带宽：STREAM / 官方规格；价格为 2026-10 各渠道估值）</figcaption>
</figure>

一台 120 美元的树莓派，和一张两万多美元的 H100，整机价钱差了两百倍；可折算到"每 GB/s 内存带宽的钱"，都落在**每 GB/s 五到十一美元**这个窄窄的区间里。有意思的是，Mac mini 这类消费级统一内存设备，单位带宽的价钱甚至比 H100 还低一点[^m4-bw]（二手 H100 随新卡铺开也在往下走[^h100-used]）；树莓派反而不是最便宜的——它赢在绝对价格和功耗，不在单位带宽。

### 原因：GPU 的价钱，大部分不是在买带宽

为什么会这样？因为一张 H100 卖两万多美元，买到的是**三样东西打包**：很高的内存带宽、很大的 HBM 显存容量、以及海量的算力。而单用户解码，只用得上其中的带宽——算力几乎全程闲置（第一节），容量也只需要装下一个模型。

换句话说，买 GPU 的大头，花在了单用户用不上的算力和昂贵的 HBM 容量上。真正被用到的那部分——带宽——按单价算，和便宜盒子上的普通内存并没有拉开量级。小盒子省掉的，正是你本来就用不上的那些。

这也顺带解释了：为什么是"内存带宽"而不是"显存大小"或"算力"成了单用户推理的硬通货。谁的带宽便宜，谁单用户跑得就划算。

可带宽便宜只解决了"跑得快不快"。还有一个更基本的问题没回答：三百亿参数的模型，怎么塞进一台 16GB 的小盒子，还能有 8 token/s？

## 三、MoE：把"装得下"和"跑得动"拆开

### 现象：16GB 装 300 亿参数，而且不慢

Qwen3-30B-A3B 是三百亿参数。就算压到 4 位量化，全部权重也有十几 GB，刚好能挤进 16GB 的树莓派。可按第一节那条式子，要是每个 token 都得把这十几 GB 全读一遍，以 Pi 约 11–15 GB/s 的带宽，一秒钟连一个 token 都吐不出来。实测却有 8 个。中间差了快一个数量级，差在哪？

### 原因：名字里的"A3B"——每个 token 只激活 30 亿

差别在模型结构。Qwen3-30B-A3B 是一个**混合专家模型**（MoE）：它有三百亿参数，但被切成了很多个"专家"，每生成一个 token，一个路由器只挑其中几个专家来算。它的名字 `A3B` 就是 **A**ctivated **3B**——每个 token 实际**激活**的参数只有约 33 亿，其余二十多亿参数这一步根本不读[^qwen3-moe]。

这就把两件一直被捆在一起的事拆开了：

- **装得下**，看的是**总参数**。三百亿都得在内存里待命，随时可能被某个 token 用到——这需要**容量**。而容量恰恰是小盒子便宜的东西：LPDDR、DDR 这类普通内存，每 GB 比 GPU 上的 HBM 便宜一两个数量级。
- **跑得动**，看的是**每个 token 激活多少**。只有被激活的那几十亿参数需要在这一步从内存读出来——这消耗的是**带宽**。激活得少，每个 token 要搬的字节就少，速度就快。

<figure class="dd dd-figure">
<div class="dd-scroll">
<svg class="dd-svg" viewBox="0 0 800 330" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="f2-title f2-desc">
<title id="f2-title">稠密模型与 MoE：同样装进 16GB，每 token 读取量差一个数量级</title>
<desc id="f2-desc">左边稠密 30B 每 token 读取全部约 15GB；右边 MoE 每 token 只读激活的约 1.65GB；两者都完整装在 16GB 内存里，但 MoE 快约八倍。</desc>
<rect class="dd-frame" width="800" height="330" rx="10"/>

<rect class="dd-zone" x="16" y="16" width="376" height="298" rx="8"/>
<text class="t-zone" x="32" y="44">稠密 30B · 16GB 内存</text>
<rect class="dd-card" x="32" y="60" width="344" height="150" rx="6"/>
<text class="t-note" x="204" y="92" text-anchor="middle">全部 30B 参数常驻</text>
<rect class="dd-fill-acc" x="44" y="108" width="320" height="86" rx="4" fill-opacity="0.85"/>
<text class="t-val" x="204" y="158" text-anchor="middle" style="fill:#fff">每 token 读取：全部 ~15 GB</text>
<text class="t-say" x="204" y="246" text-anchor="middle">~15 GB ÷ ~15 GB/s</text>
<text class="t-zone t-acc" x="204" y="276" text-anchor="middle" style="font-size:20px">≈ 1 tok/s</text>

<rect class="dd-zone" x="424" y="16" width="360" height="298" rx="8"/>
<text class="t-zone" x="440" y="44">MoE 30B（激活 3.3B）· 16GB 内存</text>
<rect class="dd-card" x="440" y="60" width="328" height="150" rx="6"/>
<text class="t-note" x="604" y="92" text-anchor="middle">全部 30B 参数常驻</text>
<rect class="dd-derived" x="452" y="108" width="304" height="86" rx="4"/>
<rect class="dd-fill-acc" x="452" y="108" width="40" height="86" rx="4"/>
<text class="t-val" x="520" y="152" text-anchor="start">每 token 只读激活 ~1.65 GB</text>
<text class="t-say" x="604" y="246" text-anchor="middle">~1.65 GB ÷ ~15 GB/s</text>
<text class="t-zone t-acc" x="604" y="276" text-anchor="middle" style="font-size:20px">≈ 8 tok/s</text>
</svg>
</div>
<figcaption>图 2 · 同样一台 16GB 的盒子、同样装着三百亿参数：稠密模型每 token 要读全部权重，MoE 只读激活的那一小块，于是快了约八倍</figcaption>
</figure>

所以 MoE 对小盒子几乎是量身定做的：它要的正是小盒子最便宜的那样东西（大容量的慢内存），而它省的正是小盒子最稀缺的那样东西（带宽）。近两年值得一跑的开源模型，大多是这个路子——从 gpt-oss[^gptoss] 到 DeepSeek-V3[^deepseek-v3]，总参数一个比一个大，每个 token 激活的却只有一小块：

<figure class="dd dd-figure dt-figure">
<div class="dt-panel">
<div class="dt-title" id="t2-title">几个 MoE 模型：总参数大，每 token 激活小</div>
<div class="dt-scroll">
<table class="dt" aria-labelledby="t2-title">
<colgroup><col style="width:34%"><col><col><col></colgroup>
<thead>
<tr><th scope="col">模型</th><th scope="col">总参数</th><th scope="col">每 token 激活</th><th scope="col">激活占比</th></tr>
</thead>
<tbody>
<tr><th scope="row">Qwen3-30B-A3B</th><td class="num">30.5B</td><td class="num">3.3B</td><td class="num">~11%</td></tr>
<tr><th scope="row">gpt-oss-20b</th><td class="num">20.9B</td><td class="num">3.6B</td><td class="num">~17%</td></tr>
<tr><th scope="row">gpt-oss-120b</th><td class="num">117B</td><td class="num">5.1B</td><td class="num">~4%</td></tr>
<tr><th scope="row">DeepSeek-V3</th><td class="num">671B</td><td class="num">37B</td><td class="num">~6%</td></tr>
</tbody>
</table>
</div>
</div>
<figcaption>表 2 · 总参数决定"要多大内存装得下"，每 token 激活决定"单用户跑多快"；MoE 让两者差出一个数量级（来源：各模型官方 / NVIDIA / Azure）</figcaption>
</figure>

到这里，小盒子跑得动大模型的两个条件都齐了：单用户只吃带宽（第一节），小盒子的带宽单价不贵（第二节），而 MoE 让"每 token 要读的字节"小到这点带宽也够用（本节）。

可这就带出一个尴尬的问题：如果单用户推理在小盒子上这么合算，那几万美元的 GPU，它的本事到底体现在哪？

## 四、GPU 的本事，在"一次搬运喂很多人"

### 现象：同样的卡，服务一个人和服务两百人，经济性天差地别

答案藏在第一节那个"每搬 1 字节只算 1 次"里。对单用户，这是浪费——算力闲着。但如果同一时刻有很多个用户的请求排在一起呢？

### 原因：权重只搬一遍，批次里每个人各拿一个 token

GPU 生成时，把一层的权重从内存搬进计算单元，这一次搬运的成本是固定的。关键在于：**这一次搬进来的权重，可以同时为批次里的每一个请求各算出一个 token**。批次里有 1 个请求，这次搬运产出 1 个 token；有 200 个请求，同样一次搬运就产出 200 个 token——而内存只读了一遍。

<figure class="dd dd-figure">
<div class="dd-scroll">
<svg class="dd-svg" viewBox="0 0 800 300" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="f3-title f3-desc">
<title id="f3-title">批量把一次权重读摊给很多用户</title>
<desc id="f3-desc">同一次把权重从内存读进计算单元，batch=1 只产出一个 token，batch=200 同时产出两百个 token；总吞吐随批次上升，但每个用户轮到下一个 token 的间隔变长。</desc>
<defs>
<marker id="f3-arrow" markerWidth="9" markerHeight="9" refX="7" refY="4.5" orient="auto"><path class="dd-head" d="M1 1 L7 4.5 L1 8"/></marker>
</defs>
<rect class="dd-frame" width="800" height="300" rx="10"/>

<rect class="dd-zone" x="16" y="16" width="250" height="268" rx="8"/>
<text class="t-zone" x="32" y="44">一次权重读</text>
<rect class="dd-card" x="36" y="64" width="210" height="40" rx="6"/>
<text class="t-mono" x="141" y="88" text-anchor="middle">把一层权重搬进计算单元</text>
<text class="t-say" x="141" y="140" text-anchor="middle">这一次搬运的</text>
<text class="t-say" x="141" y="162" text-anchor="middle">内存成本是固定的</text>
<text class="t-note" x="141" y="200" text-anchor="middle">搬一次 ⇒ 可服务</text>
<text class="t-note" x="141" y="222" text-anchor="middle">整个批次</text>

<rect class="dd-zone" x="282" y="16" width="240" height="268" rx="8"/>
<text class="t-zone" x="298" y="44">batch = 1（单用户）</text>
<line class="dd-edge" x1="266" y1="84" x2="300" y2="130" marker-end="url(#f3-arrow)"/>
<rect class="dd-card" x="310" y="110" width="180" height="40" rx="6"/>
<text class="t-name" x="400" y="134" text-anchor="middle">1 个请求 → 1 个 token</text>
<text class="t-say" x="402" y="196" text-anchor="middle">算力几乎闲置</text>
<text class="t-note" x="402" y="226" text-anchor="middle">单用户快，但卡没吃饱</text>

<rect class="dd-zone" x="538" y="16" width="246" height="268" rx="8"/>
<text class="t-zone" x="554" y="44">batch = 200</text>
<line class="dd-edge-acc" x1="522" y1="84" x2="556" y2="96" marker-end="url(#f3-arrow)" stroke-width="2"/>
<rect class="dd-card" x="556" y="60" width="210" height="22" rx="4"/><text class="t-mono" x="661" y="76" text-anchor="middle">请求 1 → token</text>
<rect class="dd-card" x="556" y="86" width="210" height="22" rx="4"/><text class="t-mono" x="661" y="102" text-anchor="middle">请求 2 → token</text>
<text class="t-note" x="661" y="126" text-anchor="middle">⋮</text>
<rect class="dd-card" x="556" y="134" width="210" height="22" rx="4"/><text class="t-mono" x="661" y="150" text-anchor="middle">请求 200 → token</text>
<text class="t-say t-acc" x="661" y="196" text-anchor="middle">一次搬运产出 200 个 token</text>
<text class="t-note" x="661" y="226" text-anchor="middle">总吞吐高，但每人更慢</text>
</svg>
</div>
<figcaption>图 3 · 批量推理把一次权重读的成本摊给整个批次：总吞吐随批次上升，这正是 GPU 省钱的来源，但每个用户轮到下一个 token 的间隔也被拉长</figcaption>
</figure>

这就是数据中心 GPU 真正的本事：**它靠把一次权重搬运摊给几百个并发用户来省钱**。BF16 下，H100 大约要同时服务两百八十个序列，算力才被喂饱、带宽也物尽其用[^spheron-roofline]。到那时，每个 token 的成本被摊薄几百倍，这才是它比小盒子"便宜"的地方——但便宜的前提是**真的有几百个用户同时在用**。

代价是：批次越大，每个用户轮到下一个 token 的间隔越长，单用户速度反而下降。总吞吐和单用户速度是此消彼长的。

现在回头看小盒子：它只有一个用户。GPU 唯一的省钱武器——大批量——在这里根本使不出来。一个用户填不满批次，那几百倍的摊薄就无从谈起。于是单用户恰好是 GPU 最发挥不出优势的区间：你要么为用不上的算力和一张卡付全价（只用了约 1/280），要么老老实实买一台只够一个人用、但带宽单价差不多的小盒子。

这也正好接回了开头那个矛盾。

## 五、同样一笔账，为什么转卖是亏的、自用不亏

### 现象：一个结论是负毛利，一个结论是划算

转卖那篇[^resale]的账是这么算的：租一张 GPU，每小时付固定租金，把它产出的 token 按市场价卖出去。算下来多数情况是负毛利——卖价还不够付租金。可同样是 GPU 和模型，小盒子自用却很划算。差别不在硬件，在**成本结构**。

### 原因：一个要去市场上拼 per-token 单价，一个不用

转卖的生意，卖的是 token，要和整个市场拼每百万 token 的价钱。而市场最低价是谁定的？是规模最大、批次最满、把第四节那套摊薄做到极致的玩家。一个租几张卡的散户，凑不齐那么多并发用户，批次填不满，每个 token 的成本就压不下来，自然拼不过市场价——这是那篇的核心结论。

自用的小盒子，账完全是另一套：

- 它**不需要去市场上和任何人拼 per-token 单价**。没有要打败的卖价，只有"这台盒子对我一个人够不够用"。
- 它的成本是**一次性购置**（一百多美元）摊到自己的使用，加上几瓦电——树莓派满载也就不到 9 瓦[^pi-power]，电费可以忽略。它大部分时间闲着也无所谓，因为它本来就便宜。
- GPU 最贵的那部分（HBM 容量、海量算力）对单用户是纯浪费（第二、四节），小盒子直接不买这部分。

<figure class="dd dd-figure dt-figure">
<div class="dt-panel">
<div class="dt-title" id="t3-title">两笔账的成本结构不一样</div>
<div class="dt-scroll">
<table class="dt" aria-labelledby="t3-title">
<colgroup><col style="width:22%"><col><col></colgroup>
<thead>
<tr><th scope="col"></th><th scope="col">租 GPU 转卖 API</th><th scope="col">小盒子自用</th></tr>
</thead>
<tbody>
<tr><th scope="row">卖给谁</th><td>公开市场，很多人</td><td>自己一个人</td></tr>
<tr><th scope="row">要对的价</th><td class="bad">市场最低 per-token 价</td><td class="good">没有，只看够不够用</td></tr>
<tr><th scope="row">靠什么省钱</th><td>大批量摊薄（要几百并发）</td><td>硬件便宜 + 功耗低</td></tr>
<tr><th scope="row">用得上 GPU 的批量优势吗</th><td>要，且很难做到</td><td class="good">不需要</td></tr>
<tr><th scope="row">成本大头</th><td>每小时租金 × 低利用率</td><td class="good">一次性购置，几瓦电</td></tr>
</tbody>
</table>
</div>
</div>
<figcaption>表 3 · 转卖要在别人最擅长的"大批量摊薄"战场上拼单价，自用则绕开了整个战场——单用户恰好是 GPU 的批量优势失效的地方</figcaption>
</figure>

一句话：**转卖是在 GPU 最擅长的战场（大批量）上和它拼，自用是在 GPU 最不擅长的战场（单用户）上绕开它。**同一组硬件事实，站在批量这边看是"GPU 碾压"，站在单用户这边看是"小盒子够用且便宜"，两篇文章并不矛盾。

说到自用，马上有人会问：那又何必买块盒子放在家里？云上随手租一个 4 核 8G 的实例，不也是一台没有显卡、靠 CPU 跑的机器吗？这个对照值得单拎出来讲，因为它能把前面几节的结论用在一个很实际的选择上。

## 六、那不如云上租个 4c8g？

### 现象：一个 4c8g 实例，看着和小盒子是一回事

一个 4 核 8G 的云实例，本质上也是一台没有独立显卡、靠 CPU 跑模型的小机器。它跑起大模型来遵循的是和盒子一模一样的那条公式，所以那个"4 核"几乎不影响解码速度——真正决定每秒多少 token 的，还是这台（虚拟）机器的**内存带宽**，以及 8GB 装得下多大的模型。两边带宽相近、又都是 8GB，出来的速度就在同一个量级。

换句话说，单论"能不能跑、跑多快"，盒子和 4c8g 实例基本是一回事。真正的差别在别处。

### 原因：带宽未必独占，8GB 是同一道坎

**带宽是不是你一个人的。** 盒子那十几 GB/s 完全归你，稳定。4c8g 则是从一台大服务器上切出来的一小片，内存控制器和同机的邻居共享。碰上"吵闹的邻居"（同一台物理机上别的租户在猛读内存），你那一份有效带宽会被挤，速度跟着抖——这是独占一台盒子时没有的问题。

**8GB 这道坎两边一样。** 第三节那个 Qwen3-30B-A3B（Q4）要 16GB 才装得下，所以 8GB 的盒子和 8GB 的 4c8g 都跑不动它，得换 16GB 的配置。8GB 大概够一个 7–8B 的稠密模型，或者更小的 MoE。容量这条线上，云实例并不占便宜。

### 解决：按成本结构和用途来选，而不是按"在云上还是在家里"

把两者真正分开的，还是第五节那套成本结构。盒子是一次性一百来美元买断，之后只有几瓦电，闲着也不花钱；4c8g 是按小时或按月租，一年算下来几百美元，而且只要不关机，它 24 小时都在计费。单用户、长期自用，盒子便宜得多。

<figure class="dd dd-figure dt-figure">
<div class="dt-panel">
<div class="dt-title" id="t4-title">小盒子、云 4c8g（CPU）、云 GPU 实例</div>
<div class="dt-scroll">
<table class="dt" aria-labelledby="t4-title">
<colgroup><col style="width:20%"><col><col><col></colgroup>
<thead>
<tr><th scope="col"></th><th scope="col">小盒子（自购）</th><th scope="col">云 4c8g（CPU）</th><th scope="col">云 GPU 实例</th></tr>
</thead>
<tbody>
<tr><th scope="row">跑模型靠什么</th><td>自己的内存带宽</td><td>切片的带宽，可能被邻居挤</td><td>HBM 带宽，快得多</td></tr>
<tr><th scope="row">8GB 级容量能装</th><td>7–8B 稠密 / 小 MoE</td><td>同左</td><td>看显存，通常更大</td></tr>
<tr><th scope="row">单用户速度</th><td>够用</td><td>与盒子同量级</td><td>快，但批量能力闲置</td></tr>
<tr><th scope="row">成本</th><td class="good">一次性约 120 美元 + 几瓦电</td><td class="bad">按时 / 按月租，一年几百美元</td><td class="bad">按时租，更贵</td></tr>
<tr><th scope="row">适合</th><td>长期自用、私有</td><td>弹性 / 免维护 / 突发</td><td>需要快、且能喂满批量</td></tr>
</tbody>
</table>
</div>
</div>
<figcaption>表 4 · 云上的 4c8g CPU 实例和小盒子性能同量级，却要按时付租；它既没有盒子的成本优势，也用不上 GPU 的批量优势</figcaption>
</figure>

再往深一层看，一个 4c8g 的 CPU 实例，恰恰是这件事里**最不划算**的一种选择：你付了数据中心的租金，却只拿到一台边缘盒子的性能。原因在第四节——单用户在一个 CPU 切片上，同样使不出数据中心唯一的那件武器（大批量摊薄）。于是你花了租机器的钱，买到的却是一台慢盒子。

那云到底什么时候值？要弹性（一小时拉起一百台、用完就关）、要稳定在线又不想自己管硬件、或者负载很突发、很多人共享的时候——这些正是数据中心擅长的场景。要是就你一个人、稳稳地跑个小模型，那买块盒子基本等价，还便宜。（注意这里说的是云上的 **CPU** 实例；要是租的是云 **GPU** 实例，那又是另一回事：带宽快得多但也贵得多，而且单用户照样浪费了它的批量能力，账就回到了转卖那篇。）

不管是买盒子还是租实例，到这里聊的都还是**一台**机器。那要是把一大片这样的小机器连成一个网络，整体又会呈现什么性质？

## 七、一大片小盒子连起来，是什么形状

### 现象：总带宽很可观，却拼不出一台大机器

把一千台树莓派的内存带宽加起来，是 11 TB/s 上下——比三张 H100 的总带宽还多。听上去很唬人。但这份带宽的**形状**和数据中心完全不同：它不是一条宽阔的大道，而是**一千条互相独立的窄车道**。

### 原因：机内带宽和机间带宽，差着两个数量级

一台盒子内部，内存到计算单元的带宽是 11–15 GB/s。可盒子和盒子之间，走的是网络——千兆以太网也就 0.125 GB/s，比机内带宽低了约两个数量级。

这个落差决定了这片网络"能做什么、不能做什么"：

- **不适合把一个大模型拆开跑**（模型并行）。要把一个模型切成几段分到不同盒子上，每生成一个 token，中间结果就得跨网络在盒子间传一次。机内搬权重只要毫秒级，跨机传一次却慢上百倍，于是整体速度被最慢的那段网络锁死。这正是开头那个现象的答案：**四台 Pi 拼集群，只从 8 到 15 token/s，没有翻两番**——多出来的带宽大半耗在了盒子之间的通信上。
- **适合很多互相独立的小模型各跑各的**（数据并行）。每台盒子完整跑一个模型、服务一个用户或一个任务，盒子之间几乎不用通信。这种"各管一摊"的活，一千台就是一千份吞吐，线性地叠加，网络落差完全不碍事。

<figure class="dd dd-figure">
<div class="dd-scroll">
<svg class="dd-svg" viewBox="0 0 800 340" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="f4-title f4-desc">
<title id="f4-title">集中的带宽与分散的带宽，两种相反的形状</title>
<desc id="f4-desc">左边数据中心把高带宽集中起来，低延迟地把一个大模型服务给很多人；右边一片小盒子把带宽摊成很多条慢车道，各自服务一个小模型，盒子之间只有很慢的网络。</desc>
<rect class="dd-frame" width="800" height="340" rx="10"/>

<rect class="dd-zone" x="16" y="16" width="372" height="308" rx="8"/>
<text class="t-zone" x="32" y="44">数据中心：集中带宽</text>
<rect class="dd-card" x="36" y="64" width="332" height="96" rx="6"/>
<rect class="dd-card-head" x="36" y="64" width="332" height="30" rx="6"/>
<text class="t-name" x="52" y="84">一个大模型</text>
<text class="t-mono t-acc" x="356" y="84" text-anchor="end">3.35 TB/s HBM</text>
<text class="t-note" x="52" y="122">低延迟、一次服务很多人</text>
<text class="t-note" x="52" y="144">（靠大批量摊薄每 token 成本）</text>
<circle class="dd-dot" cx="90" cy="210" r="7"/><circle class="dd-dot" cx="140" cy="210" r="7"/><circle class="dd-dot" cx="190" cy="210" r="7"/><circle class="dd-dot" cx="240" cy="210" r="7"/><circle class="dd-dot" cx="290" cy="210" r="7"/>
<text class="t-note" x="204" y="246" text-anchor="middle">很多用户 → 同一个大模型</text>
<text class="t-say" x="204" y="290" text-anchor="middle">带宽聚在一处</text>
<text class="t-say" x="204" y="310" text-anchor="middle">擅长：一个大模型 + 低延迟</text>

<rect class="dd-zone" x="412" y="16" width="372" height="308" rx="8"/>
<text class="t-zone" x="428" y="44">一片小盒子：分散带宽</text>
<rect class="dd-card" x="432" y="64" width="104" height="54" rx="6"/><text class="t-name" x="484" y="86" text-anchor="middle">小模型 A</text><text class="t-note" x="484" y="106" text-anchor="middle">15 GB/s</text>
<rect class="dd-card" x="548" y="64" width="104" height="54" rx="6"/><text class="t-name" x="600" y="86" text-anchor="middle">小模型 B</text><text class="t-note" x="600" y="106" text-anchor="middle">15 GB/s</text>
<rect class="dd-card" x="664" y="64" width="104" height="54" rx="6"/><text class="t-name" x="716" y="86" text-anchor="middle">小模型 C</text><text class="t-note" x="716" y="106" text-anchor="middle">15 GB/s</text>
<line class="dd-edge dd-dash" x1="536" y1="91" x2="548" y2="91"/>
<line class="dd-edge dd-dash" x1="652" y1="91" x2="664" y2="91"/>
<text class="t-say" x="600" y="150" text-anchor="middle">盒子之间只有 ~0.125 GB/s 的网络</text>
<text class="t-note" x="600" y="196" text-anchor="middle">各跑各的（数据并行）→ 吞吐线性叠加</text>
<text class="t-note" x="600" y="224" text-anchor="middle">拆一个模型跨盒（模型并行）→ 被网络拖垮</text>
<text class="t-say" x="600" y="290" text-anchor="middle">带宽摊成很多条慢车道</text>
<text class="t-say" x="600" y="310" text-anchor="middle">擅长：很多小模型 + 高总吞吐</text>
</svg>
</div>
<figcaption>图 4 · 数据中心把带宽集中起来，低延迟地服务一个大模型；一片小盒子把带宽摊成很多条慢车道，适合很多互不相干的小任务，却拼不出一台低延迟的大机器</figcaption>
</figure>

所以这片网络的"自然形状"是**吞吐导向**的，而不是延迟导向的：

- **总吞吐随盒子数量线性增长**，适合那种可以拆成大量彼此独立的小任务、又不在乎单个任务要等多久的活（离线批处理、各自独立的推理请求）。
- **单个请求的延迟，被最慢那条车道锁死**。想让某一个请求更快，唯一的办法是换更快的单台，而不是堆更多台；想靠堆机器加速一个大模型，反而会因为跨机通信变得更慢。

这恰好是数据中心的镜像。数据中心把带宽**聚**在一起，用大批量低延迟地把**一个大模型**服务给很多人；一片边缘小盒子把带宽**摊**开，各自慢慢地服务**很多个小模型**。两者不是谁强谁弱，而是形状相反、各有擅长的活。想用一片慢车道去干数据中心那条大道的活（跑一个需要低延迟的大模型），就会处处别扭——这也是为什么开头那四台 Pi 拼起来几乎不变快。

## 小结

回到开头那几个问题，这条链是这样连起来的：

1. **单用户生成卡在哪？** 卡在内存带宽。一个 token 的时间约等于把激活的权重读一遍，算力几乎闲置；速度 ≈ 带宽 ÷ 每 token 读取字节。
2. **小盒子的带宽贵多少？** 折算到每单位带宽，一台一百多美元的树莓派和一张两万多美元的 H100 都落在每 GB/s 五到十一美元，同一量级——因为 GPU 的价钱大部分买的是单用户用不上的算力和 HBM 容量。
3. **三百亿参数怎么塞进 16GB 还跑得动？** 靠 MoE 把"装得下"和"跑得动"拆开：总参数需要便宜的大容量内存，每 token 只激活其中一小块，所以低带宽也够快。
4. **GPU 的本事在哪？** 在大批量——一次权重搬运喂几百个并发用户，把每 token 成本摊薄几百倍。单用户填不满批次，用不上这个优势。
5. **为什么转卖亏、自用不亏？** 转卖要在 GPU 最擅长的"大批量摊薄"战场上拼 per-token 单价；自用绕开了市场，成本只是一次性购置加几瓦电，恰好站在 GPU 优势失效的单用户区间。
6. **那不如云上租个 4c8g？** 一个 4c8g 的 CPU 实例和盒子性能同量级（都吃内存带宽、都卡在 8GB），但它既没有盒子一次性买断的成本优势，又用不上数据中心的批量优势——等于花租金买边缘性能。云真正值的是弹性、免维护和共享突发负载。
7. **一片小盒子连起来是什么形状？** 聚合带宽可观，但碎成很多条慢车道：适合很多互相独立的小模型、总吞吐线性叠加，不适合拆一个大模型（跨机网络比机内带宽慢两个数量级）。和数据中心正好相反。

说到底，"小盒子能跑大模型"不是因为它偷偷变强了，而是因为**单用户、一个 token 一个 token 的推理，恰好是把 GPU 所有长处都用不上的那个场景**——在这个场景里，大家拼的只是内存带宽的单价，而这件事上，便宜盒子并不吃亏。

## 参考资料
