1. Retriever (Извлекатель)

Retriever (Извлекатель) - это интерфейс, инкапсулированный LangChain, который может возвращать соответствующие документы на основе неструктурированных запросов. Цель дизайна извлекателя - облегчить запрос локальных данных. В качестве базовой реализации извлекателя может использоваться векторное хранилище, и LangChain поддерживает несколько базовых реализаций интерфейса извлекателя.

2. Начало работы с извлекателем (Retriever)

2.1. Установка

Для демонстрации того, как получить извлекатель, мы воспользуемся базой данных векторов Qdrant в качестве примера.

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

2.2. Получение ключа API OpenAI

Прежде чем использовать OpenAIEmbeddings, нам необходимо получить ключ API OpenAI.

import getpass
import os

os.environ["OPENAI_API_KEY"] = getpass.getpass("Ключ API OpenAI:")

2.3. Импорт данных документа и получение клиента Qdrant

Следующий код демонстрирует, как импортировать данные документа и получить клиент Qdrant для создания извлекателя:

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. Получение извлекателя

Следующий код демонстрирует, как получить извлекатель из Qdrant:

retriever = qdrant.as_retriever()
retriever

Вы можете запросить документы, связанные с вопросом, так:

docs = retriever.get_relevant_documents("что он сказал о Кетанджи Браун Джексон")

Вы также можете установить порог сходства для извлекателя:

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

Кроме того, вы можете установить количество возвращаемых наиболее похожих записей, например, чтобы вернуть 2 наиболее похожие записи:

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

2.5. Использование извлекателя в LCEL

Поскольку извлекатели являются объектами Runnable (запускаемыми), мы легко можем объединить их с другими объектами Runnable для оркестрации рабочих процессов:

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 = """Отвечайте на вопросы только на основе следующего контекста:

{context}

Вопрос: {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("Что президент сказал о технологиях?")

Объяснение процесса:

  • Шаг 1: Цель - сгенерировать словарь, содержащий два свойства: context и question, для подготовки параметров шаблона запроса. Параметр context генерируется извлекателем на основе параметра, переданного методу invoke, который равен "Что президент сказал о технологиях?". Это извлекает документы, похожие на вопрос, затем форматирует массив документов, используя функцию format_docs и присваивает его свойству context. Функция RunnablePassthrough копирует параметр (вопрос пользователя) цепочки в свойство question.
  • Шаг 2: Передать словарь, сгенерированный на первом шаге, в шаблон запроса для форматирования.
  • Шаг 3: Передать отформатированный запрос из шаблона в модель.
  • Шаг 4: Передать результат вызова модели в парсер вывода StrOutputParser.

3. Пользовательский извлекатель (Custom Retriever)

4.1. Введение в интерфейс извлекателя (Retriever Interface)

Интерфейс извлекателя очень прост, и мы легко можем написать пользовательские извлекатели.

4.2. Пример настраиваемого ретриевера

Вот пример настраиваемого ретриевера, демонстрирующий, как написать настраиваемый ретриевер и использовать его для извлечения соответствующих документов:

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

Изучив вышеуказанные разделы, вы приобретете более глубокое понимание концепции, методов извлечения и настройки ретриеверов.