FastAPI দিয়ে model serving: REST API, request/response, validation

Project P9 — real inference API (Series 09, Episode 02)

🟡 INTERMEDIATE Series 09 — Notebook থেকে Production AI Episode 02 / 09

📑 এই পর্বে যা যা আছে

🎬 ১. গল্প: "API দাও, notebook না"

গত পর্বে Rahim বুঝেছিল তার churn model শুধু তার laptop-এ বন্দি। আজ সে Maya-র কাছে গেল: "আপা, তাহলে marketing team-কে কী দেব?" Maya বলল —

"ওদের একটা endpoint দাও। একটা URL, যেখানে ওরা একজন customer-এর তথ্য POST করবে, আর সাথে সাথে ফেরত পাবে {"churn_risk": 0.82}। ওরা জানতেও চায় না ভেতরে RandomForest আছে না XGBoost — ওরা শুধু input দেবে, output নেবে। এটাই একটা REST API, আর Python-এ এটা বানানোর সবচেয়ে ভালো আধুনিক tool হলো FastAPI।"

আজ আমরা Rahim-এর সেই প্রথম real inference API বানাব।

২. সমস্যা: model আর বাইরের দুনিয়ার মধ্যে সেতু

আমাদের কাছে একটা saved model (model.pkl) আছে। বাইরে আছে অনেক client — mobile app, web dashboard, অন্য backend service। এদের প্রত্যেকে ভিন্ন ভাষায় লেখা (JavaScript, Java, PHP...)। এরা কেউ Python object সরাসরি ব্যবহার করতে পারে না।

দরকার এমন একটা common ভাষা যা সবাই বোঝে — সেটা হলো HTTP + JSON। একটা REST API ঠিক এই সেতুটাই তৈরি করে: যেকোনো client → HTTP request → তোমার service → JSON response।

৩. REST API আসলে কী — চায়ের দোকানের গল্পে

Level 1 — সহজ intuition:
একটা চায়ের দোকান ভাবো। তুমি জানালায় গিয়ে বলো "একটা দুধ চা" (request)। ভেতরে কে চা বানাচ্ছে, কোন পদ্ধতিতে — জানার দরকার নেই। কিছুক্ষণ পর হাতে চা পাও (response)। REST API-ও তেমন: তুমি একটা নির্দিষ্ট "জানালায়" (endpoint/URL) নির্দিষ্ট ফরম্যাটে অর্ডার দাও, নির্দিষ্ট ফরম্যাটে ফল পাও।
Level 2 — technical:
REST API হলো HTTP-ভিত্তিক একটা interface। প্রতিটা "জানালা" একটা endpoint (যেমন /predict)। প্রতিটা অর্ডারের একটা method থাকে — GET (তথ্য পড়া), POST (নতুন কিছু পাঠানো/process করা)। ML prediction-এ আমরা সাধারণত POST ব্যবহার করি, কারণ আমরা input data পাঠাচ্ছি। Data যায়-আসে JSON ফরম্যাটে।
Level 3 — AI Engineer perspective:
Engineer endpoint design করে business অনুযায়ী: POST /predict (একটা prediction), POST /predict/batch (একসাথে অনেক), GET /health (service বেঁচে আছে কিনা)। প্রতিটা endpoint-এর input/output contract পরিষ্কার রাখে যাতে client team সহজে integrate করতে পারে।

৪. কেন FastAPI (Flask/Django নয় কেন)

আমরা কোনো tool "জনপ্রিয়" বলে বাছি না — কারণ দেখে বাছি:

ToolML serving-এ ভূমিকাকখন
FastAPIদ্রুত, modern, Pydantic দিয়ে auto input validation, auto docs (/docs), async supportনতুন ML API — default পছন্দ
Flaskসহজ, হালকা, কিন্তু validation/docs নিজে যোগ করতে হয়খুব ছোট/legacy project
Djangofull-stack, ভারী (ORM, admin, auth)বড় web app যেখানে ML একটা অংশমাত্র
কেন FastAPI আমাদের পছন্দ: (১) Pydantic দিয়ে input নিজে থেকেই validate হয় — ভুল data এলে পরিষ্কার error দেয়; (২) /docs-এ নিজে থেকে interactive documentation তৈরি হয় — client team খুশি; (ৃৃৃ৩) দ্রুত ও async-ready, যা LLM API-এর মতো I/O-heavy কাজে দারুণ (Series 02-এর async মনে আছে?)।

🔧 ৬. Setup ও প্রথম endpoint

প্রথমে environment (Series 02-এর uv/venv মনে করো) আর দরকারি package:

# environment তৈরি ও package install python -m venv .venv source .venv/bin/activate # Windows: .venv\Scripts\activate pip install fastapi uvicorn scikit-learn joblib pydantic

এবার সবচেয়ে ছোট FastAPI app — main.py:

# main.py from fastapi import FastAPI app = FastAPI(title="Churn Prediction API") @app.get("/health") def health(): # service বেঁচে আছে কিনা জানার সহজ উপায় return {"status": "ok"}

চালাও: uvicorn main:app --reload। এখানে uvicorn হলো সেই server যে তোমার app-কে চালু রাখে; --reload কোড বদলালে নিজে restart করে (শুধু development-এ)।

📦 ৭. Model load করা — startup-এ একবার

একটা বড় ভুল হলো প্রতিটা request-এ model joblib.load() করা — এটা প্রচণ্ড ধীর করে দেয়। সঠিক উপায়: app চালু হওয়ার সময় একবার load করে memory-তে রেখে দেওয়া।

# main.py (model load অংশ) import joblib from fastapi import FastAPI app = FastAPI(title="Churn Prediction API") # module load হওয়ার সময় একবারই চলে -> সব request এই model share করে model = joblib.load("model.pkl")
মনে রাখো — এখানে কোনো fit() নেই। এটাই inference: আগে train করা model শুধু load করে ব্যবহার করছি। train আর serve সবসময় আলাদা রাখো।

🛡️ ৮. Pydantic দিয়ে input validation

Client ভুল data পাঠাতেই পারে (tenure-এ string, বা field বাদ)। Pydantic দিয়ে আমরা input-এর একটা schema ঠিক করে দিই — FastAPI নিজে থেকেই যাচাই করে, ভুল হলে সুন্দর error দেয়।

# schemas.py from pydantic import BaseModel, Field class Customer(BaseModel): tenure: int = Field(ge=0, description="কত মাস ধরে customer") monthly_charges: float = Field(ge=0) contract_type: str # "month-to-month" | "one-year" | "two-year" class Prediction(BaseModel): churn_risk: float will_churn: bool

Field(ge=0) মানে "greater than or equal to 0" — negative tenure আসতেই পারবে না। Output-এরও একটা schema (Prediction) রাখলে API contract স্পষ্ট থাকে।

🎯 ৯. পুরো /predict endpoint (churn model)

# main.py (সম্পূর্ণ) import joblib import pandas as pd from fastapi import FastAPI from schemas import Customer, Prediction app = FastAPI(title="Churn Prediction API") model = joblib.load("model.pkl") @app.get("/health") def health(): return {"status": "ok"} @app.post("/predict", response_model=Prediction) def predict(customer: Customer): # 1) Pydantic model -> DataFrame (model যেভাবে train হয়েছিল) row = pd.DataFrame([customer.model_dump()]) # 2) inference: probability বের করা proba = model.predict_proba(row)[0][1] # churn=1 এর probability # 3) business rule: 0.5-এর বেশি হলে churn ধরি return Prediction(churn_risk=round(float(proba), 3), will_churn=bool(proba >= 0.5))
খেয়াল করো তিনটা পরিষ্কার ধাপ: input → preprocessing → inference → response। বাস্তব project-এ preprocessing (encoding, scaling) ঠিক এখানেই বসবে — আর সেটা train-এর সময় যা করেছিলে তার হুবহু একই হতে হবে (নাহলে training-serving skew হবে)।

▶️ ১০. চালানো ও test করা (docs, curl)

Server চালাও: uvicorn main:app --reload। এবার তিনভাবে test করা যায়:

# 1) Browser-এ auto docs: http://127.0.0.1:8000/docs # -> Pydantic থেকে FastAPI নিজেই interactive UI বানায় # 2) curl দিয়ে: curl -X POST http://127.0.0.1:8000/predict \ -H "Content-Type: application/json" \ -d '{"tenure": 3, "monthly_charges": 85.5, "contract_type": "month-to-month"}' # উদাহরণ response: # {"churn_risk": 0.82, "will_churn": true}

এই মুহূর্তে Rahim-এর model অবশেষে বাইরের দুনিয়ায়। marketing team-এর যেকোনো developer এই curl বা docs দেখে integrate করতে পারবে।

🧪 ১১. Experiment: ভুল input পাঠিয়ে দেখো

এটাই FastAPI-এর শক্তি: তুমি একটা line-ও validation কোড না লিখেই তোমার API-কে ভুল data থেকে রক্ষা করছ।

🇧🇩 ১২. বাংলাদেশের বাস্তব উদাহরণ

👷 ১৩. AI Engineer perspective: sync, batch, health check

💼 ১৪. Boss Question

💼 Boss: "এই API বানিয়ে আমার কী লাভ? আগে তো notebook-এও prediction হচ্ছিল।"

উত্তর: পার্থক্যটা হলো — এখন আপনার marketing app, dashboard, বা যেকোনো team নিজে থেকেই ২৪/৭ এই prediction ব্যবহার করতে পারবে, আমাকে ছাড়াই। আগে prediction পেতে আমাকে ডাকতে হতো, এখন একটা URL হিট করলেই হবে। মানে model এখন একটা পুনর্ব্যবহারযোগ্য business capability — একবার বানিয়ে বহু জায়গায় কাজে লাগবে।

🔎 ১৫. Job Requirement Decoder: "Build REST APIs for ML models (FastAPI/Flask)"

  1. কী বোঝায়? ML model-কে HTTP endpoint হিসেবে expose করা, যাতে অন্য software ব্যবহার করতে পারে।
  2. কেন চায়? প্রায় সব ML product-এই model-কে API হিসেবে serve করা হয় — এটা industry standard।
  3. কোন সমস্যা সমাধান করে? model আর বাকি system-এর মধ্যে integration সেতু।
  4. Junior-এর কী জানা লাগে? FastAPI দিয়ে GET/POST endpoint, Pydantic validation, model load, JSON response, /docs ব্যবহার।
  5. এখনই কী master লাগে না? high-throughput serving, gRPC, model server (Triton/TorchServe), streaming response — পরে।
  6. GitHub-এ কীভাবে দেখাবে? একটা app.py + schemas.py + README-তে curl example ও /docs screenshot; সম্ভব হলে live demo link।
  7. Interview-তে কী জিজ্ঞেস করতে পারে? "GET vs POST কখন?", "Pydantic কেন?", "model কোথায় load করবে — request-এ না startup-এ?", "422 error কী?"

⚠️ ১৬. সাধারণ ভুল

ভুল ১: প্রতিটা request-এ joblib.load()। → startup-এ একবার load করো।

ভুল ২: serving-এ preprocessing training-এর থেকে আলাদা। → training-serving skew, ভুল prediction। হুবহু একই preprocessing ব্যবহার করো।

ভুল ৩: input validation না রাখা। → garbage in, crash out। Pydantic ব্যবহার করো।

ভুল ৪: --reload দিয়ে production চালানো। → এটা শুধু development-এর জন্য।

ভুল ৫: error handle না করা (model file নেই, বা unknown category)। → try/except + সঠিক HTTP status ফেরত দাও।

🎤 ১৭. Interview Prep

প্রশ্ন ১: "একটা ML model কীভাবে API হিসেবে expose করবে?"
উত্তর: model save → FastAPI app-এ startup-এ load → Pydantic schema দিয়ে input → /predict POST endpoint → preprocessing + inference → JSON response।

প্রশ্ন ২: "কেন FastAPI, Flask নয়?"
উত্তর: auto validation (Pydantic), auto interactive docs, async support, ও গতি — ML serving-এ কম কোডে বেশি নিরাপত্তা।

প্রশ্ন ৩: "model কি প্রতিটা request-এ load করবে?"
উত্তর: না, startup-এ একবার; নাহলে প্রতিটা request ধীর হবে।

প্রশ্ন ৪: "training-serving skew কী?"
উত্তর: train আর serve-এর সময় preprocessing আলাদা হলে model ভুল করে — একই preprocessing pipeline দুই জায়গায় ব্যবহার করাই সমাধান।

✍️ ১৮. হাতে-কলমে

Mini exercise:
১. Series 05-এর যেকোনো model joblib.dump করে save করো।
২. উপরের কোড দিয়ে একটা FastAPI app বানাও: /health + /predict
৩. uvicorn main:app --reload চালিয়ে /docs-এ গিয়ে একটা prediction করো।
৪. একটা POST /predict/batch যোগ করো যা list[Customer] নেয় ও list ফেরত দেয়।
৫. ভুল input পাঠিয়ে দেখো কী error আসে — বুঝে নাও validation কীভাবে রক্ষা করছে।

🚀 ১৯. Project Connection: flagship V8

এই episode-এ আমাদের flagship "Bangladesh Tech Career Assistant" V7 (RAG) থেকে V8 (FastAPI)-এ পৌঁছাল। এখন আমরা একটা POST /analyze endpoint বানাব যা একটা job description নেয় এবং দরকারি skill + probable role ফেরত দেয়। এটাই আমাদের Project P9 (Production AI API)-এর মূল অংশ।

তোমার কাজ: flagship-এর inference অংশটাকে একটা function-এ আলাদা করো (analyze_jd(text) -> dict), তারপর সেটাকে FastAPI endpoint দিয়ে wrap করো। পরের episode-এ আমরা এই messy কোডকে একটা পরিষ্কার package বানাব।

📌 ২০. সারসংক্ষেপ ও পরের পর্ব

এই episode-এ আমরা শিখলাম:
✓ REST API = HTTP+JSON দিয়ে model আর বাইরের দুনিয়ার সেতু
✓ কেন FastAPI (auto validation, auto docs, async, গতি)
✓ model startup-এ একবার load করা (request-এ নয়) — এটাই সঠিক inference pattern
✓ Pydantic schema দিয়ে input/output contract ও automatic validation
/predict, /health, batch endpoint — ও curl/docs দিয়ে test
পরের episode-এ আমরা এই এক-file-এর messy কোডকে একটা পরিষ্কার Python package বানাব — config, structured logging আর secrets management সহ — যাতে এটা সত্যিকারের service-grade কোড হয়।
© 2025 Sheikh Thanbir Alam. All Rights Reserved. thanbirtamim.github.io
এই লেখা মূল লেখকের সম্পত্তি — লিখিত অনুমতি ছাড়া কপি করে অন্য কোনো ওয়েবসাইট, ব্লগ, বই বা প্ল্যাটফর্মে প্রকাশ/বিতরণ করা কঠোরভাবে নিষিদ্ধ। Content may not be copied or republished without permission.