1. Retriever

Un retriever est une interface encapsulée par LangChain, qui peut retourner des documents pertinents en fonction de requêtes non structurées. Le but de la conception du retriever est de faciliter la consultation des données locales. Le stockage vectoriel peut être utilisé comme implémentation sous-jacente du retriever, et LangChain prend en charge plusieurs implémentations sous-jacentes de l'interface retriever.

2. Démarrage avec le Retriever

2.1. Installation

Pour démontrer comment obtenir un retriever, nous utiliserons la base de données vectorielle Qdrant comme exemple.

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

2.2. Obtention de la clé d'API OpenAI

Avant d'utiliser OpenAIEmbeddings, nous devons obtenir la clé d'API OpenAI.

import getpass
import os

os.environ["OPENAI_API_KEY"] = getpass.getpass("Clé d'API OpenAI :")

2.3. Importation des données de document et obtention du client Qdrant

Le code suivant démontre comment importer les données de document et obtenir le client Qdrant pour créer 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. Obtention du Retriever

Le code suivant démontre comment obtenir un retriever à partir de Qdrant :

retriever = qdrant.as_retriever()
retriever

Vous pouvez interroger des documents liés à une question de cette manière :

docs = retriever.get_relevant_documents("qu'a-t-il dit à propos de ketanji brown jackson")

Vous pouvez également définir le seuil de similarité pour le retriever de cette manière :

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

De plus, vous pouvez configurer le retriever pour renvoyer les 'K' enregistrements les plus similaires, par exemple, pour renvoyer les 2 enregistrements les plus similaires:

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

2.5. Utilisation du Retriever dans LCEL

Puisque les retrievers sont des objets Runnable, nous pouvons facilement les combiner avec d'autres objets Runnable pour orchestrer des flux de travail :

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 = """Répondez aux questions uniquement sur la base du contexte suivant :

{context}

Question : {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("Qu'a dit le président à propos de la technologie ?")

Explication du processus :

  • Étape 1 : Le but est de générer un dictionnaire contenant deux propriétés, contexte et question, pour préparer les paramètres du modèle de prompt. Le paramètre contexte est généré par le retriever en fonction du paramètre passé à la méthode invoke, qui est "Qu'a dit le président à propos de la technologie ?". Cela permet de récupérer des documents similaires à la question, puis de formater le tableau de documents à l'aide de la fonction format_docs et de l'assigner à la propriété contexte. La fonction RunnablePassthrough copie le paramètre (question de l'utilisateur) de la chaîne dans la propriété question.
  • Étape 2 : Passer le dictionnaire généré dans la première étape au modèle de prompt pour le formater.
  • Étape 3 : Passer le prompt formaté du modèle au modèle.
  • Étape 4 : Passer le résultat de l'appel du modèle au parseur de sortie StrOutputParser.

3. Retriever Personnalisé

4.1. Introduction à l'Interface du Retriever

L'interface du retriever est très simple, et nous pouvons facilement écrire des retrieveurs personnalisés.

4.2. Exemple de récupérateur personnalisé

Voici un exemple de récupérateur personnalisé, démontrant comment écrire un récupérateur personnalisé et l'utiliser pour récupérer des documents pertinents :

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")

À travers l'étude des sections ci-dessus, vous gagnerez une compréhension approfondie du concept, des méthodes de récupération et de la personnalisation des récupérateurs.