Python 现代开发学习笔记

(三十八)把保存模型接回 FastAPI

训练完成后,服务启动只加载选定权重,后续请求做输入转换和前向预测。接口复用已经写好的 Predictor:

# 项目文件:training_project/src/readingtorch/api.py
from contextlib import asynccontextmanager
import os

from fastapi import FastAPI
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from pydantic import BaseModel, Field

from .predict import Predictor


class ReadingInput(BaseModel):
    minutes: float = Field(gt=0, allow_inf_nan=False)
    sessions: int = Field(ge=1, le=14)


class ReadingOutput(BaseModel):
    pages: float


def create_app(checkpoint=None):
    @asynccontextmanager
    async def lifespan(app):
        # 模型在启动时装入一次,后续请求复用只做推理的 Predictor。
        app.state.predictor = Predictor(checkpoint or os.environ["READING_MODEL"])
        yield

    app = FastAPI(title="阅读实验预测", lifespan=lifespan)

    @app.exception_handler(RequestValidationError)
    async def input_error(request, error):
        # 错误响应只组织字段位置和说明,NaN 等原始输入也不会进入 JSON。
        detail = [
            {key: item[key] for key in ["type", "loc", "msg"]}
            for item in error.errors()
        ]
        return JSONResponse({"detail": detail}, status_code=422)

    @app.post("/predict", response_model=ReadingOutput)
    def predict(body: ReadingInput):
        return {"pages": app.state.predictor.pages(body.minutes, body.sessions)}

    return app

lifespan 在启动时创建 Predictor 并保存到应用状态;路由读取同一个对象。ReadingInput 把分钟数与次数转换为合格数值,ReadingOutput 说明响应页数。字段错误响应只留下位置和原因,输入中的 NaN 等原始值不会被再次写进 JSON。

# 在 training_project 中安装接口依赖,选择刚才验证集选中的回归模型。
uv sync --locked --extra serve
$env:READING_MODEL = (Resolve-Path runs/regression/best.pt).Path
uv run uvicorn readingtorch.api:create_app --factory --host 127.0.0.1 --port 8776

打开 接口文档,向 /predict 提交:

{
  "minutes": 35,
  "sessions": 3
}

其中 minutes 是阅读分钟数,sessions 是次数,响应包含约 84.011 的 pages。也可以在另一个终端请求:

# HTTPX 发送 JSON,请求中的字段由同一个输入模型检查。
uv run python -c "import httpx; print(httpx.post('http://127.0.0.1:8776/predict', json={'minutes':35,'sessions':3}).json())"

这里每次请求都处于评估与推理流程,没有反向或优化步骤;训练仍从独立命令进入。模型从文件来到服务,与前面从数据库读取记录再响应的结构已经能够接起来。

服务启动读取一次 best 与预处理,后续请求依次经过字段校验、标准化、只读模型和页数还原,响应 JSON,训练更新在独立命令中执行

笔记正文与全部题解 · Ctrl / ⌘ K