I modi in cui i documenti possono entrare a far parte del nostro sistema sono disparati pertanto anche un ambito che potrebbe sembrare il più lineare dell’architettura si dirama in varie vie. Analizzeremo insieme, con tutti i dovuti esempi, l’uso di Document loader per acquisire documenti da integrare in una struttura dati in attesa che uno splitter li sminuzzi per una loro miglior digestione nella RAG.
Ci baseremo sempre sulla libreria Langchain ed in particolare sulla versione 0.3, attualmente la più recente. In Python, la richiederemo in questo modo:
pip install langchain==0.3 langchain-community
Da ricordare che, se lo si esegue in un notebook Google Colab, sarà il caso di anteporre un punto esclamativo (!
) per indicare che non si tratta di un’istruzione Python bensì di una direttiva da riga di comando Linux.
TextLoader e RAG: un documento alla volta
L’opzione più basilare consiste nel TextLoader
, un oggetto che legge un file di testo e lo carica come documento. Iniziamo con l’interpretazione di un testo di nome documento.txt
:
from langchain_community.document_loaders.text import TextLoader
loader = TextLoader(
"documento.txt",
encoding=None,
autodetect_encoding=True
)
Questo codice produce un oggetto in grado di elaborare un testo. Si noti che abbiamo applicato un paio di argomenti riguardanti l’encoding per evitare errate interpretazioni dei caratteri. Qui chiediamo di non applicare un encoding specifico ma di provare lui stesso – il Loader – ad individuare il migliore procedendo per tentativi. Fatto ciò passiamo all’estrazione dei contenuti con:
documenti = loader.load()
A questo punto l’operazione è svolta e ci troviamo in possesso di documenti
, una lista di oggetti di tipo Document
(classe definita in Langchain). Avendo interpretato un solo documento avremo a che fare con una lista di un solo item che sarà il documento che rappresenta il file da noi fornito.
E’ importante conoscere come è fatto un oggetto Document
in quanto sarà il frutto di qualsiasi Loader useremo. Al suo interno tipicamente troviamo due porzioni principali:
page_content
, una stringa che immagazzina tutto il testo del documento. In quanto stringa, ovviamente, in Python è sottoponibile con facilità a miriadi di operazioni di elaborazione;metadata
, un dizionario Python in cui vengono fissati parametri utili a definire correttamente il contenuto del documento. Nel nostro caso, i metadati prodotti coincideranno con{'source': 'documento.txt'}
, in pratica solo il nome del file di origine.
Passiamo ora al caricamento di tutti i documenti presenti in una cartella, caso ancora più comune rispetto ad un singolo testo.
DirectoryLoader e RAG: una cartella intera
Supponiamo di avere una cartella di nome archivio
che include molti documenti di testo. Il nostro scopo è acquisirli tutti in una struttura dati. Quanto visto al paragrafo precedente ci sembra già adeguato in quanto, in fin dei conti, abbiamo fatto uso di un oggetto specifico, Document
che andrà bene anche per ognuno dei documenti che tratteremo in questo esempio ed il risultato del Loader consisteva già in una lista, seppur di un solo item, pertanto in grado di ospitare potenzialmente una moltitudine di elementi.
La classe di cui facciamo uso è DirectoryLoader
ancora messa a disposizione da Langchain.
from langchain_community.document_loaders import DirectoryLoader
loader = DirectoryLoader(
"archivio",
glob="**/*.txt",
loader_cls=TextLoader,
show_progress=True,
use_multithreading=True
)
In questo modo carichiamo tutto il contenuto della cartella archivio
di cui non forniamo il percorso assoluto solo perché si trova nel nostro path di lavoro. L’argomento glob
segue il formato dell’omonima funzione Python che permette di ricercare solo file con estensione .txt
ma in ogni sottocartella (**/
).
Notare anche gli altri parametri usati:
loader_cls
dichiara la classe che servirà a caricare il singolo documento. Qui facciamo uso diTextLoader
che già conosciamo;show_progress
se impostato aTrue
chiede di mostrare una barra di progresso testuale che potrà essere comoda per tenere il segno di caricamenti molto articolati. Il suo corretto funzionamento richiede però la disponibilità della libreriatqdm
che all’occorrenza potrà essere caricata conpip
;use_multithreading
impostato aTrue
invita il sistema a parallelizzare il caricamento istanziando thread paralleli se possibile.
Potremo a questo punto procedere al caricamento dei documenti con documenti = loader.load()
per ottenere una lista di oggetti Document
dal formato identico a quello visto nell’esempio del TextLoader
.
E ora?
Parlando di RAG, abbiamo portato l’esempio di solo due loader, i più utilizzati, ma si consideri che la documentazione ufficiale ne descrive moltissimi che potranno essere sperimentati, distinti sia per formati di dato (non strutturati, PDF, HTML, etc.) sia per tipologia di origine (servizi web, servizi di storage on line, social network, etc.). Noi proseguiremo ora con lo splitting dei documenti per trasformarli in chunk molto più gestibili.
Se vuoi aggiornamenti su RAG: caricamento di documenti inserisci la tua email nel box qui sotto: