1. Retriever

Retriever to interfejs zkapitalizowany przez LangChain, który może zwrócić odpowiednie dokumenty na podstawie nieustrukturyzowanych zapytań. Celem projektu retrievera jest ułatwienie zapytania do lokalnych danych. Przechowywanie wektorowe może być użyte jako zaimplementowanie retrievera, a LangChain obsługuje wielokrotne zaimplementowania interfejsu retrievera.

2. Rozpoczęcie pracy z Retriever

2.1. Instalacja

Aby zademonstrować, jak uzyskać retriever, użyjemy bazy danych wektorów Qdrant jako przykładu.

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

2.2. Uzyskanie klucza OpenAI API

Przed użyciem OpenAIEmbeddings, musimy uzyskać klucz OpenAI API.

import getpass
import os

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

2.3. Importowanie danych dokumentów i uzyskiwanie klienta Qdrant

Poniższy kod demonstruje, jak zaimportować dane dokumentów i uzyskać klienta Qdrant do utworzenia retrievera:

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. Uzyskanie Retrievera

Poniższy kod demonstruje, jak uzyskać retrievera z Qdrant:

retriever = qdrant.as_retriever()
retriever

Możesz zapytać dokumenty związane z pytaniem w ten sposób:

docs = retriever.get_relevant_documents("co powiedział o Ketanji Brown Jackson")

Możesz także ustawić próg podobieństwa dla retrievera w ten sposób:

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

Dodatkowo, możesz ustawić retriever, aby zwrócił najlepsze 'K' najbardziej podobne rekordy, na przykład, aby zwrócić najlepsze 2 najbardziej podobne rekordy:

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

2.5. Używanie Retrievera w LCEL

Ponieważ retrievery są obiektami „Runnable”, możemy łatwo połączyć je z innymi obiektami „Runnable” w celu skomponowania workflowów:

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 = """Odpowiadać na pytania na podstawie następującego kontekstu:

{context}

Pytanie: {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("Co prezydent powiedział o technologii?")

Wyjaśnienie procesu:

  • Krok 1: Celem jest wygenerowanie słownika zawierającego dwie właściwości, context i question, do przygotowania parametrów dla szablonu promptu. Parametr context jest generowany przez retrievera na podstawie parametru przekazanego do metody invoke, czyli "Co prezydent powiedział o technologii?". To odnajduje dokumenty podobne do pytania, a następnie formatuje tablicę dokumentów za pomocą funkcji format_docs i przypisuje ją do właściwości context. Funkcja RunnablePassthrough kopiująca parametr (pytanie użytkownika) łańcucha do właściwości question.
  • Krok 2: Przekaż wygenerowany w pierwszym kroku słownik do szablonu promptu w celu sformatowania.
  • Krok 3: Przekaż sformatowany prompt z szablonu do modelu.
  • Krok 4: Przekaż wynik wywołania modelu do analizatora wyników StrOutputParser.

3. Niestandardowy Retriever

4.1. Wprowadzenie do Interfejsu Retrievera

Interfejs retrievera jest bardzo prosty i możemy łatwo pisać niestandardowe retrievery.

4.2. Przykład niestandardowego Wyszukiwacza

Oto przykład niestandardowego wyszukiwacza, który demonstruje, jak napisać niestandardowego wyszukiwacza i jak go użyć do wyszukiwania odpowiednich dokumentów:

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

Poprzez przeanalizowanie powyższych sekcji zdobędziesz głębsze zrozumienie koncepcji, metod wyszukiwania oraz dostosowywania wyszukiwaczy.