কিভাবে নিজের সার্ভারে LiteLLM গেটওয়ে সেটআপ করবেন
আপনার সব অ্যাপ্লিকেশনের জন্য একটি OpenAI-compatible endpoint তৈরি করুন। LiteLLM ব্যবহার করে ভার্চুয়াল কি, বাজেট কন্ট্রোল এবং মডেল ফলব্যাক সুবিধা কীভাবে পাবেন তা এখানে জানুন।
একটি self-hosted LLM gateway যা করে
LiteLLM হলো একটি ওপেন সোর্স LLM gateway যা আপনি নিজেই হোস্ট করেন: এটি একটি HTTP endpoint যা আপনার সমস্ত অ্যাপ্লিকেশন কল করে এবং এটি প্রতিটি অনুরোধকে সংশ্লিষ্ট প্রোভাইডারের কাছে পাঠিয়ে দেয়। LLM মানে হলো large language model। এই gateway-টি OpenAI chat completions API (application programming interface) সমর্থন করে, তাই যে কোনো client library যা আগে থেকেই OpenAI-এর সাথে কাজ করে, তা দুটি পরিবর্তনের পরেই এর সাথে কাজ করবে: base URL এবং key।
এই একটি বাড়তি স্তর বা indirection-ই হলো মূল বিষয়। আপনার অ্যাপ্লিকেশনগুলোতে আর প্রোভাইডারের credentials রাখার প্রয়োজন হয় না। একটি মডেল পরিবর্তন করতে হলে পাঁচটি সার্ভিসের কোড পরিবর্তন না করে, সার্ভারের কনফিগারেশন ফাইলে মাত্র এক লাইন পরিবর্তন করলেই হয়। এবং যেহেতু প্রতিটি কল একটি প্রসেসের মধ্য দিয়ে যায়, তাই আপনার কাছে বাজেট নির্ধারণ এবং খরচের হিসাব রাখার একটি কেন্দ্রীয় জায়গা থাকে।
এটি চালু করার পর আপনি যা যা পাবেন:
- একটি endpoint। অ্যাপ্লিকেশনগুলো
https://gateway.example.com/v1-কে লক্ষ্য করে এবং আপনার তৈরি করা কোনো মডেলের নাম, যেমনbulkবাstrong-এর জন্য অনুরোধ জানায়। - Virtual keys। প্রতিটি অ্যাপ্লিকেশন তার নিজস্ব key পায়, যার সাথে নিজস্ব model allowlist এবং spend ceiling যুক্ত থাকে। আপনি অন্যদের কোনো ক্ষতি না করেই একটি key বাতিল করতে পারেন।
- Fallbacks। কোনো কল ব্যর্থ হলে বা prompt অনেক বড় হলে তা স্বয়ংক্রিয়ভাবে অন্য একটি মডেলের মাধ্যমে পুনরায় চেষ্টা করা হয়।
- লগ করা রেকর্ড। প্রতিটি অনুরোধের সাথে খরচের হিসাবসহ একটি রেকর্ড সংরক্ষিত হয়, ফলে "কোন অ্যাপ কত খরচ করেছে" তার উত্তর সহজেই পাওয়া যায়।
কেন নিজে গেটওয়ে পরিচালনা করবেন
একটি ম্যানেজড রাউটার দেখতে একই রকম হলেও, প্রতিটি অনুরোধের মাঝে অন্য কারো প্রসেস কাজ করে। নিজে এটি পরিচালনা করলে আপনার প্রোভাইডার কি (keys) এবং প্রম্পট টেক্সট আপনার নিয়ন্ত্রণে থাকা বক্সে সংরক্ষিত থাকে। এর একটি বাস্তব খরচ আছে: এখন আপনি এমন একটি কম্পোনেন্ট পরিচালনা করছেন যার ওপর প্রতিটি অ্যাপ্লিকেশন নির্ভরশীল। এই গাইডের শেষ অংশে সেই খরচ সম্পর্কে আলোচনা করা হয়েছে, কারণ বেশিরভাগ লেখায় এই গুরুত্বপূর্ণ অংশটি বাদ পড়ে যায়।
আপনার যা প্রয়োজন
- Ubuntu 24.04 চালিত একটি VPS (virtual private server), যেখানে Docker এবং Compose plugin ইনস্টল করা আছে।
- একটি domain name যা সার্ভারের IP-কে নির্দেশ করে (যদি বাইরের কোনো মেশিন TLS (transport layer security)-এর মাধ্যমে gateway-তে যুক্ত হতে চায়)।
- অন্তত একটি provider API key।
Gateway-টি কোনো inference চালায় না। এটি অনুরোধগুলো forward করে এবং উত্তরগুলো stream করে ফেরত পাঠায়, তাই এর CPU লোড মডেলের আকারের পরিবর্তে অনুরোধের পরিমাণের ওপর নির্ভর করে। একটি 1 vCPU-এর সার্ভার কোনো সমস্যা ছাড়াই বেশ কিছু অভ্যন্তরীণ অ্যাপ্লিকেশন চালাতে পারে। যা বৃদ্ধি পায় তা হলো database, কারণ gateway প্রতিটি অনুরোধের জন্য একটি করে spend row লিখে রাখে।
প্রথমে config.yaml লিখুন
config ফাইলটি নির্ধারণ করে যে ক্লায়েন্ট কোন মডেলগুলোর জন্য অনুরোধ করতে পারবে। এখানে চারটি শীর্ষ-স্তরের সেকশন গুরুত্বপূর্ণ: model_list, litellm_settings, router_settings এবং general_settings।
model_list:
- model_name: bulk
litellm_params:
model: anthropic/claude-haiku-4-5
api_key: os.environ/ANTHROPIC_API_KEY
- model_name: strong
litellm_params:
model: anthropic/claude-sonnet-5
api_key: os.environ/ANTHROPIC_API_KEY
- model_name: strong
litellm_params:
model: openai/gpt-5.5
api_key: os.environ/OPENAI_API_KEY
litellm_settings:
num_retries: 2
request_timeout: 120
allowed_fails: 3
cooldown_time: 30
json_logs: true
set_verbose: false
router_settings:
fallbacks: [{"bulk": ["strong"]}]
context_window_fallbacks: [{"bulk": ["strong"]}]
general_settings:
background_health_checks: true
health_check_interval: 300model_name হলো সেই নাম যা আপনার ক্লায়েন্টরা পাঠায়। litellm_params.model হলো প্রকৃত মডেল, যা provider/model হিসেবে লেখা হয়। আপনার মডেলগুলোর নাম ভেন্ডরের নামের পরিবর্তে কাজের ধরন অনুযায়ী দিন। যে অ্যাপ্লিকেশনটি bulk-এর জন্য অনুরোধ করে, সেটি কাজ চালিয়ে যেতে পারে যখন আপনি পরের মাসে সিদ্ধান্ত নেন যে bulk একটি ভিন্ন মডেল হওয়া উচিত।
api_key: os.environ/ANTHROPIC_API_KEY LiteLLM-কে রান টাইমে সেই ভেরিয়েবলটি পড়তে বলে। ফাইলের মধ্যে প্রকৃত কি (key) কখনোই দেখা যায় না, যা গুরুত্বপূর্ণ কারণ config.yaml ফাইলটিই আপনি কমিট করেন।
দুটি এন্ট্রি ইচ্ছাকৃতভাবে একই নাম strong শেয়ার করে। যখন একাধিক ডিপ্লয়মেন্ট একই model_name বহন করে, তখন রাউটার সেগুলোকে অদলবদলযোগ্য হিসেবে বিবেচনা করে এবং প্রথমটি ব্যর্থ হলে অন্যটি চেষ্টা করে। এভাবেই strong কোনো প্রোভাইডারের সাময়িক সমস্যার মধ্যেও সচল থাকে।
num_retries: 2 কোনো retryable ত্রুটির ক্ষেত্রে একই ডিপ্লয়মেন্ট পুনরায় চেষ্টা করে। একটি ফলব্যাক শুধুমাত্র সেই retry-গুলো শেষ হওয়ার পরেই কার্যকর হয়। allowed_fails: 3-এর সাথে cooldown_time: 30 ব্যবহার করলে, কোনো ডিপ্লয়মেন্ট 3 বার ব্যর্থ হওয়ার পর সেটিকে 30 সেকেন্ডের জন্য রোটেশন থেকে সরিয়ে রাখা হয়, যাতে কোনো প্রোভাইডার 500 ত্রুটি দিলে প্রতি অনুরোধে সেটিকে আর চেষ্টা না করা হয়।
fallbacks এবং context_window_fallbacks-এর ট্রিগার ভিন্ন, এবং দ্বিতীয়টি অত্যন্ত কার্যকর যা অনেকেই এড়িয়ে যান।
fallbacksকার্যকর হয় যখন প্রাথমিক কলটি ব্যর্থ হয়।context_window_fallbacksকার্যকর হয় যখন প্রোভাইডার অনুরোধটিকে প্রত্যাখ্যান করে কারণ সেটি মডেলের কনটেক্সট উইন্ডোর চেয়ে বড়; ফলে একটি বড় প্রম্পট ত্রুটি দেখানোর পরিবর্তে এমন একটি মডেলে পাঠানো হয় যেখানে পর্যাপ্ত জায়গা আছে।
এছাড়াও content_policy_fallbacks রয়েছে, যা কন্টেন্ট পলিসির কারণে প্রোভাইডার অনুরোধ প্রত্যাখ্যান করলে কাজ করে। এটি তখনই সেট করুন যদি আপনার কাছে সেই কলগুলো পাঠানোর মতো উপযুক্ত কোনো জায়গা থাকে।
Docker Compose ব্যবহার করে VPS-এ LiteLLM ডেপ্লয় করা
তিনটি ফাইল ধারণকারী একটি ডিরেক্টরি তৈরি করুন: config.yaml, docker-compose.yml এবং .env। আপস্ট্রিম কুইকস্টার্ট latest ট্যাগটি পুল করে। এর পরিবর্তে একটি নির্দিষ্ট রিলিজ ট্যাগ ব্যবহার করুন, যাতে docker compose up -d পরবর্তী মাসে আপনাকে সেই একই গেটওয়ে দেয় যা আজ দিচ্ছে, এবং রোলব্যাক করা একটি লাইনের কাজ হয়ে দাঁড়ায়।
services:
litellm:
image: ghcr.io/berriai/litellm:v1.95.0
restart: unless-stopped
command: ["--config", "/app/config.yaml", "--num_workers", "1"]
ports:
- "127.0.0.1:4000:4000"
volumes:
- ./config.yaml:/app/config.yaml:ro
env_file: .env
depends_on:
db:
condition: service_healthy
db:
image: postgres:16
restart: unless-stopped
environment:
POSTGRES_USER: litellm
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}
POSTGRES_DB: litellm
healthcheck:
test: ["CMD-SHELL", "pg_isready -U litellm"]
interval: 5s
timeout: 5s
retries: 10
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:Compose এখানে .env ফাইলটি দুইবার পড়ে। একবার compose ফাইলের ভেতরে থাকা ${POSTGRES_PASSWORD} প্রতিস্থাপন করতে, এবং অন্যবার env_file এর মাধ্যমে প্রতিটি ভেরিয়েবল কন্টেইনারের ভেতরে পাঠাতে।
v1.95.0 ছিল 2026 সালের আগস্ট মাসের বর্তমান রিলিজ। প্রজেক্টের রিলিজ পেজ চেক করুন এবং ডেপ্লয় করার সময় যেটি বর্তমান রিলিজ সেটিই ব্যবহার করুন। প্রতিটি রিলিজ একটি সিগনেচার প্রকাশ করে, তাই ইমেজটিকে বিশ্বাস করার আগে আপনি তা যাচাই করতে পারেন:
cosign verify --key https://raw.githubusercontent.com/BerriAI/litellm/v1.95.0/cosign.pub ghcr.io/berriai/litellm:v1.95.0পোর্ট লাইনটি হলো 127.0.0.1:4000:4000, যা শুধুমাত্র লুপব্যাক ইন্টারফেসে পোর্টটি পাবলিশ করে। এর পরিবর্তে 4000:4000 লিখলে আপনার গেটওয়ে পুরো ইন্টারনেট থেকে অ্যাক্সেসযোগ্য হয়ে যাবে, কারণ Docker তার নিজস্ব নিয়ম iptables FORWARD চেইনে যোগ করে এবং সেগুলো ufw-এর আগেই মূল্যায়ন করা হয়, তাই ufw deny 4000 এটিকে আটকাতে পারে না। এটি একটি সেলফ-হোস্টেড গেটওয়ে উন্মুক্ত হয়ে যাওয়ার সবচেয়ে সাধারণ উপায়: দেখুন কিভাবে Docker ufw-কে পাশ কাটিয়ে কন্টেইনার পোর্ট পাবলিশ করে। বাইরের ট্রাফিক এর পরিবর্তে রিভার্স প্রক্সির মাধ্যমে আসে।
প্রোভাইডার কি (keys) ইমেজ থেকে দূরে রাখুন
.env ফাইলটিতে সমস্ত গোপন তথ্য (secrets) থাকে। রানটাইমে এটি এনভায়রনমেন্ট ভেরিয়েবল হিসেবে পাস করা হয়, তাই এটি কখনোই ইমেজের ভেতরে বেক (baked) করা হয় না এবং এটি কখনোই কমিট করা হয় না।
LITELLM_MASTER_KEY=sk-REPLACE_ME
LITELLM_SALT_KEY=sk-REPLACE_ME_TOO
POSTGRES_PASSWORD=REPLACE_ME_AS_WELL
DATABASE_URL=postgresql://litellm:REPLACE_ME_AS_WELL@db:5432/litellm
STORE_MODEL_IN_DB=True
LITELLM_MODE=PRODUCTION
LITELLM_LOG=ERROR
ANTHROPIC_API_KEY=sk-ant-...
OPENAI_API_KEY=sk-proj-...প্রকৃত র্যান্ডমনেস ব্যবহার করে দুটি LiteLLM কি তৈরি করুন, তারপর ফাইলটিকে লক করে দিন:
printf 'sk-%s\n' "$(openssl rand -hex 32)"
chmod 600 .envLITELLM_MASTER_KEY হলো অ্যাডমিন ক্রেডেনশিয়াল। এটি ম্যানেজমেন্ট API-কে অথেন্টিকেট করে এবং /ui-এ অবস্থিত অ্যাডমিন UI-এর পাসওয়ার্ড হিসেবে কাজ করে। কোনো অ্যাপ্লিকেশনের কাছেই এটি থাকা উচিত নয়।
LITELLM_SALT_KEY ডাটাবেসে সংরক্ষিত প্রোভাইডার ক্রেডেনশিয়ালগুলোকে এনক্রিপ্ট করে। এটি একবার সেট করুন এবং আর পরিবর্তন করবেন না। পরবর্তীতে এটি পরিবর্তন করলে আগে থেকে সংরক্ষিত ক্রেডেনশিয়ালগুলো ডিক্রিপ্ট করা সম্ভব হবে না; ফলে গেটওয়ে স্বাভাবিকভাবে চালু হলেও সেই প্রোভাইডারগুলোতে করা প্রতিটি কল অথেন্টিকেশন ব্যর্থতার কারণে আটকে যাবে।
STORE_MODEL_IN_DB=True আপনাকে config.yaml ফাইলটি স্পর্শ না করেই অ্যাডমিন UI থেকে মডেল যোগ এবং এডিট করার সুবিধা দেয়। এটি সুবিধাজনক, তবে এটি আপনার তথ্যের উৎসকে (source of truth) দুই ভাগে বিভক্ত করে ফেলে। কোনটি অথরিটেটিভ বা মূল উৎস হবে তা নির্ধারণ করুন এবং সেই সিদ্ধান্তটি কনফিগারেশনের পাশে লিখে রাখুন।
কনফিগারেশন ফাইল থেকে কি (keys) দূরে রাখার পেছনে যে যুক্তি কাজ করে, এজেন্টকে দেওয়া টুলস থেকেও সেগুলোকে দূরে রাখার পেছনে একই যুক্তি কাজ করে। AI এজেন্ট থেকে প্রোভাইডার সিক্রেট দূরে রাখা অংশে এই প্যাটার্নটি আলোচনা করা হয়েছে এবং Docker Compose-এ env ফাইল এবং সিক্রেট অংশে এর কৌশলগুলো বর্ণনা করা হয়েছে।
সার্ভিসটি চালু করুন এবং প্রথম বুট পর্যবেক্ষণ করুন:
docker compose up -d
docker compose logs -f litellmএটি সঠিকভাবে কাজ করছে কি না তা যাচাই করুন
এখানে দুটি unauthenticated প্রোব এবং একটি authenticated প্রোব রয়েছে, এবং বিভিন্ন কারণে সেগুলো ব্যর্থ হয়।
curl -s http://127.0.0.1:4000/health/liveliness
curl -s http://127.0.0.1:4000/health/readiness/health/liveliness-এর জন্য কোনো auth-এর প্রয়োজন হয় না এবং প্রসেসটি চলমান থাকলে এটি "I'm alive!" প্রদান করে। /health/readiness-এর জন্যও কোনো auth লাগে না। এটি একটি JSON অবজেক্ট রিটার্ন করে যাতে "status": "healthy" এবং একটি db ফিল্ড থাকে, অথবা ডাটাবেস unreachable হলে এটি 503 এরর দেয়। আপনার মনিটরিং readiness-এর দিকে নির্দেশ করুন, কারণ liveliness এমন একটি গেটওয়েতেও green থাকে যা কোনো একটি ভার্চুয়াল কি (virtual key) খুঁজে পেতে ব্যর্থ হচ্ছে।
authenticated চেকটি প্রোভাইডারদের সাথে যোগাযোগ করে:
curl -s http://127.0.0.1:4000/health \
-H "Authorization: Bearer $LITELLM_MASTER_KEY"এটি healthy_endpoints এবং unhealthy_endpoints অ্যারে দিয়ে উত্তর দেয়। unhealthy_endpoints-এ থাকা কোনো মডেলে authentication এরর আসার অর্থ হলো .env-এ থাকা প্রোভাইডার কি (provider key) ভুল বা অনুপস্থিত, যা সেই ব্যর্থতা যা আপনি এখন খুঁজে বের করতে চাচ্ছেন। যেহেতু background_health_checks: true সেট করা আছে, তাই প্রক্সি নিজেই প্রতি health_check_interval সেকেন্ড পরপর এই প্রোবগুলো চালায় এবং /health সর্বশেষ ফলাফলটি রিটার্ন করে, ফলে এটি পোল (poll) করলে প্রতিবার আপনার প্রোভাইডারদের কাছে কোনো টেস্ট রিকোয়েস্ট যায় না।
ভার্চুয়াল কি এবং প্রতি-কি বাজেট
প্রতিটি অ্যাপ্লিকেশনের জন্য আলাদা কি (key) থাকে, যা মাস্টার কি-এর বিপরীতে তৈরি করা হয়।
curl -s http://127.0.0.1:4000/key/generate \
-H "Authorization: Bearer $LITELLM_MASTER_KEY" \
-H 'Content-Type: application/json' \
-d '{
"key_alias": "nightly-summariser",
"models": ["bulk"],
"max_budget": 5,
"budget_duration": "30d",
"rpm_limit": 60,
"tpm_limit": 200000
}'প্রতিক্রিয়ার মধ্যে একটি key ফিল্ড থাকে যা sk- দিয়ে শুরু হয়। এই স্ট্রিংটিই অ্যাপ্লিকেশনটি পায় এবং এটিই একমাত্র তথ্য যা অ্যাপ্লিকেশনটি গ্রহণ করে।
modelsহলো একটি অনুমোদিত তালিকার (allowlist) অংশ যা নির্ধারণ করে এই কি কী অনুরোধ করতে পারবে। উপরের কি-টি শুধুমাত্রbulkএর জন্য অনুরোধ করতে পারবে, অন্য কিছুর জন্য নয়।max_budget: 5এবংbudget_duration: "30d"এর মাধ্যমে প্রতি 30 দিনে পাঁচ মার্কিন ডলারের বাজেট নির্ধারণ করা হয়, যার পর কি-টি কাজ করা বন্ধ করে দেয়।rpm_limitএবংtpm_limitশুধুমাত্র এই কি-এর জন্য প্রতি মিনিটে অনুরোধ এবং টোকেনের সংখ্যা সীমাবদ্ধ করে।key_aliasহলো সেই নাম যা আপনি ছয় সপ্তাহ পরে খরচ সংক্রান্ত লগে দেখতে পাবেন। এটি সর্বদা সেট করুন।
বাজেট শেষ হয়ে গেলে, কলটি HTTP 401 ত্রুটির সাথে ব্যর্থ হয় এবং এর বডি নিচের মতো দেখায়:
ExceededBudget: Current spend for token: 7.2e-05; Max Budget for Token: 2e-07এই স্ট্যাটাস কোডটি বিভ্রান্তিকর হতে পারে। একটি ক্লায়েন্ট লাইব্রেরি 401-কে প্রমাণীকরণ সমস্যা হিসেবে রিপোর্ট করে, তাই ডেভেলপার যখন স্ট্যাক ট্রেস পড়েন, তখন তিনি প্রথমেই কি-টি বৈধ কি না তা পরীক্ষা করতে শুরু করেন। স্ট্যাটাস কোডের পাশাপাশি রেসপন্স বডি লগ করুন, অন্যথায় বাজেট শেষ হয়ে যাওয়াকে প্রতিবারই নষ্ট ক্রেডেনশিয়াল বলে মনে হবে।
একই ম্যানেজমেন্ট API-এর মাধ্যমে কি-গুলো পরীক্ষা এবং পরিবর্তন করুন:
curl -s "http://127.0.0.1:4000/key/info?key=sk-..." \
-H "Authorization: Bearer $LITELLM_MASTER_KEY"
curl -s -X POST http://127.0.0.1:4000/key/update \
-H "Authorization: Bearer $LITELLM_MASTER_KEY" \
-H 'Content-Type: application/json' \
-d '{"key": "sk-...", "max_budget": 25}'গেটওয়েতে কার্যকর করা বাজেট তখনই কাজ করে যখন কোনো সমস্যা এজেন্ট নিজেই তৈরি করে, আর এই কারণেই এটি VPS-এ AI এজেন্টের খরচ নিয়ন্ত্রণের মূল ভিত্তি।
সাশ্রয়ী মডেলের মাধ্যমে বাল্ক কাজ সম্পন্ন করা
একটি ক্লায়েন্টকে গেটওয়ের দিকে নির্দেশ করুন। Base URL, key এবং model name ব্যবহার করুন:
curl -s http://127.0.0.1:4000/v1/chat/completions \
-H "Authorization: Bearer sk-<the virtual key>" \
-H 'Content-Type: application/json' \
-d '{
"model": "bulk",
"messages": [{"role": "user", "content": "Say hello in five words."}]
}'যেকোনো OpenAI client library একইভাবে কাজ করে: base_url-কে https://gateway.example.com/v1 এবং api_key-কে virtual key হিসেবে সেট করুন।
এখন caller-এর অজান্তেই config.yaml-এ থাকা routing policy কার্যকর হবে। bulk-এর জন্য করা একটি অনুরোধ সাশ্রয়ী মডেলে চলে যাবে। যদি সেই কলটি তার retries-এর পরেও ব্যর্থ হয়, তবে অনুরোধটি strong-এর বিপরীতে পুনরায় চেষ্টা করা হবে। যদি prompt-টি bulk-এর জন্য খুব দীর্ঘ হয়, তবে context_window_fallbacks কোনো error না পাঠিয়ে সেটিকে strong-এ পাঠিয়ে দেবে। classification pass বা summarising backlog-এর মতো বাল্ক কাজগুলো ডিফল্টভাবে সাশ্রয়ী মডেলে চলে, এবং শুধুমাত্র জটিল অনুরোধগুলোর ক্ষেত্রেই বেশি খরচ হয়।
টুল ব্যবহারকারী এজেন্টদের ক্ষেত্রে গেটওয়ে এখানেই তার উপযোগিতা প্রমাণ করে। একটি একই VPS-এ থাকা MCP (model context protocol) server এবং এটিকে নিয়ন্ত্রণকারী এজেন্ট—উভয়ই একটি endpoint-এর দিকে নির্দেশ করতে পারে, ফলে কোনো কিছু redeploy না করেই তাদের পেছনের মডেল পরিবর্তন করা সম্ভব।
ফলব্যাক (fallback) ঘটেছে কি না তা কীভাবে বুঝবেন?
এটি এমন এক ধরনের ব্যর্থতা যা আপনার খরচ বাড়িয়ে দেয়, কারণ বাইরে থেকে সবকিছু ঠিকঠাক মনে হয়। একটি সফল ফলব্যাক HTTP 200 স্ট্যাটাস কোড এবং সাধারণ রেসপন্স বডি প্রদান করে। আপনার সাশ্রয়ী মডেলটি হয়তো একদিন ধরে বন্ধ থাকতে পারে, কিন্তু প্রতিটি কল নীরবে ব্যয়বহুল মডেলটি দিয়ে সম্পন্ন হচ্ছে এবং এর প্রথম প্রমাণ আপনি পাবেন ইনভয়েস হাতে পাওয়ার পর।
এর প্রমাণ রেসপন্স হেডারে থাকে। সেগুলো পরীক্ষা করে দেখুন:
curl -s -D - -o /dev/null http://127.0.0.1:4000/v1/chat/completions \
-H "Authorization: Bearer sk-<the virtual key>" \
-H 'Content-Type: application/json' \
-d '{"model":"bulk","messages":[{"role":"user","content":"ping"}]}' \
| grep -i '^x-litellm'x-litellm-model-groupহলো ক্লায়েন্ট যা অনুরোধ করেছে।x-litellm-model-idহলো সেই ডিপ্লয়মেন্ট যা উত্তর দিয়েছে। যখন এই দুটির মধ্যে অমিল থাকে, তখন বুঝতে হবে ফলব্যাক ঘটেছে।x-litellm-attempted-fallbacksএবংx-litellm-attempted-retriesএগুলো গণনা করে। একটি স্বাভাবিক কলে উভয়ই 0 থাকে।x-litellm-response-costহলো সেই নির্দিষ্ট কলের খরচ, যা মার্কিন ডলারে দেওয়া থাকে।x-litellm-call-idহলো সেই আইডেন্টিফায়ার যা ব্যবহার করে আপনি আপনার লগ থেকে একই কল খুঁজে বের করতে পারবেন।
প্রতিটি অনুরোধে x-litellm-attempted-fallbacks রেকর্ড করুন এবং এটি 0-এর বেশি হলে অ্যালার্ট সেট করুন। এই একটি সংখ্যাই পার্থক্য গড়ে দেয় একটি কার্যকর রাউটিং পলিসি এবং এমন একটি পলিসির মধ্যে, যা নীরবে "সবসময় ব্যয়বহুল মডেল ব্যবহার করো" নীতিতে পরিণত হয়েছে।
এর পূর্ণাঙ্গ সংস্করণ হলো ট্রেসিং, এবং এর জন্য আলাদা সেটআপ প্রয়োজন: ট্রেসিং এজেন্ট কলের জন্য self-hosted Langfuse। LiteLLM-এ কলব্যাক সুবিধা রয়েছে, তাই এটি যুক্ত করা মাত্র দুই লাইনের কাজ এবং এর জন্য শুধু ক্রেডেনশিয়াল প্রয়োজন।
litellm_settings:
success_callback: ["langfuse"]
failure_callback: ["langfuse"]LANGFUSE_PUBLIC_KEY=pk-lf-...
LANGFUSE_SECRET_KEY=sk-lf-...
LANGFUSE_HOST=https://langfuse.example.comfailure_callback এবং success_callback উভয়ই সেট করুন। এটি না করলে আপনি কেবল সেই ট্রেসগুলোই পাবেন যেখানে কোনো সমস্যা হয়নি। এর বাইরেও, LiteLLM প্রতিটি অনুরোধের খরচের হিসাব Postgres-এ লেখে এবং /ui-এ থাকা Admin UI সেই টেবিল থেকে তথ্য পড়ে। ট্র্যাফিকের সাথে সাথে এটি বাড়তে থাকে, তাই ছোট ডিস্কে এটি ব্যবহারের সময় সতর্ক থাকুন।
গেটওয়েকে একটি reverse proxy-এর পেছনে রাখুন
বক্সের বাইরের কোনো কিছু যেন সরাসরি port 4000-এ পৌঁছাতে না পারে। nginx বা Caddy-তে TLS termination সম্পন্ন করুন এবং অনুরোধগুলো loopback address-এ পাঠিয়ে দিন।
location / {
proxy_pass http://127.0.0.1:4000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_read_timeout 600s;
}এই লাইনগুলোর মধ্যে দুটি লাইন মানুষ প্রায়ই বাদ দিয়ে দেয়। proxy_buffering off গুরুত্বপূর্ণ কারণ একটি streaming completion হলো server-sent events-এর একটি ধারাবাহিকতা, আর buffering চালু থাকলে nginx রেসপন্স শেষ না হওয়া পর্যন্ত chunks-গুলোকে আটকে রাখে; ফলে ক্লায়েন্ট কোনো সাড়া পায় না এবং শেষে একসাথে সব ডেটা গ্রহণ করে। proxy_read_timeout 600s গুরুত্বপূর্ণ কারণ একটি দীর্ঘ generation প্রক্রিয়া nginx-এর ডিফল্ট 60 সেকেন্ডের সময়সীমা অতিক্রম করে যায়, আর এমনটি ঘটলে ক্লায়েন্ট একটি 504 error পায় এবং error log-এ upstream timed out (110: Connection timed out) while reading response header from upstream রেকর্ড হয়।
সার্টিফিকেটের জন্য, nginx-এ Let's Encrypt সহ Certbot হলো দ্রুততম উপায়। যদি সার্ভারে ইতিমধ্যে একাধিক কন্টেইনার চলমান থাকে, তবে একাধিক Compose অ্যাপের সামনে Traefik ব্যবহার করলে তা এক জায়গা থেকেই রাউটিং এবং সার্টিফিকেট ব্যবস্থাপনা সম্পন্ন করতে পারে।
গেটওয়ে এখন একটি সিঙ্গেল পয়েন্ট অফ ফেইলিয়র
আপনি যা তৈরি করেছেন সে সম্পর্কে সৎ থাকুন। আপনার মালিকানাধীন প্রতিটি অ্যাপ্লিকেশন এখন একটি VPS-এ থাকা একটি কন্টেইনারের ওপর নির্ভরশীল। এটি ডাউন থাকলে কোনো মডেল কল করা সম্ভব হবে না, এমনকি যেসব প্রোভাইডার পুরোপুরি সচল আছে তাদের ক্ষেত্রেও। এর ফলে চারটি বিষয় ঘটে।
- একটি ভুল কনফিগারেশন সবকিছু একসাথে বন্ধ করে দেয়।
restart: unless-stoppedএকটি ক্র্যাশ রিস্টার্ট করে, এবং এটি এমন একটি কন্টেইনার রিস্টার্ট করে যা config.yaml পার্স করতে পারে না, বারবার। প্রতিটি কনফিগারেশন পরিবর্তনের পরdocker compose logs litellmপড়ুন, এবং কনফিগারেশন পরিবর্তন করার সময় হাতে পর্যাপ্ত সময় রাখুন যাতে আপনি তা পর্যবেক্ষণ করতে পারেন। - Postgres রিকোয়েস্ট পাথের মধ্যে থাকে। ভার্চুয়াল কি লুকআপ এবং স্পেন্ড রেকর্ডিং উভয়ই এটি ব্যবহার করে।
/health/readinessথেকে 503 এরর আসা মানে হলো গেটওয়েটি চলছে কিন্তু এর কোনোটিই করতে পারছে না। - একটি ইনস্ট্যান্স বড় না করে বরং নতুন ইনস্ট্যান্স যোগ করে স্কেল করুন। প্রজেক্টের নিজস্ব নির্দেশিকা হলো প্রতি ইনস্ট্যান্সে একটি ওয়ার্কার (
--num_workers 1) এবং একাধিক ইনস্ট্যান্স একটি ডাটাবেস শেয়ার করবে। লোড ব্যালেন্সারের পেছনে দুটি ছোট গেটওয়ে থাকলে একটি কন্টেইনারের ওপর নির্ভরতা দূর হয়। তবে এতে ডাটাবেসের ওপর নির্ভরতা দূর হয় না। - যা পুনরায় তৈরি করতে পারবেন না তার ব্যাকআপ রাখুন। এটি হলো
config.yamlএবং.env, সাথে ডাটাবেসের একটিpg_dump।LITELLM_SALT_KEYহারিয়ে ফেললে সেই ডাম্পের ভেতরে থাকা এনক্রিপ্টেড প্রোভাইডার ক্রেডেনশিয়ালগুলো অকেজো হয়ে যায়, তাই env ফাইল এবং ডাম্প একই ব্যাকআপ জবের অন্তর্ভুক্ত হওয়া উচিত: restic ব্যবহার করে অফ-বক্স স্টোরেজে ব্যাকআপ।
আপগ্রেড করার অর্থ হলো ইমেজ ট্যাগ এডিট করা এবং docker compose up -d চালানো। LiteLLM ডিফল্টভাবে স্টার্টআপের সময় prisma migrate deploy চালায়, তাই নতুন কন্টেইনারটি প্রথমবার বুট হওয়ার সময় ডাটাবেস স্কিমা মাইগ্রেট করে নেয়। ট্যাগ পরিবর্তন করার আগে ডাম্প নিয়ে রাখুন, কারণ পুরনো ইমেজ ফিরিয়ে আনলে ইতিমধ্যে সম্পন্ন হওয়া মাইগ্রেশন বাতিল হয় না।
FAQ
LiteLLM কি প্রতিটি কলে লক্ষণীয় ল্যাটেন্সি যোগ করে?
প্রকল্পটির README (আগস্ট 2026) অনুযায়ী, 1000 রিকোয়েস্ট প্রতি সেকেন্ডে এর 95তম পার্সেন্টাইল ল্যাটেন্সি 8 ms। এটিকে ভেন্ডরের দেওয়া পরিসংখ্যান হিসেবে গণ্য করুন। আপনার ল্যাটেন্সিকে মূলত প্রভাবিত করে আপনার অ্যাপ্লিকেশন এবং গেটওয়ের মধ্যকার নেটওয়ার্ক দূরত্ব, কারণ প্রতিটি কলের সাথে একটি অতিরিক্ত রাউন্ড ট্রিপ যোগ হয়। গেটওয়েকে সেই একই অঞ্চলে চালান যেখানে অ্যাপ্লিকেশনগুলো রয়েছে, তারপর একটি প্রকৃত রেসপন্সে x-litellm-overhead-duration-ms হেডার ব্যবহার করে আপনার নিজস্ব ওভারহেড পরিমাপ করুন।
Nginx সামনে বসানোর পর স্ট্রিমিং কেন কাজ করা বন্ধ করে দিল?
কারণ Nginx ডিফল্টভাবে আপস্ট্রিম রেসপন্স বাফার করে এবং একটি স্ট্রিমিং কমপ্লিশন হলো সার্ভার-সেন্ট ইভেন্টের একটি সিরিজ। proxy_buffering চালু থাকলে, Nginx চাঙ্কগুলো সংগ্রহ করে এবং রেসপন্স শেষ না হওয়া পর্যন্ত তা পাঠায় না, ফলে ক্লায়েন্ট চুপচাপ অপেক্ষা করে এবং শেষে পুরো উত্তরটি একসাথে পায়। লোকেশন ব্লকে proxy_buffering off; সেট করুন। একই ব্লকে proxy_read_timeout বাড়িয়ে দিন, কারণ দীর্ঘ জেনারেশনের ক্ষেত্রে এটি Nginx-এর ডিফল্ট 60 সেকেন্ড সময়সীমা অতিক্রম করে এবং ক্লায়েন্ট একটি 504 এরর পায়।
ভার্চুয়াল কি-এর বাজেট শেষ হয়ে গেলে কী হয়?
কলটি HTTP 401 এরর দেয় এবং বডিতে ExceededBudget: Current spend for token: 7.2e-05; Max Budget for Token: 2e-07 ফরম্যাটের মেসেজ থাকে। 401 হলো একটি ফাঁদ: ক্লায়েন্ট লাইব্রেরি এটিকে অথেন্টিকেশন ফেইলর হিসেবে রিপোর্ট করে, তাই মানুষ মেসেজটি না পড়ে কি-টি বৈধ কি না তা পরীক্ষা করতে শুরু করে। স্ট্যাটাস কোডের পাশাপাশি রেসপন্স বডিও লগ করুন। মাস্টার কি-এর বিপরীতে /key/info?key=sk-... ব্যবহার করে কি-টির প্রকৃত অবস্থা নিশ্চিত করুন এবং বাজেট কম সেট করা থাকলে /key/update ব্যবহার করে তা বাড়িয়ে দিন।
গেটওয়ে কি হোস্ট করা মডেলের পাশাপাশি লোকাল মডেলেও রাউট করতে পারে?
হ্যাঁ, এবং এটি model_list-এ আরও একটি এন্ট্রি হিসেবে যোগ করা যায়। api_base সহ ollama_chat/ প্রিফিক্স ব্যবহার করুন, উদাহরণস্বরূপ api_base: http://ollama:11434-এর পাশাপাশি model: ollama_chat/llama3.1। কন্টেইনারের ভেতর থেকে, localhost বলতে সেই কন্টেইনারকেই বোঝায়, তাই Docker নেটওয়ার্কে Compose সার্ভিস নেম বা হোস্টের অ্যাড্রেস ব্যবহার করুন, কখনোই 127.0.0.1 ব্যবহার করবেন না। লোকাল মডেল সেটআপ করা একটি আলাদা কাজ: দেখুন VPS-এ Ollama দিয়ে LLM সেলফ-হোস্টিং।