1pewte1a Mqerot Jdof Cw.gif

Cómo utilizar la reducción de dimensionalidad de UMAP para incrustaciones para mostrar múltiples preguntas de evaluación y sus relaciones con los documentos fuente con Ragas, OpenAI, Langchain y ChromaDB

Recuperación-Generación Aumentada (RAG) agrega un paso de recuperación al flujo de trabajo de un LLM, lo que le permite consultar datos relevantes de fuentes adicionales como documentos privados al responder preguntas y consultas. [1]. Este flujo de trabajo no requiere capacitación costosa ni ajustes de los LLM en los documentos adicionales. Los documentos se dividen en fragmentos, que luego se indexan, a menudo utilizando una representación vectorial compacta generada por ML (incrustación). Los fragmentos con contenido similar estarán uno cerca del otro en este espacio de inserción.

La aplicación RAG proyecta las preguntas proporcionadas por el usuario en el espacio de incrustación para recuperar fragmentos de documentos relevantes en función de su distancia a la pregunta. El LLM puede utilizar la información recuperada para responder la consulta y fundamentar su conclusión presentando los fragmentos como referencias.

Animación de las iteraciones de una UMAP. [3] Reducción de dimensionalidad para artículos de Fórmula Uno de Wikipedia en el espacio de incrustación con grupos etiquetados manualmente, creado por el autor.

La evaluación de una solicitud RAG es un desafío [2]. Existen diferentes enfoques: por un lado, hay métodos en los que la respuesta como verdad fundamental la debe proporcionar el desarrollador; por otro lado, la respuesta (y la pregunta) también puede ser generada por otro LLM. Uno de los sistemas de código abierto más grandes para respuestas respaldadas por LLM es Ragas [4](Evaluación de generación aumentada de recuperación), que proporciona

  • Métodos para generar datos de prueba basados ​​en los documentos y
  • Evaluaciones basadas en diferentes métricas para evaluar los pasos de recuperación y generación uno por uno y de un extremo a otro.

En este artículo aprenderás

El El código está disponible en Github.

Inicie una computadora portátil e instale los paquetes de Python necesarios

!pip install langchain langchain-openai chromadb renumics-spotlight
%env OPENAI_API_KEY=<your-api-key>

Este tutorial utiliza los siguientes paquetes de Python:

  • Cadena Lang: un marco para integrar modelos de lenguaje y componentes RAG, lo que facilita el proceso de configuración.
  • Renumics-Spotlight: una herramienta de visualización para explorar interactivamente conjuntos de datos de aprendizaje automático no estructurados.
  • ragas: un marco que le ayuda a evaluar sus tuberías RAG

Descargo de responsabilidad: el autor de este artículo también es uno de los desarrolladores de Spotlight.

Puede utilizar su propia aplicación RAG; pase a la siguiente parte para aprender a evaluar, extraer y visualizar.

O puede utilizar la aplicación RAG desde el último artículo con nuestro conjunto de datos preparado de todos los artículos de Fórmula Uno de Wikipedia. Allí también puede insertar sus propios documentos en una subcarpeta ‘docs/’.

Este conjunto de datos se basa en artículos de Wikipedia y tiene la licencia Creative Commons Attribution-ShareAlike License. Los artículos originales y una lista de autores se pueden encontrar en las respectivas páginas de Wikipedia.

Ahora puedes usar Langchain DirectoryLoader para cargar todos los archivos del subdirectorio docs y dividir los documentos en fragmentos usando el RecursiveCharacterTextSpliter. Con OpenAIEmbeddings puedes crear incrustaciones y almacenarlas en un ChromaDB como almacén de vectores. Para la cadena en sí puedes usar LangChains ChatOpenAI y un ChatPromptTemplate.

El código vinculado Este artículo contiene todos los pasos necesarios y puede encontrar una descripción detallada de todos los pasos anteriores en el último artículo.

Un punto importante es que debes usar una función hash para crear identificadores para fragmentos en ChromaDB. Esto permite encontrar las incrustaciones en la base de datos si solo tienes el documento con su contenido y metadatos. Esto hace posible omitir documentos que ya existen en la base de datos.

import hashlib
import json
from langchain_core.documents import Document

def stable_hash_meta(doc: Document) -> str:
"""
Stable hash document based on its metadata.
"""
return hashlib.sha1(json.dumps(doc.metadata, sort_keys=True).encode()).hexdigest()

...
splits = text_splitter.split_documents(docs)
splits_ids = [
{"doc": split, "id": stable_hash_meta(split.metadata)} for split in splits
]

existing_ids = docs_vectorstore.get()["ids"]
new_splits_ids = [split for split in splits_ids if split["id"] not in existing_ids]

docs_vectorstore.add_documents(
documents=[split["doc"] for split in new_splits_ids],
ids=[split["id"] for split in new_splits_ids],
)
docs_vectorstore.persist()

Para un tema común como la Fórmula Uno, también se puede utilizar ChatGPT directamente para generar preguntas generales. En este artículo, se utilizan cuatro métodos de generación de preguntas:

  • GPT4: Se generaron 30 preguntas usando ChatGPT 4 con el siguiente mensaje «Escribe 30 preguntas sobre la Fórmula Uno»
    – Ejemplo aleatorio: “¿Qué equipo de Fórmula 1 es conocido por su logotipo del caballo rampante?”
  • GPT3.5: Se generaron otras 199 preguntas con ChatGPT 3.5 con el siguiente mensaje «Escribe 100 preguntas sobre la Fórmula Uno» y repite «Gracias, escribe otras 100, por favor».
    – Ejemplo: “¿Qué piloto ganó el Campeonato Mundial inaugural de Fórmula Uno en 1950?”
  • Ragas_GPT4: Se generaron 113 preguntas utilizando Ragas. Ragas utiliza los documentos nuevamente y su propio modelo de incrustación para construir una base de datos vectorial, que luego se usa para generar preguntas con GPT4.
    – Ejemplo: “¿Puedes contarme más sobre el desempeño del auto de Fórmula Uno Jordan 198 en el Campeonato Mundial de 1998?”
  • Trapos_GPT3.5: Se generaron 226 preguntas adicionales con Ragas; aquí usamos GPT3.5
    – Ejemplo: “¿Qué incidente ocurrió en el Gran Premio de Bélgica de 2014 que provocó el abandono de Hamilton de la carrera?”
from ragas.testset import TestsetGenerator

generator = TestsetGenerator.from_default(
openai_generator_llm="gpt-3.5-turbo-16k",
openai_filter_llm="gpt-3.5-turbo-16k"
)

testset_ragas_gpt35 = generator.generate(docs, 100)

Las preguntas y respuestas no fueron revisadas ni modificadas de ninguna manera. Todas las preguntas se combinan en un único marco de datos con las columnas. id, question, ground_truth, question_by y answer.

A continuación, se plantearán las preguntas al sistema RAG. Para más de 500 preguntas, esto puede llevar algo de tiempo e generar costos. Si hace las preguntas fila por fila, puede pausar y continuar el proceso o recuperarse de un bloqueo sin perder los resultados hasta el momento:

for i, row in df_questions_answers.iterrows():
if row["answer"] is None or pd.isnull(row["answer"]):
response = rag_chain.invoke(row["question"])

df_questions_answers.loc[df_questions_answers.index[i], "answer"] = response[
"answer"
]
df_questions_answers.loc[df_questions_answers.index[i], "source_documents"] = [
stable_hash_meta(source_document.metadata)
for source_document in response["source_documents"]
]

No solo se almacena la respuesta, sino también los ID de origen de los fragmentos de documentos recuperados y su contenido de texto como contexto: