Lesson 116 — Advanced

Application Serving & Containerization

Notebook chal jaata hai, par user ko chahiye tez, stream hua jawab jo kisi bhi machine pe same chale. Is lesson mein hum FastAPI backend, server-sent events se streaming, timeouts aur disconnect handling, health/readiness endpoints, ek thin frontend, aur poore stack ko Docker Compose se ek command mein chalayenge.

⏱ 30 min• Advanced• Runtime Guardrails

Serving ka structure kyun matter karta hai

Kya hai?

Serving matlab app logic ko ek HTTP service mein daalna (backend), uske upar sirf UI lagaana (frontend), aur dono ko container mein pack karna taaki laptop aur server pe same chale.

Kab kaam aata hai?

Jab pehla real user aaye, ya pehli baar kisi aur ko demo dena ho, ya CI ko app chala kar test karna ho. Notebooks aur scripts yahin retire ho jaate hain.

Kahan milta hai?

Backend framework (FastAPI) ke andar, UI framework (Streamlit jaisa) ke roop mein frontend, Dockerfile aur docker-compose.yaml mein packaging.

LLM apps ka serving ka khaas masla: request lambi hai. Model seconds leta hai, agent minutes tak. Isliye normal request-response ka template kaafi nahi — streaming chahiye, timeouts chahiye, aur disconnect pe token kharcha bhi band karna padta hai.

Rule: Backend ke paas hi business logic hai — config, RAG chain, guardrails, tracing. Frontlight frontend sirf render karta hai. Do logic wale layers = do jagah bug, do jagah fix.

FastAPI backend — validated requests, typed responses

from fastapi import FastAPI
from pydantic import BaseModel, Field

app = FastAPI()

class ChatRequest(BaseModel):
    message: str = Field(min_length=1, max_length=4000)
    session_id: str

class ChatResponse(BaseModel):
    answer: str
    request_id: str
    prompt_version: str

@app.post("/chat", response_model=ChatResponse)
def chat(req: ChatRequest):
    rid = new_request_id()
    answer = rag_chain(req.message, request_id=rid)
    return ChatResponse(answer=answer, request_id=rid,
                        prompt_version=CFG.prompt_version)
Error shape: Errors ka bhi ek fixed shape rakho (code, message, request_id) — frontend unhe plain language mein dikha sake. "500 Internal Server Error" user ko kuch nahi batata.

Streaming — server-sent events aur disconnects

from fastapi.responses import StreamingResponse
from fastapi import Request
import json, asyncio

@app.post("/chat/stream")
async def chat_stream(req: ChatRequest, request: Request):
    async def gen():
        try:
            async for tok in rag_chain.astream(req.message):
                if await request.is_disconnected():
                    log_disconnect(req.session_id)   # token kharcha roko
                    break
                yield "data: " + json.dumps({"tok": tok}) + "\n\n"
            yield "data: [DONE]\n\n"
        except asyncio.TimeoutError:
            yield "data: " + json.dumps({"error": "timeout"}) + "\n\n"

    return StreamingResponse(gen(), media_type="text/event-stream")
UX line: Streaming sirf technical nahi, UX ka hissa hai — user ko jawab banta hua dikhta hai, perceived latency kaafi kam ho jaati hai. LLM apps mein ye default hona chahiye.

Health aur readiness endpoints

@app.get("/healthz")
def healthz():
    return {"ok": True}          # process zinda hai? bas

@app.get("/readyz")
def readyz():
    checks = {
        "config": CFG is not None,
        "vector_db": ping_vector_db(timeout=1.0),
        "provider": ping_provider(timeout=2.0),
        "prompt_registry": registry_ping(),
    }
    ready = all(checks.values())
    return JSONResponse(status_code=200 if ready else 503, content=checks)
Do alag cheezein: Health aur readiness same nahi hote — app zinda ho sakta hai par provider down ho. Deployment systems dono expect karte hain; confuse kiya toh restart loops ya black-hole traffic dono mumkin hain.

Thin frontend — sirf render karo

import streamlit as st, requests

st.title("Ask the docs")
if msg := st.chat_input("Sawaal poochho"):
    with st.chat_message("user"):
        st.write(msg)
    with st.chat_message("assistant"):
        box = st.empty()
        text = ""
        with requests.post(BACKEND + "/chat/stream",
                           json={"message": msg, "session_id": SID},
                           stream=True) as r:
            for line in r.iter_lines():
                if line.startswith(b"data: ") and b"[DONE" not in line:
                    text += json.loads(line[6:])["tok"]
                    box.markdown(text)          # token-by-token render
        if "error" in text:
            st.error("Jawab nahi aaya — dobara koshish karo.")
Kyun thin? Frontend mein logic daal diya toh har prompt fix dobara deploy karega — do artefacts, do pipelines. Thin frontend = backend hi business ka ghar hai, UI kabhi bhi badal jaaye.

Docker images aur Compose stack

# Dockerfile (backend — frontend ka bhi same pattern)
# FROM python:slim
# WORKDIR /app
# COPY requirements.txt . && RUN pip install -r requirements.txt
# COPY . .
# CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0"]

# docker-compose.yaml
services:
  backend:
    build: ./backend
    environment:
      - PROVIDER_API_KEY   # runtime secret, image ke andar nahi
    ports: ["8000:8000"]
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/healthz"]
      interval: 30s
  frontend:
    build: ./frontend
    environment:
      - BACKEND_URL=http://backend:8000
  vectordb:
    image: <tumhara vector store>
    volumes: ["vdb_data:/data"]
volumes:
  vdb_data:
Clean machine test: Naye machine (ya CI runner) pe sirf compose command se stack up karke streaming test karo. Wahan chala = "mere laptop pe chala" wala excuse khatam. Secrets ke bina image build honi chahiye — sirf run ke liye chahiye.

Exercise

Question: Token-by-token jawab bhejne ke liye HTTP streaming ka aam protocol kya hai? (SSE / gRPC)

Question: Dependencies ki reachable check karne wala endpoint kya kehlata hai — liveness ya readiness?

Question: Ek command mein poora stack (backend + frontend + DB) chalane wala Docker tool kya kehlata hai?

Question: API keys ko image ke andar bake karna chahiye ya runtime environment se deni chahiye?

Common mistakes

Desi example: Tiffin service ka standard setup

Tiffin wala roz alag jagah banaaye toh taste badalta rahe — isliye same kitchen kit (container), fixed menu card (config) aur delivery slip number (request id). Kisi bhi nayi jagah pe same setup = same tiffin:

text
kitchen kit   -> container image (ek jaisi har jagah)
menu card     -> config.yaml
slip no.      -> request id
thali packing -> streaming (ek-ek item dikhta jaaye)
store room    -> volume (data restart pe safe)
Interview angle — yahan se sawaal aate hain
  • Q: SSE aur WebSocket ka farq? — SSE server se client ka one-way stream (LLM tokens ke liye kaafi), WebSocket two-way; SSE normal HTTP se chalta hai.
  • Q: Liveness aur readiness mein farq? — Liveness = process zinda (restart trigger); readiness = dependencies ready (traffic gate).
  • Q: Client disconnect pe kya karna chahiye? — Model call abort, tokens ka kharcha rokna, disconnect log karna.
  • Q: Secrets container mein kaise dete hain? — Runtime environment ya secret manager se; image ke andar bake kabhi nahi — supply-chain risk.
Lesson complete?

Stack ek command mein up hota hai, streaming har layer se guzarti hai. Agla lesson — CI/CD with GitHub Actions — mein ye stack ko commit se image tak automatic le jaayenge.

Popular courses: Data Science Course in Lucknow · AI Course in Lucknow · Python Course in Lucknow · Power BI Course · Data Analytics Course