Apprendi le conoscenze fondamentali per la creazione di app IA, in un inglese semplice
Retrieval Augmented Generation, o RAG, è di gran moda in questi giorni perché introduce alcune funzionalità importanti in modelli linguistici di grandi dimensioni come GPT-4 di OpenAI, ovvero la capacità di utilizzare e sfruttare i propri dati.
Questo post ti insegnerà l'intuizione fondamentale dietro RAG fornendo allo stesso tempo un semplice tutorial per aiutarti a iniziare.
C'è così tanto rumore nello spazio dell'intelligenza artificiale e in particolare su RAG. I venditori stanno cercando di complicarlo eccessivamente. Stanno cercando di introdurre i loro strumenti, i loro ecosistemi, la loro visione.
Sta rendendo RAG molto più complicato di quanto dovrebbe essere. Questo tutorial è progettato per aiutare i principianti a imparare come creare applicazioni RAG da zero. Nessuna sciocchezza, nessun gergo (ok, minimo), nessuna libreria, solo una semplice applicazione RAG passo dopo passo.
Jerry di LlamaIndex sostiene la costruzione di cose da zero per comprendere veramente i pezzi. Una volta fatto, usare una libreria come LlamaIndex ha più senso.
Costruisci da zero per imparare, quindi costruisci con le librerie per adattarlo.
Cominciamo!
Potresti o meno aver sentito parlare di Retrieval Augmented Generation o RAG.
Ecco la definizione da il post sul blog che introduce il concetto da Facebook:
Costruire un modello che ricerca e contestualizza è più impegnativo, ma è essenziale per i progressi futuri. Recentemente abbiamo compiuto progressi sostanziali in questo ambito con la nostra architettura Retrieval Augmented Generation (RAG), un modello differenziabile end-to-end che combina un componente di recupero delle informazioni (il sistema di recupero dei passaggi densi di Facebook AI) con un generatore seq2seq (il nostro Modello dei trasformatori bidirezionali e auto-regressivi (BART). RAG può essere messo a punto su attività downstream ad alta intensità di conoscenza per ottenere risultati all'avanguardia rispetto anche ai più grandi modelli linguistici seq2seq preaddestrati. E a differenza di questi modelli preaddestrati, la conoscenza interna di RAG può essere facilmente modificata o addirittura integrata al volo, consentendo a ricercatori e ingegneri di controllare ciò che RAG sa e non sa senza perdere tempo o potenza di calcolo riqualificando l'intero modello.
Wow, è un boccone.
Semplificando la tecnica per i principianti, possiamo affermare che l'essenza di RAG consiste nell'aggiungere i propri dati (tramite uno strumento di recupero) al prompt che si passa in un modello linguistico di grandi dimensioni. Di conseguenza, ottieni un output. Ciò ti offre diversi vantaggi:
- Puoi includere fatti nel prompt per aiutare il LLM a evitare allucinazioni
- Puoi fare riferimento (manualmente) a fonti di verità quando rispondi alla domanda di un utente, aiutandoti a ricontrollare eventuali potenziali problemi.
- È possibile sfruttare i dati su cui il LLM potrebbe non essere stato formato.
- una raccolta di documenti (formalmente chiamata corpus)
- Un input da parte dell'utente
- una misura di similarità tra la raccolta di documenti e l'input dell'utente
Sì, è così semplice.
Per iniziare ad apprendere e comprendere i sistemi basati su RAG, non è necessario un archivio di vettori, non è nemmeno necessario Bisogno un LLM (almeno per imparare e comprendere concettualmente).
Anche se spesso viene descritto come complicato, non deve esserlo.
Eseguiremo i seguenti passaggi in sequenza.
- Ricevi un input dall'utente
- Esegui la nostra misura di somiglianza
- Postelaborare l'input dell'utente e i documenti recuperati.
La post-elaborazione viene eseguita con un LLM.
Il vero documento RAG è ovviamente IL risorsa. Il problema è che presuppone MOLTO contesto. È più complicato di quanto abbiamo bisogno.
Ad esempio, ecco la panoramica del sistema RAG proposto nel documento.
È denso.
È fantastico per i ricercatori, ma per il resto di noi sarà molto più facile imparare passo dopo passo costruendo il sistema da soli.
Torniamo a costruire RAG da zero, passo dopo passo. Ecco i passaggi semplificati su cui lavoreremo. Anche se tecnicamente non è “RAG”, è un buon modello semplificato con cui imparare e che ci consente di progredire verso variazioni più complicate.
Qui sotto puoi vedere che abbiamo un semplice corpus di “documenti” (per favore sii generoso 😉).
corpus_of_documents = (
"Take a leisurely walk in the park and enjoy the fresh air.",
"Visit a local museum and discover something new.",
"Attend a live music concert and feel the rhythm.",
"Go for a hike and admire the natural scenery.",
"Have a picnic with friends and share some laughs.",
"Explore a new cuisine by dining at an ethnic restaurant.",
"Take a yoga class and stretch your body and mind.",
"Join a local sports league and enjoy some friendly competition.",
"Attend a workshop or lecture on a topic you're interested in.",
"Visit an amusement park and ride the roller coasters."
)
Ora abbiamo bisogno di un modo per misurare la somiglianza tra i input dell'utente riceveremo e il collezione di documenti che abbiamo organizzato. Probabilmente la misura di somiglianza più semplice è somiglianza con Jaccard. Ne ho scritto in passato (vedi questo post ma la risposta breve è che il somiglianza con Jaccard è l'intersezione divisa dall'unione degli “insiemi” di parole.
Ciò ci consente di confrontare l'input dell'utente con i documenti di origine.
Nota a margine: preelaborazione
Una sfida è che se abbiamo una stringa semplice come "Take a leisurely walk in the park and enjoy the fresh air.",
dovremo pre-elaborarlo in un set, in modo da poter eseguire questi confronti. Lo faremo nel modo più semplice possibile, minuscolo e diviso " "
.
def jaccard_similarity(query, document):
query = query.lower().split(" ")
document = document.lower().split(" ")
intersection = set(query).intersection(set(document))
union = set(query).union(set(document))
return len(intersection)/len(union)
Ora dobbiamo definire una funzione che accetti la query esatta e il nostro corpus e selezioni il documento “migliore” da restituire all'utente.
def return_response(query, corpus):
similarities = ()
for doc in corpus:
similarity = jaccard_similarity(query, doc)
similarities.append(similarity)
return corpus_of_documents(similarities.index(max(similarities)))
Ora possiamo eseguirlo, inizieremo con un semplice prompt.
user_prompt = "What is a leisure activity that you like?"
E un semplice input da parte dell'utente…
user_input = "I like to hike"
Ora possiamo restituire la nostra risposta.
return_response(user_input, corpus_of_documents)
'Go for a hike and admire the natural scenery.'
Congratulazioni, hai creato un'applicazione RAG di base.
Ho 99 problemi e una brutta somiglianza è uno
Ora abbiamo optato per una semplice misura di somiglianza per l'apprendimento. Ma questo sarà problematico perché è così semplice. Non ne ha idea semantica. Basta guardare quali parole ci sono in entrambi i documenti. Ciò significa che se forniamo un esempio negativo, otterremo lo stesso “risultato” perché quello è il documento più vicino.
user_input = "I don't like to hike"
return_response(user_input, corpus_of_documents)
'Go for a hike and admire the natural scenery.'
Questo è un argomento che verrà fuori molto con “RAG”, ma per ora, stai certo che affronteremo questo problema più tardi.
A questo punto, non abbiamo effettuato alcuna post-elaborazione del “documento” a cui stiamo rispondendo. Finora abbiamo implementato solo la parte di “recupero” di “Retrieval-Augmented Generation”. Il prossimo passo è aumentare la generazione incorporando un modello linguistico di grandi dimensioni (LLM).
Per fare ciò, utilizzeremo essere per essere subito operativi con un LLM open source sul nostro computer locale. Potremmo usare altrettanto facilmente gpt-4 di OpenAI o Claude di Anthropic, ma per ora inizieremo con l'open source llama2 di MetaIA.
Questo post presuppone una conoscenza di base dei modelli linguistici di grandi dimensioni, quindi passiamo subito a interrogare questo modello.
import requests
import json
Per prima cosa definiremo gli input. Per lavorare con questo modello, prenderemo
- input dell'utente,
- recuperare il documento più simile (misurato dalla nostra misura di somiglianza),
- passarlo in un prompt per il modello linguistico,
- Poi restituire il risultato all'utente
Ciò introduce un nuovo termine, the richiesta. In breve, sono le istruzioni che fornisci al LLM.
Quando esegui questo codice, vedrai il risultato dello streaming. Lo streaming è importante per l'esperienza dell'utente.
user_input = "I like to hike"
relevant_document = return_response(user_input, corpus_of_documents)
full_response = ()
prompt = """
You are a bot that makes recommendations for activities. You answer in very short sentences and do not include extra information.
This is the recommended activity: {relevant_document}
The user input is: {user_input}
Compile a recommendation to the user based on the recommended activity and the user input.
"""
Avendolo definito, effettuiamo ora la chiamata API a ollama (e llama2). un passo importante è assicurarsi che ollama sia già in esecuzione sul tuo computer locale eseguendo ollama serve
.
Nota: questo potrebbe essere lento sulla tua macchina, lo è sicuramente sulla mia. Sii paziente, giovane cavalletta.
url = 'http://localhost:11434/api/generate'
data = {
"model": "llama2",
"prompt": prompt.format(user_input=user_input, relevant_document=relevant_document)
}
headers = {'Content-Type': 'application/json'}
response = requests.post(url, data=json.dumps(data), headers=headers, stream=True)
try:
count = 0
for line in response.iter_lines():
# filter out keep-alive new lines
# count += 1
# if count % 5== 0:
# print(decoded_line('response')) # print every fifth token
if line:
decoded_line = json.loads(line.decode('utf-8'))full_response.append(decoded_line('response'))
finally:
response.close()
print(''.join(full_response))
Great! Based on your interest in hiking, I recommend trying out the nearby trails for a challenging and rewarding experience with breathtaking views Great! Based on your interest in hiking, I recommend checking out the nearby trails for a fun and challenging adventure.
Questo ci dà un'applicazione RAG completa, da zero, senza fornitori, senza servizi. Conosci tutti i componenti di un'applicazione di generazione aumentata di recupero. Visivamente, ecco cosa abbiamo costruito.
Il LLM (se sei fortunato) gestirà l'input dell'utente che va contro il documento consigliato. Possiamo vederlo qui sotto.
user_input = "I don't like to hike"
relevant_document = return_response(user_input, corpus_of_documents)
# https://github.com/jmorganca/ollama/blob/main/docs/api.md
full_response = ()
prompt = """
You are a bot that makes recommendations for activities. You answer in very short sentences and do not include extra information.
This is the recommended activity: {relevant_document}
The user input is: {user_input}
Compile a recommendation to the user based on the recommended activity and the user input.
"""
url = 'http://localhost:11434/api/generate'
data = {
"model": "llama2",
"prompt": prompt.format(user_input=user_input, relevant_document=relevant_document)
}
headers = {'Content-Type': 'application/json'}
response = requests.post(url, data=json.dumps(data), headers=headers, stream=True)
try:
for line in response.iter_lines():
# filter out keep-alive new lines
if line:
decoded_line = json.loads(line.decode('utf-8'))
# print(decoded_line('response')) # uncomment to results, token by token
full_response.append(decoded_line('response'))
finally:
response.close()
print(''.join(full_response))
Sure, here is my response:Try kayaking instead! It's a great way to enjoy nature without having to hike.
Se torniamo al nostro diagramma dell'applicazione RAG e pensiamo a ciò che abbiamo appena costruito, vedremo varie opportunità di miglioramento. Queste opportunità sono il luogo in cui vengono coinvolti strumenti come archivi di vettori, incorporamenti e “ingegneria” immediata.
Ecco dieci potenziali aree in cui potremmo migliorare la configurazione attuale:
- Il numero di documenti ðŸ'‰ più documenti potrebbero significare più raccomandazioni.
- La profondità/dimensione dei documenti ðŸ'‰ contenuti di qualità superiore e documenti più lunghi con più informazioni potrebbero essere migliori.
- Il numero di documenti che forniamo al LLM ðŸ'‰ In questo momento, stiamo dando al LLM solo un documento. Potremmo inserirne diversi come “contesto” e consentire al modello di fornire consigli più personalizzati in base all'input dell'utente.
- Le parti dei documenti che diamo al LLM ðŸ'‰ Se disponiamo di documenti più grandi o più approfonditi, potremmo semplicemente voler aggiungere parti di tali documenti, parti di vari documenti o qualche variazione degli stessi. Nel lessico questo si chiama “chunking”.
- Il nostro strumento di archiviazione dei documenti ðŸ'‰ Potremmo archiviare i nostri documenti in un modo diverso o in un database diverso. In particolare, se disponiamo di molti documenti, potremmo valutare l'idea di archiviarli in un data Lake o in un archivio vettoriale.
- La misura della somiglianza ðŸ'‰ Il modo in cui misuriamo la somiglianza è importante, potremmo dover bilanciare prestazioni e accuratezza (ad esempio, esaminando ogni singolo documento).
- La pre-elaborazione dei documenti e l'input dell'utente ðŸ'‰ Potremmo eseguire qualche ulteriore preelaborazione o aumento dell'input dell'utente prima di passarlo alla misura di somiglianza. Ad esempio, potremmo utilizzare un incorporamento per convertire l'input in un vettore.
- La misura della somiglianza ðŸ'‰ Possiamo modificare la misura di somiglianza per recuperare documenti migliori o più pertinenti.
- Il modello ðŸ'‰ Possiamo cambiare il modello finale che utilizziamo. Stiamo usando llama2 sopra, ma potremmo altrettanto facilmente usare un modello antropico o Claude.
- Il suggerimento ðŸ'‰ Potremmo utilizzare un prompt diverso nel LLM/Modello e ottimizzarlo in base all'output che vogliamo ottenere.
- Se sei preoccupato per i risultati nocivi o tossici ðŸ'‰ Potremmo implementare una sorta di “interruttore automatico” che gestisce l'input dell'utente per vedere se ci sono discussioni tossiche, dannose o pericolose. Ad esempio, in un contesto sanitario potresti vedere se le informazioni contengono lingue non sicure e rispondere di conseguenza, al di fuori del flusso tipico.
L'ambito di miglioramento non si limita a questi punti; le possibilità sono vaste e le approfondiremo nei tutorial futuri. Fino ad allora, non esitate a farlo contattaci su Twitter se hai qualche domanda. Buon RAGING :).
Questo post è stato originariamente pubblicato su learnbybuilding.ai. Nei prossimi mesi terrò un corso su come creare prodotti di intelligenza artificiale generativa per i product manager. iscriviti qui.
Fonte: towardsdatascience.com