Docs Menu
Docs Home
/ /

Evalúe su solicitud de RAG

En este tutorial aprenderás a evaluar un Aplicación RAG. La evaluación le ayuda a elegir el modelo adecuado, garantizar que su rendimiento se adapte del prototipo a la producción y detectar regresiones de rendimiento.

En concreto, realizas las siguientes acciones:

  • Configura el entorno.

  • Descargue un conjunto de datos de evaluación.

  • Crear fragmentos de documentos e incrustaciones.

  • Ingerir las incrustaciones en Atlas.

  • Comparar modelos de incrustación para recuperación.

  • Comparar modelos de finalización para generación.

  • Medir el rendimiento general de RAG.

  • Realice un seguimiento del rendimiento a lo largo del tiempo con los gráficos de MongoDB.

Nota

Este tutorial se centra en la evaluación de aplicaciones LLM, no de modelos LLM. La evaluación de modelos LLM implica medir el rendimiento de un modelo determinado en diferentes tareas. La evaluación de aplicacionesLLM consiste en evaluar los diferentes componentes de una aplicación LLM, como los indicadores y los recuperadores, así como el sistema en su conjunto.

Trabaje con una versión ejecutable de este tutorial como Cuaderno de Python.

Este tutorial utiliza el marco de evaluación de código abierto RAGAS para medir el rendimiento de RAG con las siguientes métricas:

  • Métricas de recuperación: la precisión del contexto y la recuperación del contexto miden qué tan bien su recuperador encuentra información relevante.

  • Métricas de generación: la fidelidad y la relevancia de las respuestas miden qué tan bien su LLM genera respuestas precisas y relevantes.

  • Métricas generales: la similitud de respuestas y la exactitud de las respuestas comparan las respuestas generadas con la verdad fundamental.

Para obtener más información sobre estas métricas, consulte Métricas RAGAS en la documentación de RAGAS.

Este tutorial utiliza el conjunto de datos ragas-wikiqa de Hugging Face, que contiene aproximadamente 230 preguntas de conocimiento general con respuestas basadas en la verdad fundamental.

Para completar este tutorial, debes tener lo siguiente:

  • Un clúster de MongoDB Atlas con MongoDB versión 6.0.11 o posterior. Asegúrese de que su dirección IP esté en la lista de acceso de su proyecto.

  • Una clave API de OpenAI para utilizar los modelos de integración y finalización de chat de OpenAI.

  • Un terminal configurado con lo siguiente:

1

Ejecute el siguiente comando para instalar las bibliotecas necesarias:

pip install -qU datasets ragas langchain langchain-mongodb langchain-openai \
pymongo pandas tqdm matplotlib seaborn nest_asyncio
2

Ejecute el siguiente código en su cuaderno para configurar su cadena de conexión MongoDB y su clave API OpenAI:

import getpass
import os
from openai import OpenAI
MONGODB_URI = getpass.getpass("Enter your MongoDB connection string:")
os.environ["OPENAI_API_KEY"] = getpass.getpass("Enter your OpenAI API Key:")
openai_client = OpenAI()

Descargue el conjunto de datos ragas-wikiqa de Hugging Face y conviértalo en un marco de datos de pandas:

from datasets import load_dataset
import pandas as pd
data = load_dataset("explodinggradients/ragas-wikiqa", split="train")
df = pd.DataFrame(data)

El conjunto de datos contiene las siguientes columnas:

  • question:Preguntas de los usuarios

  • correct_answerRespuestas de verdad fundamental

  • context:Lista de textos de referencia para responder las preguntas

Divida los textos de referencia en fragmentos más pequeños antes de incrustarlos:

from langchain.text_splitter import RecursiveCharacterTextSplitter
# Split text by tokens using the tiktoken tokenizer
text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(
encoding_name="cl100k_base", keep_separator=False, chunk_size=200, chunk_overlap=30
)
def split_texts(texts):
chunked_texts = []
for text in texts:
chunks = text_splitter.create_documents([text])
chunked_texts.extend([chunk.page_content for chunk in chunks])
return chunked_texts
# Split the context field into chunks
df["chunks"] = df["context"].apply(lambda x: split_texts(x))
# Aggregate list of all chunks
all_chunks = df["chunks"].tolist()
docs = [item for chunk in all_chunks for item in chunk]

Tip

Experimente con diferentes estrategias de fragmentación al evaluar la recuperación. Este tutorial se centra en la evaluación de modelos de incrustación.

Incruste los documentos fragmentados e ingréselos en Atlas. Cree colecciones independientes para cada modelo de incrustación que desee comparar:

1

Cree una función para generar incrustaciones utilizando la API de OpenAI:

from typing import List
def get_embeddings(docs: List[str], model: str) -> List[List[float]]:
"""Generate embeddings using the OpenAI API."""
docs = [doc.replace("\n", " ") for doc in docs]
response = openai_client.embeddings.create(input=docs, model=model)
return [r.embedding for r in response.data]
2

Incruste e ingiera los documentos fragmentados en colecciones de Atlas:

from pymongo import MongoClient
from tqdm.auto import tqdm
client = MongoClient(MONGODB_URI)
DB_NAME = "ragas_evals"
db = client[DB_NAME]
batch_size = 128
EVAL_EMBEDDING_MODELS = ["text-embedding-ada-002", "text-embedding-3-small"]
for model in EVAL_EMBEDDING_MODELS:
embedded_docs = []
print(f"Getting embeddings for the {model} model")
for i in tqdm(range(0, len(docs), batch_size)):
end = min(len(docs), i + batch_size)
batch = docs[i:end]
batch_embeddings = get_embeddings(batch, model)
batch_embedded_docs = [
{"text": batch[i], "embedding": batch_embeddings[i]}
for i in range(len(batch))
]
embedded_docs.extend(batch_embedded_docs)
collection = db[model]
collection.delete_many({})
collection.insert_many(embedded_docs)
print(f"Finished inserting embeddings for the {model} model")
3

Cree un índice de búsqueda vectorial de MongoDB para cada colección. Utilice la siguiente definición de índice con el nombre vector_index:

{
"fields": [
{
"numDimensions": 1536,
"path": "embedding",
"similarity": "cosine",
"type": "vector"
}
]
}

Para saber cómo crear el índice, consulte Crear un índice de búsqueda vectorial de MongoDB.

Tip

Tanto text-embedding-ada-002 como text-embedding-3-small tienen 1536 dimensiones, por lo que la misma definición de índice funciona para ambas colecciones.

Para asegurar la recuperación del contexto correcto para el LLM, compare diferentes modelos de incrustación. Este tutorial compara text-embedding-ada-002 y.text-embedding-3-small

1

Cree una función para obtener un recuperador de almacén de vectores utilizando LangChain y MongoDB Atlas:

from langchain_openai import OpenAIEmbeddings
from langchain_mongodb import MongoDBAtlasVectorSearch
from langchain_core.vectorstores import VectorStoreRetriever
def get_retriever(model: str, k: int) -> VectorStoreRetriever:
"""
Get a vector store retriever for a given embedding model.
Args:
model (str): Embedding model to use
k (int): Number of results to retrieve
Returns:
VectorStoreRetriever: A vector store retriever object
"""
embeddings = OpenAIEmbeddings(model=model)
vector_store = MongoDBAtlasVectorSearch.from_connection_string(
connection_string=MONGODB_URI,
namespace=f"{DB_NAME}.{model}",
embedding=embeddings,
index_name="vector_index",
text_key="text",
)
retriever = vector_store.as_retriever(
search_type="similarity", search_kwargs={"k": k}
)
return retriever
2

Extraiga las preguntas y las respuestas de verdad fundamental de su conjunto de datos:

QUESTIONS = df["question"].to_list()
GROUND_TRUTH = df["correct_answer"].tolist()
3

Utilice las métricas context_precision y context_recall de la biblioteca RAGAS para evaluar cada modelo de inserción:

from datasets import Dataset
from ragas import evaluate, RunConfig
from ragas.metrics import context_precision, context_recall
import nest_asyncio
# Allow nested use of asyncio (used by RAGAS)
nest_asyncio.apply()
for model in EVAL_EMBEDDING_MODELS:
data = {"question": [], "ground_truth": [], "contexts": []}
data["question"] = QUESTIONS
data["ground_truth"] = GROUND_TRUTH
retriever = get_retriever(model, 2)
# Get relevant documents for the evaluation dataset
for i in tqdm(range(0, len(QUESTIONS))):
data["contexts"].append(
[doc.page_content for doc in retriever.invoke(QUESTIONS[i])]
)
# RAGAS expects a Dataset object
dataset = Dataset.from_dict(data)
# RAGAS runtime settings to avoid hitting OpenAI rate limits
run_config = RunConfig(max_workers=4, max_wait=180)
result = evaluate(
dataset=dataset,
metrics=[context_precision, context_recall],
run_config=run_config,
raise_exceptions=False,
)
print(f"Result for the {model} model: {result}")

Los resultados de la evaluación de los modelos de inserción en el conjunto de datos de muestra son los siguientes:

Modelo
Precisión del contexto
Recuerdo del contexto

incrustación de texto ADA002

0.9310

0.8561

incrustación de texto-3-pequeño

0.9116

0.8826

Con base en estos resultados, text-embedding-ada-002 clasifica los resultados más relevantes en un nivel superior, pero text-embedding-3-small recupera contextos más alineados con las respuestas de la verdad fundamental. Para este tutorial, utilice text-embedding-3-small como modelo de incrustación.

Ahora que ha seleccionado el mejor modelo de integración, compare los modelos de finalización para el componente de generación de su aplicación RAG.

1

Cree una función que construya una cadena RAG usando LangChain:

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_core.runnables.base import RunnableSequence
from langchain_core.output_parsers import StrOutputParser
def get_rag_chain(retriever: VectorStoreRetriever, model: str) -> RunnableSequence:
"""
Create a basic RAG chain.
Args:
retriever (VectorStoreRetriever): Vector store retriever object
model (str): Chat completion model to use
Returns:
RunnableSequence: A RAG chain
"""
# Generate context using the retriever, and pass the user question through
retrieve = {
"context": retriever
| (lambda docs: "\n\n".join([d.page_content for d in docs])),
"question": RunnablePassthrough(),
}
template = """Answer the question based only on the following context: \
{context}
Question: {question}
"""
# Define the chat prompt
prompt = ChatPromptTemplate.from_template(template)
# Define the model for chat completion
llm = ChatOpenAI(temperature=0, model=model)
# Parse output as a string
parse_output = StrOutputParser()
# RAG chain
rag_chain = retrieve | prompt | llm | parse_output
return rag_chain
2

Utilice las métricas faithfulness y answer_relevancy para evaluar diferentes modelos de finalización:

from ragas.metrics import faithfulness, answer_relevancy
for model in ["gpt-3.5-turbo-1106", "gpt-3.5-turbo"]:
data = {"question": [], "ground_truth": [], "contexts": [], "answer": []}
data["question"] = QUESTIONS
data["ground_truth"] = GROUND_TRUTH
# Use the best embedding model from the retriever evaluation
retriever = get_retriever("text-embedding-3-small", 2)
rag_chain = get_rag_chain(retriever, model)
for i in tqdm(range(0, len(QUESTIONS))):
question = QUESTIONS[i]
data["answer"].append(rag_chain.invoke(question))
data["contexts"].append(
[doc.page_content for doc in retriever.invoke(question)]
)
# RAGAS expects a Dataset object
dataset = Dataset.from_dict(data)
# RAGAS runtime settings to avoid hitting OpenAI rate limits
run_config = RunConfig(max_workers=4, max_wait=180)
result = evaluate(
dataset=dataset,
metrics=[faithfulness, answer_relevancy],
run_config=run_config,
raise_exceptions=False,
)
print(f"Result for the {model} model: {result}")

Los resultados de la evaluación de los modelos de finalización en el conjunto de datos de muestra son los siguientes:

Modelo
Fidelidad
Relevancia de la respuesta

gpt-3.5-turbo

0.9714

0.9087

gpt-3.5-turbo-1106

0.9671

0.9105

Con base en estos resultados, la versión más reciente gpt-3.5-turbo produce resultados más consistentes con los hechos, mientras que la versión anterior genera respuestas más pertinentes a la pregunta planteada. Para este tutorial, utilice gpt-3.5-turbo como modelo de finalización.

Tip

Si no desea elegir entre métricas, considere crear métricas consolidadas utilizando una suma ponderada o personalizar las indicaciones utilizadas para la evaluación.

Evalúe el rendimiento general de su aplicación RAG utilizando los modelos de mejor rendimiento:

from ragas.metrics import answer_similarity, answer_correctness
data = {"question": [], "ground_truth": [], "answer": []}
data["question"] = QUESTIONS
data["ground_truth"] = GROUND_TRUTH
# Use the best embedding model from the retriever evaluation
retriever = get_retriever("text-embedding-3-small", 2)
# Use the best completion model from the generator evaluation
rag_chain = get_rag_chain(retriever, "gpt-3.5-turbo")
for question in tqdm(QUESTIONS):
data["answer"].append(rag_chain.invoke(question))
dataset = Dataset.from_dict(data)
run_config = RunConfig(max_workers=4, max_wait=180)
result = evaluate(
dataset=dataset,
metrics=[answer_similarity, answer_correctness],
run_config=run_config,
raise_exceptions=False,
)
print(f"Overall metrics: {result}")

Esta evaluación muestra que la cadena RAG produce una similitud de respuesta de 0.8873 y una corrección de respuesta de en el conjunto de datos de 0.5922 muestra.

Para investigar más a fondo los resultados, conviértalos en un marco de datos de pandas y filtre las respuestas con puntaje bajo:

result_df = result.to_pandas()
result_df[result_df["answer_correctness"] < 0.7]

Para un análisis visual, cree un mapa de calor de preguntas versus métricas:

import seaborn as sns
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 8))
sns.heatmap(
result_df[1:10].set_index("question")[["answer_similarity", "answer_correctness"]],
annot=True,
cmap="flare",
)
plt.show()

El código anterior genera el siguiente mapa de calor:

Mapa de calor que visualiza el rendimiento de una aplicación RAG

Mapa de calor que visualiza el rendimiento de la aplicación RAG

Al investigar los resultados con puntuaciones bajas, es posible que encuentre lo siguiente:

  • Algunas respuestas de la verdad fundamental en el conjunto de datos de evaluación son incorrectas. Aunque la respuesta generada por LLM es correcta, no coincide con la verdad fundamental, lo que resulta en una puntuación baja.

  • Algunas respuestas verdaderas son oraciones completas, mientras que la respuesta generada por LLM es una sola palabra o número.

Estos hallazgos resaltan la importancia de verificar puntualmente las evaluaciones de LLM y conservar conjuntos de datos de evaluación precisos.

La evaluación no debe ser un evento único. Cada vez que modifique un componente de su sistema, evalúe los cambios para evaluar su impacto en el rendimiento. Una vez que su aplicación esté en producción, monitoree el rendimiento en tiempo real y detecte los cambios.

Utilice gráficos para supervisar el rendimiento de su solicitud de Maestría en Derecho (LLM). Registre los resultados de la evaluación y las métricas de retroalimentación que desee monitorear en una colección de Atlas.

from datetime import datetime
result["timestamp"] = datetime.now()
collection = db["metrics"]
collection.insert_one(result)

Este código añade un campo timestamp al resultado de la evaluación y lo escribe en una colección metrics de la base de datos ragas_evals. El documento en Atlas tiene este aspecto:

{
"answer_similarity": 0.8873,
"answer_correctness": 0.5922,
"timestamp": "2024-04-07T23:27:30.655+00:00"
}

Cree un panel en MongoDB Charts para visualizar sus métricas a lo largo del tiempo. Para aprender a crear gráficos y paneles, consulte Crear gráficos.

En este tutorial, aprendiste a evaluar una aplicación RAG con el framework RAGAS y MongoDB Atlas. Comparaste modelos de incrustación para la recuperación, modelos de finalización para la generación y mediste el rendimiento general de tu aplicación. También aprendiste a monitorizar el rendimiento a lo largo del tiempo con MongoDB Charts.

Para obtener más información sobre cómo crear aplicaciones RAG con MongoDB, consulte los siguientes recursos:

Volver

Queries en lenguaje natural