作为一名长期从事AI模型部署的工程师,我最近在多个生产环境中使用了vLLM作为大语言模型推理引擎。今天我想重点分享一下vLLM启动后的API接口使用经验,这些接口是我们日常开发中频繁打交道的"老朋友"。
vLLM默认会在启动后监听8000端口(我习惯改为8001避免冲突),提供一整套完善的API接口。这些接口大致可以分为四类:文档与规范类、基础运维监控类、核心模型推理类以及文本处理工具类。每个接口都有其特定的使用场景和最佳实践,接下来我会结合具体案例详细说明。
提示:在生产环境中,建议通过Nginx等反向代理对外暴露服务,而不是直接开放8000/8001端口。同时记得配置防火墙规则,只允许特定IP访问管理接口。
vLLM默认使用8000端口启动服务,但实际部署时我们经常需要修改这个端口。修改方法有两种:
bash复制python -m vllm.entrypoints.api_server --port 8001
bash复制export VLLM_PORT=8001
python -m vllm.entrypoints.api_server
我更喜欢第一种方式,因为参数显式明确,方便在Docker或Kubernetes部署时直接传递。修改端口后,服务会监听在http://0.0.0.0:8001,这意味着它会接受来自任何网络接口的连接。
在实际生产部署时,我通常会做以下安全加固:
--host参数限制监听IP(如仅内网IP)--allow-credentials和--allowed-origins控制跨域访问/openapi.json接口返回的是标准的OpenAPI 3.0规范文件,这个文件实际上是整个API服务的"说明书"。我经常用它来做以下几件事:
bash复制npx openapi-typescript http://localhost:8001/openapi.json --output vllm.d.ts
而/docs提供的Swagger UI界面是我们日常开发中最常用的工具之一。它不仅展示了所有可用接口,还支持直接发起测试请求。这里分享几个使用技巧:
/redoc接口则提供了另一种文档展示方式,它的特点是:
/docs/oauth2-redirect是Swagger UI在进行OAuth2认证时使用的回调接口。虽然大多数情况下我们直接用API Key认证,但在需要集成企业SSO时,这个接口就变得很重要。配置示例:
yaml复制components:
securitySchemes:
oauth2:
type: oauth2
flows:
authorizationCode:
authorizationUrl: https://your-sso.com/oauth/authorize
tokenUrl: https://your-sso.com/oauth/token
scopes:
read: Grants read access
write: Grants write access
/health和/ping接口虽然都是健康检查,但在实际使用中有细微差别:
| 接口 | 检查深度 | 响应时间 | 适用场景 |
|---|---|---|---|
| /ping | 浅 | <50ms | 负载均衡健康检查 |
| /health | 深 | 100-300ms | 容器就绪检查 |
我通常会在Kubernetes中这样配置:
yaml复制livenessProbe:
httpGet:
path: /health
port: 8001
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ping
port: 8001
initialDelaySeconds: 5
periodSeconds: 5
/metrics接口暴露的Prometheus指标对我们优化服务性能至关重要。以下是一些关键指标:
vllm_request_duration_seconds:请求处理耗时vllm_gpu_utilization:GPU利用率vllm_kv_cache_usage_ratio:KV缓存使用率vllm_pending_requests:排队请求数我常用的Grafana监控面板会重点关注:
/version接口返回的版本信息在CI/CD流程中非常有用。我通常在部署脚本中加入版本校验:
bash复制DEPLOYED_VERSION=$(curl -s http://localhost:8001/version)
if [ "$DEPLOYED_VERSION" != "$EXPECTED_VERSION" ]; then
echo "Version mismatch!"
exit 1
fi
/load接口返回的负载信息可以帮助我们实现简单的自动扩缩容。一个典型的响应示例:
json复制{
"queue_size": 5,
"active_workers": 3,
"gpu_utilization": 0.75
}
/v1/models接口返回的信息看似简单,但在多模型部署场景下非常有用。典型响应:
json复制{
"data": [
{
"id": "gpt-3.5-turbo",
"object": "model",
"created": 1686935002,
"owned_by": "openai"
}
]
}
/v1/completions是最基础的文本补全接口,它的核心参数包括:
prompt: 输入文本max_tokens: 最大生成token数temperature: 采样温度top_p: 核采样参数stop: 停止序列我常用的请求示例:
python复制import requests
response = requests.post(
"http://localhost:8001/v1/completions",
json={
"model": "gpt-3.5-turbo",
"prompt": "Once upon a time",
"max_tokens": 50,
"temperature": 0.7
}
)
/v1/chat/completions是我们使用最频繁的接口,完全兼容OpenAI的格式。一个典型的多轮对话请求:
json复制{
"model": "gpt-3.5-turbo",
"messages": [
{"role": "system", "content": "你是一个专业的AI助手"},
{"role": "user", "content": "如何优化Python代码性能?"}
],
"temperature": 0.7
}
在实际使用中,我总结了以下经验:
response_id进行分片处理流式响应(stream)的实现方式:
python复制response = requests.post(
"http://localhost:8001/v1/chat/completions",
json={
"model": "gpt-3.5-turbo",
"messages": [...],
"stream": True
},
stream=True
)
for chunk in response.iter_content(chunk_size=None):
if chunk:
print(chunk.decode(), end="", flush=True)
/v1/responses系列接口为复杂场景提供了更多可能性。例如,我们可以这样实现异步生成:
python复制# 启动异步任务
start_resp = requests.post(
"http://localhost:8001/v1/responses",
json={"prompt": "长文本生成..."}
)
response_id = start_resp.json()["id"]
# 定期获取结果
result_resp = requests.get(
f"http://localhost:8001/v1/responses/{response_id}"
)
/v1/chat/completions/render接口在开发聊天界面时特别有用,它返回的是格式化后的HTML:
html复制<div class="chat-message">
<div class="message-user">用户</div>
<div class="message-content">你好!</div>
</div>
/tokenize接口在调试prompt时非常实用。比如我们想知道一个prompt会消耗多少token:
python复制response = requests.post(
"http://localhost:8001/tokenize",
json={"text": "你好,世界!"}
)
token_count = len(response.json()["tokens"])
实际使用中的注意事项:
/detokenize的典型使用场景是将日志中的token ID转换回可读文本:
python复制detokenized = requests.post(
"http://localhost:8001/detokenize",
json={"token_ids": [123, 456, 789]}
).json()["text"]
/scale_elastic_ep接口在应对流量波动时非常有用。一个典型的扩缩容流程:
bash复制curl -X POST "http://localhost:8001/scale_elastic_ep?workers=5"
/is_scaling_elastic_ep检查状态在Kubernetes环境中,我通常会结合HPA实现自动扩缩容:
yaml复制metrics:
- type: External
external:
metric:
name: vllm_pending_requests
selector:
matchLabels:
service: vllm
target:
type: AverageValue
averageValue: 10
| 错误码 | 含义 | 解决方案 |
|---|---|---|
| 400 | 无效请求 | 检查请求体JSON格式 |
| 429 | 请求限流 | 降低请求频率或扩容 |
| 503 | 服务不可用 | 检查GPU资源或等待服务恢复 |
| 504 | 网关超时 | 增加超时时间或优化模型 |
批处理优化:将多个请求合并为一个batch
python复制# 好:批处理请求
requests.post("/v1/completions", json={
"prompt": ["prompt1", "prompt2", "prompt3"],
"max_tokens": 50
})
# 不好:单独请求
for prompt in prompts:
requests.post("/v1/completions", json={
"prompt": prompt,
"max_tokens": 50
})
KV缓存调优:根据模型大小调整--block-size参数
bash复制# 对于7B模型
python -m vllm.entrypoints.api_server --block-size 16
# 对于175B模型
python -m vllm.entrypoints.api_server --block-size 8
量化加速:使用AWQ或GPTQ量化
bash复制python -m vllm.entrypoints.api_server \
--quantization awq \
--model facebook/opt-6.7b-awq
vLLM的内存使用主要来自三个方面:
我常用的内存估算公式:
code复制总内存 ≈ 模型参数内存 + (并发数 × 输入长度 × 每token缓存大小)
对于A100 40GB显卡,不同模型的推荐并发数:
| 模型大小 | 推荐并发数 | 输入长度限制 |
|---|---|---|
| 7B | 16-32 | 4096 |
| 13B | 8-16 | 2048 |
| 70B | 2-4 | 1024 |
在实际部署中,我发现这些接口组合使用可以构建出非常强大的LLM应用。比如通过将/tokenize与/v1/chat/completions结合,可以实现动态的token预算管理;而/metrics与/scale_elastic_ep的组合则能实现智能的自动扩缩容。