Optymalizowanie szybkości wnioskowania za pomocą buforowania prefiksów

Buforowanie prefiksów to funkcja, która skraca czas wnioskowania, przechowując i ponownie wykorzystując pośredni stan LLM podczas przetwarzania wspólnej i powtarzającej się części prefiksu prompta. Aby włączyć buforowanie prefiksów, wystarczy oddzielić statyczny prefiks od dynamicznego sufiksu w żądaniu do interfejsu API.

Buforowanie prefiksów obsługuje obecnie tylko dane wejściowe tekstowe, więc nie należy używać tej funkcji, jeśli w prompcie podajesz obraz.

Istnieją 2 sposoby wdrożenia buforowania prefiksów: niejawny i jawny:

Niejawne używanie buforowania prefiksów

Aby włączyć buforowanie prefiksów, dodaj wspólną część prompta do pola promptPrefix, jak pokazano w tych fragmentach kodu:

Kotlin

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

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

Java

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();

W poprzednim fragmencie dynamicSuffix jest przekazywany jako główna treść, a promptPrefix jest podawany osobno.

Szacowane zwiększenie wydajności

Bez buforowania prefiksów

Z buforowaniem prefiksów

(Gdy prefiks jest używany po raz pierwszy, może wystąpić brak w pamięci podręcznej prefiksów)

Pixel 9 z 300-tokenowym stałym prefiksem i 50-tokenowym dynamicznym sufiksem podpowiedź

0,82 sekundy

0,45 sekundy

Pixel 9 z 1000-tokenowym stałym prefiksem i 100-tokenowym dynamic sufiksem

2,11 sekundy

0,5 sekundy

Wskazówki dotyczące pamięci

W przypadku niejawnego buforowania prefiksów pliki pamięci podręcznej są zapisywane w prywatnym miejscu na dane aplikacji klienckiej, co zwiększa wykorzystanie miejsca na dane przez aplikację. Przechowywane są zaszyfrowane pliki pamięci podręcznej i powiązane z nimi metadane, w tym oryginalny tekst prefiksu. Pamiętaj o tych kwestiach związanych z pamięcią:

  • Liczba pamięci podręcznych jest zarządzana przez mechanizm LRU (Least Recently Used). Najrzadziej używane pamięci podręczne są automatycznie usuwane po przekroczeniu maksymalnej łącznej ilości pamięci podręcznej.
  • Rozmiary pamięci podręcznej promptów zależą od długości prefiksu.
  • Aby wyczyścić wszystkie pamięci podręczne utworzone na podstawie buforowania prefiksów, użyj metody generativeMode.clearImplicitCaches().

Korzystanie z jawnego zarządzania pamięcią podręczną

Interfejs Prompt API zawiera metody jawnego zarządzania pamięcią podręczną, które zapewniają deweloperom większą kontrolę nad sposobem tworzenia, wyszukiwania, używania i usuwania pamięci podręcznej. Te operacje ręczne działają niezależnie od automatycznego zarządzania pamięcią podręczną przez system.

Ten przykład pokazuje, jak zainicjować jawne zarządzanie pamięcią podręczną i przeprowadzić wnioskowanie:

Kotlin

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
  }
)

Java

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();

Ten przykład pokazuje, jak wysyłać zapytania, pobierać i usuwać pamięci podręczne zarządzane jawnie za pomocą generativeModel.caches:

Kotlin

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)

Java

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);