Oltre l’inglese: implementare una soluzione RAG multilingue |  di Jesper Alkestrup |  Dicembre 2023

 | Intelligenza-Artificiale

Dividere il testo in modo semplice (Immagine generata dall’autore w. Dall-E 3)

Quando si preparano i dati per l’incorporamento e il recupero in un sistema RAG, è fondamentale suddividere il testo in blocchi di dimensioni adeguate. Questo processo è guidato da due fattori principali, i vincoli del modello e l’efficacia del recupero.

Vincoli del modello

I modelli di incorporamento hanno una lunghezza massima del token per l’input; qualsiasi cosa oltre questo limite viene troncata. Tieni presente le limitazioni del modello scelto e assicurati che ogni blocco di dati non superi la lunghezza massima del token.

I modelli multilingue, in particolare, hanno spesso limiti di sequenza più brevi rispetto alle loro controparti inglesi. Ad esempio, il modello MiniLM-L12 v2 multilingue Paraphrase ampiamente utilizzato ha una finestra di contesto massima di soli 128 token.

Inoltre, considera la lunghezza del testo su cui è stato addestrato il modello: alcuni modelli potrebbero tecnicamente accettare input più lunghi ma sono stati addestrati su blocchi più brevi, il che potrebbe influire sulle prestazioni su testi più lunghi. Uno di questi è un esempio, è il Base Multi QA di SBERT come visto di seguito,

Efficacia del recupero

Sebbene suddividere i dati in blocchi fino alla lunghezza massima del modello sembri logico, potrebbe non portare sempre ai migliori risultati di recupero. I blocchi più grandi offrono più contesto per il LLM ma possono oscurare i dettagli chiave, rendendo più difficile il recupero di corrispondenze precise. Al contrario, porzioni più piccole possono migliorare la precisione della corrispondenza ma potrebbero non avere il contesto necessario per risposte complete. Gli approcci ibridi utilizzano blocchi più piccoli per la ricerca ma includono il contesto circostante al momento della query per bilanciare.

Sebbene non esista una risposta definitiva per quanto riguarda la dimensione del blocco, le considerazioni relative alla dimensione del blocco rimangono coerenti sia che si lavori su progetti multilingue o in inglese. Consiglierei di leggere ulteriori approfondimenti sull’argomento da risorse come Valutazione della dimensione ideale del blocco per il sistema RAG utilizzando Llamaindex O Creazione di applicazioni LLM basate su RAG per la produzione.

Suddivisione del testo: metodi per suddividere il testo

Il testo può essere diviso utilizzando vari metodirientrano principalmente in due categorie: modelli basati su regole (concentrati sull’analisi dei personaggi) e modelli basati sull’apprendimento automatico. Gli approcci ML, dai semplici tokenizzatori NLTK e Spacy ai modelli di trasformazione avanzati, spesso dipendono da una formazione specifica per lingua, principalmente in inglese. Sebbene modelli semplici come NLTK e Spacy supportino più lingue, affrontano principalmente la suddivisione delle frasi, non il sezionamento semantico.

Poiché i divisori di frasi basati su ML attualmente funzionano male per la maggior parte delle lingue diverse dall’inglese e richiedono un’elaborazione intensiva, consiglio di iniziare con un semplice divisore basato su regole. Se hai conservato la struttura sintattica pertinente dei dati originali e hai formattato correttamente i dati, il risultato sarà di buona qualità.

Un metodo comune ed efficace è uno divisore di testo di caratteri ricorsivo, come quelli utilizzati in LangChain o LlamaIndex, che accorcia le sezioni trovando il carattere diviso più vicino in una sequenza con priorità (ad esempio, \n\n, \n, ., ?, !).

Prendendo il testo formattato dalla sezione precedente, un esempio di utilizzo dello splitter di caratteri ricorsivo di LangChains sarebbe simile a:

from langchain.text_splitter import RecursiveCharacterTextSplitter
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("intfloat/e5-base-v2")

def token_length_function(text_input):
return len(tokenizer.encode(text_input, add_special_tokens=False))

text_splitter = RecursiveCharacterTextSplitter(
# Set a really small chunk size, just to show.
chunk_size = 128,
chunk_overlap = 0,
length_function = token_length_function,
separators = ("\n\n", "\n", ". ", "? ", "! ")
)

split_texts = text_splitter(formatted_document('Boosting RAG: Picking the Best Embedding & Reranker models'))

Qui è importante notare che si dovrebbe definire il tokenizer come il modello di incorporamento che si intende utilizzare, poiché diversi modelli “contano” le parole in modo diverso. La funzione ora, in ordine di priorità, dividerà qualsiasi testo più lungo di 128 token prima in base al \n\n introdotto alla fine delle sezioni e, se ciò non è possibile, quindi alla fine dei paragrafi delimitati da \n e così via . I primi 3 pezzi saranno:

Token of text: 111 

UPDATE: The pooling method for the Jina AI embeddings has been adjusted to use mean pooling, and the results have been updated accordingly. Notably, the JinaAI-v2-base-en with bge-reranker-largenow exhibits a Hit Rate of 0.938202 and an MRR (Mean Reciprocal Rank) of 0.868539 and withCohereRerank exhibits a Hit Rate of 0.932584, and an MRR of 0.873689.

-----------

Token of text: 112

When building a Retrieval Augmented Generation (RAG) pipeline, one key component is the Retriever. We have a variety of embedding models to choose from, including OpenAI, CohereAI, and open-source sentence transformers. Additionally, there are several rerankers available from CohereAI and sentence transformers.
But with all these options, how do we determine the best mix for top-notch retrieval performance? How do we know which embedding model fits our data best? Or which reranker boosts our results the most?

-----------

Token of text: 54

In this blog post, we’ll use the Retrieval Evaluation module from LlamaIndex to swiftly determine the best combination of embedding and reranker models. Let's dive in!
Let’s first start with understanding the metrics available in Retrieval Evaluation

Ora che abbiamo suddiviso con successo il testo in modo semanticamente significativo, possiamo passare alla parte finale dell’incorporamento di questi blocchi per l’archiviazione.

Fonte: towardsdatascience.com

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *