为什么换这个角度
很多本地部署教程把注意力全放在「4-bit 还是 8-bit」上。量化档只解决「能不能装下」,不解决「请求来了模型在不在」。真实使用中,最贵的成本不是显存,而是每次冷启动那几十秒到几分钟的加载时间——这段时间用户拿不到 Token,团队就会回头去用云端 API。
所以本文的目标不是榨显存,而是让「热模型」始终在线、让「冷模型」按需出现,把首 Token 延迟压到可接受范围。
操作步骤
第一步:用 Ollama 常驻一个「日常档」小模型
Ollama 的 keep_alive 参数决定模型在最后一次请求后驻留多久。默认 5 分钟,对日常对话偏短。
```bash
# 让 7B/8B 级别模型常驻,避免反复加载
curl http://localhost:11434/api/generate -d '{
"model": "qwen2.5:7b-instruct",
"prompt": "ping",
"keep_alive": -1
}'
```
keep_alive: -1 表示不主动卸载。适合显存放得下、调用频率高的小模型。若显存紧张,用 "keep_alive": "30m" 之类的时间值,让它在空闲一段时间后自动让位。
要点:常驻模型要选「够用就好」的尺寸,它的职责是承接 80% 的日常请求(摘要、分类、改写、简单问答),把大模型留给真正需要的任务。
第二步:用 systemd 管住 vLLM 的「按需档」
vLLM 启动一个 32B 级别模型通常要几十秒到一两分钟(取决于权重加载速度与是否启用 --enforce-eager)。不要在脚本里裸跑 python -m vllm.entrypoints.openai.api_server,用 systemd 单元管理生命周期,才能被路由按需唤醒、空闲回收。
```ini
# /etc/systemd/system/vllm-large.service
[Unit]
Description=vLLM large model (on-demand)
After=network.target
[Service]
Type=simple
ExecStart=/opt/venv/bin/python -m vllm.entrypoints.openai.api_server \
--model /models/Qwen2.5-32B-Instruct-AWQ \
--served-model-name large \
--port 8000 \
--gpu-memory-utilization 0.85 \
--max-model-len 8192
Restart=on-failure
[Install]
WantedBy=multi-user.target
```
关键点:
--served-model-name固定成large,路由层就不用关心具体权重路径;--gpu-memory-utilization留出余量,避免和常驻小模型抢显存时 OOM;- 用
Restart=on-failure兜住加载失败。
第三步:写一个「唤醒 + 等待就绪」的钩子
路由在把请求转给 vLLM 之前,先探测 /v1/models。不通就 systemctl start,然后轮询直到就绪。
```python
import subprocess, time, requests
def ensure_large(timeout=180):
url = "http://127.0.0.1:8000/v1/models"
try:
requests.get(url, timeout=2)
return True
except Exception:
pass
subprocess.run(["systemctl", "start", "vllm-large"], check=False)
deadline = time.time() + timeout
while time.time() < deadline:
try:
requests.get(url, timeout=2)
return True
except Exception:
time.sleep(2)
return False
```
注意:首次唤醒的请求会等很久,路由层要给它一个独立的、更长的超时,并且不要让所有请求都触发唤醒——只有被判定为「需要大模型」的请求才走这条路径。
第四步:加一个空闲回收定时器
按需档不能一直占着显存,否则常驻小模型会被挤掉。用 systemd timer 或一个简单的守护脚本,在连续 N 分钟无请求后 systemctl stop vllm-large。
```bash
# 粗略示例:检查最近请求时间,超时则停止
systemctl stop vllm-large
```
回收阈值取决于你的使用节奏。团队白天高频、夜间低频,可以设成夜里停、白天保活。
第五步:路由层做「两级分流」
一个最小的分流规则:
- 请求带
model: small或未指定 → 直接打 Ollama 的 OpenAI 兼容端点(http://localhost:11434/v1); - 请求带
model: large或长度/任务复杂度超过阈值 → 先ensure_large(),再打 vLLM 的/v1/chat/completions; - 大模型唤醒失败 → 降级回小模型并记录日志,保证「不断供」。
这样客户端只认一个 base_url,背后是「常驻 + 按需」两条供给。
注意事项
- 显存是共享资源:常驻模型和按需模型必须算好总占用。经验上,小模型常驻 + 大模型
--gpu-memory-utilization 0.85的组合在多卡机器上更稳;单卡时要把小模型调小或改用时间型keep_alive。 - 冷启动时间不可消除:权重加载受磁盘速度影响很大。把模型放在 NVMe 上,或使用
--load-format相关选项,能明显缩短唤醒时间。 - 不要把「唤醒等待」算进用户体验:异步任务(批处理、离线摘要)适合走按需档;交互式对话尽量只走常驻档。
- Ollama 与 vLLM 的端口要分开,并在路由里显式配置,避免默认端口冲突。
- 日志要记全:唤醒次数、唤醒耗时、降级次数,这三个指标直接决定这套方案值不值得留。
- 模型名称、版本与许可证以各项目官方仓库为准;商用前确认权重许可。
适用场景
- 团队日常有大量轻量请求(分类、抽取、改写),偶尔需要大模型做复杂推理;
- 只有一两张卡,显存不足以同时常驻两个模型;
- 对「首 Token 延迟」敏感,但对「复杂任务可以等一会」可以接受;
- 希望把云端 API 的调用量压下来,把 Token 成本变成固定的电费与硬件折旧。
与量化档方案的区别
量化档方案回答的是「一张卡能装多大模型」;本文回答的是「模型什么时候该在显存里」。两者不冲突:你可以先按显存预算选好量化档,再用本文的常驻/按需分层决定谁一直在线、谁按需出现。