决定能不能跑起来的是两件事的乘积:量化等级决定权重本身占多少显存,上下文长度决定 KV cache 要额外占多少。权重文件就位只说明第一步过了,长度没定就开服务,通常在加载阶段不报错、在首次推理按实际长度分配 KV cache 时爆掉。建议的顺序是:先确认这份 Beam 权重是哪档量化,再用 nvidia-smi 记下加载后的显存基线,然后把上下文长度从小往大加,最后在四组组合里挑一组能稳定推理的固化下来。
判断方向:量化等级和上下文长度要一起定,不能只看权重文件大小。先确认权重自带的量化标识,再记录加载后与首次推理后的显存差值,用差值反推还能留多少给 KV cache。上下文从小档开始加,每档记录显存变化。四组组合按“能加载、能完成一次推理、能支撑目标上下文长度”逐条筛,只有三条都过才固化进启动脚本。以上限值和差值都来自本机实测,不做跨机器套用。
下面的命令和配置片段都是骨架,框架名、参数名和路径需要按你本机实际环境替换;记录表里的数值必须自己跑出来后填,别人机器上的数字对你的显存没有参考意义。
在模型目录里确认这份 Beam 权重带的是哪档量化
先看目录结构和权重文件名,再读配置文件,避免按文件名猜档位。在模型目录下执行:
cd /path/to/beam-model
ls -lh
find . -maxdepth 2 -type f \( -name '*.safetensors' -o -name '*.gguf' -o -name '*.bin' \)
cat config.json | python -m json.tool | grep -iE 'quant|dtype|bits|group_size|quant_method'读法大致是这样:.gguf 单文件通常把档位写在文件名里,形如 Q4_K_M、Q5_K_M、Q8_0,字母后缀表示分组方式和混合精度策略;.safetensors 多为分片命名,-00001-of-0000N 这类后缀只是分片序号,量化信息一般不在文件名里,要看 config.json 里的 quantization_config,关注 quant_method(例如 AWQ、GPTQ 这类)、bits 和 group_size;如果只看到 torch_dtype 为 float16 或 bfloat16,说明这份权重是未量化的原始精度,显存占用按参数量乘每参数字节数量级估算。先写清楚是哪一档,再决定后面用哪个启动参数去匹配,不要用低量化参数去加载高精度权重。
用 nvidia-smi 记录加载前后的显存差值
要的不是绝对显存数字,而是三个时间点之间的差值。开一个终端持续观察:
watch -n 1 'nvidia-smi `--query-gpu`=index,memory.used,memory.total `--format`=csv,noheader'三个采样时机分别是:进程启动前,记下基线,这一步包含桌面环境、其他常驻进程已经占掉的部分;权重加载完成、服务开始监听端口之后,记下第二个值,它与基线的差值近似等于权重加上运行时框架自身占用;首次推理返回结果之后,记下第三个值,它与加载后值的差值主要来自 KV cache 首次按实际输入长度分配,以及推理过程中的中间张量。差值各自代表什么要写清楚:加载前后差值决定权重这一块能不能压,首次推理前后差值决定上下文这一块还能放多长。建议把三个值连同时刻一起记进表格,只记一个总占用会在后面调参时失去判断依据。
把上下文长度从最小值往上加并记录显存变化
控制上下文长度的字段各家框架命名不同,常见的有 `--ctx-size`、`--max-model-len`、`--max-seq-len`、`--context-length`,配置文件里也可能叫 n_ctx 或 max_seq_len,先在你所用框架的启动帮助里确认字段名。三档取值建议这样设:第一档取框架允许的最小值或 2048,用来确认参数生效;第二档取 8192,作为多数本地对话场景的中间值;第三档取你业务真正需要的最大长度,例如 32768 或更高。每换一档,重复上一节的三点采样,并额外做一次同长度推理请求,把加载后显存、首次推理后显存和该长度下的稳定显存都记下来。KV cache 通常随上下文长度近似线性增长,阶梯之间的差值比绝对值更有用,它能告诉你从 8192 加到目标长度还要额外吃掉多少。
量化等级与上下文长度的四组组合取舍
把量化等级和上下文长度当成两个正交的旋钮,四组组合的取舍如下表,判断标准统一为三步:服务能加载起来不 OOM、能完整完成一次真实长度的推理、能稳定支撑目标上下文长度而不是刚好擦线。
| 组合 | 显存压力 | 适用场景 | 主要风险 |
|---|---|---|---|
| 高量化等级 + 长上下文 | 最高,权重和 KV cache 两头都要 | 对输出质量敏感、机器显存充足 | 加载后剩余显存不足以按目标长度分配 KV cache |
| 高量化等级 + 短上下文 | 权重占比高,KV cache 占比小 | 单轮问答、短文档处理 | 超过设定长度的输入被截断,输出不完整 |
| 低量化等级 + 长上下文 | 权重让出一部分给 KV cache | 需要长上下文、可接受一定质量损失 | 精度下降带来的输出偏差需自行评估 |
| 低量化等级 + 短上下文 | 最低,最容易跑通 | 先用它确认流程通了,再逐项加 | 容易误以为这就是可用配置,缺少扩展余量 |
顺序上建议从最后一行往上加:先用低量化加短上下文确认整条链路通,再把上下文加到目标长度,如果显存不够,再考虑换更低量化等级或拆权重到多卡。不要同时动两个旋钮,否则出问题时无法归因。
把选定组合固化成启动脚本并复测
调参时的命令行容易记混,把它写成脚本固定下来,参数全部显式写出:
#!/usr/bin/env bash
set -euo pipefail
MODEL_DIR='/path/to/beam-model'
CTX=8192
PORT=8080
python -m your_framework.serve \
`--model` "$MODEL_DIR" \
`--ctx-size` "$CTX" \
`--max-num-seqs` 1 \
`--host` 127.0.0.1 \
`--port` "$PORT"脚本里的 `--ctx-size` 换成你框架实际的字段名,MODEL_DIR 和 PORT 按本机改。复测方式是连续发起两次同长度请求,请求长度取接近目标上下文的值:
curl -s http://127.0.0.1:8080/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{"model":"beam","messages":[{"role":"user","content":"<你的长输入>"}],"max_tokens":256}'两次请求之间用 nvidia-smi 观察显存:如果第一次请求结束后显存回落到接近加载后的基线,第二次请求仍能正常返回,说明 KV cache 的正常释放路径是通的;如果显存只升不降,或者第二次请求明显变慢、报显存不足,就说明当前上下文长度已经贴近上限,应退回上一档长度或换更低量化等级。输出侧检查两点:返回内容是否完整结束、有没有被长度截断的迹象。两份记录——组合表和启动脚本——一起留存,下次换机器或换权重时按同样步骤重跑一遍即可。