1. Retrieve

Il Retriever è un'interfaccia incapsulata da LangChain, che restituisce documenti correlati basati su query non strutturate. Lo scopo del design del retriever è quello di facilitare l'interrogazione dei dati locali. Lo storage vettoriale può essere utilizzato come implementazione sottostante del retriever, e LangChain supporta più implementazioni sottostanti dell'interfaccia del retriever.

2. Inizia con il Retriever

2.1. Installazione

Per mostrare come ottenere un retriever, useremo il database vettoriale Qdrant come esempio.

%pip install --upgrade --quiet qdrant-client

2.2. Ottenere la Chiave API di OpenAI

Prima di utilizzare OpenAIEmbeddings, è necessario ottenere la chiave API di OpenAI.

import getpass
import os

os.environ["OPENAI_API_KEY"] = getpass.getpass("Chiave API di OpenAI:")

2.3. Importare i Dati dei Documenti e Ottenere il Cliente Qdrant

Il seguente codice mostra come importare i dati dei documenti e ottenere il cliente Qdrant per creare un retriever:

from langchain_community.document_loaders import TextLoader
from langchain_community.vectorstores import Qdrant
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import CharacterTextSplitter

loader = TextLoader("../../modules/state_of_the_union.txt")
documents = loader.load()
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
docs = text_splitter.split_documents(documents)

embeddings = OpenAIEmbeddings()

qdrant = Qdrant.from_documents(
    docs,
    embeddings,
    path="/tmp/local_qdrant",
    collection_name="my_documents",
)

2.4. Ottenere il Retriever

Il seguente codice mostra come ottenere un retriever da Qdrant:

retriever = qdrant.as_retriever()
retriever

Puoi interrogare i documenti correlati a una domanda in questo modo:

docs = retriever.get_relevant_documents("di cosa ha parlato ketanji brown jackson")

Puoi anche impostare la soglia di similarità per il retriever in questo modo:

retriever = db.as_retriever(
    search_type="similarity_score_threshold", search_kwargs={"score_threshold": 0.5}
)

Inoltre, puoi impostare il retriever per restituire i primi 'K' record più simili, ad esempio, per restituire i primi 2 record più simili:

retriever = db.as_retriever(search_kwargs={"k": 2})

2.5. Utilizzo del Retriever in LCEL

Poiché i retriever sono oggetti eseguibili, possiamo facilmente combinarli con altri oggetti eseguibili per orchestrare flussi di lavoro:

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough

template = """Rispondi alle domande basandoti solo sul seguente contesto:

{context}

Domanda: {question}
"""
prompt = ChatPromptTemplate.from_template(template)
model = ChatOpenAI()

def format_docs(docs):
    return "\n\n".join([d.page_content for d in docs])

chain = (
    {"context": retriever | format_docs, "question": RunnablePassthrough()}
    | prompt
    | model
    | StrOutputParser()
)

chain.invoke("Di cosa ha parlato il presidente riguardo alla tecnologia?")

Spiegazione del processo:

  • Passaggio 1: L'obiettivo è generare un dizionario contenente due proprietà, context e question, per preparare i parametri per il template della prompt. Il parametro context è generato dal retriever basato sul parametro passato al metodo invoke, che è "Di cosa ha parlato il presidente riguardo alla tecnologia?". Questo recupera documenti simili alla domanda, quindi formatta l'array di documenti utilizzando la funzione format_docs e lo assegna alla proprietà context. La funzione RunnablePassthrough copia il parametro (domanda dell'utente) della catena alla proprietà question.
  • Passaggio 2: Passa il dizionario generato nel primo passaggio al template della prompt per la formattazione.
  • Passaggio 3: Passa la prompt formattata dal template al modello.
  • Passaggio 4: Passa il risultato della chiamata al modello all'output parser StrOutputParser.

3. Retriever Personalizzato

4.1. Introduzione all'Interfaccia del Retriever

L'interfaccia del retriever è molto semplice e possiamo facilmente scrivere retriever personalizzati.

4.2. Esempio di Recupero Personalizzato

Di seguito è riportato un esempio di un recupero personalizzato, che illustra come scrivere un recupero personalizzato e usarlo per recuperare documenti rilevanti:

from langchain_core.retrievers import BaseRetriever
from langchain_core.callbacks import CallbackManagerForRetrieverRun
from langchain_core.documents import Document
from typing import List

class CustomRetriever(BaseRetriever):
  
    def _get_relevant_documents(
        self, query: str, *, run_manager: CallbackManagerForRetrieverRun
    ) -> List[Document]:
        return [Document(page_content=query]

retriever = CustomRetriever()

retriever.get_relevant_documents("bar")

Attraverso lo studio delle sezioni precedenti, acquisirai una comprensione più approfondita del concetto, dei metodi di recupero e della personalizzazione dei recuperi.