3. 启动服务
这是什么:vllm serve = 一条命令把模型变成 HTTP 服务,接口长得跟 OpenAI 一模一样。
为什么用:上一章只能用 Python 脚本调模型,别的程序连不上。起了服务,你的 Web 应用、脚本、甚至 curl 都能把它当成 OpenAI 用,以后换模型业务代码也不用动。
如何用:本章起一个服务,用 curl 和 OpenAI SDK 各调一次,再把常用参数、流式输出和 API key 鉴权理一遍。
3.1 一条命令起服务
vllm serve Qwen/Qwen3-8B --max-model-len 8192
你会看到(示意):
INFO: Started server process [1]
INFO: Waiting for application startup.
INFO: Application startup complete.
看到 Application startup complete. 才算真的起来了。启动过程分几步:下载模型权重 → 探测显存并给 KV cache 定量 → 编译 CUDA graph。模型大、机器慢的时候等几分钟很正常,第一次跑还要额外等下载。
服务默认监听 8000 端口,OpenAI 兼容接口挂在 /v1 前缀下。
3.2 常用参数速查表
| 参数 | 作用 | 备注 |
|---|---|---|
--max-model-len |
上下文最大长度(token) | 不填就按模型配置来,设小了省显存 |
--gpu-memory-utilization |
这实例能用多大比例显存 | 默认 0.92,同卡跑多实例要调小 |
--dtype |
权重精度 | auto / half / bfloat16 / float |
--quantization |
量化方式 | awq / fp8 / gptq 等,也可省略让它自动判断 |
--tensor-parallel-size |
张量并行卡数 | 模型一张卡塞不下时用 |
--port |
监听端口 | 默认 8000 |
--host |
监听地址 | 要让局域网访问就填 0.0.0.0 |
--api-key |
请求鉴权 | 客户端要带上一样的 key |
--served-model-name |
对外暴露的模型名 | 客户端 model 字段填它 |
--enable-prefix-caching |
开启前缀缓存 | V1 引擎默认已开,写上更保险 |
3.3 用 curl 试第一口
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen/Qwen3-8B",
"messages": [{"role": "user", "content": "用一句话介绍你自己"}],
"max_tokens": 64
}'
你会看到(示意):
{
"id": "chatcmpl-8f21...",
"object": "chat.completion",
"model": "Qwen/Qwen3-8B",
"choices": [{"index": 0, "message": {"role": "assistant", "content": "我是 Qwen3..."}, "finish_reason": "stop"}],
"usage": {"prompt_tokens": 18, "completion_tokens": 24, "total_tokens": 42}
}
常用的四个接口:
| 路径 | 用途 |
|---|---|
/v1/chat/completions |
对话补全,最常用 |
/v1/completions |
文本续写,不带对话历史 |
/v1/embeddings |
向量化,需要嵌入模型 |
/v1/models |
列出服务里的模型 |
3.4 用 OpenAI SDK 接上
from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1", api_key="EMPTY")
resp = client.chat.completions.create(
model="Qwen/Qwen3-8B",
messages=[{"role": "user", "content": "用一句话介绍你自己"}],
)
print(resp.choices[0].message.content)
你会看到(示意):
我是 Qwen3,一个可以帮你写代码、查资料、做翻译的语言模型。
base_url 改一行就接上了。api_key 随便填——本地服务没开鉴权时,官方 SDK 仍要求这个字段存在,填 "EMPTY" 或 "dummy" 即可。
本地还跑着别家的 API 服务时,把 base_url 指回原来的地址就能一键切回去。这正是接口标准化的好处:换后端只改一行,业务代码一个字都不用动。
3.5 流式输出
加上 stream=True,模型就一个字一个字吐出来(这叫 SSE,服务端持续推送):
from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1", api_key="EMPTY")
stream = client.chat.completions.create(
model="Qwen/Qwen3-8B",
messages=[{"role": "user", "content": "写一首关于夜晚的两行小诗"}],
stream=True,
)
for chunk in stream:
print(chunk.choices[0].delta.content or "", end="", flush=True)
你会看到(示意):
星光落在窗台,
夜风翻过旧书页。
3.6 给服务加锁
服务默认不鉴权,谁连上都能用。正式环境请加 --api-key:
vllm serve Qwen/Qwen3-8B --api-key my-secret-key --served-model-name qwen3
client = OpenAI(base_url="http://localhost:8000/v1", api_key="my-secret-key")
resp = client.chat.completions.create(model="qwen3", messages=[...])
你会看到(示意):
{"object":"error","message":"Invalid API key","type":"BadRequestError"}
--served-model-name 把对外的名字改成你习惯的(这里是 qwen3),客户端 model 字段填它就行,和模型全名解耦。
⚠️
--api-key只保护/v1、/v2、/inference前缀的接口,/health、/metrics这些运维接口不鉴权。别把它当唯一的安全防线。
动手改
- 用
--served-model-name把名字改成my-qwen,然后调/v1/models看返回的模型名 - 故意填错
api_key再调一次,读懂报错里说了什么 - 加上
--api-key后,用 curl 不带 key 请求/v1/chat/completions,观察被拒的方式
小结
vllm serve <模型>一条命令起服务,默认 8000 端口、/v1前缀- 等
Application startup complete.再发请求 - 四个常用接口:
/v1/chat/completions、/v1/completions、/v1/embeddings、/v1/models - OpenAI SDK 只改
base_url就能接上,本地服务api_key填"EMPTY" - 正式环境加
--api-key,但它管不到/health、/metrics
下一章:性能调优 🐸