بهینه‌سازی سرعت استنتاج با ذخیره‌سازی پیشوندی

ذخیره سازی پیشوند (prefix caching) قابلیتی است که با ذخیره و استفاده مجدد از حالت LLM میانی پردازش یک بخش پیشوند اعلان مشترک و تکرارشونده، زمان استنتاج را کاهش می‌دهد. برای فعال کردن ذخیره سازی پیشوند، فقط باید پیشوند استاتیک را از پسوند پویا در درخواست API خود جدا کنید.

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

دو رویکرد برای پیاده‌سازی ذخیره‌سازی پیشوندی وجود دارد: ضمنی یا صریح:

  • ذخیره‌سازی پیشوند ضمنی یک رویکرد سبک است که در آن برنامه فقط نیاز به تعریف بخش مشترکی از اعلان دارد.
  • ذخیره سازی پیشوندی صریح به برنامه‌ها اجازه می‌دهد تا کنترل بیشتری بر حافظه‌های پنهان، از جمله ایجاد حافظه پنهان، پرس و جو و حذف آن، داشته باشند.

استفاده ضمنی از ذخیره سازی پیشوندی

برای فعال کردن ذخیره پیشوند، بخش مشترک prompt را به فیلد promptPrefix اضافه کنید، همانطور که در قطعه کد زیر نشان داده شده است:

کاتلین

val promptPrefix = "Reverse the given sentence: "
val dynamicSuffix = "Hello World"

val result = generativeModel.generateContent(
  generateContentRequest(TextPart(dynamicSuffix)) {
    promptPrefix = PromptPrefix(promptPrefix)
  }
)

جاوا

String promptPrefix = "Reverse the given sentence: ";
String dynamicSuffix = "Hello World";

GenerateContentResponse response = generativeModelFutures.generateContent(
    new GenerateContentRequest.Builder(new TextPart(dynamicSuffix))
    .setPromptPrefix(new PromptPrefix(promptPrefix))
    .build())
    .get();

در قطعه کد قبلی، dynamicSuffix به عنوان محتوای اصلی ارسال شده و promptPrefix به صورت جداگانه ارائه شده است.

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

بدون ذخیره سازی پیشوند

با پیشوند cache-hit

(ممکن است خطای Prefix cache-miss هنگام استفاده از Prefix برای اولین بار رخ دهد)

پیکسل ۹ با پیشوند ثابت ۳۰۰ توکنی و پسوند پویای ۵۰ توکنی

۰.۸۲ ثانیه

۰.۴۵ ثانیه

پیکسل ۹ با پیشوند ثابت ۱۰۰۰ توکنی و پسوند پویای ۱۰۰ توکنی

۲.۱۱ ثانیه

۰.۵ ثانیه

ملاحظات ذخیره‌سازی

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

  • تعداد حافظه‌های پنهان توسط مکانیزم LRU (کمترین استفاده اخیر) مدیریت می‌شود. حافظه‌های پنهان کم‌استفاده‌شده، زمانی که از حداکثر مقدار کل حافظه پنهان تجاوز کنند، به‌طور خودکار حذف می‌شوند.
  • اندازه حافظه پنهان سریع به طول پیشوند بستگی دارد.
  • برای پاک کردن تمام کش‌های ایجاد شده از prefix caching، از متد generativeMode.clearImplicitCaches() استفاده کنید.

از مدیریت حافظه پنهان صریح استفاده کنید

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

این مثال نحوه مقداردهی اولیه مدیریت حافظه پنهان صریح و انجام استنتاج را نشان می‌دهد:

کاتلین

val cacheName = "my_cache"
val promptPrefix = "Reverse the given sentence: "
val dynamicSuffix = "Hello World"

// Create a cache
val cacheRequest = createCachedContextRequest(cacheName, PromptPrefix(promptPrefix))
val cache = generativeModel.caches.create(cacheRequest)

// Run inference with the cache
val response = generativeModel.generateContent(
  generateContentRequest(TextPart(dynamicSuffix)) {
    cachedContextName = cache.name
  }
)

جاوا

String cacheName = "my_cache";
String promptPrefix = "Reverse the given sentence: ";
String dynamicSuffix = "Hello World";

// Create a cache
CachedContext cache = cachesFutures.create(
  new CreateCachedContextRequest.Builder(cacheName, new PromptPrefix(promptPrefix))
  .build())
  .get();

// Run inference with the cache
GenerateContentResponse response = generativeModelFutures.generateContent(
  new GenerateContentRequest.Builder(new TextPart(dynamicSuffix))
  .setCachedContextName(cache.getName())
  .build())
  .get();

این مثال نحوه‌ی پرس‌وجو، بازیابی و حذف حافظه‌های پنهان مدیریت‌شده‌ی صریح را با استفاده از generativeModel.caches نشان می‌دهد:

کاتلین

val cacheName = "my_cache"

// Query pre-created caches
for (cache in generativeModel.caches.list()) {
  // Do something with cache
}

// Get specific cache
val cache = generativeModel.caches.get(cacheName)

// Delete a pre-created cache
generativeModel.caches.delete(cacheName)

جاوا

String cacheName = "my_cache";

// Query pre-created caches
for (PrefixCache cache : cachesFutures.list().get()) {
  // Do something with cache
}

// Get specific cache
PrefixCache cache = cachesFutures.get(cacheName).get();

// Delete a pre-created cache
cachesFutures.delete(cacheName);