1. Retriever

Retriever é uma interface encapsulada pela LangChain, que pode retornar documentos relevantes com base em consultas não estruturadas. O objetivo do design do retriever é facilitar a consulta a dados locais. O armazenamento vetorial pode ser usado como a implementação subjacente do retriever, e LangChain suporta múltiplas implementações subjacentes da interface retriever.

2. Começando com Retriever

2.1. Instalação

Para demonstrar como obter um retriever, utilizaremos o banco de dados de vetores Qdrant como exemplo.

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

2.2. Obtendo a Chave da API do OpenAI

Antes de usar OpenAIEmbeddings, precisamos obter a chave da API do OpenAI.

import getpass
import os

os.environ["OPENAI_API_KEY"] = getpass.getpass("Chave da API do OpenAI:")

2.3. Importando Dados do Documento e Obtendo o Cliente Qdrant

O código a seguir demonstra como importar dados de documentos e obter o cliente Qdrant para criar um 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="meus_documentos",
)

2.4. Obtendo o Retriever

O código a seguir demonstra como obter um retriever do Qdrant:

retriever = qdrant.as_retriever()
retriever

Você pode consultar documentos relacionados a uma pergunta assim:

docs = retriever.get_relevant_documents("o que ele disse sobre ketanji brown jackson")

Também é possível definir o limiar de similaridade para o retriever desta forma:

retriever = db.as_retriever(
    search_type="limiar_pontuacao_similaridade", search_kwargs={"limiar_pontuacao": 0.5}
)

Além disso, você pode configurar o retriever para retornar os 'K' registros mais similares, por exemplo, para retornar os 2 registros mais similares:

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

2.5. Usando o Retriever no LCEL

Como os retrievers são objetos 'Runnable', podemos facilmente combiná-los com outros objetos 'Runnable' para orquestrar fluxos de trabalho:

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 = """Responder perguntas com base apenas no seguinte contexto:

{context}

Pergunta: {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("O que o presidente disse sobre tecnologia?")

Explicação do processo:

  • Etapa 1: O objetivo é gerar um dicionário contendo duas propriedades, contexto e pergunta, para preparar parâmetros para o modelo de prompt. O parâmetro contexto é gerado pelo retriever com base no parâmetro passado para o método invoke, que é "O que o presidente disse sobre tecnologia?". Isso recupera documentos semelhantes à pergunta, formata o array de documentos usando a função format_docs e atribui-o à propriedade contexto. A função RunnablePassthrough copia o parâmetro (pergunta do usuário) da corrente para a propriedade pergunta.
  • Etapa 2: Passe o dicionário gerado na primeira etapa para o modelo de prompt para formatação.
  • Etapa 3: Passe o prompt formatado do modelo de prompt para o modelo.
  • Etapa 4: Passe o resultado da chamada do modelo para o analisador de saída StrOutputParser.

3. Retriever Personalizado

4.1. Introdução à Interface do Retriever

A interface do retriever é muito simples, e podemos escrever facilmente retrievers personalizados.

4.2. Exemplo de Retriever Personalizado

Aqui está um exemplo de um retriever personalizado, demonstrando como escrever um retriever personalizado e usá-lo para recuperar documentos relevantes:

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

Através do estudo das seções acima, você ganhará uma compreensão mais profunda do conceito, métodos de recuperação e customização de retrievers.