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

مشکل دسته‌بندی ساده

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

continuous batching

continuous batching این اتلاف منابع را از بین می‌برد. در این روش به‌جای انتظار برای اتمام کار کل گروه، به‌محض اینکه پردازش یک درخواست به پایان رسید، آن را از گروه خارج کرده و درخواست جدیدی را جایگزینش می‌کنند. بدین ترتیب، ظرفیت گروه همواره تکمیل می‌ماند و هیچ جایگاه پردازشی معطل نمی‌شود. تأثیر این تغییر شگفت‌انگیز است: نرخ گذردهی، به‌ویژه زمانی که طول درخواست‌ها تفاوت زیادی با هم دارند، می‌تواند چندین برابرِ روش ایستای سنتی شود.

مشکل حافظه KV

اما گلوگاه دومی نیز وجود دارد: حافظهٔ KV. هر درخواست برای نگهداری تاریخچه خود به فضا نیاز دارد و این فضا با افزایش طول متن بزرگ‌تر می‌شود. روش ساده برای حل این مسئله، رزرو یک بلوک پیوسته و بزرگ از حافظه برای هر درخواست است — پدیده‌ای که متناسب با طولانی‌ترین حالت ممکن در نظر گرفته می‌شود. اما از آنجا که بیشتر درخواست‌ها به آن حد از طولانی بودن نمی‌رسند، بخش عمده‌ای از حافظه اختصاص‌یافته هدر می‌رود. در عمل، معمولاً تنها حدود نیمی از این حافظه واقعاً به کار می‌آید.

PagedAttention

راهکار این مشکل، ایده‌ای الهام‌گرفته از سامانه‌های عامل است: PagedAttention. درست همان‌طور که یک سامانه عامل حافظه را به صفحات کوچک تقسیم کرده و آن‌ها را به‌صورت غیرپیوسته مدیریت می‌کند، در اینجا نیز حافظهٔ KV به بلوک‌های کوچکی (مثلاً هر بلوک معادل ۱۶ توکن) تقسیم می‌شود. هر درخواست تنها به اندازه نیاز واقعی خود بلوک دریافت می‌کند و نیازی نیست که این بلوک‌ها در حافظه در کنار یکدیگر قرار گیرند. در نتیجه، مشکلِ تکه‌تکه‌شدن حافظه از بین رفته و بهره‌وری آن به بالای ۹۰ درصد می‌رسد.

این روش مزیت جانبی دیگری نیز دارد: اگر چند درخواست دارای پیشوندی مشترک باشند — مانند دستورالعمل‌های یکسانِ سامانه — می‌توانند به‌جای ذخیره نسخه‌های مجزا، همان بلوک‌های حافظه را به اشتراک بگذارند. این ویژگی در کاربردهایی مانند گفت‌وگو که دستور ثابتی دارند، صرفه‌جویی چشمگیری در مصرف حافظه به همراه دارد.

چرا این دو با هم اهمیت دارند

continuous batching ظرفیت محاسباتی را همواره پر نگه می‌دارد و تکنیک PagedAttention حافظه را آزاد می‌کند تا درخواست‌های بیشتری در آن جای گیرند. این دو روش مکمل یکدیگرند: آزاد شدن حافظه به معنای امکان ایجاد گروه‌های بزرگ‌تر است و گروه‌های بزرگ‌تر به نرخ گذردهی بالاتری می‌انجامد. دقیقاً به همین دلیل است که ترکیب این دو ترفند، شالودهٔ کتابخانه‌های مدرنِ سرویس‌دهی مدل‌های زبانی را تشکیل می‌دهد.

جمع‌بندی

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