共计 3641 个字符,预计需要花费 10 分钟才能阅读完成。
上周帮团队排查一套基于 FastChat 搭建的内部大模型代理服务,业务方一接入自动化工作流,显卡直接 OOM 宕机;紧接着前端又报 SSE 流式响应频繁中途被截断。很多朋友用 Python 写个简易的 FastAPI 脚本套上 Hugging Face Transformers 就敢跑生产,结果遇到长 Prompt 并发或多轮对话上下文膨胀,GPU 显存碎片化立刻暴露出短板。
本文不扯抽象架构,直接端出一套我和团队在多节点服务器上跑了半年多的工业级组合方案: 底层推理引擎采用 vLLM,上层网关调度采用 LiteLLM Proxy。这套方案不仅支撑起每天数十万次流式 Token 调用,还原生补齐了 API Key 鉴权、多租户配额管理以及自动 Fallback 机制。
一、为什么是 vLLM + LiteLLM?痛点拆解
在工程落地场景中,模型推理服务往往面临三大核心死穴:
- KV Cache 显存碎片化: 传统 Attention 机制必须为每个请求提前预分配连续的显存空间,一旦并发请求的输出长度不确定,显存利用率往往不足 30% 就直接 OOM。vLLM 的
PagedAttention算法将显存虚拟内存化,把吞吐量直接提升了 2~4 倍。 - 长连接与 SSE 截断问题: 自建网关如果没有针对 Nginx 或代理层的反向代理缓冲(proxy_buffering)做针对性适配,客户端接收流式数据时经常会出现长时间无数据回传(TTFT 过长)导致的 504 网关超时。
- 多模型混合调度与鉴权缺失: 业务层需要兼容 OpenAI 协议,同时又要给不同的项目分配独立的 API Key 和 Token 消耗限额,单靠模型推理引擎原生接口根本无法维系。
二、底层推理层:vLLM 的关键参数压榨
跑单卡 RTX 4090 或 A100/H800 时,绝对不要直接无脑执行 vllm serve。显存分配比、最大序列长度与并行度参数必须根据实际硬件进行精细调校。以目前主流的 Qwen2.5-14B-Instruct 为例,推荐的启动配置如下:
python3 -m vllm.entrypoints.openai.api_server \
--model /data/models/Qwen2.5-14B-Instruct \
--served-model-name qwen-14b \
--tensor-parallel-size 1 \
--gpu-memory-utilization 0.92 \
--max-model-len 8192 \
--max-num-seqs 64 \
--swap-space 8 \
--trust-remote-code \
--host 0.0.0.0 \
--port 8000 \
--disable-log-requests
踩坑细节备忘:
--gpu-memory-utilization 0.92:千万不要设为1.0。PyTorch 底层需要留出少量显存处理临时上下文和 CUDA 算子缓存,设为 0.90~0.93 是最稳定的甜点区间。--max-num-seqs 64:根据业务的平均延迟容忍度设置。序列过多虽然提升了总体吞吐,但每个并发请求的单字延迟(Time Per Output Token)会被拉长。--swap-space 8:指定 8GB 主机内存作为交换空间。当瞬间突发流量超过显存容量时,可以让超出的 KV Cache 暂时换出到系统内存,避免进程崩溃。
三、网关层:LiteLLM Proxy 容器化与鉴权接入
为了让业务端像调用原生 OpenAI 接口一样接入,并具备多 Key 限流机制,我们在 vLLM 上层堆叠 LiteLLM Proxy。使用 Docker Compose 进行全量编排是目前最干净、可复现度最高的方式。
首先准备网关配置文件 litellm_config.yaml:
model_list:
- model_name: gpt-4o-mini # 业务层别名
litellm_params:
model: openai/qwen-14b
api_base: "http://vllm-engine:8000/v1"
api_key: "EMPTY"
tpm: 200000
rpm: 1200
general_settings:
master_key: "sk-nassky-master-super-secret-key"
database_url: "postgresql://postgres:postgres123@postgres:5432/litellm"
litellm_settings:
drop_params: true
set_verbose: false
request_timeout: 120
接下来是完整的 docker-compose.yml 编排文件:
version: '3.8'
services:
postgres:
image: postgres:15-alpine
container_name: litellm-db
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres123
POSTGRES_DB: litellm
volumes:
- ./data/postgres:/var/lib/postgresql/data
restart: always
litellm-proxy:
image: ghcr.io/berriai/litellm:main-latest
container_name: litellm-gateway
ports:
- "4000:4000"
volumes:
- ./litellm_config.yaml:/app/config.yaml
command: ["--config", "/app/config.yaml", "--port", "4000", "--num_workers", "4"]
depends_on:
- postgres
restart: always
执行 docker compose up -d 后,LiteLLM 将在 4000 端口提供标准的 OpenAI 兼容入口,并将所有调用日志与 Token 消耗指标沉淀至 PostgreSQL 中。
四、关键网络配置:解决 Nginx 流式代理中途截断
将服务通过 Nginx 暴露给外网或前端应用时,绝大多数开发者都会踩进 SSE 缓冲坑: 前端收不到逐字回显,而是等整个模型生成完毕后瞬间一股脑吐出,甚至因为超时断连。
解决这个问题的核心是在 Nginx 的反向代理块中彻底关闭缓冲,并调高长连接超时时间:
location /v1/ {
proxy_pass http://127.0.0.1:4000/v1/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 关键参数:禁用代理缓存与分块缓冲
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 600s;
proxy_connect_timeout 60s;
# 强制 HTTP/1.1 支持持续流式传输
proxy_http_version 1.1;
proxy_set_header Connection "";
chunked_transfer_encoding on;
}
五、性能对比与选型实测
在单张 A100-80G 环境下,针对 Qwen2.5-14B 模型,输入 1024 Tokens、输出 512 Tokens,在并发量逐步递增的测试场景下,自研 FastAPI 管道与 vLLM + LiteLLM 架构的实测表现对比:
| 并发量 (Concurrency) | FastAPI 原生方案 (Tokens/s) | vLLM 方案 (Tokens/s) | 首字延迟 (TTFT P95) | 显存状态 |
|---|---|---|---|---|
| 8 并发 | 95 tok/s | 280 tok/s | 210 ms | 占用 38GB / 稳定 |
| 32 并发 | 110 tok/s (部分排队) | 780 tok/s | 480 ms | 占用 68GB / 无碎片 |
| 64 并发 | 直接 CUDA OOM 崩盘 | 1240 tok/s | 890 ms | 动态分页置换 / 稳定 |
实测数据非常明显:随着并发量提升,vLLM 依靠 PagedAttention 和连续批处理(Continuous Batching)几乎将吞吐拉满,而传统的串行或简单批处理模式在并发达到 30 以上时就会触发显存抖动并迅速宕机。
总结与避坑心得
在企业级自建 AI 基础设施的初期,不要盲目去造前端调用的轮子。选用 vLLM 做算力极限压榨,配合 LiteLLM 做模型层路由与治理 ,是一套极低试错成本、高扩展性的组合方案。
最后提两条实战军规:
- 模型权重必须放 NVMe 本地盘: 别试图把模型权重挂在百兆带宽的 NFS 或普通机械盘上,冷启动读取 30GB 权重文件能卡到你怀疑人生。
- 善用 LiteLLM 的 fallback 功能: 当本地单卡出现算力拥堵、排队超过阈值时,直接在配置文件配置降级路由,自动将流量无缝转发至 DeepSeek 或 Azure 商业接口,这才是保障线上业务 SLA 真正可用的兜底手段。
===END===