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
epergunta
, para preparar parâmetros para o modelo de prompt. O parâmetrocontexto
é gerado pelo retriever com base no parâmetro passado para o métodoinvoke
, que é "O que o presidente disse sobre tecnologia?". Isso recupera documentos semelhantes à pergunta, formata o array de documentos usando a funçãoformat_docs
e atribui-o à propriedadecontexto
. A funçãoRunnablePassthrough
copia o parâmetro (pergunta do usuário) da corrente para a propriedadepergunta
. - 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.