1. Retrievers
Ein Retriever ist eine von LangChain gekapselte Schnittstelle, die relevante Dokumente basierend auf unstrukturierten Abfragen zurückgeben kann. Der Zweck des Retriever-Designs besteht darin, die Abfrage lokaler Daten zu erleichtern. Als zugrunde liegende Implementierung des Retrievers kann Vektorspeicher verwendet werden, und LangChain unterstützt mehrere zugrunde liegende Implementierungen der Retriever-Schnittstelle.
2. Erste Schritte mit Retriever
2.1. Installation
Um zu zeigen, wie man einen Retriever erhält, verwenden wir die Qdrant-Vektordatenbank als Beispiel.
%pip install --upgrade --quiet qdrant-client
2.2. Erhalt des OpenAI API Keys
Bevor wir OpenAIEmbeddings
verwenden, müssen wir den OpenAI API Key erhalten.
import getpass
import os
os.environ["OPENAI_API_KEY"] = getpass.getpass("OpenAI API Key:")
2.3. Import von Dokumentendaten und Erhalt des Qdrant-Clients
Der folgende Code zeigt, wie man Dokumentendaten importiert und den Qdrant-Client erhält, um einen Retriever zu erstellen:
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. Erhalt des Retrievers
Der folgende Code zeigt, wie man einen Retriever von Qdrant erhält:
retriever = qdrant.as_retriever()
retriever
Sie können Dokumente zu einer Frage abfragen, wie folgt:
docs = retriever.get_relevant_documents("Was hat er über Ketanji Brown Jackson gesagt")
Sie können auch den Ähnlichkeitsschwellenwert für den Retriever wie folgt festlegen:
retriever = db.as_retriever(
search_type="similarity_score_threshold", search_kwargs={"score_threshold": 0.5}
)
Darüber hinaus können Sie den Retriever so einstellen, dass er die 'K' am meisten ähnlichen Datensätze zurückgibt. Zum Beispiel, um die zwei am meisten ähnlichen Datensätze zurückzugeben:
retriever = db.as_retriever(search_kwargs={"k": 2})
2.5. Verwendung von Retriever in LCEL
Da Retriever Runnable
-Objekte sind, können wir sie leicht mit anderen Runnable
-Objekten kombinieren, um Workflows zu orchestrieren:
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 = """Beantworte Fragen basierend nur auf dem folgenden Kontext:
{context}
Frage: {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("Was hat der Präsident über Technologie gesagt?")
Erklärung des Ablaufs:
- Schritt 1: Das Ziel ist es, ein Dictionary zu generieren, das zwei Eigenschaften,
context
undquestion
, für die Vorbereitung der Parameter für die Prompt-Vorlage enthält. Dercontext
-Parameter wird vomretriever
-Retriever basierend auf dem derinvoke
-Methode übergebenen Parameter "Was hat der Präsident über Technologie gesagt?" generiert. Dies ruft Dokumente ab, die der Frage ähnlich sind, formatiert dann das Dokumenten-Array mithilfe derformat_docs
-Funktion und weist es dercontext
-Eigenschaft zu. DieRunnablePassthrough
-Funktion kopiert den Parameter (Benutzereingabe-Frage) der Kette in diequestion
-Eigenschaft. - Schritt 2: Das im ersten Schritt generierte Dictionary wird an die Prompt-Vorlage zur Formatierung übergeben.
- Schritt 3: Die formatierte Eingabeaufforderung von der Prompt-Vorlage wird an das Modell übergeben.
- Schritt 4: Das Ergebnis des Modellaufrufs wird an den Ausgabe-Parser
StrOutputParser
übergeben.
3. Eigener Retriever
4.1. Einführung in die Retriever-Schnittstelle
Die Retriever-Schnittstelle ist sehr einfach, und wir können leicht benutzerdefinierte Retriever schreiben.
4.2. Beispiel für benutzerdefinierten Retriever
Hier ist ein Beispiel für einen benutzerdefinierten Retriever, das zeigt, wie man einen benutzerdefinierten Retriever schreibt und verwendet, um relevante Dokumente abzurufen:
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")
Durch das Studium der obigen Abschnitte erhalten Sie ein tieferes Verständnis des Konzepts, der Abrufmethoden und der Anpassung von Retrievern.