پرش به محتوا
← همهٔ یادداشت‌ها

SGLang یا vLLM؟ اجرای مدل زبانی روی GPU ابری

·۷ دقیقه مطالعه·تیم جی‌پی‌یو

یک ترازوی دوکفهٔ برنجی قدیمی با پایهٔ ستونی و دو کفهٔ خالی هم‌تراز، روی پایهٔ مرمر سفید و پس‌زمینهٔ خاکستری.

اگر می‌خواهید اجرای مدل زبانی را پشت یک API برای اپلیکیشن خودتان بگذارید، دو موتور سرو اصلی پیش رویتان است: SGLang و vLLM. هر دو مدل باز را روی GPU ابری بالا می‌آورند، هر دو API سازگار با OpenAI می‌دهند و هر دو در جی‌پی‌یو قالب آماده دارند. فرقشان در جزئیاتی است که وقتی چند کاربر هم‌زمان دارید خودش را نشان می‌دهد. این راهنما می‌گوید کی کدام را بردارید و چطور با یک آزمایش کوچک، روی کار خودتان تصمیم بگیرید.

کل آزمایش، یعنی بالا آوردن یک مدل ۷ میلیاردی روی هر دو موتور و فرستادن چند ده درخواست هم‌زمان، حدود یک ساعت طول می‌کشد. روی یک RTX 3090 این یعنی چیزی نزدیک ۴۵ هزار تومان خرج (در زمان نوشتن این مطلب). اگر فقط یکی از دو موتور را لازم دارید، نصف این وقت و هزینه کافی است.

پیش‌نیازها

SGLang و vLLM در اجرای مدل زبانی چه فرقی دارند؟

هر دو پروژه یک هدف دارند: بیشترین تعداد پاسخ در ثانیه از یک کارت گرافیک. هر دو درخواست‌ها را به‌صورت پیوسته دسته‌بندی می‌کنند، حافظهٔ میانی (KV cache) را صفحه‌بندی می‌کنند و کوانتیزه‌سازی‌هایی مثل AWQ و FP8 را می‌شناسند. در عمل برای یک مدل معمولی و یک کاربر، تفاوت سرعتشان کم است.

فرق اصلی در نگاه آن‌ها به پیشوند مشترک است. SGLang حافظهٔ میانی همهٔ درخواست‌ها را در یک درخت (RadixAttention) نگه می‌دارد و هر بخشی از ورودی را که قبلاً دیده، دوباره حساب نمی‌کند. vLLM هم ذخیرهٔ پیشوند دارد، اما طراحی SGLang از اول دور همین ایده ساخته شده است. نتیجه: هر جا درخواست‌ها شروع یکسانی دارند، SGLang معمولاً جلوتر است.

کی SGLang را انتخاب کنید

  • چت چندمرحله‌ای: هر پیام جدید کل تاریخچهٔ قبلی را دوباره می‌فرستد. با پیشوند مشترک، فقط پیام تازه پردازش می‌شود.
  • پرامپت سیستمی بلند یا مثال‌های ثابت: وقتی صدها درخواست همه با یک دستورالعمل دوهزارکلمه‌ای شروع می‌شوند.
  • عامل‌ها (agents) و زنجیرهٔ فراخوانی: که یک متن را چند بار با ادامه‌های مختلف به مدل می‌دهند.
  • خروجی ساختاریافته: SGLang تولید محدود به JSON را سریع انجام می‌دهد؛ برای استخراج داده از متن به کار می‌آید.

کی vLLM را انتخاب کنید

  • مدل تازه یا کم‌رایج: vLLM جامعهٔ بزرگ‌تری دارد و پشتیبانی از معماری‌های جدید معمولاً زودتر به آن می‌رسد.
  • درخواست‌های مستقل و متنوع: مثل خلاصه‌سازی هزار سند متفاوت؛ این‌جا پیشوند مشترکی نیست و برتری SGLang کم‌رنگ می‌شود.
  • مستندات و نمونه‌های بیشتر: اگر اولین بار است که مدلی را سرو می‌کنید، پیدا کردن جواب خطاها برای vLLM راحت‌تر است.

قاعدهٔ ساده: اگر نمی‌دانید، با vLLM شروع کنید؛ اگر بار کاریتان پر از پیشوند تکراری است، SGLang را آزمایش کنید. بهترین داور خود بار کاری شماست، و آزمایشش ارزان است.

انتخاب ماشین مناسب

نیاز VRAM در هر دو موتور تقریباً یکی است: وزن مدل به‌علاوهٔ چند گیگابایت برای حافظهٔ میانی. هر دو هم بخش بزرگی از کارت را از همان ابتدا رزرو می‌کنند، پس nvidia-smi حتی وقتی بیکارند پر نشان می‌دهد.

  • مدل ۷ میلیاردی چهاربیتی: کارت ۱۲ گیگابایتی کافی است؛ RTX 3060 از حدود ۱۶ هزار تومان در ساعت (در زمان نوشتن این مطلب).
  • مدل ۱۴ میلیاردی کوانتیزه: RTX A4000 با ۱۶ گیگابایت، از حدود ۲۵ هزار تومان در ساعت (در زمان نوشتن این مطلب).
  • پیشنهاد اقتصادی این آموزش: RTX 3090 با ۲۴ گیگابایت، از حدود ۴۴ هزار تومان در ساعت (در زمان نوشتن این مطلب). مدل ۷ میلیاردی با دقت کامل و جای کافی برای حافظهٔ میانی.
  • پیشنهاد سریع: RTX 4090 با همان ۲۴ گیگابایت و توان پردازشی بیشتر، از حدود ۱۰۳ هزار تومان در ساعت (در زمان نوشتن این مطلب).

برای فیلتر بر اساس حافظه و قیمت، به بازار GPU بروید. برای مقایسهٔ منصفانه، هر دو موتور را روی یک مدل کارت امتحان کنید.

اجاره و راه‌اندازی SGLang

در بازار کارت را انتخاب کنید و موقع اجاره قالب SGLang را بردارید. چند دقیقه بعد وضعیت ماشین «در حال اجرا» می‌شود. در صفحهٔ ماشین دستور آمادهٔ SSH، لینک Jupyter و توکنش، دستور «تونل امن» و فهرست «پورت‌های منتشرشده» را می‌بینید؛ همه با یک کلیک کپی می‌شوند. با دستور SSH وارد شوید و اول کارت را چک کنید:

nvidia-smi

سرور را داخل tmux اجرا کنید تا با قطع شدن SSH از بین نرود:

apt-get update && apt-get install -y tmux
tmux new -s sglang

حالا مدل را سرو کنید. این‌جا از Qwen2.5 7B Instruct با دقت کامل استفاده می‌کنیم:

python3 -m sglang.launch_server \
  --model-path Qwen/Qwen2.5-7B-Instruct \
  --host 0.0.0.0 \
  --port 30000 \
  --context-length 8192 \
  --mem-fraction-static 0.85

بار اول حدود ۱۵ گیگابایت وزن از Hugging Face دانلود می‌شود. ماشین خارج از ایران است و این دانلود با سرعت گیگابیتی روی خود ماشین انجام می‌شود، معمولاً در چند دقیقه. --mem-fraction-static سهم کارت برای وزن‌ها و حافظهٔ میانی است و --context-length بیشینهٔ طول متن را تعیین می‌کند. پورت پیش‌فرض SGLang 30000 است. با Ctrl+b و بعد d از tmux بیرون بیایید.

یک تست سریع از داخل ماشین:

curl http://localhost:30000/v1/models
curl http://localhost:30000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model": "Qwen/Qwen2.5-7B-Instruct", "messages": [{"role": "user", "content": "سلام، خودت را معرفی کن."}]}'

پاسخ همان ساختار آشنای OpenAI را دارد. برای رسیدن از لپ‌تاپ، از دستور «تونل امن» صفحهٔ ماشین استفاده کنید. اگر پورت را بیرون منتشر می‌کنید، --api-key را به دستور اضافه کنید.

آزمایش هم‌زمانی: کدام برای کار شما سریع‌تر است؟

این اسکریپت ۳۲ درخواست هم‌زمان می‌فرستد که همه با یک پرامپت سیستمی بلند شروع می‌شوند، یعنی همان حالتی که برتری SGLang باید دیده شود. اول کتابخانهٔ OpenAI را نصب کنید:

pip install openai

بعد فایل bench.py را بسازید:

import asyncio, sys, time
from openai import AsyncOpenAI

port = sys.argv[1]
client = AsyncOpenAI(api_key="EMPTY", base_url=f"http://localhost:{port}/v1")
system = "You are a support agent for an online shop. " * 150
questions = [f"Customer #{i}: where is my order? Answer in two sentences." for i in range(32)]

async def ask(q):
    r = await client.chat.completions.create(
        model="Qwen/Qwen2.5-7B-Instruct",
        messages=[{"role": "system", "content": system}, {"role": "user", "content": q}],
        max_tokens=128,
    )
    return r.usage.completion_tokens

async def main():
    t = time.time()
    tokens = sum(await asyncio.gather(*[ask(q) for q in questions]))
    dt = time.time() - t
    print(f"{len(questions)} requests, {tokens} tokens, {dt:.1f}s, {tokens/dt:.0f} tok/s")

asyncio.run(main())

و اجرایش کنید:

python3 bench.py 30000

خروجی تعداد توکن‌ها، زمان کل و توکن در ثانیه را می‌دهد. یکی دو بار اجرا کنید؛ بار اول پیشوند هنوز در حافظه نیست.

همان آزمایش با vLLM

حالا ماشین SGLang را حذف کنید و یک ماشین دیگر با همان مدل کارت و قالب vLLM اجاره کنید. داخل tmux سرور را با تنظیمات مشابه بالا بیاورید:

vllm serve Qwen/Qwen2.5-7B-Instruct \
  --max-model-len 8192 \
  --gpu-memory-utilization 0.85 \
  --port 8000

همان bench.py را بسازید، pip install openai را بزنید و این بار با پورت ۸۰۰۰ اجرا کنید:

python3 bench.py 8000

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

اگر به مشکل خوردید

  • CUDA out of memory هنگام بالا آمدن: در SGLang مقدار --mem-fraction-static را کم کنید (مثلاً ۰٫۷۵) یا --context-length را پایین بیاورید؛ در vLLM همین کار را با --gpu-memory-utilization و --max-model-len بکنید. یا سراغ نسخهٔ کوانتیزهٔ مدل بروید.
  • پورت در حال استفاده است: اگر پیام اشغال بودن پورت گرفتید، فرایندی از قبل روی آن گوش می‌دهد. پورت دیگری مثل ۳۰۰۰۱ بدهید و در اسکریپت هم همان را بنویسید.
  • مدل در پاسخ پیدا نمی‌شود (model not found): نام مدل در درخواست باید دقیقاً همان باشد که /v1/models برمی‌گرداند. اگر --served-model-name داده‌اید، همان نام را بفرستید.
  • سرور با قطع SSH از کار افتاد: داخل tmux اجرایش نکرده‌اید. با tmux attach -t sglang برگردید یا از نو اجرا کنید.
  • دانلود مدل نیمه‌کاره ماند: دستور را دوباره اجرا کنید؛ فایل‌های کامل‌شده دوباره دانلود نمی‌شوند.

هزینه و صرفه‌جویی

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

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

قدم بعدی

وقتی موتورتان را انتخاب کردید، اندازهٔ مدل را جدی بگیرید: اجرای مدل زبانی: جدول VRAM و انتخاب کارت گرافیک می‌گوید مدل‌های ۱۴ و ۳۲ میلیاردی روی کدام کارت جا می‌شوند. مستندات رسمی هر دو پروژه هم در مستندات SGLang و مستندات vLLM هست.

پرسش‌های متداول

SGLang بهتر است یا vLLM؟

هیچ‌کدام همه‌جا بهتر نیست. SGLang در بار کاری با پیشوند مشترک، مثل چت چندمرحله‌ای و پرامپت سیستمی بلند، معمولاً جلوتر است. vLLM پشتیبانی گسترده‌تر از مدل‌ها و جامعهٔ بزرگ‌تری دارد. با اسکریپت بالا روی کار خودتان بسنجید.

آیا کدی که برای vLLM نوشته‌ام با SGLang کار می‌کند؟

بله، تا وقتی از API سازگار با OpenAI استفاده می‌کنید. فقط base_url را به آدرس و پورت سرور SGLang تغییر دهید؛ پورت پیش‌فرض آن ۳۰۰۰۰ است.

SGLang چقدر VRAM لازم دارد؟

تقریباً همان‌قدر که vLLM: وزن مدل به‌علاوهٔ چند گیگابایت حافظهٔ میانی. مدل ۷ میلیاردی چهاربیتی روی ۱۲ گیگابایت و همان مدل با دقت کامل روی ۲۴ گیگابایت راحت اجرا می‌شود.

آیا برای اجرای SGLang به کارت گرافیک نیاز است؟

بله. SGLang برای سرو مدل روی GPU ساخته شده است. اگر کارت گرافیک ندارید، یک ماشین ساعتی از بازار GPU اجاره کنید و با قالب آماده شروع کنید.


تصویر کاور: «Balance scale MET DP318014» اثر Henry N. Hooper and Company و O.P. Drake، از ویکی‌مدیا کامنز، لایسنس CC0.