SSD Nodes Learn 🎉 VPS از $5.50/ماه
راهنماها Matt Connorتوسط Matt Connor · به‌روزرسانی شده 2026-08-13

راهنمای راه‌اندازی LiteLLM به عنوان گیت‌وی LLM

با نصب LiteLLM روی سرور شخصی، یک endpoint واحد سازگار با OpenAI بسازید. مدیریت بودجه، کلیدهای مجازی و قابلیت Fallback را برای تمامی مدل‌های زبانی در یک مکان متمرکز کنید.

گیت‌وی LLM خودمیزبان چه کاری انجام می‌دهد

LiteLLM یک گیت‌وی متن‌باز برای LLM است که خودتان آن را میزبانی می‌کنید: یک endpoint واحد HTTP که تمام برنامه‌های شما با آن در ارتباط هستند و درخواست‌ها را به ارائه‌دهنده‌ای که باید پاسخگو باشد، هدایت می‌کند. LLM مخفف مدل زبانی بزرگ (Large Language Model) است. این گیت‌وی از API (رابط برنامه‌نویسی اپلیکیشن) چت کامپلیشن OpenAI پشتیبانی می‌کند، بنابراین هر کتابخانه کلاینتی که پیش‌تر با OpenAI کار می‌کرده، پس از دو تغییر در base URL و کلید، با آن سازگار می‌شود.

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

پس از راه‌اندازی، امکانات زیر را در اختیار دارید:

  • یک endpoint واحد. برنامه‌ها به https://gateway.example.com/v1 متصل می‌شوند و نام مدلی که خودتان تعریف کرده‌اید، مانند bulk یا strong را درخواست می‌کنند.
  • کلیدهای مجازی. هر برنامه کلید اختصاصی خود را با لیست مجاز مدل‌ها و سقف بودجه مشخص دریافت می‌کند. می‌توانید بدون تأثیر بر سایر برنامه‌ها، دسترسی یکی را لغو کنید.
  • جایگزین‌های خودکار (Fallbacks). فراخوانی‌های ناموفق یا پرامپت‌های بیش از حد بزرگ، به‌طور خودکار با یک مدل دیگر دوباره تلاش می‌شوند.
  • ثبت لاگ. هر درخواست، ردیفی شامل هزینه مربوطه را ثبت می‌کند، بنابراین پاسخ به این سؤال که «کدام برنامه آن هزینه را ایجاد کرده» همیشه در دسترس است.

چرا باید گیت‌وی را خودتان اجرا کنید

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

پیش‌نیازها

  • یک سرور مجازی (VPS) با سیستم‌عامل Ubuntu 24.04 که Docker و افزونه Compose روی آن نصب شده باشد.
  • یک نام دامنه که به سرور اشاره می‌کند، در صورتی که قرار است ماشین‌های خارج از شبکه از طریق TLS (امنیت لایه انتقال) به gateway دسترسی داشته باشند.
  • حداقل یک کلید API از ارائه‌دهنده سرویس.

این gateway هیچ پردازش استنتاجی (inference) انجام نمی‌دهد. وظیفه آن ارسال درخواست‌ها و بازگرداندن پاسخ‌ها به صورت stream است، بنابراین بار پردازنده (CPU) آن متناسب با حجم درخواست‌ها تغییر می‌کند، نه اندازه مدل. یک سرور با 1 هسته پردازنده (vCPU) می‌تواند چندین برنامه داخلی را بدون مشکل مدیریت کند. آنچه با گذشت زمان افزایش می‌یابد، حجم پایگاه داده است، زیرا gateway برای هر درخواست یک ردیف هزینه (spend row) ثبت می‌کند.

ابتدا فایل config.yaml را بنویسید

فایل پیکربندی تعیین می‌کند که کلاینت‌ها مجاز به درخواست کدام مدل‌ها هستند. چهار بخش سطح بالا اهمیت دارند: 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: 300

model_name نامی است که کلاینت‌های شما ارسال می‌کنند. litellm_params.model مدل واقعی است که به صورت provider/model نوشته می‌شود. مدل‌های خود را بر اساس وظیفه نام‌گذاری کنید، نه بر اساس فروشنده. برنامه‌ای که درخواست bulk را می‌دهد، زمانی که ماه آینده تصمیم بگیرید bulk باید مدل متفاوتی باشد، همچنان به کار خود ادامه می‌دهد.

api_key: os.environ/ANTHROPIC_API_KEY به LiteLLM می‌گوید که آن متغیر را در زمان اجرا بخواند. کلید واقعی هرگز در فایل ظاهر نمی‌شود، که این موضوع اهمیت دارد زیرا config.yaml فایلی است که شما commit می‌کنید.

دو ورودی به عمد نام strong را به اشتراک می‌گذارند. هنگامی که بیش از یک deployment دارای model_name یکسان باشد، روتر با آن‌ها به عنوان موارد جایگزین رفتار می‌کند و در صورت شکست اولی، دیگری را امتحان می‌کند. اینگونه است که strong از خرابی یک ارائه‌دهنده در یک بازه زمانی خاص جان سالم به در می‌برد.

num_retries: 2 در صورت بروز خطای قابل‌تکرار، همان deployment را دوباره امتحان می‌کند. مکانیزم fallback تنها پس از اتمام آن تلاش‌های مجدد فعال می‌شود. allowed_fails: 3 با cooldown_time: 30 یک deployment را پس از 3 بار شکست، به مدت 30 ثانیه از چرخه خارج می‌کند، بنابراین ارائه‌دهنده‌ای که خطای 500 برمی‌گرداند، دیگر در هر درخواست امتحان نمی‌شود.

fallbacks و context_window_fallbacks محرک‌های متفاوتی دارند و دومی همان مورد مفیدی است که افراد از آن غافل می‌شوند.

  • fallbacks زمانی فعال می‌شود که فراخوانی اصلی با شکست مواجه شود.
  • context_window_fallbacks زمانی فعال می‌شود که ارائه‌دهنده درخواست را به دلیل طولانی‌تر بودن از پنجره متنی (context window) آن مدل رد کند؛ بنابراین یک prompt بیش از حد بزرگ، به جای بازگرداندن خطا به فراخواننده، به مدلی با فضای کافی ارسال می‌شود.

همچنین content_policy_fallbacks وجود دارد که برای مواردی است که ارائه‌دهنده به دلایل سیاست‌های محتوایی درخواست را رد می‌کند. آن را تنها در صورتی تنظیم کنید که مکان مناسبی برای ارسال آن فراخوانی‌ها داشته باشید.

استقرار LiteLLM روی یک VPS با استفاده از Docker Compose

یک دایرکتوری ایجاد کنید که شامل سه فایل config.yaml، docker-compose.yml و .env باشد. راهنمای شروع سریع (quickstart) بالادستی، تگ latest را دریافت می‌کند. به جای آن یک تگ نسخه (release tag) را ثابت کنید تا docker compose up -d در ماه آینده همان gateway امروز را به شما بدهد و بازگشت به نسخه قبلی (rollback) تنها با یک خط دستور انجام شود.

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 را دو بار می‌خواند. یک بار برای جایگذاری ${POSTGRES_PASSWORD} در داخل خود فایل compose و یک بار از طریق env_file برای انتقال تمام متغیرها به داخل container.

نسخه v1.95.0 آخرین نسخه منتشر شده در آگوست 2026 بود. صفحه نسخه‌های پروژه را بررسی کنید و هر نسخه‌ای که در زمان استقرار جاری است را ثابت کنید. هر نسخه یک امضا منتشر می‌کند، بنابراین می‌توانید پیش از اعتماد به image، آن را بررسی کنید:

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 است که پورت را فقط روی رابط loopback منتشر می‌کند. اگر به جای آن 4000:4000 را بنویسید، gateway شما از کل اینترنت قابل دسترسی خواهد بود، زیرا Docker قوانین خاص خود را در زنجیره iptables FORWARD اضافه می‌کند و این قوانین پیش از قوانین ufw ارزیابی می‌شوند، بنابراین ufw deny 4000 مانع آن نمی‌شود. این رایج‌ترین روشی است که یک gateway شخصی‌سازی‌شده (self-hosted) به صورت عمومی باز می‌ماند: به چگونگی انتشار پورت container توسط Docker و دور زدن ufw مراجعه کنید. ترافیک از خارج باید به جای آن از طریق reverse proxy وارد شود.

کلیدهای ارائه‌دهنده را خارج از ایمیج نگه دارید

فایل .env تمام اسرار را در خود جای می‌دهد. این فایل در زمان اجرا به عنوان متغیر محیطی (environment) تزریق می‌شود، بنابراین هرگز در ایمیج نهایی قرار نمی‌گیرد و در مخزن کد (commit) ذخیره نمی‌شود.

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 .env

LITELLM_MASTER_KEY اعتبارنامه مدیریت است. این کلید، API مدیریت را احراز هویت می‌کند و رمز عبور برای رابط کاربری Admin در /ui است. هیچ برنامه‌ای نباید آن را در اختیار داشته باشد.

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

STORE_MODEL_IN_DB=True به شما امکان می‌دهد مدل‌ها را از طریق رابط کاربری Admin اضافه یا ویرایش کنید، بدون اینکه نیازی به دستکاری فایل config.yaml باشد. این کار راحت است، اما باعث می‌شود منبع حقیقت (source of truth) شما به دو بخش تقسیم شود. تصمیم بگیرید کدام‌یک مرجع اصلی است و این تصمیم را در کنار فایل پیکربندی یادداشت کنید.

استدلالی که باعث می‌شود کلیدها را خارج از فایل پیکربندی نگه داریم، همان استدلالی است که آن‌ها را از ابزارهایی که به یک عامل (agent) می‌دهید، دور نگه می‌دارد. دور نگه داشتن اسرار ارائه‌دهنده از عامل‌های هوش مصنوعی این الگو را پوشش می‌دهد و فایل‌های env و اسرار در Docker Compose جزئیات فنی آن را توضیح می‌دهد.

سرویس را بالا بیاورید و اولین بوت را نظارت کنید:

docker compose up -d
docker compose logs -f litellm

بررسی عملکرد صحیح

دو کاوشگر (probe) بدون احراز هویت و یک کاوشگر با احراز هویت وجود دارند که به دلایل متفاوتی با شکست مواجه می‌شوند.

curl -s http://127.0.0.1:4000/health/liveliness
curl -s http://127.0.0.1:4000/health/readiness

/health/liveliness به احراز هویت نیاز ندارد و تا زمانی که پردازش در حال اجرا باشد، پاسخ "I'm alive!" را برمی‌گرداند. /health/readiness نیز به احراز هویت نیاز ندارد. این کاوشگر یک شیء JSON شامل "status": "healthy" و فیلد db برمی‌گرداند، یا در صورتی که دیتابیس در دسترس نباشد، کد خطای 503 را ارسال می‌کند. مانیتورینگ خود را روی readiness تنظیم کنید، زیرا liveliness در gatewayای که قادر به جستجوی یک کلید مجازی نیست، همچنان سبز باقی می‌ماند.

بررسی احراز هویت‌شده، همان کاوشگری است که با ارائه‌دهندگان (providers) ارتباط برقرار می‌کند:

curl -s http://127.0.0.1:4000/health \
  -H "Authorization: Bearer $LITELLM_MASTER_KEY"

این کاوشگر با آرایه‌های healthy_endpoints و unhealthy_endpoints پاسخ می‌دهد. قرار گرفتن یک مدل در وضعیت unhealthy_endpoints همراه با خطای احراز هویت، به این معنی است که کلید ارائه‌دهنده در .env اشتباه است یا وجود ندارد؛ این همان خطایی است که اکنون باید شناسایی کنید. از آنجا که background_health_checks: true تنظیم شده است، پروکسی این کاوشگرها را هر health_check_interval ثانیه به‌طور خودکار اجرا می‌کند و /health آخرین نتیجه را برمی‌گرداند؛ بنابراین، polling کردن آن باعث نمی‌شود که هر بار یک درخواست تست به ارائه‌دهندگان شما ارسال شود.

کلیدهای مجازی و بودجه‌بندی به ازای هر کلید

هر برنامه کلید اختصاصی خود را دریافت می‌کند که بر اساس کلید اصلی (master 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 و بدنه (body) زیر مواجه می‌شود:

ExceededBudget: Current spend for token: 7.2e-05; Max Budget for Token: 2e-07

کد وضعیت، دلیل اصلی سردرگمی در این بخش است. کتابخانه کلاینت، خطای 401 را به عنوان مشکل احراز هویت گزارش می‌کند، بنابراین توسعه‌دهنده‌ای که stack trace را می‌خواند، شروع به بررسی معتبر بودن کلید می‌کند. بدنه پاسخ را در کنار کد وضعیت لاگ کنید، در غیر این صورت اتمام بودجه همیشه به شکل خرابی اعتبارنامه (credential) به نظر می‌رسد.

کلیدها را از طریق همان 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}'

بودجه‌ای که در gateway اعمال می‌شود، حتی زمانی که عامل (agent) دچار مشکل شده باشد نیز معتبر باقی می‌ماند؛ به همین دلیل است که این قابلیت، ستون فقرات کنترل هزینه برای عامل‌های هوش مصنوعی روی VPS محسوب می‌شود.

ارسال کارهای انبوه به یک مدل ارزان

کلاینت را به سمت gateway هدایت کنید. Base URL، کلید و نام مدل را تنظیم کنید:

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 به همین صورت عمل می‌کند: base_url را روی https://gateway.example.com/v1 و api_key را روی کلید مجازی تنظیم کنید.

سیاست مسیریابی از فایل config.yaml اکنون بدون اطلاع کلاینت اعمال می‌شود. یک درخواست برای bulk به مدل ارزان ارسال می‌شود. اگر آن فراخوانی پس از تلاش‌های مجدد (retries) شکست بخورد، درخواست مجدداً علیه strong امتحان می‌شود. اگر طول prompt برای bulk بیش از حد باشد، context_window_fallbacks آن را به‌جای بازگرداندن خطا، به strong می‌فرستد. کارهای انبوه مانند مرحله دسته‌بندی یا خلاصه‌سازی backlog به‌صورت پیش‌فرض با هزینه کم اجرا می‌شوند و فقط درخواست‌های دشوار هزینه بیشتری دارند.

اینجاست که یک gateway جایگاه خود را در میان ایجنت‌های دارای ابزار (tool-using agents) تثبیت می‌کند. یک سرور MCP (پروتکل زمینه مدل) روی همان VPS و ایجنتی که آن را هدایت می‌کند، هر دو می‌توانند به یک endpoint اشاره کنند، بنابراین مدل پشت آن‌ها بدون نیاز به redeploy کردن هیچ‌کدام، تغییر می‌کند.

چگونه متوجه شویم که fallback رخ داده است؟

این همان حالت شکستی است که هزینه مالی به همراه دارد، زیرا در ظاهر هیچ‌چیز خراب به نظر نمی‌رسد. یک fallback موفق، کد وضعیت HTTP 200 را به همراه یک بدنه پاسخ معمولی برمی‌گرداند. مدل ارزان‌قیمت شما ممکن است یک روز کامل از دسترس خارج باشد و تمام درخواست‌ها بی‌سروصدا توسط مدل گران‌قیمت پاسخ داده شوند؛ در این صورت، اولین نشانه از این اتفاق، صورت‌حساب شما خواهد بود.

شواهد این اتفاق در هدرهای پاسخ (response headers) موجود است. آن‌ها را درخواست کنید:

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 نشان‌دهنده deploymentای است که به درخواست پاسخ داده است. هرگاه این دو با هم متفاوت باشند، یعنی یک fallback رخ داده است.
  • مقادیر x-litellm-attempted-fallbacks و x-litellm-attempted-retries تعداد این موارد را می‌شمارند. در یک فراخوانی سالم، هر دو مقدار 0 هستند.
  • مقدار x-litellm-response-cost هزینه همان یک فراخوانی خاص به دلار آمریکا است.
  • مقدار x-litellm-call-id شناسه‌ای است که برای یافتن همان فراخوانی در لاگ‌های خود از آن استفاده می‌کنید.

مقدار x-litellm-attempted-fallbacks را در هر درخواست ثبت کنید و زمانی که از 0 تغییر کرد، هشدار دریافت کنید. همین یک عدد، تفاوت بین یک سیاست مسیریابی کارآمد و سیاستی است که بی‌سروصدا به «همیشه از مدل گران‌قیمت استفاده کن» تبدیل شده است.

نسخه کامل این قابلیت، tracing است که نیاز به راه‌اندازی اختصاصی دارد: میزبانی Langfuse برای رهگیری فراخوانی‌های agent. ابزار LiteLLM این callback را ارائه می‌دهد، بنابراین اتصال آن تنها به دو خط کد به علاوه اعتبارنامه‌ها نیاز دارد.

litellm_settings:
  success_callback: ["langfuse"]
  failure_callback: ["langfuse"]
LANGFUSE_PUBLIC_KEY=pk-lf-...
LANGFUSE_SECRET_KEY=sk-lf-...
LANGFUSE_HOST=https://langfuse.example.com

مقدار failure_callback و همچنین success_callback را تنظیم کنید. اگر این کار را انجام ندهید، تنها traceهایی که ذخیره می‌کنید مربوط به مواردی است که هیچ مشکلی در آن‌ها رخ نداده است. جدا از تمام این موارد، LiteLLM به ازای هر درخواست یک ردیف هزینه در Postgres می‌نویسد و رابط کاربری مدیریتی در /ui آن جدول را می‌خواند. این جدول با افزایش ترافیک رشد می‌کند، بنابراین مراقب فضای دیسک کوچک خود باشید.

قرار دادن درگاه پشت یک reverse proxy

هیچ چیزی خارج از این سرور نباید به پورت 4000 دسترسی داشته باشد. عملیات TLS termination را در nginx یا Caddy انجام دهید و درخواست‌ها را به آدرس loopback هدایت کنید.

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، مجموعه‌ای از server-sent events است؛ در صورت فعال بودن buffering، nginx تکه‌ها را تا پایان پاسخ نگه می‌دارد و در نتیجه کلاینت در سکوت منتظر می‌ماند و سپس همه داده‌ها را یک‌جا دریافت می‌کند. تنظیم proxy_read_timeout 600s نیز حیاتی است زیرا تولید متن طولانی ممکن است از حد پیش‌فرض 60 ثانیه‌ای nginx فراتر رود؛ در این صورت کلاینت خطای 504 دریافت می‌کند و در لاگ خطا، پیام upstream timed out (110: Connection timed out) while reading response header from upstream ثبت می‌شود.

برای دریافت گواهی، استفاده از Certbot و Let's Encrypt روی nginx کوتاه‌ترین مسیر است. اگر سرور در حال حاضر چندین container را میزبانی می‌کند، استفاده از Traefik برای مدیریت چندین برنامه Compose مسیریابی و گواهی‌ها را در یک نقطه متمرکز مدیریت می‌کند.

درگاه اکنون یک نقطه شکست واحد است

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

  • یک پیکربندی نادرست همه چیز را همزمان از کار می‌اندازد. restart: unless-stopped یک کرش را ری‌استارت می‌کند و کانتینری را که نمی‌تواند config.yaml را پارس کند، بارها و بارها بازنشانی می‌کند. پس از هر تغییر در پیکربندی، docker compose logs litellm را بخوانید و تغییرات را زمانی اعمال کنید که فرصت کافی برای نظارت بر آن‌ها دارید.
  • Postgres در مسیر درخواست قرار دارد. جستجوی کلید مجازی و ثبت هزینه‌ها هر دو از آن استفاده می‌کنند. /health/readiness که خطای 503 برمی‌گرداند، هشدار شماست که درگاه در حال اجراست اما نمی‌تواند هیچ‌کدام از این دو کار را انجام دهد.
  • به جای بزرگ‌تر کردن یک نمونه، با افزودن نمونه‌های جدید مقیاس‌پذیری کنید. راهنمای خود پروژه، یک worker برای هر نمونه (--num_workers 1) با چندین نمونه که از یک دیتابیس مشترک استفاده می‌کنند، است. دو درگاه کوچک پشت یک load balancer، کانتینر واحد را از معادله حذف می‌کنند. آن‌ها دیتابیس را حذف نمی‌کنند.
  • از آنچه نمی‌توانید دوباره تولید کنید، نسخه پشتیبان تهیه کنید. این شامل config.yaml و .env به همراه یک pg_dump از دیتابیس است. از دست دادن LITELLM_SALT_KEY باعث می‌شود اعتبارنامه‌های رمزگذاری‌شده ارائه‌دهنده در آن dump بی‌فایده شود، بنابراین فایل env و dump باید در یک job پشتیبان‌گیری یکسان قرار بگیرند: پشتیبان‌گیری restic در فضای ذخیره‌سازی خارج از سرور.

ارتقا به معنای ویرایش تگ image و اجرای docker compose up -d است. LiteLLM به‌طور پیش‌فرض در زمان شروع به کار prisma migrate deploy را اجرا می‌کند، بنابراین کانتینر جدید در اولین بوت، شمای دیتابیس را مهاجرت می‌دهد. پیش از تغییر تگ، یک dump تهیه کنید، زیرا بازگرداندن image قدیمی، مهاجرتی را که قبلاً انجام شده است، خنثی نمی‌کند.

FAQ

آیا LiteLLM تأخیر محسوسی به هر فراخوانی اضافه می‌کند؟

این پروژه طبق README خود در اوت 2026، تأخیر 8 میلی‌ثانیه را در صدک 95 برای 1000 درخواست در ثانیه گزارش کرده است. این عدد را به عنوان یک آمار تبلیغاتی در نظر بگیرید. عددی که واقعاً تأخیر شما را تغییر می‌دهد، فاصله شبکه بین برنامه‌های شما و gateway است، زیرا شما یک رفت‌وبرگشت (round trip) به هر فراخوانی اضافه کرده‌اید. gateway را در همان منطقه‌ای (region) اجرا کنید که برنامه‌های فراخواننده در آن قرار دارند، سپس سربار خود را با استفاده از هدر x-litellm-overhead-duration-ms در یک پاسخ واقعی اندازه‌گیری کنید.

چرا پس از قرار دادن nginx در مقابل سرویس، streaming از کار افتاد؟

زیرا nginx به‌طور پیش‌فرض پاسخ‌های upstream را بافر می‌کند و تکمیل یک جریان (streaming completion) مجموعه‌ای از رویدادهای ارسالی از سمت سرور (server-sent events) است. با فعال بودن proxy_buffering، nginx تکه‌ها را جمع‌آوری کرده و تنها زمانی که پاسخ به پایان رسید آن‌ها را ارسال می‌کند؛ بنابراین کلاینت در سکوت منتظر می‌ماند و سپس کل پاسخ را یکجا دریافت می‌کند. گزینه proxy_buffering off; را در بلاک location تنظیم کنید. مقدار proxy_read_timeout را نیز در همان بلاک افزایش دهید، زیرا در غیر این صورت تولید طولانی متن از حد پیش‌فرض 60 ثانیه‌ای nginx فراتر رفته و کلاینت خطای 504 دریافت می‌کند.

وقتی بودجه یک virtual key تمام می‌شود چه اتفاقی می‌افتد؟

فراخوانی با خطای HTTP 401 و بدنه پاسخ به فرمت ExceededBudget: Current spend for token: 7.2e-05; Max Budget for Token: 2e-07 شکست می‌خورد. کد 401 یک تله است: کتابخانه‌های کلاینت آن را به عنوان خطای احراز هویت گزارش می‌کنند، بنابراین کاربران به‌جای خواندن پیام خطا، شروع به بررسی اعتبار کلید می‌کنند. بدنه پاسخ را در کنار کد وضعیت لاگ کنید. وضعیت واقعی کلید را با استفاده از /key/info?key=sk-... در برابر master key بررسی کنید و اگر بودجه خیلی کم تنظیم شده است، سقف آن را با /key/update افزایش دهید.

آیا gateway می‌تواند علاوه بر مدل‌های میزبانی‌شده، به یک مدل محلی نیز درخواست ارسال کند؟

بله، این مورد تنها یک ورودی دیگر در model_list است. از پیشوند ollama_chat/ به همراه یک api_base استفاده کنید، برای مثال model: ollama_chat/llama3.1 در کنار api_base: http://ollama:11434. از داخل یک کانتینر، localhost به همان کانتینر اشاره دارد، بنابراین از نام سرویس در Compose یا آدرس میزبان در شبکه Docker استفاده کنید و هرگز از 127.0.0.1 استفاده نکنید. راه‌اندازی مدل محلی یک وظیفه جداگانه است: به میزبانی شخصی یک LLM با Ollama روی VPS مراجعه کنید.