استقرار مدل یادگیری ماشین یعنی تبدیل یک آزمایش به خدمتی با ورودی، خروجی و رفتار مشخص. ذخیرهٔ فایل مدل یا ساختن یک مسیر HTTP به‌تنهایی کافی نیست؛ باید پیش‌پردازش، نسخه، محدودیت ورودی، خطا و پایش هم روشن باشد. FastAPI برای ساخت API در پایتون ابزار مناسبی است، اما کیفیت مدل و ایمنی سرویس را خودکار تضمین نمی‌کند. این دو مسئولیت باید در طراحی از هم تفکیک و سپس به هم متصل شوند.

در این راهنما یک مدل آموزشی روی دادهٔ Iris را به API پیش‌بینی متصل می‌کنیم. مثال برای فهم قرارداد و گردش بارگذاری است، نه نسخهٔ آمادهٔ انتشار عمومی. در محصول واقعی باید احراز هویت، سقف درخواست، TLS و سیاست داده متناسب با محیط تنظیم شوند. هیچ مسیر آموزشی نباید بدون بررسی به اینترنت باز شود یا دادهٔ محرمانه را در گزارش‌ها ذخیره کند.

قرارداد سرویس را قبل از نوشتن endpoint مشخص کنید

ورودی مدل ما چهار اندازهٔ عددی گل است. نام، ترتیب و واحد هر ویژگی باید ثابت باشد. فهرست چهار عدد از نظر فنی ساده است، اما نام‌گذاری صریح ویژگی‌ها برای توسعهٔ واقعی قابل‌فهم‌تر است. اگر مصرف‌کننده دو ستون را جابه‌جا کند، مدل ممکن است خروجی تولید کند و هیچ خطایی رخ ندهد. بنابراین اعتبارسنجی نوع فقط بخشی از قرارداد است؛ معنا نیز باید مستند شود.

خروجی باید نوع پاسخ و نسخهٔ مدل را مشخص کند. اگر کلاس را عددی برمی‌گردانید، نگاشت آن به نام کلاس باید معلوم باشد. اگر امتیاز احتمالی می‌دهید، دربارهٔ کالیبراسیون و محدودیت تفسیر صریح باشید. پاسخ موفق نباید صرفاً رشته‌ای مبهم باشد. مصرف‌کننده باید بتواند بدون دانستن جزئیات داخلی آموزش، پاسخ را بخواند و ناسازگاری نسخه را تشخیص دهد.

پیش‌پردازش و مدل را یک بستهٔ منطقی بدانید

مدلی که با استانداردسازی آموزش دیده، در سرویس هم همان استانداردسازی را لازم دارد. محاسبهٔ دوبارهٔ میانگین روی درخواست‌های کاربران کار درستی نیست. بهتر است تبدیل و مدل در Pipeline نگه داشته شوند تا قرارداد در یک شیء مشخص باشد. ترتیب ستون، تبدیل دسته‌ای و مدیریت مقدار خالی نیز باید همان چیزی باشند که ارزیابی شده است، نه بازنویسی تقریبی آن در کد API.

فایل مدل را فقط از منبع مورداعتماد بارگذاری کنید. قالب‌هایی مانند pickle و بعضی روش‌های مبتنی بر آن می‌توانند هنگام بارگذاری کد اجرا کنند؛ دریافت فایل دلخواه از کاربر و بارگذاری آن خطرناک است. مسیر artifact باید در کنترل استقرار باشد و نسخه و وابستگی‌ها مشخص باشند. «فایل وزن» نامی نیست که ماهیت اجرایی یا خطر منبع ناشناس را خنثی کند.

نمونهٔ حداقلی با بارگذاری یک‌باره

برای اینکه مثال بدون artifact ناشناس قابل‌فهم باشد، مدل کوچک در شروع برنامه از دادهٔ داخلی کتابخانه ساخته می‌شود. در تولید، آموزش از فرایند سرویس جداست و artifact تأییدشده در شروع بارگذاری می‌شود. lifespan مکان مناسبی برای آماده‌سازی منابع مشترک است؛ نباید در هر درخواست مدل را از نو آموزش دهید یا فایل بزرگ را بارگذاری کنید.

from contextlib import asynccontextmanager
from typing import Annotated
import math
from fastapi import FastAPI
from pydantic import BaseModel, Field, field_validator
from sklearn.datasets import load_iris
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression

class Flower(BaseModel):
    features: Annotated[list[float], Field(min_length=4, max_length=4)]

    @field_validator("features")
    @classmethod
    def valid_numbers(cls, values):
        if any(not math.isfinite(v) or v <= 0 for v in values):
            raise ValueError("Expected four finite positive measurements")
        return values

class Prediction(BaseModel):
    species: str
    model_version: str

@asynccontextmanager
async def lifespan(app: FastAPI):
    data = load_iris()
    model = make_pipeline(StandardScaler(), LogisticRegression(max_iter=500))
    model.fit(data.data, data.target)
    app.state.model = model
    app.state.names = data.target_names
    yield

app = FastAPI(lifespan=lifespan)

@app.post("/predict", response_model=Prediction)
def predict(payload: Flower):
    index = int(app.state.model.predict([payload.features])[0])
    return Prediction(species=str(app.state.names[index]), model_version="iris-demo-1")

این کد از Pydantic نسخهٔ دوم استفاده می‌کند. وابستگی‌ها را با نسخه‌های سازگار و آزموده ثبت کنید. اعتبارسنجی مثبت‌بودن فقط یک محدودیت دامنه‌ای برای اندازه‌های مثال است و مناسب همهٔ مدل‌ها نیست. همچنین در نمونه، مدل روی کل دادهٔ آموزشی ساخته می‌شود؛ این مرحله ارزیابی نیست و از آن هیچ ادعای دقت استخراج نمی‌کنیم. سنجش مستقل باید پیش از بسته‌بندی انجام شده باشد.

اعتبارسنجی ورودی در مرز سامانه

تعداد ویژگی، نوع عدد، مقدار متناهی و محدودیت دامنه را بررسی کنید. NaN و بی‌نهایت می‌توانند محاسبه را خراب کنند و باید سیاست روشنی داشته باشند. برای دستهٔ ناشناخته و ستون غایب نیز تصمیم بگیرید: رد درخواست، مقدار جایگزین مجاز یا مسیر بازبینی. رفتار باید با طراحی مدل سازگار باشد، نه اینکه هر ورودی را به شکلی اجباری به عدد تبدیل کنیم.

حجم بدنه، اندازهٔ batch و طول متن را هم محدود کنید. اعتبارسنجی تک‌نمونه‌ای جلوی ارسال هزاران نمونه در یک درخواست را نمی‌گیرد. این محدودیت‌ها را در برنامه و لایهٔ استقرار مناسب هماهنگ کنید. پیام خطا باید برای مصرف‌کننده روشن باشد، ولی مسیر فایل، جزئیات زیرساخت و دادهٔ حساس را افشا نکند. ثبت خطا نیز باید با حداقل اطلاعات لازم برای رفع مشکل انجام شود.

هم‌زمانی، async و هزینهٔ CPU

نوشتن async def محاسبهٔ CPU را خودکار غیرمسدود نمی‌کند. پیش‌بینی مدل ممکن است پردازنده را درگیر کند و باید با شیوهٔ اجرای مناسب مدیریت شود. در FastAPI، مسیر همگام معمولاً در thread pool اجرا می‌شود، اما این به معنای مقیاس‌پذیری نامحدود نیست. نوع مدل، قفل‌های داخلی، کتابخانهٔ عددی و تعداد هسته‌ها بر رفتار واقعی اثر دارند؛ اندازه‌گیری لازم است.

افزایش worker معمولاً نسخه‌های جداگانه‌ای از حافظهٔ مدل ایجاد می‌کند. برای مدل بزرگ، تعداد زیاد worker می‌تواند به کمبود حافظه برسد. از تنظیم تصادفی تعداد پردازش برای جبران کندی خودداری کنید. ابتدا زمان پیش‌بینی، مصرف حافظه و اندازهٔ درخواست نماینده را بسنجید. در صورت نیاز، صف، batch یا سرویس استنتاج تخصصی می‌تواند مناسب باشد، اما این معماری‌ها باید از نیاز واقعی بیایند.

خطا، آمادگی و قرارداد HTTP

برای ورودی نامعتبر پاسخ مناسب خطای کاربر بدهید و شکست داخلی را از آن جدا کنید. endpoint سلامت ساده می‌تواند زنده‌بودن فرایند را نشان دهد، اما آمادگی باید بررسی کند مدل و منابع ضروری آماده‌اند. پاسخ ۲۰۰ از یک مسیر خالی ثابت نمی‌کند پیش‌بینی ممکن است. این تمایز در استقرار پشت توازن‌بار و هنگام تعویض نسخه اهمیت پیدا می‌کند.

خطای مدل را با خروجی ساختگی موفق پنهان نکنید. اگر سرویس آماده نیست، مصرف‌کننده باید بتواند این وضعیت را بفهمد و تصمیم بگیرد. جزئیات استثنا را در پاسخ عمومی نریزید و شناسهٔ پیگیری غیرحساس برای ربط‌دادن رخدادها کافی است. برای درخواست تکراری نیز به اثر عملیات توجه کنید؛ پیش‌بینی بدون تغییر وضعیت با عملیاتی که هزینه یا ثبت تجاری ایجاد می‌کند یکسان نیست.

آزمون API بدون مرورگر

قرارداد را با آزمون مستقیم HTTP یا TestClient بررسی کنید: ورودی درست، تعداد ویژگی اشتباه، مقدار منفی، ورودی نامتناهی و دادهٔ خارج از قرارداد. پاسخ موفق باید کلیدهای انتظاررفته و نسخهٔ مدل را داشته باشد. آزمون شروع برنامه نیز مهم است؛ در TestClient معمولاً استفاده از context manager لازم است تا lifespan اجرا شود و مدل آماده گردد.

from fastapi.testclient import TestClient
from app import app

with TestClient(app) as client:
    response = client.post("/predict", json={"features": [5.1, 3.5, 1.4, 0.2]})
    assert response.status_code == 200
    assert response.json()["model_version"] == "iris-demo-1"
    invalid = client.post("/predict", json={"features": [1.0, 2.0]})
    assert invalid.status_code == 422

این آزمون صحت قرارداد نمونه را می‌سنجد، نه کیفیت آماری مدل در جهان واقعی. تست نرم‌افزار و ارزیابی مدل مکمل‌اند. می‌توانید API کاملاً درست داشته باشید که مدلش ضعیف است یا مدل خوبی که سرویس آن ترتیب ویژگی‌ها را اشتباه می‌کند. هر دو لایه باید معیار پذیرش جداگانه و آزمون متناسب داشته باشند تا خطا به لایهٔ دیگر نسبت داده نشود.

امنیت استقرار و حریم خصوصی

برای سرویس خصوصی، احراز هویت و مجوز دسترسی لازم است. کلید را در کد، URL یا مخزن نگذارید و از سازوکار امن محیط استقرار استفاده کنید. TLS، محدودیت درخواست و تنظیم درست پراکسی نیز بخشی از کارند. CORS جای احراز هویت نیست و تعیین دامنهٔ مجاز مرورگر، دسترسی مستقیم سایر کلاینت‌ها را محدود نمی‌کند. این دو مفهوم را با هم اشتباه نگیرید.

متن یا ویژگی حساس را بی‌دلیل در log ننویسید. برای پایش، تعداد درخواست، زمان پاسخ، اندازهٔ ورودی و نوع خطا اغلب کافی‌اند. اگر ذخیرهٔ نمونه برای بازبینی لازم است، مجوز، مدت نگهداری و دسترسی را مشخص کنید. همچنین پیش‌بینی روی دادهٔ کاربر را بدون سیاست روشن وارد آموزش بعدی نکنید. امکان فنی جمع‌آوری، معادل رضایت و مجوز استفادهٔ ثانویه نیست.

نسخه‌بندی و انتشار قابل‌برگشت

نسخهٔ مدل، کد پیش‌پردازش و schema ورودی را به هم متصل کنید. تغییر نام یا ترتیب ویژگی ممکن است نیازمند نسخهٔ تازهٔ API یا قرارداد مهاجرت باشد. حتی وقتی شکل JSON عوض نمی‌شود، تغییر معنای یک واحد می‌تواند شکستن قرارداد باشد. پیش از انتشار، نمونه‌های مرجع را با نسخهٔ قبلی مقایسه و معیار پذیرش کیفیت و عملکرد را مشخص کنید.

برای انتشار، نسخهٔ قبلی و راه برگشت داشته باشید. ابتدا روی محیط آزمون، سپس با دامنهٔ محدودِ مجاز بررسی کنید. بازگشت مدل بدون بازگشت پیش‌پردازش می‌تواند ناسازگار باشد؛ بستهٔ منطقی باید هماهنگ بماند. هیچ انتشار موفق فنی تضمین نمی‌کند دادهٔ آینده تغییر نکند، بنابراین پایش پس از استقرار بخشی از چرخه است. پایان کدنویسی، پایان مسئولیت مدل نیست.

پایش کیفیت و هزینه

زمان پاسخ را فقط با میانگین گزارش نکنید؛ صدک‌های بالاتر و رفتار در اندازه‌های مختلف درخواست نیز مهم‌اند. تعداد خطا، مصرف حافظه و نسخهٔ فعال را پایش کنید. اگر برچسب واقعی با تأخیر می‌آید، کیفیت را پس از رسیدن آن بسنجید. شاخص تغییر توزیع ورودی می‌تواند هشدار بدهد، اما به‌تنهایی میزان افت دقت را ثابت نمی‌کند. تصمیم بازآموزی باید به شواهد وابسته باشد.

برای مدل‌های بیرونی یا محاسبات گران، هزینهٔ هر درخواست و محدودیت بودجه را روشن کنید. timeout و ظرفیت را با رفتار مصرف‌کننده هماهنگ کنید و از تلاش مجدد بی‌حد پرهیز کنید. نسخهٔ جدیدی که کمی دقیق‌تر اما بسیار کندتر است، ممکن است نیاز عملیاتی را برآورده نکند. کیفیت سرویس ترکیبی از صحت مدل، قابلیت اتکا، هزینه و زمان پاسخ است و باید یک‌جا سنجیده شود.

چک‌لیست تحویل یک سرویس کوچک

پیش از تحویل، درخواست مرجع و پاسخ موردانتظار را همراه نسخهٔ مدل نگه دارید. سپس همان درخواست را در محیط آزمون اجرا کنید و مطمئن شوید پیش‌پردازش، نگاشت کلاس و schema هماهنگ‌اند. اگر پاسخ عددی شناور دارد، مقایسه با تلورانس مناسب انجام شود؛ برابری رشته‌ای همهٔ رقم‌ها همیشه انتظار درستی نیست. معیار آزمون باید تفاوت بی‌اهمیت عددی را از تغییر واقعی رفتار جدا کند.

شروع ناموفق را هم بررسی کنید. اگر مدل پیدا نشد یا وابستگی ناسازگار بود، سرویس نباید ظاهراً آماده اعلام شود. رفتار آمادگی و پیام ثبت‌شده باید برای تیم عملیات قابل‌فهم باشد، بدون اینکه مسیر یا اطلاعات حساس به مصرف‌کننده افشا شود. همچنین خروج منظم فرایند و آزادکردن منابع را در محیط استقرار بسنجید. این رفتارها در نمونهٔ کوچک ساده‌اند، اما در تعویض نسخه و چند worker اهمیت بیشتری پیدا می‌کنند.

مستندات مصرف‌کننده باید واحد ویژگی‌ها، محدودیت ورودی، شکل خطا و سیاست نسخه‌بندی را بیان کند. یک مثال درخواست درست و چند مثال نادرست از توضیح کلی طولانی مفیدترند. اگر اندازهٔ batch محدود است، سقف را روشن بنویسید. اگر سرویس تنها در دامنه‌ای خاص ارزیابی شده، همان محدودیت را نزدیک توضیح خروجی اعلام کنید. مصرف‌کننده نباید از پاسخ موفق نتیجه بگیرد که هر ورودی از نظر آماری معتبر بوده است.

پس از تحویل، مسئول پایش و مسیر گزارش خطا را مشخص کنید. معیار انتشار نسخهٔ بعدی و بازگشت به قبلی باید از پیش معلوم باشد. برای پروژهٔ کوچک، یک روند ساده و دستیِ روشن بهتر از خودکارسازی پیچیده و بدون کنترل است. هدف این نیست که همهٔ ابزارهای عملیات مدل را از روز نخست اضافه کنید؛ هدف آن است که هیچ تصمیم حیاتی میان آموزش، نرم‌افزار و استقرار بی‌صاحب نماند.

پرسش‌های متداول

آیا باید مدل را در هر درخواست آموزش دهیم؟

خیر، مگر مسئله عمداً طراحی برخط ویژه‌ای داشته باشد. در سرویس معمول، آموزش مرحله‌ای جداست و مدل تأییدشده در شروع بارگذاری می‌شود. آموزش در درخواست، زمان پاسخ، تکرارپذیری و مصرف منابع را مشکل‌دار می‌کند. مثال آموزشی ساخت مدل در lifespan نیز برای سادگی است و الگوی نگهداری artifact در تولید را جایگزین نمی‌کند.

آیا Swagger به معنای آماده‌بودن محصول است؟

نه. مستندات تعاملی قرارداد را قابل‌مشاهده می‌کنند، اما امنیت، کیفیت آماری و تحمل بار را ثابت نمی‌کنند. آزمون ورودی مرزی، ارزیابی مستقل مدل و تنظیمات استقرار همچنان لازم‌اند. حتی مسیرهای مستندات در سرویس خصوصی باید مطابق سیاست دسترسی محیط تنظیم شوند، نه اینکه صرف موجودبودن ابزار را مجوز انتشار عمومی فرض کنیم.

برای شروع چه خروجی‌هایی آماده کنم؟

یک مدل ارزیابی‌شده، قرارداد ورودی و خروجی، آزمون API، وابستگی‌های ثبت‌شده و راه بازگشت تهیه کنید. سپس روی محیط مجاز، عملکرد و خطاها را بسنجید. برای تکمیل پایه‌ها، مقالهٔ ارزیابی مدل و یادگیری ماشین را دوباره مرور کنید؛ API معتبر باید همان فرایندی را سرو کند که واقعاً آزمایش شده است، نه نسخه‌ای ساده‌شده با رفتار متفاوت.

منابع و مطالعهٔ بیشتر

برای بررسی جزئیات و ادامهٔ مطالعه؛ متن این راهنما مستقلاً برای نوونتیکس نوشته شده است.