本地大语言模型起初运行起来快如闪电。你加载一个 7B 或 13B 参数的模型,发送一个简短的提示词,token 会以非常舒适的速度在屏幕上流出。但当你粘贴一段长代码块,或者聊天记录累积到十几轮时,模型就开始变得极其缓慢。这种减速很少是平缓的,而更像是一个悬崖。前一秒 GPU 还在飞速输出 token,下一秒你的系统监视器就显示内存压力正在积聚,生成速度开始变得断断续续。你无法用一个简单的公式准确预测这种情况何时发生。你唯一可靠的指南就是硬件本身。
上下文的隐藏成本
你生成的每一个 token 都会为 KV 缓存(KV cache)增加状态。该缓存存储了在预填充(prefill)和生成阶段计算出的键(keys)和值(values),它与模型权重、注意力缓冲区(attention buffers)以及运行时开销一起驻留在内存中。在拥有 12 GB 或 16 GB 显存(VRAM)的典型消费级 GPU 上,KV 缓存最终会与其他所有内容竞争空间。当专用显存填满时,操作系统并不会报错并停止运行,而是会悄无声息地将溢出的数据转入共享内存,通过 PCIe 总线在 GPU 和系统 RAM 之间来回传输数据。该总线在进行文件传输时很快,但与显卡内部的内存带宽相比,简直慢如蜗牛。其结果不是性能的小幅下降,而是性能的崩塌。
性能悬崖降临的三个信号
在模型运行时,请观察你的硬件监视器。一旦性能悬崖出现,你会看到三个明显的信号。
- 共享显存(Shared VRAM)上升。 这是 GPU 驱动程序将数据从专用显存移出,转入由主机操作系统管理的内存池。一旦这一指标升至零以上,你就已经越过了界限。
- 系统 RAM 使用量激增。 溢出的数据必须有去处,而那个目的地就是你的主内存。如果你的 RAM 使用量在模型生成 token 时不断增长,说明数据正在从 GPU 卸载。
- 推理(Eval)速度下降一半或更多。 10% 的减速可能意味着热节流(thermal throttling)或后台进程干扰。而 50% 或更严重的下降,则意味着瓶颈已从张量核心(tensor cores)转移到了内存带宽和 PCIe 延迟。当你看到生成速度从两位数掉到个位数时,你就已经掉下悬崖了。
为什么你的快速基准测试可能在骗你
简短的快速测试会给你一种虚假的信心。如果你用一百个 token 的提示词进行基准测试,看到吞吐量表现良好,然后就草草收场,那你测量的只是“蜜月期”。此时 KV 缓存几乎是空的,模型层也没有受到长预填充的压力。真正的内存占用只有在模型处理了大量提示词且缓存填充到实际工作规模后才会显现。你必须通过深度预填充和长文本生成运行来进行测试,让上下文真正累积起来。只有这样,内存压力才会趋于稳定,并向你展示真实的极限。
使用 llama.cpp 寻找你的极限
如果你正在通过 llama.cpp 运行模型,你可以通过简单的算术和耐心的测试运行来测量你的极限。
1. 测量共享内存使用量。
使用极短的提示词记录你的基础专用显存占用,然后运行一个长上下文任务并记录峰值。用峰值减去基础值,差值就是从 GPU 溢出到系统共享内存中的数据量。
2. 计算 RAM 增量。
对系统 RAM 执行同样的减法操作。用长文本运行期间的峰值 RAM 减去基础 RAM。这个数字能准确告诉你,有多少数据被从显卡推送到主内存中了。它量化了跨总线的“泄漏”程度。
3. 记录推理速度崩溃的时间点。
将你的基础每秒 token 数(tokens-per-second)与模型吞吐完长文档后的速率进行对比。你可能会看到模型在上下文较新时以每秒 17 个 token 的速度飞驰,而一旦缓存膨胀,速度就掉到了每秒仅 2 个 token。这 15 个 token 的跌幅就是你的“矿井里的金丝雀”(预警信号)。
三角定位崩溃点
To map the curve accurately, do not settle for one lonely data point. Run three distinct trials at 16,000 tokens, 32,000 tokens, and 65,000 tokens. Two points might suggest a line, but two dots are just a guess. The third point proves whether you are looking at measurement noise or a real memory wall. Subtract the results between runs to calculate how much extra memory each additional thousand tokens consumes on your specific combination of model, quantization layer, and GPU.
Once you have that slope, you can project forward. Take your per-token cost, multiply it by the target context length, divide by 1024 to move between units, and add the result to your base model VRAM load. The equation looks like this:
Model VRAM load + (tokens × memory per token ÷ 1024) = Theoretical VRAM usage
This projection is not prophecy. It is a guidepost derived from actual behavior. Use it to estimate your ceiling before you commit to a full production run.
Why Paper Formulas Fail, and What Quantization Can Fix
Textbook formulas ignore the messy reality of local inference. Different architectures allocate attention buffers differently. Your operating system reserves VRAM for the display driver, compositor, and CUDA context. Driver versions change how aggressively they use shared memory. A theoretical equation cannot know how much VRAM is actually free on your machine at 2:00 PM with a browser full of tabs open. You have to run the model on your specific hardware and watch the meters.
Quantization offers partial relief. Moving the KV cache from f16 to q8_0 halves its memory footprint while keeping precision high enough for nearly all practical tasks. That change buys you headroom. It does not grant immunity. The cache still grows linearly with every token you feed in. Eventually, even the reduced size overwhelms your available dedicated memory and the spillover to system RAM begins. The pressure only stops when the context window is capped or the data stops moving.
The Real Takeaway
Do not trust marketing slides, parameter counts, or back-of-the-envelope math. Load the model. Open your system monitor. Run a 65,000-token thread, watch the RAM climb, and count the tokens per second. The numbers that appear on your specific screen, on your specific GPU, are the only numbers that matter. Context always wins. Your job is to know exactly when it wins on your machine.
