使用flask/fastapi部署模型(工业级)
前言
LLM部署,首先介绍fastapi和flask,两者都是用于构建Web应用程序的框架。再介绍工业级部署策略。简单调试可以用第二小节内容,真正部署可以用第三节内容。
使用fastapi或者flask
笔者更喜欢flask框架,觉得他更接地气,且易于使用。
使用fastapi实现
使用了客户端和服务端的分离,使得你可以在需要的时候发送推理请求。
1 | # start_server.py |
客户端代码如下:
1 | # client.py |
1 | # 在shell输入下面指令,获取ip |
使用flask实现
使用flask,记得安装相应的库pip install Flask requests
将服务启动和推理分开为两个脚本。以下是一个简单的示例,其中一个脚本 start_server.py 负责启动服务,另一个脚本 client.py 负责进行推理:
1 | # start_server.py |
客户端代码如下:
1 | # client.py |
1 | # 也可以直接在终端输入下面指令调用 |
工业级改造建议
方案A:用 Gunicorn + Uvicorn + FastAPI 替代 Flask
原理:Gunicorn 做多进程管理,每个进程绑定一块 GPU,互不干扰,能安全高并发。
实现步骤:
-
用 FastAPI 重写 infer 逻辑(大部分和 Flask 类似)
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# server.py
from fastapi import FastAPI, Request
from transformers import T5ForConditionalGeneration, T5Tokenizer
import torch
app = FastAPI()
# 这里假设每个进程只用一个GPU(外部启动进程时设置CUDA_VISIBLE_DEVICES)
model_id = "/home/jerry/workspace/code/t5/saved/checkpoint_199500"
model = T5ForConditionalGeneration.from_pretrained(model_id).cuda()
tokenizer = T5Tokenizer.from_pretrained(model_id)
async def infer(request: Request):
data = await request.json()
input_text = data.get('input_smile')
beam_size = data.get('beam_size', 1)
# infer 逻辑同之前
input_ids = tokenizer(input_text, return_tensors="pt", max_length=256, truncation=True).input_ids.cuda()
outputs = model.generate(
input_ids=input_ids, return_dict_in_generate=True, output_scores=True,
do_sample=False, max_length=256, num_beams=20, num_return_sequences=20,
diversity_penalty=1.5, num_beam_groups=10
)
decoded_outputs = tokenizer.batch_decode(outputs.sequences, skip_special_tokens=True)
decoded_scores = [float(s) for s in outputs.sequences_scores.cpu().numpy()]
# 你的 normalize、process_final_result逻辑...
# ...
return {"topk": decoded_outputs, "score": decoded_scores} -
使用tmux启动多个进程,分别绑定不同 GPU
用 shell 脚本run_server.py
,假设你有4张卡:1
2
3
4
5
6run_server.py
CUDA_VISIBLE_DEVICES=0 gunicorn server:app -k uvicorn.workers.UvicornWorker -b 0.0.0.0:9007 --workers 1 &
CUDA_VISIBLE_DEVICES=1 gunicorn server:app -k uvicorn.workers.UvicornWorker -b 0.0.0.0:9008 --workers 1 &
CUDA_VISIBLE_DEVICES=2 gunicorn server:app -k uvicorn.workers.UvicornWorker -b 0.0.0.0:9009 --workers 1 &
CUDA_VISIBLE_DEVICES=3 gunicorn server:app -k uvicorn.workers.UvicornWorker -b 0.0.0.0:9010 --workers 1 &其中server是第一步中的server.py文件去掉
.py
,这里要保持一致。需要在 server.py 所在目录执行 gunicorn,或者确保 server:app 可以被 import 到!也就是直接把run_server.py放在server.py所在目录执行gunicorn就行了。 -
配置 nginx 轮询端口分流(负载均衡到4个端口)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15upstream t5_backend {
server 127.0.0.1:9007;
server 127.0.0.1:9008;
server 127.0.0.1:9009;
server 127.0.0.1:9010;
}
server {
listen 9006;
location / {
proxy_pass http://t5_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}新建
t5_backend.conf
放在你的nginx 配置目录下,然后sudo nginx -t
,sudo nginx -s reload
重启 nginx 即可。过程中如果有端口被占用,假如是80端口,可以使用下面指令杀掉:sudo kill -9sudo lsof -i:80 -t
。
这样,client 只需要访问 http://服务器IP:9006,nginx 自动转发到不同 GPU 实例,天然支持高并发和多线程! curl http://127.0.0.1:9006
即可,返回 {“detail”:“Method Not Allowed”} 其实是 FastAPI/服务端的正常提示!
方案B:用 Triton Inference Server / vLLM / TensorRT-LLM(推荐大模型/生产环境)
如果你要“卷得更专业”,用工业级推理服务器:
- vLLM: 专为 LLM 高吞吐、并发推理设计,兼容 transformers API,自动管理多卡。
- Triton: NVIDIA 官方推理引擎,可动态批量、热升级、Prometheus 监控。
- 优势:自动 batch 请求、显存隔离、API 并发量超 Flask/FastAPI 百倍,性能极强。
- 迁移:你只需写一个 handler/model wrapper,然后按官方文档启动多 GPU,RESTful API 无缝调用。
后续继续优化中…
client 端并发优化建议
- 线程池/进程池调用,提高本地 CPU 并发
- 不用手动指定 gpu_id,由负载均衡自动分发
- 如果响应慢,client 端可以用 retry 机制自动重试
eg:
1 | from concurrent.futures import ThreadPoolExecutor |
总结与推荐
- 如果要和 OpenAI、GLM、Llama 一样的高并发体验,必须用专业推理服务+多进程/多卡绑定+负载均衡
- Flask/单进程/线程只是调试用,不能用于生产高并发
- 最优推荐:FastAPI + Gunicorn + 多进程(每进程单卡) + nginx 负载均衡
- 进阶推荐:直接用 vLLM、Triton,完全无缝支持 Huggingface/transformers,简单几行代码即可