4、在线服务基础:vLLM OpenAI兼容API介绍、启动API服务器(vllm serve命令)、使用curl调用API、理解/v1/completions端点
好,咱们进入在线服务部分。离线批处理搞定了,接下来就是让模型真正跑起来,对外提供API服务。这一章我会带你亲手启动一个vLLM API服务器,然后用curl去调它。说白了,就是让你亲眼看到模型是怎么通过HTTP接口响应请求的。
4.1 为什么需要OpenAI兼容API?
你可能要问:为什么非得兼容OpenAI的API格式?我直接自己写个Flask服务不行吗?
当然可以。但你想过没有,现在市面上几乎所有LLM工具链——LangChain、LlamaIndex、AutoGPT——它们默认调用的都是OpenAI的API格式。如果你自己搞一套,就得让用户改代码、改SDK。我见过太多团队因为API不兼容,集成时踩了一堆坑。
vLLM直接实现了OpenAI的API规范,这意味着:
- 你现有的OpenAI客户端代码,换个base_url就能用
- 生态工具开箱即用,不用额外适配
- 团队迁移成本极低
核心要点:vLLM的API服务器实现了 /v1/completions、/v1/chat/completions、/v1/embeddings 等端点。本章我们重点讲 /v1/completions,这是最基础的文本补全接口。
4.2 启动API服务器:vllm serve命令
启动服务器其实就一行命令。我个人习惯先指定模型路径和端口,其他参数按需加。
vllm serve /data/models/Qwen2.5-7B-Instruct \
--port 8000 \
--host 0.0.0.0 \
--max-model-len 8192 \
--gpu-memory-utilization 0.9 \
--dtype auto
解释一下关键参数:
| 参数 | 说明 | 我的建议 |
|---|---|---|
--port |
监听端口,默认8000 | 生产环境别用默认,容易冲突 |
--host |
绑定地址,0.0.0.0表示所有网卡 | 本地测试用127.0.0.1更安全 |
--max-model-len |
最大输入+输出长度 | 根据显存调整,别设太大 |
--gpu-memory-utilization |
GPU显存利用率 | 0.85-0.95之间,留点余量 |
--dtype |
模型精度,auto自动选择 | 显存紧张可以指定float16 |
小技巧:启动时加上 --enforce-eager 可以禁用CUDA图优化,虽然推理慢一点,但显存占用更低。调试阶段我经常这么干。
启动成功后,你会看到类似这样的日志:
INFO: Started server process [12345]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:8000
嗯,看到这个就说明服务器跑起来了。这时候你可以打开浏览器访问 http://localhost:8000/docs,vLLM会自动生成Swagger文档,方便你测试接口。
4.3 使用curl调用API
服务器启动后,咱们用curl发个请求试试。这是最直接的方式,不用写任何代码。
curl http://localhost:8000/v1/completions \
-H "Content-Type: application/json" \
-d '{
"model": "/data/models/Qwen2.5-7B-Instruct",
"prompt": "请用一句话解释什么是大语言模型",
"max_tokens": 100,
"temperature": 0.7
}'
返回结果大概长这样:
{
"id": "cmpl-abc123",
"object": "text_completion",
"created": 1700000000,
"model": "/data/models/Qwen2.5-7B-Instruct",
"choices": [
{
"text": "大语言模型是一种基于深度学习的人工智能模型,通过海量文本数据训练,能够理解和生成自然语言。",
"index": 0,
"logprobs": null,
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 12,
"completion_tokens": 28,
"total_tokens": 40
}
}
注意:model字段必须和启动时指定的模型路径完全一致。我曾经因为路径末尾多了一个斜杠,折腾了半小时才找到原因。
4.4 理解/v1/completions端点
这个端点是最基础的文本补全接口。它的核心逻辑就是:你给一段文本,模型接着往下写。
咱们拆解一下请求参数:
- prompt:输入文本,模型会基于它继续生成
- max_tokens:最多生成多少个token
- temperature:控制随机性,0-2之间。0基本确定,1比较随机
- top_p:核采样,只从概率最高的top_p部分采样
- stop:遇到这些字符串就停止生成
- stream:是否流式返回,设为true可以实时看到生成过程
响应里的关键字段:
- choices[0].text:模型生成的文本
- choices[0].finish_reason:停止原因,stop表示正常结束,length表示达到max_tokens
- usage:token用量统计,方便计费或监控
避坑指南:我曾经在生产环境遇到一个问题——用户请求的prompt特别长,超过了模型的上下文窗口。结果模型直接报错。后来我加了个前置检查,如果prompt token数超过max_model_len的80%,就拒绝请求并提示用户缩短输入。
4.5 流式调用:实时看到生成过程
非流式调用要等模型全部生成完才返回,体验不太好。流式调用可以实时看到每个token的生成过程。
curl http://localhost:8000/v1/completions \
-H "Content-Type: application/json" \
-d '{
"model": "/data/models/Qwen2.5-7B-Instruct",
"prompt": "写一首关于春天的诗",
"max_tokens": 200,
"temperature": 0.8,
"stream": true
}'
流式返回的数据是一行一行的:
data: {"id":"cmpl-xyz","object":"text_completion","choices":[{"text":"春","index":0,"finish_reason":null}]}
data: {"id":"cmpl-xyz","object":"text_completion","choices":[{"text":"天","index":0,"finish_reason":null}]}
data: {"id":"cmpl-xyz","object":"text_completion","choices":[{"text":"来","index":0,"finish_reason":null}]}
data: [DONE]
每行都是一个独立的JSON,最后以 [DONE] 结束。前端拿到这些数据后,可以逐字展示,用户体验非常好。
个人经验:流式调用时,记得在客户端做缓冲。因为网络传输可能把多个data包合并成一个,直接解析会出错。我一般用换行符分割,逐行处理。
4.6 本章知识体系
下面这张图帮你理清本章的核心逻辑:
这张图展示了从客户端发起请求,到vLLM API服务器接收、调度推理引擎执行,最后返回结果的完整链路。你想想看,整个过程其实就三步:发请求、等推理、收结果。但背后vLLM做了大量优化,比如PagedAttention管理显存、连续批处理提高吞吐量,这些我们后面章节会深入讲。
总结一下:这一章我们学会了怎么启动vLLM API服务器,怎么用curl调用 /v1/completions 端点,以及流式和非流式调用的区别。这些都是在线服务的基础,后面的高级特性都建立在这之上。
公众号:蓝海资料掘金营,微信deep3321