用 FastAPI + Uvicorn 构建机器学习 API 必须分离模型加载、并发配置、输入校验和错误兜底:模型需启动时全局加载,Uvicorn 须设 --workers;输入须 Pydantic 校验并捕获异常;Swagger 示例需手动指定,版本号应显式声明。

直接上结论:用 FastAPI + Uvicorn 构建机器学习 API,不是“能跑就行”,而是必须把模型加载、请求并发、输入校验和错误兜底这四件事拆开处理——否则上线后第一个高并发请求就可能卡死或返回空结果。
模型不能在路由函数里加载
常见错误是把 tf.keras.models.load_model() 或 joblib.load() 写在 @app.post("/predict") 函数内部。这会导致每次请求都重新加载模型,内存暴涨、响应延迟飙升,甚至触发 OOM。
- 正确做法:在应用启动前一次性加载,存为全局变量或通过依赖注入管理
- 推荐方式:用
on_event("startup")钩子(注意:FastAPI 0.110+ 已弃用,改用lifespan) - 更稳妥的替代:把模型对象封装进自定义类,在
main.py顶层实例化一次
示例:
from fastapi import FastAPI
import joblib
<h1>✅ 模型只加载一次</h1><p>model = joblib.load("model.pkl")</p><p><span>立即学习</span>“<a href="https://pan.quark.cn/s/00968c3c2c15" style="text-decoration: underline !important; color: blue; font-weight: bolder;" rel="nofollow" target="_blank">Python免费学习笔记(深入)</a>”;</p><p>app = FastAPI()</p><p>@app.post("/predict")
def predict(data: dict):</p><h1>直接用已加载的 model,不重复 IO</h1><pre class="brush:php;toolbar:false;">result = model.predict([data["features"]])
return {"prediction": result.tolist()}Uvicorn 启动参数决定实际吞吐能力
uvicorn app.main:app 默认单进程、单 worker,对机器学习推理这种 CPU 密集型任务几乎毫无并发能力——哪怕你用的是异步框架,模型本身仍是同步阻塞的。
- 必须加
--workers N(N 通常设为 CPU 核心数),否则所有请求排队等一个模型实例 - 慎用
--reload:开发时方便,但会触发多次模型加载,且无法用于生产 - 生产部署建议加
--host 0.0.0.0 --port 8000 --timeout-keep-alive 5,避免长连接堆积
错误命令:
uvicorn app.main:app --reload
生产可用命令:
uvicorn app.main:app --workers 4 --host 0.0.0.0 --port 8000 --timeout-keep-alive 5
输入校验不是可选项,是防崩底线
机器学习模型对输入格式极其敏感。用户传个空数组、字符串代替数字、字段名拼错,model.predict() 很可能直接抛 ValueError 或返回 NaN,而 FastAPI 默认会把这类异常转成 500,前端得不到任何提示。
- 必须用
Pydantic定义输入 Schema,强制类型和结构校验 - 对数值型字段加
ge/le约束(比如age: int = Field(ge=0, le=120)) - 捕获模型层异常,统一转成 422 或带提示的 400 响应
示例:
from pydantic import BaseModel, Field
<p>class PredictionRequest(BaseModel):
features: list[float] = Field(min_length=10, max_length=10)</p><p>@app.post("/predict")
def predict(req: PredictionRequest):
try:
result = model.predict([req.features])
return {"prediction": result.item()}
except ValueError as e:
raise HTTPException(400, f"输入格式错误:{e}")
自动文档在 ML 场景下容易误导人
FastAPI 自动生成的 Swagger UI 对简单 API 很友好,但对机器学习接口常有严重偏差:它把 list[float] 渲染成空数组示例,用户点“Try it out”发过去,模型却因维度不匹配崩溃。
- 别依赖默认示例,用
example参数手写真实可用的测试数据 - 对二进制输入(如图像 base64)、大数组等,Swagger 本身就不适合调试,应明确提示用 curl 或 Postman
- 关键路径(如
/health和/predict)建议额外提供curl命令注释
容易被忽略的一点:模型版本信息没暴露在 OpenAPI metadata 里。你应该在 FastAPI(...) 初始化时传入 version="v2.1.0",并在 /docs 页面右上角看到它——这对下游调用方做灰度切换很关键。


















