人工智能实战:大模型推理接口响应慢?从模型加载到 FastAPI 部署的完整优化方案
一、问题场景
在公司内部做 AI 助手系统时,我一开始直接把 HuggingFace 模型加载到 FastAPI 接口里,想着先跑通再优化。
结果上线测试时遇到几个典型问题:
- 第一次请求非常慢,接口要等几十秒
- 并发一上来,接口直接卡死
- GPU 显存占用很高,但吞吐量并不理想
- 模型加载写在接口里,导致重复初始化
- 经常出现 CUDA OOM
这类问题非常典型:模型能跑 ≠ 服务能用
二、真实问题复现(错误写法)
1. 安装依赖
bash
pip install fastapi uvicorn torch transformers
2. 错误示例代码
python
from fastapi import FastAPI
from pydantic import BaseModel
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
app = FastAPI()
class ChatRequest(BaseModel):
prompt: str
@app.post("/chat")
def chat(req: ChatRequest):
model_name = "Qwen/Qwen2.5-0.5B-Instruct"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
model_name,
torch_dtype=torch.float16,
device_map="auto"
)
inputs = tokenizer(req.prompt, return_tensors="pt").to(model.device)
outputs = model.generate(
**inputs,
max_new_tokens=128
)
result = tokenizer.decode(outputs[0], skip_special_tokens=True)
return {"answer": result}
3. 启动服务
bash
uvicorn main:app --port 8000
三、问题分析(核心原因)
❌ 问题 1:模型每次请求都加载
- IO + 权重加载 + GPU拷贝
- 每次请求 = 重启一次模型
👉 直接炸性能
❌ 问题 2:未关闭梯度
python
outputs = model.generate(...)
应该:
python
with torch.inference_mode():
❌ 问题 3:输入无限制
用户输入几千字 → Attention 爆炸 → OOM
四、正确架构设计
text
请求
↓
FastAPI
↓
参数校验
↓
ModelService(单例)
↓
GPU 推理
↓
返回结果
五、完整解决方案
1. 项目结构
text
llm_demo/
├── app.py
├── model_service.py
├── schemas.py
2. 参数校验 schemas.py
python
from pydantic import BaseModel, Field
class ChatRequest(BaseModel):
prompt: str = Field(..., min_length=1, max_length=2000)
max_new_tokens: int = Field(default=128, le=512)
class ChatResponse(BaseModel):
answer: str
prompt_tokens: int
output_tokens: int
3. 模型封装 model_service.py
python
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
class ModelService:
def __init__(self, model_name):
self.model_name = model_name
self.tokenizer = None
self.model = None
def load_model(self):
print("加载模型中...")
self.tokenizer = AutoTokenizer.from_pretrained(self.model_name)
self.model = AutoModelForCausalLM.from_pretrained(
self.model_name,
torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
device_map="auto"
)
self.model.eval()
print("模型加载完成")
def generate(self, prompt, max_new_tokens=128):
inputs = self.tokenizer(
prompt,
return_tensors="pt",
truncation=True,
max_length=2048
)
inputs = {k: v.to(self.model.device) for k, v in inputs.items()}
prompt_tokens = inputs["input_ids"].shape[-1]
with torch.inference_mode():
outputs = self.model.generate(
**inputs,
max_new_tokens=max_new_tokens,
temperature=0.7
)
output_tokens = outputs.shape[-1] - prompt_tokens
result = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
return {
"answer": result,
"prompt_tokens": prompt_tokens,
"output_tokens": output_tokens
}
4. FastAPI 接口 app.py
python
from fastapi import FastAPI
from model_service import ModelService
from schemas import ChatRequest, ChatResponse
app = FastAPI()
model_service = ModelService("Qwen/Qwen2.5-0.5B-Instruct")
@app.on_event("startup")
def startup():
model_service.load_model()
@app.post("/chat", response_model=ChatResponse)
def chat(req: ChatRequest):
return model_service.generate(
req.prompt,
req.max_new_tokens
)
@app.get("/health")
def health():
return {"status": "ok"}
六、验证步骤(可复现)
1. 启动
bash
uvicorn app:app --port 8000
2. 请求测试
bash
curl -X POST "http://127.0.0.1:8000/chat" \
-H "Content-Type: application/json" \
-d '{"prompt":"什么是深度学习"}'
七、性能对比
| 版本 | 首次响应 | 并发能力 |
|---|---|---|
| 原始版本 | 30s+ | ❌ |
| 优化后 | 1~3s | ✅ |
八、踩坑记录(重点)
🚨 坑 1:模型写在接口里
直接废掉性能
🚨 坑 2:忘记 eval()
输出会不稳定
🚨 坑 3:不限制输入
OOM 99%来自这里
🚨 坑 4:没用 inference_mode
显存浪费 20%+
九、适合收藏的结构总结
✅ 标准部署流程
text
1. 模型封装
2. 启动加载
3. 参数校验
4. 推理优化
5. 接口设计
6. 压测验证
✅ 核心优化点
text
模型只加载一次
推理关闭梯度
限制输入长度
结构解耦
返回token信息
十、避坑清单(建议收藏)
text
不要每次请求加载模型
不要允许无限输入
不要忽略GPU显存
不要把逻辑写在一个文件
不要直接上大模型
十一、总结
大模型部署最大误区就是:
👉 只关注"能不能跑",不关注"能不能服务"
真正工程化需要:
- 生命周期管理(startup)
- 推理优化(no_grad)
- 输入控制
- 结构解耦
- 性能验证
十二、下一步优化方向
- vLLM 替代 transformers
- GPU 批处理
- 多实例部署
- 接入 Redis 队列
- Prometheus 监控