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 (automatyczne) buforowanie prefiksów to uproszczone rozwiązanie, w którym aplikacja musi tylko zdefiniować wspólną część prompta.
- Jawne (ręczne) buforowanie prefiksów pozwala aplikacjom mieć większą kontrolę nad pamięcią podręczną, w tym nad jej tworzeniem, wyszukiwaniem i usuwaniem.
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);