৩. বিল্ড — ল্যাপটপের স্ক্রিপ্ট থেকে পরিষেবায়¶
সময়: ৪–৮ সপ্তাহ, ১টা ওয়ার্কফ্লো, ২–৩ জন ইঞ্জিনিয়ার + ১ জন অপস/ডেভঅপ্স। বের-হওয়ার মানদণ্ড: প্রোডাকশনে ডিপ্লয় হয়েছে, রানবুক আছে, রোলব্যাক পরীক্ষিত, অবজার্ভেবিলিটি চলছে।
পাইলট-এ আপনার কাছে একটা শ্যাডো-মোড স্ক্রিপ্ট আছে যেটা ১ সপ্তাহ ধরে বার পূরণ করে এবং একটা "হ্যাঁ" সিদ্ধান্ত আছে। বিল্ড সেই ল্যাপটপ স্ক্রিপ্টটাকে পরিষেবায় রূপান্তর করে — এমন কিছু যেটা ৯০ দিন ধরে চলে, ৫+ ব্যবহারকারী ব্যবহার করে, এবং একজন ইঞ্জিনিয়ার ছুটিতে থাকলেও ভাঙে না।
বিল্ড কাজটা বেশিরভাগ সময় কোড লেখা না — চারটা প্যারালাল ওয়ার্কস্ট্রিমে সমন্বয় করা যা ৪–৮ সপ্তাহে একসাথে শেষ হতে হবে।
flowchart TB
subgraph Code["কোড"]
C1[প্যাকেজিং: Pydantic + Dockerfile + pyproject]
C2[টেস্ট: ৩-স্তর — ইউনিট, চুক্তি, রিগ্রেশন]
C3[CI: গিটহাব অ্যাকশন, লিন্ট + টেস্ট + ইভ্যাল]
end
subgraph Runtime["রানটাইম"]
R1[কন্টেইনারাইজ]
R2[LM Studio / vLLM হোস্ট]
R3[হেলথ চেক + রিস্টার্ট পলিসি]
end
subgraph Observability["অবজার্ভেবিলিটি"]
O1[লগ: প্রম্পট, আউটপুট, ল্যাটেন্সি]
O2[মেট্রিক: ল্যাটেন্সি, অ্যাগ্রিমেন্ট, এরর]
O3[CI-তে ইভ্যাল-সেট: প্রতিটা PR-এ স্যাম্পল ৫০]
end
subgraph Operations["অপারেশনস"]
P1[রানবুক: ঠান্ডা-অবস্থায় পরীক্ষিত]
P2[রোলব্যাক: একবার ফায়ার-ড্রিল]
P3[অন-কল: ২+ নাম, ১ প্রাইমারি]
end
Code --> Deploy[প্রোডাকশন ডিপ্লয়]
Runtime --> Deploy
Observability --> Deploy
Operations --> Deploy
Deploy --> Verify[ডিফিনিশন অফ ডান চেকলিস্ট]
এই চারটা স্ট্রিম কেন আলাদা করে লিখছি, কারণ এগুলো আলাদা মানুষের কাজ, আলাদা সময়ে এগোয়, আর একটা পিছিয়ে গেলে পুরো বিল্ড পিছিয়ে যায়। কোড স্ট্রিমে ইঞ্জিনিয়ার একা এগোতে পারে, রানটাইমে অপস/ডেভঅপ্স লাগে, অবজার্ভেবিলিটি মানে ইনফ্রা লাগে, আর অপারেশনস মানে টিমের সম্মতি। "পরে করলেও হবে" বলতে গেলে বিল্ড থেকে বের হওয়া যায় না — প্রোডাকশনে কিছু আছে মানে সেটার ওপর মানুষ নির্ভর করছে।
বিল্ডে যা না¶
এটা নতুন ফিচার না। এটা মডেল রিপ্লেসমেন্ট না। বিল্ডে আপনি ফিচার বাড়াচ্ছেন না, মডেল টিউন করছেন না, বা প্ল্যাটফর্ম বানাচ্ছেন না। সেগুলো স্কেল-এ। বিল্ড হলো: ল্যাপটপে যেটা কাজ করে সেটাকে এমন কিছুতে রূপান্তর করা যেটা নির্ভরযোগ্যভাবে চলে।
একটা সহজ উদাহরণ দিই। পাইলট-এ আপনি হয়তো ISP টিকিট ট্রায়াজের একটা প্রম্পট লিখেছ, LM Studio-তে Qwen ১.৫B মডেল চালিয়েছ, আর ৪০০টা টিকিটের ওপর শ্যাডো মোডে টেস্ট করেছেন। আপনার ল্যাপটপে সেটা চলছে, ফলাফল সঠিক, আর আপনি খুশি। কিন্তু সেই মুহূর্তে আপনি ছাড়া আর কেউ সেটা চালাতে পারে না — আপনি ছাড়া অন্য কেউ জানে না কোন পোর্টে মডেল চলছে, কোন ভার্সনের LM Studio ব্যবহার হচ্ছে, কোন প্রম্পট ফাইলটা আসল। আপনি ছুটিতে গেলে সিস্টেম বন্ধ। ল্যাপটপ হারিয়ে গেলে পুরো প্রজেক্ট শেষ। বিল্ডের কাজ হলো এই "আপনি ছাড়া কিছু না" অবস্থাটাকে ভেঙে দেওয়া — যাতে সিস্টেমটা আপনার চেয়ে বেশিদিন বাঁচে।
ওয়ার্কস্ট্রিম ১ — কোড¶
লক্ষ্য: পাইলটের স্ক্রিপ্টকে এমন কোডবেসে রূপান্তর করা যেটা টিমের বাকি অংশ বুঝতে পারে, পরীক্ষা করতে পারে, আর প্রয়োজনে পরিবর্তন করতে পারে। আপনি একা সেটা লিখেছ, কিন্তু কাল আপনার সহকর্মী সেটা চালাবে — সেই সহকর্মীর চোখ দিয়ে লিখতে হবে।
প্যাকেজিং। প্রজেক্টে Pydantic মডেল থাকবে (চুক্তি), একটা Dockerfile থাকবে (রানটাইমের জন্য), একটা pyproject.toml বা requirements.txt থাকবে (নির্ভরতা পিন করা), আর একটা "এটা কী" README থাকবে। পাইলটে আপনার প্রম্পট আর LM Studio URL-ই যথেষ্ট ছিল। বিল্ডে সেটা ভাঙে — কারণ কালকে আপনার সহকর্মী যখন কোড ওপেন করবেন, তখন সে জানবে না আপনি কোন ভার্সনের Pydantic ব্যবহার করেছেন, কোন prompt ফাইল আসল, কোন output schema enforce হচ্ছে। প্যাকেজিং মানে এই "জানা" জিনিসগুলোকে ফাইলে লিখে রাখা — যাতে ডকুমেন্টেশন না পড়েও বোঝা যায়।
৩-স্তরের টেস্ট।
প্রথম স্তর হলো ইউনিট — যেকোনো pure ফাংশন (যেমন কনফিডেন্স থ্রেশহোল্ড, প্রায়োরিটি ক্যাপ)। দ্রুত, কোনো LLM ছাড়া। মিলিসেকেন্ডে রান হয়, মডেলের দরকার নেই, আর ভুল হলে সাথে সাথে ধরা পড়ে। দ্বিতীয় স্তর হলো চুক্তি — প্রম্পট-আউটপুট পার্সিং Pydantic-এর বিরুদ্ধে। "আউটপুট TriageResult-এ ভ্যালিডেট হয়", "প্ল্যাটিনাম + আউটেজ P1 বা P2 দেয়" — এই ধরনের ব্যবসায়িক নিয়ম চুক্তি টেস্টে থাকে। তৃতীয় স্তর হলো রিগ্রেশন — পাইলটের ৫০-উদাহরণের শ্যাডো সেট, সংরক্ষিত, প্রতিটা রিলিজের আগে রান করে, ব্যর্থতার ধরন গণনা করে। এই ৫০টা উদাহরণই হলো আপনার "আগে যা কাজ করেছেন, এখনো কাজ করছে" প্রমাণ।
CI। GitHub Actions (বা যেটাই আছে) এখন রান করে: লিন্ট, ইউনিট টেস্ট, চুক্তি টেস্ট, রিগ্রেশন ইভ্যাল। মার্জ করতে গেলে সবুজ। কোনো "আমি ম্যানুয়ালি রান করেছেনিলাম, কাজ করে" না। "CI সবুজ" ছাড়া কোনো PR মার্জ হয় না — এটাই নিয়ম। একটা ভাঙা প্রম্পট, একটা হারানো Pydantic ফিল্ড, একটা বদলে যাওয়া মডেল আচরণ — সব ধরা পড়ে কোড মার্জ হওয়ার আগেই।
একটা ছোট উদাহরণ দিই। পাইলটে আপনার একটা ফাংশন ছিল normalize_priority(raw: str) -> int যেটা মডেলের "P3" আউটপুটকে ইন্টিজারে কনভার্ট করত। পাইলটে আপনি ধরে নিয়েছ মডেল সবসময় "P1", "P2", "P3", "P4" দেয়। বাস্তবে একদিন মডেল "P-3" দিল, ড্যাশ সহ। ফাংশন ক্র্যাশ করল। পাইলটে আপনি হয়তো হাতে ঠিক করেছেন। বিল্ডে এই কেসটা ইউনিট টেস্টে ঢোকানো হলো, CI-তে ধরা পড়ল, আর কালকে কেউ "P-3" দিলে সিস্টেম নিজেই সামলাবে।
ওয়ার্কস্ট্রিম ২ — রানটাইম¶
লক্ষ্য: LM Studio যেটা পাইলটে ল্যাপটপে ছিল সেটাকে এমন কিছুতে রূপান্তর করা যেটা ৯০ দিন চলে, রিস্টার্ট সারভাইভ করে, আর ২০ সমকালীন ব্যবহারকারীকে ধাক্কা দেয়।
তিনটা বাস্তবসম্মত রানটাইম বিকল্প, সবচেয়ে ছোট থেকে সবচেয়ে ভারী:
অপশন A — LM Studio ডেডিকেটেড হোস্ট (বেশিরভাগ দলের জন্য সুপারিশকৃত)। একটা ডেডিকেটেড মেশিন (iGPU ওয়ার্কস্টেশন বা ছোট সার্ভার)। সিস্টেমড সার্ভিস হিসেবে LM Studio চলে, হেলথ চেক সহ। সুবিধা: পাইলটের সঠিক স্ট্যাক, শূন্য নতুন অপস লোড, ইঞ্জিনিয়ার যা জানে তাই। অসুবিধা: ম্যানুয়াল স্কেলিং, একক পয়েন্ট অফ ফেইলিউর (একটা হোস্ট = একটা ব্যর্থতা)। একটা ওয়ার্কফ্লো, ≤ ২০ সমকালীন ব্যবহারকারীর জন্য সেরা।
অপশন B — vLLM কন্টেইনার। মডেলকে একটা OpenAI-সামঞ্জস্যপূর্ণ HTTP API-তে পরিবেশন করে, Docker-এ প্যাকেজড। সুবিধা: ভালো থ্রুপুট, GPU-বান্ধব, স্ট্যান্ডার্ড অপস টুলিং (Kubernetes, Helm) কাজ করে। অসুবিধা: নতুন ইনফ্রা পাথ, vLLM-নির্দিষ্ট কনফিগারেশন, "কেন এটা সব LM Studio না" প্রশ্ন। ≥ ৫০ সমকালীন ব্যবহারকারী বা ≥ ২ ওয়ার্কফ্লো চললে বিবেচনা করেন।
অপশন C — ম্যানেজড গেটওয়ে (OpenRouter, LiteLLM, নিজস্ব)। মডেল রাউটিং, রেট লিমিট, ক্যাশিং, মাল্টি-মডেল। সুবিধা: একাধিক ওয়ার্কফ্লো / মডেল পরিবেশন করা সহজ। অসুবিধা: আরেকটা চলমান সিস্টেম, আরেকটা ডাউনস্ট্রিম ভেন্ডর লক-ইন। স্কেল-এ ≥ ৩ ওয়ার্কফ্লো চললে বিবেচনা করেন, বিল্ডে না।
হেলথ চেক। সার্ভিসটা /health এন্ডপয়েন্ট এক্সপোজ করে। LB / k8s / systemd চেক করে। মডেল লোড না হলে বা ৩০ সেকেন্ডের বেশি সাড়া না দিলে — রিস্টার্ট। পাইলটে স্বাস্থ্য পরীক্ষা করতাম ল্যাপটপ খুলে দেখে; বিল্ডে সিস্টেম দেখে। এটাই পার্থক্য — মানুষের চোখ থেকে সিস্টেমের চোখে।
ওয়ার্কস্ট্রিম ৩ — অবজার্ভেবিলিটি¶
লক্ষ্য: সমস্যা হলে ৫ মিনিটে বুঝতে পারা। তিনটা সিগন্যাল, পর্যাপ্ত — তার বেশি দরকার নেই বিল্ডে:
- ল্যাটেন্সি p50 + p95 (প্রতিটা ওয়ার্কফ্লোর জন্য)। p50 বলে কত দ্রুত সাধারণ কেস, p95 বলে কত ধীর খারাপ কেস। মডেল + প্রম্পট + পার্সিং সহ। সময়ের সাথে p95 বাড়তে থাকলে বুঝবে কিছু আটকাচ্ছে — হয় মডেল স্লো, হয় prompt লম্বা হচ্ছে, হয় ইনপুট বড় হচ্ছে।
- অ্যাগ্রিমেন্ট রেট (স্যাম্পল্ড)। প্রতিটা ১০০০ ইনভোকেশনে ১০টা মানব-পরীক্ষিত ফলাফল — মানে একজন মানুষ বসে ১০টা কেস দেখে বলে মডেলের উত্তর ঠিক ছিল কিনা। বেসলাইনের চেয়ে ১০ পয়েন্ট ড্রপ হলে পেজ। এটা ধরে রাখা সস্তা কিন্তু মূল্যবান — কারণ মডেল ভালো উত্তর দিচ্ছে কিনা সেটা শুধু latency দিয়ে বোঝা যায় না।
- এরর রেট। পার্সিং ফেইল, টাইমআউট, ৫xx। সবুজ থেকে ১% এ উঠলে পেজ।
টুলিং — Grafana + Prometheus যথেষ্ট, Datadog না। যদি বাড়িতে কুকি জার আছে, ওটাই। বিল্ডের মূল পয়েন্ট হলো সিগন্যালগুলো কাগজে সংজ্ঞায়িত, যন্ত্রে না — যাতে অন-কল ইঞ্জিনিয়ার জানে কোনটা দেখবে। "ভালো ড্যাশবোর্ড" একটা বোনাস, "ভালো সিগন্যাল" আসল।
CI-তে ইভ্যাল। প্রতিটা PR রিগ্রেশন সেটের ৫০-উদাহরণের সাবসেটের বিরুদ্ধে চলে। ১০ মিনিটের কাজ, "আমরা কি এই সপ্তাহে লঙ্ঘন করেছেন" প্রশ্নের উত্তর দেয়। PR ওপেন হলে ১০ মিনিট পরে সবুজ/লাল — এটা ছাড়া কোনো PR মার্জ হয় না, বিল্ডের আগে থেকেই।
ওয়ার্কস্ট্রিম ৪ — অপারেশনস¶
লক্ষ্য: ব্যর্থতা ঘটলে নিরাপদে সামলানো। ব্যর্থতা ঘটবেই — প্রশ্ন হলো কখন, কিভাবে, আর কত দ্রুত সামলাবে। তিনটা জিনিস দরকার, প্রতিটাই লেখা আর পরীক্ষা করা।
রানবুক — ঠান্ডা-অবস্থায় পরীক্ষিত। ১ পৃষ্ঠা: "মডেল টাইমআউট হলে কী", "পার্সিং এরর স্পাইক হলে কী", "GPU ফেইল হলে কী", "কম কনফিডেন্স স্পাইক হলে কী"। "ঠান্ডা-অবস্থায় পরীক্ষিত" মানে যে ইঞ্জিনিয়ার ৩ মাস ধরে কোড দেখেনি তিনি মাঝরাতে ১৫ মিনিটে সমস্যা সমাধান করতে পারেন। "রানবুক লেখা" যথেষ্ট না — পড়া, অনুসরণ করা, টাইমার ধরা। লেখা আর পড়া দুটো আলাদা কাজ।
রোলব্যাক — একবার ফায়ার-ড্রিল। রোলব্যাক প্ল্যান ("আগের মডেল ভার্সনে ফিরে যান", "ওয়ার্কফ্লো ডিজেবল করেন", "সব ইনভোকেশন ম্যানুয়ালিতে রাউট করেন") থাকা একটা জিনিস। ফায়ার-ড্রিলে এটা একবার রান করা আরেকটা জিনিস। বিল্ডের ডেলিভারেবল: ফায়ার-ড্রিলের তারিখ, কে রান করেছে, কত সময় লেগেছে — লিখিত, সাক্ষীসহ।
অন-কল — ২+ নাম, ১ প্রাইমারি। যেকোনো ওয়ার্কফ্লো চললে PagerDuty / টেলিগ্রাম / ফোন কল — যাই হোক — দিয়ে ২+ ইঞ্জিনিয়ার রোটেট করে, ১ জন প্রাইমারি, ১ জন সেকেন্ডারি। একজন ইঞ্জিনিয়ার ছুটিতে গেলে সিস্টেম স্টপ না হওয়াই এটার পয়েন্ট। "কেউ ডিউটি করবেন" লেখা যথেষ্ট না, "রাকিব এই সপ্তাহে, তানভীর পরের সপ্তাহে, ব্যাকআপ হাবিব" — এটা যথেষ্ট। রোস্টারে নাম না থাকলে অন-কল মানে সবাই, মানে কেউ না।
যা করবেন না¶
- মডেল ফাইন-টিউন করবেন না। বিল্ডের উইন্ডোতে না। ফাইন-টিউনিং ডেটা সংগ্রহ, ট্রেনিং, ইভ্যাল, রিগ্রেশন — ৪–৮ সপ্তাহের বিল্ডের সাথে কাজ করে না। ফাইন-টিউনিং একটা স্কেল পর্বের কাজ, যদি কখনো হয়, যখন ক্রমাগত ইভ্যাল ফেইল হয়।
- জেনেরিক AI প্ল্যাটফর্ম বানাবেন না। আপনার বিল্ড এই ওয়ার্কফ্লোর জন্য। প্ল্যাটফর্ম কাজ স্কেল-এ, ৩+ ওয়ার্কফ্লো চললে, ২+ টিম চললে। একটা ওয়ার্কফ্লোতে প্ল্যাটফর্ম বানানো = ওভার-ইঞ্জিনিয়ারিং।
- অবজার্ভেবিলিটি আর্গুমেন্ট স্কিপ করবেন না। "আমরা পেজ করলে দেখব" — অন-কল ইঞ্জিনিয়ার ভুলে যায়, সিগন্যাল দেখতে দেরি হয়, ব্যবহারকারী আগে ধরে ফেলে। ৫ মিনিটের সেটআপ, ৯০ দিন সাশ্রয় — সহজ অঙ্ক।
- প্রম্পট চেঞ্জকে রিলিজ ছাড়া করবেন না। প্রম্পট = কোড। একটা PR, একটা CI রান, একটা রিগ্রেশন ইভ্যাল। "আমি দ্রুত একটা ওয়ার্ড বদলে দিলাম" — প্রোডাকশনে অনুমোদিত না, কারণ আজকের ছোট বদল কালকে বড় আচরণ বদলে দিতে পারে।
ডিফিনিশন অফ ডান¶
বিল্ড শেষ, নিচের সব সত্য হলে আপনি স্কেল-এর জন্য প্রস্তুত:
- কোড প্যাকেজড (Pydantic, Dockerfile, pyproject) + CI সবুজ
- ৩-স্তরের টেস্ট: ইউনিট, চুক্তি, রিগ্রেশন — সব CI-তে
- রানটাইম ডেডিকেটেড (LM Studio / vLLM) + হেলথ চেক
- ৩ সিগন্যাল ড্যাশবোর্ডে: ল্যাটেন্সি p50/p95, অ্যাগ্রিমেন্ট, এরর
- রানবুক ঠান্ডা-অবস্থায় পরীক্ষিত (তারিখ, কে, কত সময়)
- রোলব্যাক ফায়ার-ড্রিল (তারিখ, কে, কত সময়)
- অন-কল রোস্টার ২+ নাম, ১ প্রাইমারি
- প্রোডাকশনে ≥ ৪ সপ্তাহ আপটাইম, ০ আনপ্ল্যান্ড আউটেজ
সব সত্য হলে আপনি স্কেল-এ প্রবেশ করেছেন। এক বা একাধিক মিস হলে — বিল্ডে থাকো, ঠিক করেন, তারপর এগোন। তাড়াহুড়ো করে স্কেলে ঢুকলে সেই ঘাটতি ১০ গুণ বড় হয়ে ফিরে আসবে — ১টা ওয়ার্কফ্লোতে চাপা পড়া সমস্যা ৫টা ওয়ার্কফ্লোতে বিস্ফোরিত হয়।
আরও পড়ার জন্য: [ডিসকাভারি]\(discover.md\)-তে ফিরে যান (বিল্ডের আগে কী হয়েছিল), বা স্কেল-এ এগোন (বিল্ডের পরে কী হয়)।