Files
zhuangang/topics/ai/llm-serving/01-routing-vllm-lora.md
T

6.0 KiB

id, title, type, domain, stack, tags, level, prerequisites, est_hours, related, week, order
id title type domain stack tags level prerequisites est_hours related week order
ai.llm-serving.routing-vllm-lora 模型侧基础:多模型接入和路由、vLLM 部署、LoRA / QLoRA 概念 lesson ai
llm-serving
多模型路由
OpenAI 兼容接口
降级
熔断
vLLM
量化
LoRA
QLoRA
微调
intermediate
python.asyncio.concurrency-control
3
ai.agent-ops.observability-cost
ai.llm-serving.scenario.multi-provider-gateway
ai.llm-serving.interview
10
13
1

模型侧基础:多模型接入和路由、vLLM 部署、LoRA / QLoRA 概念

本课定位是了解级:应用开发岗位面试会问到“模型怎么接、怎么部署、什么时候微调”,能讲清楚原理和取舍即可,不要求会训练模型。vLLM 等工具参数变化快,以官方文档为准:https://docs.vllm.ai/

解释说明

1. 多模型接入和路由

企业里通常同时使用多个模型:不同厂商的大模型、便宜的小模型、自部署的开源模型。统一接入层(自建网关或 LiteLLM 这类开源网关)负责:

功能 说明
统一接口 大多数厂商和 vLLM 都提供 OpenAI 兼容接口,业务代码用同一套 SDK,只换 base_url 和模型名
按任务路由 分类、改写用小模型;复杂推理用大模型;敏感数据只走自部署模型
超时、重试 限流(429)退避后重试;故障 / 超时换下一个提供方
熔断 某个提供方连续失败时暂时跳过,冷却后试探
降级 主模型不可用时切备用;都不可用时返回友好提示
配额和成本 按业务方 / 用户限额;记录每次调用的 token 和成本
密钥管理 业务方不直接持有厂商密钥

2. vLLM 部署基础

vLLM 是常用的开源大模型推理服务框架:

  • 核心技术:PagedAttention(像操作系统分页一样管理 KV 缓存,减少显存浪费)和连续批处理(请求随到随加入批次),吞吐量高。
  • 启动:vllm serve <模型名或路径>,默认在 8000 端口提供 OpenAI 兼容接口(/v1/chat/completions)。
  • 常用参数:--tensor-parallel-size(多卡切分)、--max-model-len(最大上下文,影响显存)、--gpu-memory-utilization(显存占用比例)、--quantization(量化)。
  • 显存粗估:参数量 × 每个参数的字节数(FP16 为 2 字节),7B 模型权重约 14GB,另外还需要 KV 缓存空间;量化到 4 bit 后权重约 4GB 左右。
  • 同类工具:SGLang、TGI、Ollama(本地体验)、llama.cpp。

自部署的理由:数据不能出内网、调用量很大时成本更低、需要定制模型。代价:GPU 成本、运维、模型效果通常不如顶级商用模型。

3. 微调和 LoRA / QLoRA(概念)

方法 说明
全量微调 更新全部参数,效果上限高,显存和数据要求高
LoRA 冻结原模型,只训练插在部分层上的低秩矩阵(W + BA,A、B 很小),可训练参数通常不到 1%;训练好的“适配器”文件很小,可以一个底座挂多个适配器
QLoRA 把底座模型量化到 4 bit 再做 LoRA 训练,进一步降低显存,单张消费级显卡也能微调中等规模模型

什么时候需要微调? 先用提示词 + RAG;当需要固定的输出风格 / 格式、特定领域的表达、用小模型替代大模型降低成本,并且有足够的高质量标注数据和评测集时,才考虑微调。知识更新类需求用 RAG,不用微调。

案例

公司客服系统:意图分类走便宜的小模型;答案生成走商用大模型,备用另一家厂商;涉及员工身份证、薪资的问题只走内网 vLLM 部署的开源模型。一次主厂商故障,网关在 3 次失败后熔断,自动切到备用厂商,用户基本无感;事后看台账,降级期间成本上升了,但服务没有中断。

代码示例

路由、重试、熔断、降级、成本台账(完整版本 examples/model-router/router.py,只用标准库):

async def chat(self, task, messages):
    errors = []
    for name in self.routes[task]:                     # 按优先级尝试提供方
        p, br = self.providers[name], self.breakers.setdefault(name, Breaker())
        if not br.allow():
            continue                                    # 熔断中,跳过
        for attempt in range(self.max_retries + 1):
            try:
                r = await p.call(messages, self.timeout)
            except RateLimited:
                await asyncio.sleep(0.01 * 2 ** attempt)   # 限流:退避后重试同一个
                continue
            except (ProviderDown, asyncio.TimeoutError):
                br.record(False)
                break                                   # 故障 / 超时:换下一个
            br.record(True)
            return r
    raise RuntimeError("所有模型都不可用")

调用自部署的 vLLM(OpenAI 兼容接口,示意):

from openai import OpenAI

client = OpenAI(base_url="http://127.0.0.1:8000/v1", api_key="token-local")   # vLLM 可用 --api-key 设置
resp = client.chat.completions.create(
    model="Qwen/Qwen2.5-7B-Instruct",
    messages=[{"role": "user", "content": "你好"}],
)
print(resp.choices[0].message.content)

易错点

  • 业务代码直接依赖某个厂商的 SDK 特有功能,换模型时大面积修改。
  • 所有错误都重试:参数错误、内容审核拒绝重试也没用。
  • 降级到备用模型后不记录、不告警,效果下降没人知道。
  • 自部署模型的成本只算 token 为 0,忘了 GPU 和运维成本。
  • --max-model-len 设得过大导致显存不足启动失败,或者并发能力很低。
  • 把微调当成“让模型学会公司知识”的方法:知识更新用 RAG。

面试常问

  • 怎么同时接入多家模型?怎么做降级?
  • vLLM 为什么快?
  • LoRA 是什么?什么时候需要微调?