Cache dei LLM generativi | Risparmio sui costi API

Cache LLM generativi | Risparmio costi API

Introduzione

L’IA generativa si è diffusa così tanto che molti di noi saranno o avranno già iniziato a lavorare su applicazioni che coinvolgono modelli di IA generativa, che si tratti di generatori di immagini o dei famosi modelli di linguaggio di grandi dimensioni. Molti di noi lavorano con modelli di linguaggio di grandi dimensioni, in particolare quelli a codice chiuso come OpenAI, dove dobbiamo pagare per utilizzare i modelli sviluppati da loro. Ora, se siamo abbastanza attenti, possiamo ridurre al minimo i costi quando lavoriamo con questi modelli, ma in qualche modo i prezzi si accumulano molto. Ed è su questo che ci concentreremo in questo articolo, ovvero sulla cattura delle risposte/chiamate API inviate ai modelli di linguaggio di grandi dimensioni. Sei entusiasta di imparare a fare il caching dei LLM generativi?

Obiettivi di Apprendimento

  • Comprendere cosa sia il caching e come funziona
  • Imparare come fare il caching dei modelli di linguaggio di grandi dimensioni
  • Imparare diversi modi per fare il caching dei LLM in LangChain
  • Comprendere i potenziali vantaggi del caching e come riduce i costi delle API

Questo articolo è stato pubblicato come parte del Data Science Blogathon.

Cos’è il Caching? Perché è Necessario?

Una cache è un luogo in cui archiviare temporaneamente i dati in modo che possano essere riutilizzati, e il processo di archiviazione di questi dati è chiamato caching. Qui vengono archiviati i dati più frequentemente utilizzati per potervi accedere più velocemente. Questo ha un effetto drastico sulle prestazioni del processore. Immaginiamo il processore che esegue un’attività intensiva che richiede molto tempo di calcolo. Ora immaginiamo una situazione in cui il processore deve eseguire nuovamente il calcolo esatto. In questo scenario, il caching del risultato precedente aiuta davvero. Ciò ridurrà il tempo di calcolo, poiché il risultato è stato memorizzato nella cache quando l’attività è stata eseguita.

Nel tipo di cache descritto sopra, i dati vengono memorizzati nella cache del processore e la maggior parte dei processi rientra in una memoria cache integrata. Ma ciò potrebbe non essere sufficiente per altre applicazioni. Quindi, in questi casi, la cache viene memorizzata nella RAM. L’accesso ai dati dalla RAM è molto più veloce rispetto a un hard disk o un SSD. Il caching può anche ridurre i costi delle chiamate API. Supponiamo che inviamo una richiesta simile al modello Open AI. Verrà addebitato un costo per ogni richiesta inviata e il tempo impiegato per rispondere sarà maggiore. Ma se memorizziamo in cache queste chiamate, possiamo prima cercare nella cache per verificare se abbiamo inviato una richiesta simile al modello e, se l’abbiamo fatto, anziché chiamare l’API, possiamo recuperare i dati, ovvero la risposta, dalla cache.

Caching nei Modelli di Linguaggio di Grandi Dimensioni

Sappiamo che i modelli a codice chiuso come GPT 3.5 di OpenAI e altri addebitano all’utente le chiamate API effettuate ai loro modelli generativi di linguaggio di grandi dimensioni. Il costo o il costo associato alla chiamata API dipende principalmente dal numero di token passati. Più è grande il numero di token, più alto è il costo associato. Questo deve essere gestito con attenzione in modo da non pagare somme elevate.

Ora, un modo per risolvere questo problema o ridurre i costi delle chiamate API è fare il caching delle richieste e delle risposte corrispondenti. Quando inviamo per la prima volta una richiesta al modello e otteniamo la risposta corrispondente, la memorizziamo nella cache. Ora, quando viene inviata un’altra richiesta, prima di inviarla al modello, cioè prima di effettuare una chiamata API, verificheremo se la richiesta è simile a una delle richieste salvate nella cache; se lo è, prenderemo la risposta dalla cache anziché inviare la richiesta al modello (cioè fare una chiamata API) e quindi ottenere la risposta da esso.

Ciò permetterà di risparmiare costi ogni volta che richiediamo prompt simili al modello, e anche il tempo di risposta sarà inferiore, poiché lo stiamo ottenendo direttamente dalla cache anziché inviare una richiesta al modello e quindi ottenere una risposta da esso. In questo articolo, vedremo diversi modi per memorizzare nella cache le risposte del modello.

Caching con la InMemoryCache di LangChain

Sì, hai letto bene. Possiamo memorizzare nella cache le risposte e le chiamate al modello con la libreria LangChain. In questa sezione, vedremo come configurare il meccanismo di caching e vedremo anche degli esempi per assicurarci che i nostri risultati vengano memorizzati nella cache e che le risposte alle query simili vengano prese dalla cache. Iniziamo scaricando le librerie necessarie.

!pip install langchain openai

Per iniziare, installa tramite pip le librerie LangChain e OpenAI. Lavoreremo con i modelli OpenAI e vedremo come vengono tariffate le nostre chiamate API e come possiamo lavorare con la cache per ridurre i costi. Ora iniziamo con il codice.

import os
import openai
from langchain.llms import OpenAI


os.environ["OPENAI_API_KEY"] = "La tua chiave API"

llm = OpenAI(model_name="text-davinci-002", openai_api_key=os.environ["OPENAI_API_KEY"])

llm("Chi è stata la prima persona a andare nello spazio?")

  • Qui abbiamo impostato il modello OpenAI con cui lavorare. Dobbiamo fornire la chiave API di OpenAI alla funzione os.environ[] per memorizzare la nostra chiave API nella variabile di ambiente OPNEAI_API_KEY.
  • Poi importiamo il wrapper LLM di LangChain per OpenAI. Il modello su cui stiamo lavorando è “text-davinci-002” e alla funzione OpenAI() passiamo anche la variabile di ambiente che contiene la nostra chiave API.
  • Per testare il funzionamento del modello, possiamo effettuare le chiamate API e interrogare l’LLM con una semplice domanda.
  • Possiamo vedere la risposta generata dall’LLM nell’immagine sopra. Ciò garantisce che il modello sia attivo e funzionante e che possiamo inviare richieste al modello e ottenere risposte generate da esso.

Caching tramite LangChain

Analizziamo ora la memorizzazione nella cache tramite LangChain.

import langchain
from langchain.cache import InMemoryCache
from langchain.callbacks import get_openai_callback


langchain.llm_cache = InMemoryCache()
  • La libreria LangChain ha una funzione integrata per la memorizzazione nella cache chiamata InMemoryCache. Lavoreremo con questa funzione per memorizzare nella cache gli LLM.
  • Per iniziare la memorizzazione nella cache con LangChain, passiamo la funzione InMemoryCache() a langchain.llm_cache
  • Quindi, qui, prima di tutto, stiamo creando una cache LLM in LangChain utilizzando langchain.llm_cache
  • Poi prendiamo InMemoryCache (una tecnica di memorizzazione nella cache) e la passiamo a langchain.llm_cache
  • In questo modo creeremo una InMemoryCache per noi in LangChain. Possiamo sostituire InMemoryCache con quello con cui vogliamo lavorare per utilizzare un meccanismo di memorizzazione nella cache diverso.
  • Stiamo anche importando get_openai_callback. Questo ci fornirà informazioni sul numero di token passati al modello quando viene effettuata una chiamata API, il costo sostenuto, il numero di token di risposta e il tempo di risposta.

Interrogare l’LLM

Ora interroghiamo l’LLM, memorizziamo la risposta, quindi interroghiamo l’LLM per verificare se la memorizzazione nella cache sta funzionando e se le risposte vengono memorizzate e recuperate dalla cache quando vengono poste domande simili.

%%time
import time


with get_openai_callback() as cb:
  start = time.time()
  result = llm("Qual è la distanza tra Terra e Luna?")
  end = time.time()
  print("Tempo impiegato per la risposta",end-start)
  print(cb)
  print(result)

Funzione del tempo

Nel codice sopra, utilizziamo la funzione %% timeline in colab per indicarci il tempo impiegato dalla cella per eseguire. Importiamo anche la funzione time per ottenere il tempo impiegato per effettuare la chiamata API e ottenere la risposta. Come già detto, stiamo lavorando con get_openai_callback(). La stampiamo dopo aver passato la query al modello. Questa funzione stamperà il numero di token passati, il costo del trattamento della chiamata API e il tempo impiegato. Vediamo l’output qui sotto.

L’output mostra che il tempo impiegato per elaborare la richiesta è di 0,8 secondi. Possiamo anche vedere il numero di token nella query prompt che abbiamo inviato, che è 9, e il numero di token nell’output generato, cioè 21. Possiamo anche vedere il costo del trattamento della nostra chiamata API nei callback generati, cioè $0.0006. Il tempo della CPU è di 9 millisecondi. Ora proviamo a eseguire di nuovo il codice con la stessa query e vediamo l’output generato.

Qui vediamo una differenza significativa nel tempo impiegato per la risposta. Sono necessari 0,0003 secondi, che sono 2666 volte più veloci rispetto alla prima volta che è stato eseguito. Anche nell’output del callback, vediamo che il numero di token di prompt è 0, il costo è di $0 e i token di output sono anch’essi 0. Anche le richieste di successo sono impostate su 0, indicando che nessuna chiamata / richiesta API è stata inviata al modello. Invece, è stato recuperato dalla cache.

Con questo, possiamo dire che LangChain ha memorizzato nella cache il prompt e la risposta generata dal Modello di Linguaggio di Grandi Dimensioni di OpenAI quando è stato eseguito per lo stesso prompt l’ultima volta. Questo è il metodo per memorizzare nella cache i LLM attraverso la funzione InMemoryCache() di LangChain.

Memorizzazione nella cache con SQLiteCache

Un altro modo per memorizzare nella cache i prompt e le risposte dei Modelli di Linguaggio di Grandi Dimensioni è tramite SQLiteCache. Iniziamo con il codice per farlo

from langchain.cache import SQLiteCache

langchain.llm_cache = SQLiteCache(database_path=".langchain.db")

Qui definiamo la Cache LLM in LangChain allo stesso modo in cui abbiamo definito in precedenza. Ma qui, stiamo utilizzando un metodo di memorizzazione nella cache diverso. Stiamo lavorando su SQLiteCache, che memorizza i prompt del database e le risposte dei Modelli di Linguaggio di Grandi Dimensioni. Forniamo anche il percorso del database in cui memorizzare questi prompt e risposte. Qui sarà langchain.db.

Quindi proviamo a testare il meccanismo di memorizzazione nella cache come abbiamo fatto prima. Eseguiamo una query al Modello di Linguaggio di Grandi Dimensioni di OpenAI due volte e verifichiamo se i dati vengono memorizzati nella cache osservando l’output generato nella seconda esecuzione. Il codice per questo sarà

%%time
import time

start = time.time()
result = llm("Chi ha creato la bomba atomica?")
end = time.time()
print("Tempo richiesto per la risposta",end-start)
print(result)

%%time
import time

start = time.time()
result = llm("Chi ha creato la bomba atomica?")
end = time.time()
print("Tempo richiesto per la risposta",end-start)
print(result)

Nella prima uscita, quando abbiamo eseguito per la prima volta la query al Modello di Linguaggio di Grandi Dimensioni, ci sono voluti 0,7 secondi per inviare la richiesta al modello e ottenere la risposta. Ma quando proviamo a eseguire la stessa query al Modello di Linguaggio di Grandi Dimensioni, vediamo che il tempo richiesto per la risposta è di 0,002 secondi. Questo dimostra che quando la query “Chi ha creato la bomba atomica” è stata eseguita per la prima volta, sia il Prompt che la risposta generata dal Modello di Linguaggio di Grandi Dimensioni sono stati memorizzati nella cache SQLiteCache.

Poi, quando abbiamo eseguito la stessa query per la seconda volta, ha prima cercato nella cache e, poiché era disponibile, ha semplicemente preso la risposta corrispondente dalla cache anziché inviare una richiesta al modello di OpenAI e ottenere una risposta. Quindi questa è un altro modo per memorizzare nella cache i Modelli di Linguaggio di Grandi Dimensioni.

Vantaggi della memorizzazione nella cache

Riduzione dei costi

La memorizzazione nella cache riduce significativamente i costi dell’API quando si lavora con Modelli di Linguaggio di Grandi Dimensioni. I costi dell’API sono associati all’invio di una richiesta al modello e alla ricezione della sua risposta. Quindi più richieste inviamo al Modello di Linguaggio Generativo di Grandi Dimensioni, maggiori sono i costi. Abbiamo visto che quando abbiamo eseguito la stessa query per la seconda volta, la risposta per la query è stata presa dalla cache anziché inviare una richiesta al modello per generare una risposta. Questo aiuta molto quando si ha un’applicazione in cui vengono inviate molte volte query simili ai Modelli di Linguaggio di Grandi Dimensioni.

Aumento delle prestazioni / Riduzione del tempo di risposta

Sì. La memorizzazione nella cache aiuta a migliorare le prestazioni. Anche se non direttamente ma indirettamente. Un aumento delle prestazioni si ha quando memorizziamo le risposte che richiedono molto tempo per essere calcolate dal processore e poi dobbiamo ricalcolarle nuovamente. Ma se le abbiamo memorizzate nella cache, possiamo accedere direttamente alla risposta anziché ricalcolarla. In questo modo, il processore può dedicare tempo ad altre attività.

Quando si tratta di memorizzare nella cache Large Language Models, memorizziamo sia la Prompt che la risposta. Quindi, quando ripetiamo una query simile, la risposta viene presa dalla cache anziché inviare una richiesta al modello. Ciò ridurrà significativamente il tempo di risposta, poiché proviene direttamente dalla cache anziché inviare una richiesta al modello e ricevere una risposta. Abbiamo persino controllato le velocità di risposta nei nostri esempi.

Conclusioni

In questo articolo, abbiamo appreso come funziona la memorizzazione nella cache in LangChain. Hai acquisito una comprensione di cosa sia la memorizzazione nella cache e quale sia il suo scopo. Abbiamo anche visto i potenziali benefici di lavorare con una cache anziché senza una. Abbiamo esaminato diversi modi di memorizzare nella cache Large Language Models in LangChain (InMemoryCache e SQLiteCache). Attraverso esempi, abbiamo scoperto i vantaggi dell’utilizzo di una cache, come può ridurre i costi delle nostre applicazioni e, allo stesso tempo, garantire risposte rapide.

Punti chiave

Alcuni dei punti chiave di questa guida includono:

  • La memorizzazione nella cache è un modo per archiviare informazioni che possono poi essere recuperate in un momento successivo
  • I Large Language Models possono essere memorizzati nella cache, dove la Prompt e la risposta generate sono quelle salvate nella memoria cache.
  • LangChain consente diverse tecniche di memorizzazione nella cache, tra cui InMemoryCache, SQLiteCache, Redis e molte altre.
  • La memorizzazione nella cache dei Large Language Models comporterà meno chiamate API ai modelli, una riduzione dei costi delle API e fornirà risposte più veloci.

Domande frequenti

I media mostrati in questo articolo non sono di proprietà di Analytics Vidhya e vengono utilizzati a discrezione dell’autore.