从云原生走向 AI 原生:一套面向未来的架构方法论 → 阅读《AI 原生基础设施》

vllm serve:OpenAI 兼容 API 服务

草稿

vLLM serve 让本地模型秒变 OpenAI 兼容服务,自动批处理和智能调度让推理性能大幅提升。

什么是 vLLM serve?

vLLM serve 是 vLLM 的核心工作模式,提供了一个完整的生产级 API 服务,支持自动批处理和高效资源调度。

vLLM serve 通过自动化 Batch 合并、KV Cache 管理和动态调度,将本地大语言模型(LLM)服务化,兼容 OpenAI API,极大简化模型部署流程。

vLLM serve 的核心特性

下表总结了 vLLM serve 的主要功能和优势。

特性说明
OpenAI 兼容 API100% 兼容 OpenAI Chat Completions / Completions API
自动 Batch 合并动态合并不同时间到达的请求,最大化吞吐量
KV Cache 管理智能管理中间结果缓存,减少重复计算
动态调度Scheduler 优化请求优先级和资源分配
流式输出Server-Sent Events (SSE) 实时流式返回结果
多模型支持可同时加载多个模型(GPU 环境)
表 1: vLLM serve 核心特性

vLLM serve 与传统方案对比

为了帮助理解 vLLM serve 的优势,下面通过表格对比主流推理服务方案。

方案优点缺点适用场景
Transformers 直接推理简单、快速原型无 Batch 优化、无缓存开发测试、学习
Flask API 自建灵活、可定制需手动管理 Batch、缓存简单服务、演示
vLLM serve生产就绪、自动优化依赖 vLLM 库生产部署、高吞吐
表 2: 推理服务方案对比

macOS 中的注意事项

在 macOS 环境下使用 vLLM serve 时,需要关注以下兼容性和性能问题。

vLLM 在 macOS 上的限制

当前 vLLM 在 macOS 上的原生支持尚在完善阶段,存在如下已知问题:

问题现状解决方案
vLLM CLI 不可用macOS 上 vllm serve 命令存在 C 扩展兼容性问题使用 Transformers + Uvicorn 或 Flask 替代
仅支持 CPU 推理无法使用 GPU(Metal 支持还在开发中)使用 bfloat16 优化 CPU 性能
性能受限CPU 推理速度远低于 GPU选择小型模型(1.5B)
表 3: macOS 下 vLLM 兼容性问题

推荐方案

由于 vLLM CLI 在 macOS 上暂不可用,推荐采用以下替代方案:

  • 方案 A:vLLM 库 + Uvicorn(推荐)
    通过 vLLM 的 API 类手动启动 HTTP 服务,兼容 OpenAI API。

  • 方案 B:Transformers + Flask
    适合简单演示和开发测试。

  • 方案 C:等待 vLLM 完善 macOS 支持
    未来有望直接使用 vllm serve 命令。

下面以方案 A 为例,展示最接近 vLLM serve 的服务化部署方式。

实现:使用 vLLM API + Uvicorn

本节介绍如何在 macOS 上用 vLLM 库和 Uvicorn 启动生产级推理服务。

代码结构

项目目录结构如下:

vllm-serve/
├── index.md              # 本文档
├── main.py               # vLLM API 服务器
├── requirements.txt      # 依赖清单
└── test_api.sh           # API 测试脚本

安装依赖

请先安装 vLLM、Uvicorn 和 Pydantic:

pip install vllm uvicorn pydantic

创建 main.py

以下代码展示了如何用 vLLM API 启动 HTTP 服务:

📄 main.py
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
#!/usr/bin/env python3
"""
vLLM API 服务器(macOS 替代方案)

使用 vLLM 的核心引擎和 Uvicorn ASGI 框架,
在 macOS 上实现 OpenAI 兼容 API 服务。

原生 vLLM serve 命令在 macOS 上不可用(C 扩展兼容性问题),
本方案使用 vLLM 的 API 类和手动 HTTP 路由实现等效功能。
"""

from fastapi import FastAPI, Request
from fastapi.responses import StreamingResponse, JSONResponse
import uvicorn
from vllm import LLM, SamplingParams
from vllm.entrypoints.openai.protocol import (
    ChatCompletionRequest,
    CompletionRequest,
)
import json
import asyncio
from typing import AsyncGenerator

# ============================================================================
# vLLM 引擎初始化(全局变量,在 main 中初始化)
# ============================================================================

llm = None

# ============================================================================
# FastAPI 应用初始化
# ============================================================================

app = FastAPI(title="vLLM OpenAI-Compatible API")

# ============================================================================
# 健康检查端点
# ============================================================================

@app.get("/health")
async def health():
    """健康检查端点"""
    return {"status": "ok", "model": "Qwen/Qwen2.5-1.5B-Instruct"}

# ============================================================================
# 聊天补全端点(OpenAI 兼容)
# ============================================================================

@app.post("/v1/chat/completions")
async def chat_completions(request: ChatCompletionRequest):
    """
    聊天补全 API(OpenAI 兼容)
    
    请求格式:
    {
      "messages": [
        {"role": "user", "content": "你好"}
      ],
      "temperature": 0.7,
      "max_tokens": 256,
      "stream": false
    }
    """
    
    # 从消息列表构建 prompt
    # vLLM 提供了 apply_chat_template 方法
    prompt = llm.get_tokenizer().apply_chat_template(
        request.messages,
        tokenize=False,
        add_generation_prompt=True,
    )
    
    # 配置生成参数
    # vLLM 的 SamplingParams 管理温度、top-p 等采样参数
    sampling_params = SamplingParams(
        temperature=request.temperature,
        top_p=request.top_p if request.top_p else 0.95,
        max_tokens=request.max_tokens if request.max_tokens else 256,
    )
    
    # 如果请求流式输出
    if request.stream:
        # 返回流式响应
        async def generate():
            # vLLM 的 generate 方法支持流式输出
            outputs = llm.generate([prompt], sampling_params)
            output = outputs[0]
            text = output.outputs[0].text
            
            # 流式返回 OpenAI 格式的消息
            for char in text:
                chunk = {
                    "choices": [{
                        "delta": {"content": char},
                        "index": 0,
                    }]
                }
                yield f"data: {json.dumps(chunk)}\n\n"
            
            # 流式结束标记
            yield "data: [DONE]\n\n"
        
        return StreamingResponse(generate(), media_type="text/event-stream")
    
    else:
        # 非流式输出:直接生成,一次返回完整结果
        outputs = llm.generate([prompt], sampling_params)
        output = outputs[0]
        text = output.outputs[0].text
        
        return JSONResponse({
            "choices": [{
                "message": {
                    "role": "assistant",
                    "content": text,
                },
                "index": 0,
                "finish_reason": "stop",
            }]
        })

# ============================================================================
# 文本补全端点(OpenAI 兼容)
# ============================================================================

@app.post("/v1/completions")
async def completions(request: CompletionRequest):
    """
    文本补全 API(OpenAI 兼容)
    
    请求格式:
    {
      "prompt": "今天天气",
      "temperature": 0.7,
      "max_tokens": 128
    }
    """
    
    # 配置生成参数
    sampling_params = SamplingParams(
        temperature=request.temperature,
        top_p=request.top_p if request.top_p else 0.95,
        max_tokens=request.max_tokens if request.max_tokens else 256,
    )
    
    # 生成文本
    outputs = llm.generate([request.prompt], sampling_params)
    output = outputs[0]
    text = output.outputs[0].text
    
    return JSONResponse({
        "choices": [{
            "text": text,
            "index": 0,
            "finish_reason": "stop",
        }]
    })

# ============================================================================
# 启动服务器
# ============================================================================

if __name__ == "__main__":
    """
    启动 Uvicorn ASGI 服务器
    
    Uvicorn 是一个轻量级 ASGI 服务器,比 Flask 更高效,
    原生支持异步处理和流式响应。
    
    启动命令:
      python main.py
    
    生产部署(多 worker):
      uvicorn main:app --host 0.0.0.0 --port 8000 --workers 1
    
    注意:
    - workers=1 是因为 vLLM 引擎不是线程安全的
    - 如果需要并发,应该使用进程池或消息队列
    - macOS 上必须在 if __name__ == '__main__': 块中初始化 vLLM,因为它使用多进程
    """
    # vLLM 使用 LLM 引擎作为核心推理组件
    # 相比 Transformers,vLLM 提供了自动 Batch 处理和 KV Cache 管理
    print("Initializing vLLM engine...")
    llm = LLM(
        model="Qwen/Qwen2.5-1.5B-Instruct",
        dtype="bfloat16",  # macOS 推荐 bfloat16
        gpu_memory_utilization=0.3,  # 限制内存使用(针对 CPU 推理)
        max_model_len=2048,  # 限制最大序列长度,节省内存
    )
    print("vLLM engine initialized!\n")
    
    print("Starting vLLM API server on http://0.0.0.0:8000")
    print("API 文档:http://localhost:8000/docs")
    
    uvicorn.run(
        app,
        host="0.0.0.0",
        port=8000,
        log_level="info",
    )

运行服务器

启动服务后,终端会输出如下日志:

📄 main.py 服务端日志输出
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
INFO 11-15 19:43:34 [__init__.py:216] Automatically detected platform cpu.
Initializing vLLM engine...
INFO 11-15 19:43:35 [utils.py:233] non-default args: {'dtype': 'bfloat16', 'max_model_len': 2048, 'gpu_memory_utilization': 0.3, 'disable_log_stats': True, 'model': 'Qwen/Qwen2.5-1.5B-Instruct'}
INFO 11-15 19:43:38 [model.py:547] Resolved architecture: Qwen2ForCausalLM
`torch_dtype` is deprecated! Use `dtype` instead!
INFO 11-15 19:43:38 [model.py:1510] Using max model len 2048
WARNING 11-15 19:43:38 [cpu.py:117] Environment variable VLLM_CPU_KVCACHE_SPACE (GiB) for CPU backend is not set, using 4 by default.
INFO 11-15 19:43:38 [arg_utils.py:1166] Chunked prefill is not supported for ARM and POWER and S390X CPUs; disabling it for V1 backend.
INFO 11-15 19:43:41 [__init__.py:216] Automatically detected platform cpu.
(EngineCore_DP0 pid=70077) INFO 11-15 19:43:42 [core.py:644] Waiting for init message from front-end.
(EngineCore_DP0 pid=70077) INFO 11-15 19:43:42 [core.py:77] Initializing a V1 LLM engine (v0.11.0) with config: model='Qwen/Qwen2.5-1.5B-Instruct', speculative_config=None, tokenizer='Qwen/Qwen2.5-1.5B-Instruct', skip_tokenizer_init=False, tokenizer_mode=auto, revision=None, tokenizer_revision=None, trust_remote_code=False, dtype=torch.bfloat16, max_seq_len=2048, download_dir=None, load_format=auto, tensor_parallel_size=1, pipeline_parallel_size=1, data_parallel_size=1, disable_custom_all_reduce=True, quantization=None, enforce_eager=False, kv_cache_dtype=auto, device_config=cpu, structured_outputs_config=StructuredOutputsConfig(backend='auto', disable_fallback=False, disable_any_whitespace=False, disable_additional_properties=False, reasoning_parser=''), observability_config=ObservabilityConfig(show_hidden_metrics_for_version=None, otlp_traces_endpoint=None, collect_detailed_traces=None), seed=0, served_model_name=Qwen/Qwen2.5-1.5B-Instruct, enable_prefix_caching=True, chunked_prefill_enabled=False, pooler_config=None, compilation_config={"level":2,"debug_dump_path":"","cache_dir":"","backend":"inductor","custom_ops":["none"],"splitting_ops":null,"use_inductor":true,"compile_sizes":null,"inductor_compile_config":{"enable_auto_functionalized_v2":false,"dce":true,"size_asserts":false,"nan_asserts":false,"epilogue_fusion":true},"inductor_passes":{},"cudagraph_mode":0,"use_cudagraph":true,"cudagraph_num_of_warmups":0,"cudagraph_capture_sizes":[],"cudagraph_copy_inputs":false,"full_cuda_graph":false,"use_inductor_graph_partition":false,"pass_config":{},"max_capture_size":null,"local_cache_dir":null}
(EngineCore_DP0 pid=70077) INFO 11-15 19:43:42 [importing.py:63] Triton not installed or not compatible; certain GPU-related functions will not be available.
(EngineCore_DP0 pid=70077) WARNING 11-15 19:43:42 [cpu.py:316] Pin memory is not supported on CPU.
(EngineCore_DP0 pid=70077) INFO 11-15 19:43:43 [cpu_worker.py:66] Warning: NUMA is not enabled in this build. `init_cpu_threads_env` has no effect to setup thread affinity.
(EngineCore_DP0 pid=70077) INFO 11-15 19:43:43 [parallel_state.py:1208] rank 0 in world size 1 is assigned as DP rank 0, PP rank 0, TP rank 0, EP rank 0
(EngineCore_DP0 pid=70077) INFO 11-15 19:43:43 [cpu_model_runner.py:106] Starting to load model Qwen/Qwen2.5-1.5B-Instruct...
(EngineCore_DP0 pid=70077) INFO 11-15 19:43:43 [cpu.py:104] Using Torch SDPA backend.
(EngineCore_DP0 pid=70077) INFO 11-15 19:43:44 [weight_utils.py:392] Using model weights format ['*.safetensors']
(EngineCore_DP0 pid=70077) INFO 11-15 19:43:44 [weight_utils.py:450] No model.safetensors.index.json found in remote.
Loading safetensors checkpoint shards:   0% Completed | 0/1 [00:00<?, ?it/s]
Loading safetensors checkpoint shards: 100% Completed | 1/1 [00:04<00:00,  4.08s/it]
Loading safetensors checkpoint shards: 100% Completed | 1/1 [00:04<00:00,  4.08s/it]
(EngineCore_DP0 pid=70077) 
(EngineCore_DP0 pid=70077) INFO 11-15 19:43:48 [default_loader.py:267] Loading weights took 4.09 seconds
(EngineCore_DP0 pid=70077) INFO 11-15 19:43:48 [kv_cache_utils.py:1087] GPU KV cache size: 149,792 tokens
(EngineCore_DP0 pid=70077) INFO 11-15 19:43:48 [kv_cache_utils.py:1091] Maximum concurrency for 2,048 tokens per request: 73.14x
(EngineCore_DP0 pid=70077) INFO 11-15 19:43:49 [cpu_model_runner.py:117] Warming up model for the compilation...
(EngineCore_DP0 pid=70077) WARNING 11-15 19:43:49 [cudagraph_dispatcher.py:106] cudagraph dispatching keys are not initialized. No cudagraph will be used.
(EngineCore_DP0 pid=70077) INFO 11-15 19:43:58 [cpu_model_runner.py:121] Warming up done.
(EngineCore_DP0 pid=70077) INFO 11-15 19:43:58 [core.py:210] init engine (profile, create kv cache, warmup model) took 9.83 seconds
(EngineCore_DP0 pid=70077) WARNING 11-15 19:43:59 [cpu.py:117] Environment variable VLLM_CPU_KVCACHE_SPACE (GiB) for CPU backend is not set, using 4 by default.
INFO 11-15 19:43:59 [llm.py:306] Supported_tasks: ['generate']
vLLM engine initialized!

Starting vLLM API server on http://0.0.0.0:8000
API 文档:http://localhost:8000/docs
INFO:     Started server process [70042]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)

从日志中观察请求的生命周期

下图展示一次推理请求的生命周期:

图 1: vLLM 推理请求生命周期
图 1: vLLM 推理请求生命周期

通过 vLLM serve 的启动和推理日志,可以清晰看到一次推理请求的完整生命周期。下面结合 server-output.txt 的关键日志,梳理各阶段流程:

  1. 平台检测与引擎初始化

    • Automatically detected platform cpu.
      自动检测运行环境(如 CPU/GPU),决定后续推理方式。
  2. 参数解析与模型配置

    • non-default args: {...}
      加载模型参数(如 dtype、max_model_len),配置推理引擎。
  3. 模型架构解析与权重加载

    • Resolved architecture: Qwen2ForCausalLM
      解析模型结构,准备加载权重。
    • Loading weights took 4.09 seconds
      权重文件加载完成,准备推理。
  4. KV Cache 初始化与并发能力评估

    • GPU KV cache size: ... tokens
      初始化 KV Cache,评估最大并发能力。
  5. 模型预热与编译优化

    • Warming up model for the compilation...
      预热模型,编译优化推理流程。
  6. API 服务启动

    • Starting vLLM API server on http://0.0.0.0:8000
      启动 HTTP 服务,等待客户端请求。
  7. 请求调度与推理执行

    • Scheduler 动态合并请求,分配资源,执行推理。
  8. 结果返回与日志输出

    • 实时输出推理结果,记录服务状态。

每个阶段的日志都对应着 vLLM serve 的内部组件运作,便于开发者定位性能瓶颈和故障。后续章节将深入分析各阶段的原理与优化策略。

API 测试

本节介绍常用 API 测试方法,帮助验证服务功能。

健康检查

检查服务状态:

curl http://localhost:8000/health

响应:

{"status":"ok","model":"Qwen/Qwen2.5-1.5B-Instruct"}

非流式聊天补全

请求一次性返回完整结果:

curl -X POST http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      {"role": "user", "content": "1 加 3 等于几?"}
    ],
    "temperature": 0.7,
    "max_tokens": 128,
    "stream": false
  }' | jq

响应:

{
  "choices": [
    {
      "message": {
        "role": "assistant",
        "content": "1 加 3 等于 4。"
      },
      "index": 0,
      "finish_reason": "stop"
    }
  ]
}

流式聊天补全(实时输出)

支持逐字流式返回,提升对话体验:

curl -s -X POST http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
  "messages": [
    {"role": "user", "content": "写一首关于春天的诗,不超过 50 字"}
  ],
  "temperature": 0.8,
  "max_tokens": 128,
  "stream": true
}'

你将看到类似如下的输出:

data: {"choices": [{"delta": {"content": "\u6625"}, "index": 0}]}

data: {"choices": [{"delta": {"content": "\u98ce"}, "index": 0}]}

data: {"choices": [{"delta": {"content": "\u8f7b"}, "index": 0}]}

此处省略...

data: [DONE]

这是后续理解 Node/EngineCore 输出链(OutputProcessor)的基础。

为了能够更好的显示输出到中文内容,你可以使用下面的命令:

curl -s -X POST http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      {"role": "user", "content": "写一首关于春天的诗,不超过 50 字"}
    ],
    "temperature": 0.8,
    "max_tokens": 128,
    "stream": true
  }' | jq -Rrs 'split("\n") | .[] | select(startswith("data: ")) | .[6:] | select(. != "[DONE]") | try fromjson catch . | .choices[0].delta.content // empty' | tr -d '\n'; echo
详细说明

该命令向本地 vLLM serve 的 OpenAI 兼容 Chat Completions 接口发送一个开启流式(stream:true)的请求,随后通过管道用 jq 解析 Server-Sent Events (SSE) 格式的逐行输出并拼接成最终文本。主要参数说明:

  • -s:静默模式,不显示进度或错误信息。
  • -X POST:使用 POST 方法。
  • -H "Content-Type: application/json":请求体为 JSON。
  • 请求体字段:messages(对话消息列表)、temperature(采样温度,值越大越随机)、max_tokens(最多生成的 token 数量)、stream(是否启用流式增量返回)。
  • jq 处理:过滤以 data: 开头的 SSE 行,去掉前缀并排除 [DONE],尝试将每行解析为 JSON 并提取增量字段 .choices[0].delta.content,最后用 tr -d '\\n' 去除换行并输出为一行结果。

该方式适合实时显示模型增量生成内容并在客户端拼接为完整回答。

响应(流式):

抱歉,作为一个 AI 助手,我无法直接生成文本。但我可以为你提供一些关于春天的诗歌创作的灵感:春天到了,花儿盛开,鸟语花香,万物复苏,春风吹拂,温暖而柔和,阳光普照,万物生长。春雨绵绵,滋润万物,鸟语花香,春天的景色美不胜收,春天的美景,令人心旷神怡,让人心灵得到释放。春天是一个美好的季节,万物复苏,花儿盛开,鸟语花香,春天是一个充满希望的季节,让人感到无限的喜悦和希望,春天是一个让人沉

注意:因为我们使用的是 Qwen2.5-1.5B-Instruct 模型,而且得益于 Mac Mini M4 的性能,你可能看不到流式输出,结果瞬间输出,没有明显的延迟。

文本补全

支持传统 prompt 补全:

curl -X POST http://localhost:8000/v1/completions \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "人生的意义是",
    "temperature": 0.7,
    "max_tokens": 64
  }' | jq

响应:

{
  "choices": [
    {
      "text": "____。\nA. 自我价值的实现\nB. 对自己生活的满意\nC. 对他人生活的满足\nD. 个人与社会的和谐\n答案:AD\n\n在对专业服务公司进行管理时,主要考虑以下哪几个方面?____\nA. 战略方向\nB",
      "index": 0,
      "finish_reason": "stop"
    }
  ]
}

vLLM 的核心优化机制

vLLM serve 通过以下机制实现高效推理和资源利用:

  • 自动 Batch 处理
    Scheduler 会动态合并队列中的请求,实现高吞吐量:

    时刻 t1: 请求 1 到达 → 加入队列
    时刻 t2: 请求 2 到达 → 与请求 1 合并推理
    时刻 t3: 请求 3 到达 → 与前两个合并推理
    
    结果:三个请求几乎同时完成,而不是顺序等待
  • KV Cache 管理
    采用 PagedAttention 技术优化键值缓存:

    • 分页存储,减少内存碎片
    • 多请求共享 KV Cache 段
    • 支持更大 batch,提升并发能力
  • 动态调度
    Scheduler 支持多种调度策略:

    • FCFS(先进先出),保证公平性
    • 优先级调度,关键请求优先处理
    • Preemption,动态暂停和恢复请求,支持抢占式调度

与 Flask API 的对比

下表对比了 Flask API 与 vLLM serve 的主要差异。

方面Flask APIvLLM serve
实现难度简单中等
Batch 优化手动自动
KV Cache智能管理
吞吐量高(3-5 倍)
延迟不稳定稳定
适用场景开发、演示生产部署
表 4: Flask API 与 vLLM serve 对比

macOS 部署建议

在 macOS 上部署 vLLM 服务时,可参考以下配置和优化建议。

  • 最小化配置
    推荐最简启动流程:

    pip install vllm uvicorn
    python main.py
  • 性能优化
    通过参数优化内存和并发:

    llm = LLM(
        model="Qwen/Qwen2.5-1.5B-Instruct",
        dtype="bfloat16",           # 节省内存
        max_model_len=2048,         # 限制序列长度
        max_num_seqs=4,             # 限制同时处理的序列数
        enable_prefix_caching=True, # 启用前缀缓存(如果支持)
    )
  • 监控和日志
    实时监控服务状态和资源消耗:

    python main.py --log-level debug
    while true; do ps aux | grep main.py; sleep 1; done

常见问题

以下为 macOS 环境下 vLLM serve 常见问题及解答。

为什么我的 vLLM serve 命令不工作?

macOS 上 vLLM CLI 存在 C 扩展兼容性问题。解决方案:

  • 使用本文的替代方案:FastAPI + Uvicorn + vLLM 库
  • 关注 vLLM GitHub issues,等待官方修复
  • 如需完整 CLI 支持,建议迁移到 Linux/GPU 环境
vLLM 的自动 Batch 是如何工作的?

vLLM 的 Scheduler 会:

  • 等待新请求到达(设定时间阈值或 batch size 限制)
  • 合并队列中的请求为一个 batch
  • 一次性执行推理,所有请求同时处理
  • 逐个返回结果

相比手动 Batch,自动调度更灵活,能动态平衡延迟与吞吐量。

如何处理超长输入?

macOS CPU 内存有限,建议:

  • 设置 max_model_len=2048,限制最长输入
  • 超长请求可拒绝或截断
  • 优先选择小型模型(0.5B 或 1.1B)

如需大规模部署,建议迁移到 GPU 环境。

总结

本章介绍了如何在 macOS 上用 vLLM 库和 Uvicorn 启动生产级推理服务,兼容 OpenAI API,自动批处理和智能调度显著提升推理性能。关键收获包括:

  • OpenAI 兼容 API:客户端无需更改,直接使用 OpenAI SDK
  • 自动优化:Batch 处理、KV Cache、动态调度完全自动化
  • 流式输出:支持 Server-Sent Events,实时返回生成结果
  • macOS 友好:绕过 vLLM CLI 的兼容性问题,使用纯 Python API

若想进一步理解这些机制背后的代码组织,可继续阅读 vLLM 源码结构与内部机制路线图

创建于 2025/11/15 更新于 2026/09/18 5147 字 阅读约 11 分钟