1. Recuperadores

Retriever es una interfaz encapsulada por LangChain, que puede devolver documentos relevantes basados en consultas no estructuradas. El propósito del diseño del recuperador es facilitar la consulta de datos locales. El almacenamiento vectorial puede ser utilizado como la implementación subyacente del recuperador, y LangChain soporta múltiples implementaciones subyacentes de la interfaz del recuperador.

2. Comenzando con el Recuperador

2.1. Instalación

Para demostrar cómo obtener un recuperador, utilizaremos la base de datos de vectores Qdrant como ejemplo.

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

2.2. Obteniendo la Clave de API de OpenAI

Antes de utilizar OpenAIEmbeddings, necesitamos obtener la clave de API de OpenAI.

import getpass
import os

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

2.3. Importar Datos del Documento y Obtener el Cliente de Qdrant

El siguiente código demuestra cómo importar datos del documento y obtener el cliente de Qdrant para crear un recuperador:

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="mis_documentos",
)

2.4. Obtención del Recuperador

El siguiente código demuestra cómo obtener un recuperador de Qdrant:

recuperador = qdrant.como_recuperador()
recuperador

Puedes consultar documentos relacionados con una pregunta de esta manera:

docs = recuperador.obtener_documentos_relevantes("¿Qué dijo sobre Ketanji Brown Jackson?")

También puedes establecer el umbral de similitud para el recuperador de esta manera:

recuperador = db.como_recuperador(
    tipo_de_busqueda="umbral_de_puntuacion_de_similitud", argumentos_de_busqueda={"umbral_de_puntuacion": 0.5}
)

Además, puedes configurar el recuperador para que devuelva los 'K' registros más similares, por ejemplo, para devolver los 2 registros más similares:

recuperador = db.como_recuperador(argumentos_de_busqueda={"k": 2})

2.5. Uso del Recuperador en LCEL

Dado que los recuperadores son objetos Ejecutables, podemos combinarlos fácilmente con otros objetos Ejecutables para orquestar flujos de trabajo:

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough

plantilla = """Responder preguntas basadas únicamente en el siguiente contexto:

{contexto}

Pregunta: {pregunta}
"""
prompt = ChatPromptTemplate.from_template(plantilla)
modelo = ChatOpenAI()

def formatear_docs(docs):
    return "\n\n".join([d.contenido_pagina for d in docs])

cadena = (
    {"contexto": recuperador | formatear_docs, "pregunta": RunnablePassthrough()}
    | prompt
    | modelo
    | StrOutputParser()
)

cadena.invocar("¿Qué dijo el presidente sobre la tecnología?")

Explicación del proceso:

  • Paso 1: El objetivo es generar un diccionario que contenga dos propiedades, contexto y pregunta, para preparar parámetros para la plantilla de la sugerencia. El parámetro contexto es generado por el recuperador basado en el parámetro pasado al método invocar, que es "¿Qué dijo el presidente sobre la tecnología?". Esto recupera documentos similares a la pregunta, luego formatea el array de documentos usando la función formatear_docs y lo asigna a la propiedad contexto. La función RunnablePassthrough copia el parámetro (pregunta del usuario) de la cadena a la propiedad pregunta.
  • Paso 2: Pasa el diccionario generado en el primer paso a la plantilla de la sugerencia para formatearlo.
  • Paso 3: Pasa la sugerencia formateada desde la plantilla de la sugerencia al modelo.
  • Paso 4: Pasa el resultado de la llamada al modelo al analizador de salida StrOutputParser.

3. Recuperador Personalizado

4.1. Introducción a la Interfaz del Recuperador

La interfaz del recuperador es muy sencilla, y podemos escribir recuperadores personalizados fácilmente.

4.2. Ejemplo de recuperador personalizado

Aquí tienes un ejemplo de un recuperador personalizado, que demuestra cómo escribir un recuperador personalizado y usarlo 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")

A través del estudio de las secciones anteriores, obtendrás una comprensión más profunda del concepto, los métodos de recuperación y la personalización de los recuperadores.