本节导读:当业务模型不是HuggingFace现成格式、或是微调产物(LoRA适配器、自研架构)时,如何让它跑上vLLM的高性能引擎?本节覆盖自定义模型接入、多LoRA动态服务、量化基座组合三大场景。
vLLM启动时按 config.json 的 architectures 字段在注册表中查找对应实现类。接入自定义模型有三条路:
| 路线 | 做法 | 适用 |
|---|---|---|
| 复用现有架构 | 微调不改结构(最常见) | 99%的业务场景,直接加载 |
| 转换为标准格式 | 导出为LLaMA/Qwen等标准结构 | 自研但结构相似 |
| 注册新架构 | 实现 *ForCausalLM 类并注册 |
真正的新架构 |
绝大多数"自训练模型"其实只是LoRA/全参微调产物,结构未变,走第一条路即可。
LoRA微调产物 = 基座权重 + 小体积适配器(几MB~几百MB)。两种服务方式:
merge_and_unload() 把适配器并进基座,产出一个独立模型。简单高效,但N个业务要N份完整模型副本;--enable-lora # 开启LoRA运行时 --max-loras 4 # 并发驻留的适配器数 --max-lora-rank 32 # 支持的最大rank --max-cpu-loras 16 # CPU侧缓存池(热备)
适配器按LRU在GPU/CPU间换入换出,max_loras 建议设为并发租户数并留余量。
from peft import PeftModel from transformers import AutoModelForCausalLM base = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-7B-Instruct", torch_dtype="bfloat16") merged = PeftModel.from_pretrained(base, "my-lora-adapter").merge_and_unload() merged.save_pretrained("my-merged-model") # tokenizer一并拷贝后,直接 vllm serve my-merged-model
vllm serve Qwen/Qwen2.5-7B-Instruct \ --enable-lora \ --max-loras 4 --max-lora-rank 32 \ --lora-modules \ legal=./adapters/legal \ medical=./adapters/medical \ cs=./adapters/customer-service
from openai import OpenAI client = OpenAI(base_url="http://localhost:8000/v1", api_key="EMPTY") resp = client.chat.completions.create( model="legal", # 直接用适配器名当model messages=[{"role": "user", "content": "合同中定金条款的风险?"}], )
对租户侧完全透明:切换领域=换一个model名,无需新建连接或实例。
# 上新适配器不停服 curl -X POST http://localhost:8000/v1/load_lora_adapter \ -d '{"lora_name": "finance", "lora_path": "./adapters/finance"}' curl -X POST http://localhost:8000/v1/unload_lora_adapter \ -d '{"lora_name": "cs"}'
新业务上线→load;旧版本下线→unload。配合CI产出适配器目录,可实现"训练完成即自动上架"。
from vllm.model_executor.models.registry import register_model from vllm.model_executor.models import LlamaForCausalLM @register_model("MyNetForCausalLM") class MyNetForCausalLM(LlamaForCausalLM): """结构与LLaMA兼容的自定义变体:覆写需要差异化的层""" ...
要点:①实现与基类一致的 forward() 签名;②config.json 的 architectures 填注册名;③优先继承最接近的现有类,只覆写差异部分。这条路维护成本高,能转标准格式就转。
平台上有12个行业客户,各自一个LoRA适配器(rank=16,约50MB):
部署形态:单实例 Qwen2.5-7B 基座 + --enable-lora --max-loras 8 --max-cpu-loras 32 访问方式:model=<tenant_lora_name> 成本对比:合并式 12份7B副本 ≈ 168GB显存 动态式 1份基座 + 适配器池 ≈ 16GB显存
峰值并发时LRU自动把冷租户适配器换到CPU,热租户保持GPU驻留,显存开销几乎与租户数无关。
Q1:加载LoRA报错 rank 超限?
适配器rank超过 --max-lora-rank(默认16)。查看适配器 adapter_config.json 中的 r 字段,把启动参数调到不小于该值。rank越大适配器越占显存,16/32覆盖绝大多数场景。
Q2:LoRA推理和合并后推理结果一致吗?
数学上等价,工程上LoRA运行时有轻微额外计算开销(吞吐略降),合并式吞吐最优。租户少且固定时优先合并式;租户多、更新频繁用动态式。
Q3:量化基座能挂LoRA吗?
部分组合可行:GPTQ/AWQ基座+LoRA在vLLM中有支持,但需适配器与量化方案配套训练(如用QLoRA流程)。上线前务必做精度对比,量化+LoRA的双重近似可能叠加放大误差。
Q4:训练用PEFT保存的适配器直接报"不是有效的LoRA"?
检查目录结构:需要 adapter_config.json 与 adapter_model.safetensors。若保存的是完整模型(save_pretrained输出含大权重文件),说明训练时已合并,直接当普通模型部署即可。
Q5:多个适配器能同时命中一个请求吗?
不能,一个请求只挂一个适配器。需要"复合能力"时应在训练侧混合数据训练单一适配器,而非运行时叠加。
--max-loras 设得过小导致频繁换入换出,吞吐抖动。观察指标中的lora换页次数,调大或把高频租户常驻;lora_name 中带上版本号(legal-v3),灰度与回滚都在路由层完成;本节的核心结论:微调产物接vLLM首选"标准结构直接加载",多租户用"一份基座+动态LoRA"获得数量级的显存节约;真自研架构才走注册路线。配套的版本纪律(基座锁定、适配器入库、回归评估)决定这套体系能否长期稳定运转。下一节看vLLM的另一块扩展疆土——多模态。