Per ulteriori idee su come migliorare le prestazioni della pipeline RAG per renderla pronta per la produzione, continua a leggere qui:
In questa sezione vengono illustrati i pacchetti e le chiavi API richiesti da seguire in questo articolo.
Pacchetti richiesti
Questo articolo ti guiderà attraverso l’implementazione di una pipeline RAG ingenua e avanzata utilizzando LlamaIndex in Pitone.
pip install llama-index
In questo articolo utilizzeremo LlamaIndex v0.10
. Se stai eseguendo l’aggiornamento da una versione precedente di LlamaIndex, devi eseguire i seguenti comandi per installare ed eseguire LlamaIndex correttamente:
pip uninstall llama-index
pip install llama-index --upgrade --no-cache-dir --force-reinstall
LlamaIndex offre un’opzione per archiviare incorporamenti di vettori localmente in file JSON per l’archiviazione persistente, il che è ottimo per prototipare rapidamente un’idea. Tuttavia, utilizzeremo un database vettoriale per l’archiviazione persistente poiché le tecniche RAG avanzate mirano ad applicazioni pronte per la produzione.
Poiché avremo bisogno di archiviazione di metadati e funzionalità di ricerca ibrida oltre all’archiviazione degli incorporamenti vettoriali, utilizzeremo il database vettoriale open source Tessitura (v3.26.2
), che supporta queste funzionalità.
pip install weaviate-client llama-index-vector-stores-weaviate
Chiavi API
Utilizzeremo Weaviate embedded, che puoi utilizzare gratuitamente senza registrarti per una chiave API. Tuttavia, questa esercitazione utilizza un modello di incorporamento e LLM da OpenAIper il quale avrai bisogno di una chiave API OpenAI. Per ottenerne uno è necessario un account OpenAI e poi “Crea nuova chiave segreta” sotto Chiavi API.
Successivamente, crea un local .env
file nella directory root e definisci le tue chiavi API al suo interno:
OPENAI_API_KEY="<YOUR_OPENAI_API_KEY>"
Successivamente, puoi caricare le tue chiavi API con il seguente codice:
# !pip install python-dotenv
import os
from dotenv import load_dotenv,find_dotenvload_dotenv(find_dotenv())
In questa sezione viene illustrato come implementare una pipeline RAG ingenua utilizzando LlamaIndex. Puoi trovare l’intera ingenua pipeline RAG in questo Taccuino di Giove. Per l’implementazione utilizzando LangChain, puoi continuare questo articolo (pipeline RAG ingenua che utilizza LangChain).
Passaggio 1: definire il modello di incorporamento e LLM
Innanzitutto è possibile definire un modello di incorporamento e un LLM in un oggetto delle impostazioni globali. Ciò significa che non è necessario specificare nuovamente i modelli esplicitamente nel codice.
- Modello di incorporamento: utilizzato per generare incorporamenti di vettori per i blocchi di documento e la query.
- LLM: utilizzato per generare una risposta in base alla query dell’utente e al contesto pertinente.
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.llms.openai import OpenAI
from llama_index.core.settings import SettingsSettings.llm = OpenAI(model="gpt-3.5-turbo", temperature=0.1)
Settings.embed_model = OpenAIEmbedding()
Passaggio 2: caricare i dati
Successivamente, creerai una directory locale denominata data
nella directory principale e scarica alcuni dati di esempio dal file Repository GitHub di LlamaIndex (licenza MIT).
!mkdir -p 'data'
!wget '<https://raw.githubusercontent.com/run-llama/llama_index/main/docs/examples/data/paul_graham/paul_graham_essay.txt>' -O 'data/paul_graham_essay.txt'
Successivamente è possibile caricare i dati per un’ulteriore elaborazione:
from llama_index.core import SimpleDirectoryReader# Load data
documents = SimpleDirectoryReader(
input_files=("./data/paul_graham_essay.txt")
).load_data()
Passaggio 3: suddividere i documenti in nodi
Poiché l’intero documento è troppo grande per adattarsi alla finestra di contesto di LLM, sarà necessario suddividerlo in parti di testo più piccole, chiamate Nodes
in LlamaIndex. È possibile analizzare i documenti caricati in nodi utilizzando il file SimpleNodeParser
con una dimensione del blocco definita pari a 1024.
from llama_index.core.node_parser import SimpleNodeParsernode_parser = SimpleNodeParser.from_defaults(chunk_size=1024)
# Extract nodes from documents
nodes = node_parser.get_nodes_from_documents(documents)
Passaggio 4: crea l’indice
Successivamente, creerai l’indice in cui archivia tutta la conoscenza esterna Tessituraun database vettoriale open source.
Innanzitutto, dovrai connetterti a un’istanza Weaviate. In questo caso, stiamo utilizzando Weaviate incorporatoche ti consente di sperimentare gratuitamente su Notebook senza una chiave API. Per una soluzione pronta per la produzione, distribuire Weaviate da soli, ad esempio, tramite Docker o utilizzando a servizio gestitoè raccomandato.
import weaviate# Connect to your Weaviate instance
client = weaviate.Client(
embedded_options=weaviate.embedded.EmbeddedOptions(),
)
Successivamente, costruirai un file VectorStoreIndex
dal client Weaviate per archiviare i tuoi dati e con cui interagire.
from llama_index.core import VectorStoreIndex, StorageContext
from llama_index.vector_stores.weaviate import WeaviateVectorStoreindex_name = "MyExternalContext"
# Construct vector store
vector_store = WeaviateVectorStore(
weaviate_client = client,
index_name = index_name
)
# Set up the storage for the embeddings
storage_context = StorageContext.from_defaults(vector_store=vector_store)
# Setup the index
# build VectorStoreIndex that takes care of chunking documents
# and encoding chunks to embeddings for future retrieval
index = VectorStoreIndex(
nodes,
storage_context = storage_context,
)
Passaggio 5: imposta il motore di query
Infine, imposterai l’indice come motore di query.
# The QueryEngine class is equipped with the generator
# and facilitates the retrieval and generation steps
query_engine = index.as_query_engine()
Passaggio 6: esegui una query RAG ingenua sui tuoi dati
Ora puoi eseguire una query RAG ingenua sui tuoi dati, come mostrato di seguito:
# Run your naive RAG query
response = query_engine.query(
"What happened at Interleaf?"
)
In questa sezione, tratteremo alcune semplici modifiche che puoi apportare per trasformare la pipeline RAG ingenua di cui sopra in una pipeline avanzata. Questa procedura dettagliata coprirà la seguente selezione di tecniche RAG avanzate:
Poiché qui tratteremo solo le modifiche, puoi trovare il file pipeline RAG avanzata end-to-end completa in questo Jupyter Notebook.
Per il tecnica di recupero della finestra di frasedevi apportare due modifiche: in primo luogo, devi modificare il modo in cui archivi e post-elabora i tuoi dati. Invece del SimpleNodeParser
useremo il SentenceWindowNodeParser
.
from llama_index.core.node_parser import SentenceWindowNodeParser# create the sentence window node parser w/ default settings
node_parser = SentenceWindowNodeParser.from_defaults(
window_size=3,
window_metadata_key="window",
original_text_metadata_key="original_text",
)
IL SentenceWindowNodeParser
fa due cose:
- Separa il documento in singole frasi, che verranno incorporate.
- Per ogni frase, crea una finestra di contesto. Se specifichi a
window_size = 3
la finestra risultante sarà lunga tre frasi, iniziando dalla frase precedente della frase incorporata e attraversando la frase successiva. La finestra verrà archiviata come metadati.
Durante il recupero, viene restituita la frase che corrisponde maggiormente alla query. Dopo il recupero, è necessario sostituire la frase con l’intera finestra dai metadati definendo a MetadataReplacementPostProcessor
e utilizzarlo nell’elenco di node_postprocessors
.
from llama_index.core.postprocessor import MetadataReplacementPostProcessor# The target key defaults to `window` to match the node_parser's default
postproc = MetadataReplacementPostProcessor(
target_metadata_key="window"
)
...
query_engine = index.as_query_engine(
node_postprocessors = (postproc),
)
Implementare una ricerca ibrida in LlamaIndex è facile come modificare due parametri nel file query_engine
se il database vettoriale sottostante supporta query di ricerca ibride. IL alpha
Il parametro specifica la ponderazione tra la ricerca vettoriale e la ricerca basata su parole chiave, dove alpha=0
significa ricerca basata su parole chiave e alpha=1
significa ricerca vettoriale pura.
query_engine = index.as_query_engine(
...,
vector_store_query_mode="hybrid",
alpha=0.5,
...
)
L’aggiunta di un reranker alla tua pipeline RAG avanzata richiede solo tre semplici passaggi:
- Innanzitutto, definire un modello di riclassificazione. Qui stiamo usando il
BAAI/bge-reranker-base
da Il viso che abbraccia. - Nel motore di query, aggiungi il modello di riclassificazione all’elenco di
node_postprocessors
. - Aumentare il
similarity_top_k
nel motore di query per recuperare più passaggi di contesto, che possono essere ridotti atop_n
dopo la riclassificazione.
# !pip install torch sentence-transformers
from llama_index.core.postprocessor import SentenceTransformerRerank# Define reranker model
rerank = SentenceTransformerRerank(
top_n = 2,
model = "BAAI/bge-reranker-base"
)
...
# Add reranker to query engine
query_engine = index.as_query_engine(
similarity_top_k = 6,
...,
node_postprocessors = (rerank),
...,
)
Fonte: towardsdatascience.com