Desenvolvimento de RAGs Orientado por Métricas
Em uma apresentação recente no Zilliz Unstructured Data Meetup, Jithin James e Shahul Es, mantenedores do Ragas, compartilharam insights sobre como aproveitar o desenvolvimento orientado por métricas para avaliar sistemas de Geração Aumentada por Recuperação (RAG). Os desenvolvedores podem ajustar seus sistemas com base nos resultados da avaliação para obter melhor desempenho.
Em sua palestra, Jithin e Shahul discutiram tanto os fundamentos teóricos quanto as aplicações práticas da avaliação de sistemas RAG. Eles explicaram como compreender a teoria por trás do código de avaliação pode fornecer insights mais profundos sobre sua funcionalidade. Após essa parte, eles demonstraram o processo de avaliação usando um sistema RAG real alimentado pelo Milvus, um banco de dados vetorial open-source líder conhecido por sua eficiência em busca por similaridade e aplicações de IA.
Para uma compreensão mais detalhada, assista ao replay da palestra do meetup.
Como Avaliar o Desempenho de Sistemas RAG
Shahul abordou como o Ragas calcula a veracidade de uma resposta gerada pelo sistema RAG. Esta é uma métrica de avaliação crucial, pois a resposta é o que o usuário final vê. Vamos desacelerar um pouco e nos aprofundar. O Ragas usa a seguinte fórmula para calcular a veracidade de uma resposta:
Fig 1- Fórmula de cálculo da métrica answer_truthfulness do Ragas
Calculando a Correção da Resposta em Sistemas de Geração Aumentada por Recuperação (RAG)
O processo envolve duas métricas principais: similaridade factual e similaridade semântica. Essas métricas ajudam a determinar a qualidade e a relevância da resposta gerada em comparação com a verdade fundamental.
Métricas Principais
Similaridade Factual:
- Esta métrica mede a correção factual da resposta gerada comparando a presença de informações factuais entre a verdade fundamental e a resposta gerada.
Similaridade Semântica:
- Esta métrica mede quão semanticamente semelhante a resposta gerada é à verdade fundamental, garantindo que o significado transmitido pela resposta gerada esteja alinhado com a verdade fundamental.
Etapas para Calcular a Correção da Resposta
Identificar Verdadeiros Positivos (TP), Falsos Positivos (FP) e Falsos Negativos (FN):
Verdadeiros Positivos: Declarações corretamente presentes tanto na verdade fundamental quanto na resposta gerada.
Falsos Positivos: Declarações presentes na resposta gerada, mas não na verdade fundamental.
Falsos Negativos: Declarações presentes na verdade fundamental, mas não na resposta gerada.
Calcular a Pontuação F1:
- A pontuação F1 é uma média de precisão e revocação, fornecendo um equilíbrio entre as duas. A fórmula para a pontuação F1 é mostrada na Figura 1.
Exemplo Prático
Considere uma declaração de verdade fundamental e uma resposta gerada:
Verdade Fundamental: "Alan Turing desenvolveu o conceito da máquina de Turing."
Resposta Gerada: "Alan Turing é conhecido por desenvolver o conceito da máquina de Turing e da inteligência artificial."
Etapa 1: Identificar TP, FP e FN
Verdadeiros Positivos (TP):
- "Alan Turing desenvolveu o conceito da máquina de Turing."
Falsos Positivos (FP):
- "Alan Turing é conhecido por desenvolver inteligência artificial."
Falsos Negativos (FN):
- Nenhum (já que a resposta gerada inclui todos os elementos da verdade fundamental).
Etapa 2: Calcular a Pontuação F1
TP = 1
FP = 1
FN = 0
F1 = 1 / (1 + 0.5 * (1 + 0))
= 1 / 1.5
≈ 0.67
Interpretação<
Similaridade Factual: A resposta gerada é factualmente correta, pois inclui as informações essenciais da verdade fundamental.
Similaridade Semântica: A resposta gerada mantém alinhamento semântico com a verdade fundamental, embora inclua informações adicionais.
A pontuação F1 combina esses aspectos para fornecer uma medida da correção da resposta, equilibrando precisão e revocação. Esse método ajuda a avaliar o quão bem a resposta gerada corresponde à verdade fundamental em termos tanto de conteúdo factual quanto de significado geral.
Mas a veracidade da resposta não é a única métrica que você pode usar para avaliar seus sistemas RAG. Outras métricas são fidelidade, relevância da resposta, revocação de contexto e precisão de contexto. Vamos dar uma olhada prática em como você pode avaliar e melhorar um sistema RAG com Milvus.
Avaliando e melhorando um sistema RAG com Milvus
Agora que você entendeu a base teórica para avaliar sistemas RAG, vamos mergulhar em um exemplo prático de RAG criado com o banco de dados vetorial Milvus. Vamos percorrer a configuração, a implementação e a avaliação de um sistema RAG. Com base nos resultados, veremos então como podemos melhorar o sistema.
Configurando o ambiente
Primeiro, precisamos configurar nosso ambiente de desenvolvimento. Para fazer isso, primeiro, instale todas as bibliotecas necessárias:
!pip install pymilvus[model] ragas langchain langchain_openai python-dotenv nest_asyncio pypdf langchain_community
Vamos detalhar qual será o uso de cada biblioteca no código:
Pymilvus[model]ajudará você a se conectar ao Milvus, criar coleções, inserir dados e realizar buscas por similaridade.Ragasfornecerá métricas de avaliação, gerará conjuntos de teste sintéticos e avaliará pipelines RAG.Langchaincarregará documentos, os dividirá em partes e preparará dados de texto para incorporação e consulta.Langchain_openaifará interface com os modelos da OpenAI, gerará embeddings e responderá a perguntas usando chamadas de API.Python-dotenvcarregará variáveis de ambiente de um arquivo .env para gerenciar informações sensíveis, como chaves de API.Nest_asynciopermitirá operações assíncronas aninhadas dentro de ambientes síncronos. Especialmente se você estiver usando notebooks Jupiter.Pypdfcarregará documentos PDF, extrairá conteúdo e preparará texto para processamento.Langchain_communityfornecerá carregadores de documentos adicionais e utilitários para integrar recursos contribuídos pela comunidade. Depois de instalar as bibliotecas, importe-as para o seu código e configure suas chaves de API:
import os
import pandas as pd
import nest_asyncio
import openai
from pymilvus import MilvusClient, model
from ragas import evaluate
from ragas.metrics import (
faithfulness,
answer_relevancy,
context_recall,
context_precision,
answer_correctness,
)
from ragas.testset.generator import TestsetGenerator
from ragas.testset.evolutions import simple, reasoning, multi_context
from langchain_community.document_loaders import DirectoryLoader
from langchain.document_loaders import PyPDFLoader
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from dotenv import load_dotenv
from datasets import Dataset
# Load environment variables
# Apply nest_asyncio to allow nested event loops
nest_asyncio.apply()
# Set up OpenAI API key
os.environ["OPENAI_API_KEY"] = "Your API Key"
client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
Importar as bibliotecas e os módulos para o código permitirá que você chame e use suas funções. A chave da OpenAI ajudará você a se autenticar na OpenAI ao fazer chamadas de API. Se você não tiver uma, acesse a página da API da OpenAI e gere uma.
Carregando e preparando documentos
Em seguida, carregaremos nossos documentos e os prepararemos para processamento:
# Load PDF documents from a directory
pdf_loader = DirectoryLoader("/content/data", loader_cls=PyPDFLoader)
documents = pdf_loader.load()
# Ensure each document has a filename in its metadata
for document in documents:
document.metadata['filename'] = document.metadata['source'
O código carrega documentos PDF de um diretório usando a classe PyPDFLoader. Em seguida, cria uma instância de DirectoryLoader, carrega os documentos e itera por cada documento para adicionar um atributo filename aos seus metadados. Isso garante que cada documento seja devidamente identificado e gerenciado com seu nome de arquivo correspondente. Esta etapa é crucial, pois forma a base de conhecimento para o nosso sistema RAG. Estamos usando documentos PDF neste exemplo, mas você poderia adaptar isso para outros tipos de documentos conforme necessário.
Gerando um Conjunto de Teste
Agora que você carregou os dados, precisa de um conjunto diverso de perguntas de teste para ajudar a avaliar efetivamente nosso sistema RAG. Usaremos o framework Ragas para gerar um conjunto de teste sintético.
# Initialize OpenAI models for test set generation
generator_llm = ChatOpenAI(model="gpt-3.5-turbo-16k")
critic_llm = ChatOpenAI(model="gpt-4")
embeddings = OpenAIEmbeddings()
# Create a TestsetGenerator
generator = TestsetGenerator.from_langchain(
generator_llm,
critic_llm,
embeddings
)
# Generate synthetic test set with 10 samples
testset = generator.generate_with_langchain_docs(documents, test_size=10, distributions={simple: 0.5, reasoning: 0.25, multi_context: 0.25})
# Convert test set to Pandas DataFrame
testset_df = testset.to_pandas()
print(testset_df)
Este código inicializa dois modelos de linguagem (gpt-3.5-turbo-16k para gerar conjuntos de teste e gpt-4 para avaliação) e um modelo de embedding da OpenAI. Em seguida, cria uma instância de TestsetGenerator usando esses modelos. O gerador produz um conjunto de teste sintético de 10 amostras a partir dos documentos PDF carregados, com distribuições especificadas para diferentes tipos de perguntas. Este conjunto de teste ajudará você a avaliar vários aspectos do desempenho do seu sistema RAG, incluindo sua capacidade de lidar com consultas simples, tarefas de raciocínio e perguntas que exigem múltiplos contextos. Aqui está um exemplo de um conjunto de teste gerado.
Fig 2- Conjunto de teste gerado usando Ragas
A verdade fundamental é a resposta real a uma determinada pergunta. Mais tarde, a usaremos para medir quão bem nosso sistema RAG está se saindo, avaliando o quão próxima sua saída está dessas respostas fundamentais. Como Shahul aponta na palestra, gerar o conjunto de teste sintético usando Ragas não significa que você o use cegamente. Você precisa filtrar e usar as amostras de que precisa.
Como você tem o conjunto de teste, vamos criar um sistema RAG simples alimentado pelo Milvus e depois avaliá-lo usando o conjunto de teste acima.
Configurando o Milvus e Inserindo Embeddings de Documentos
Agora, vamos configurar nosso banco de dados vetorial Milvus e inserir nossos embeddings de documentos. Certifique-se de ter o Milvus instalado e em execução. Caso contrário, siga este guia abrangente de instalação do Milvus.
# Connect to Milvus instance
milvus_client = MilvusClient(uri="http://localhost:19530")
# Define collection name
collection_name = "pdf_collection"
# Drop the collection if it already exists
if milvus_client.has_collection(collection_name):
milvus_client.drop_collection(collection_name)
# Create a new collection
milvus_client.create_collection(
collection_name=collection_name,
dimension=768, # Dimension of vectors
overwrite=True
)
# Initialize the embedding function
embedding_fn = model.DefaultEmbeddingFunction()
# Extract document texts and generate embeddings
expanded_docs = [doc.page_content for doc in documents]
expanded_vectors = embedding_fn.encode_documents(expanded_docs)
# Prepare data for insertion
expanded_data = [
{"id": i, "vector": expanded_vectors[i], "text": expanded_docs[i], "subject": "pdf_documents"}
for i in range(len(expanded_vectors))
]
# Insert expanded data into the collection
milvus_client.insert(data=expanded_data, collection_name=collection_name)
O código acima se conecta a uma instância do Milvus e configura uma coleção chamada pdf_collection para armazenar vetores de documentos. Se a coleção já existir, ele a exclui e a recria com uma dimensão de 768 para os vetores. Ele inicializa uma função de embedding, extrai texto dos documentos carregados e gera seus embeddings. Em seguida, o código prepara os dados com embeddings e o texto associado e insere esses dados na coleção do Milvus. Esta etapa é onde o Milvus realmente se destaca, pois permite que você realize buscas de similaridade rápidas e eficientes nos embeddings de dados armazenados, o que é crucial para a parte de recuperação do seu sistema RAG.
Realizando Busca por Similaridade
Com seus documentos indexados no Milvus, agora você pode realizar buscas por similaridade para recuperar contextos relevantes para nossas perguntas:
# Define the search parameters
search_params = {"metric_type": "COSINE", "params": {"nprobe": 20}} # nprobe for better recall
# Perform the search
query_vectors = embedding_fn.encode_queries(testset_df['question'].tolist())
results = milvus_client.search(
collection_name=collection_name,
data=query_vectors,
anns_field="vector", # specify the vector field name
search_params=search_params,
limit=3, # number of top results to retrieve
output_fields=["id", "text"]
)
O código acima configura parâmetros de busca para a coleção do Milvus usando similaridade de cosseno e um valor de nprobe de 20 para melhor recall. Ele codifica as perguntas do conjunto de teste em vetores de consulta e realiza uma busca na coleção pdf_collection, recuperando os três vetores mais semelhantes para cada consulta. Os resultados da busca incluem os IDs e o text dos documentos correspondentes.
Gerando Respostas Usando um Modelo de Linguagem Grande
Com os contextos relevantes recuperados, agora você pode gerar respostas usando um modelo de linguagem. Neste caso, usaremos GPT 3.5 turbo.
# Function to generate answers using OpenAI
def generate_answer(question, contexts):
context_text = " ".join(contexts)
messages = [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": f"Context: {context_text}nnQuestion: {question}nAnswer:"}
]
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=messages,
max_tokens=100,
temperature=0.7,
)
return response.choices[0].message.content.strip()
# Extract contexts and generate answers using OpenAI
contexts = []
answers = []
for i, result in enumerate(results):
context = [match['entity']['text'] for match in result]
contexts.append(context)
question = testset_df['question'].iloc[i]
answer = generate_answer(question, context)
answers.append(answer)
O código define uma função generate_answer que usa o modelo gpt-3.5-turbo da OpenAI para gerar respostas com base em uma determinada pergunta e contexto. Ele prepara mensagens para a chamada da API, concatena o contexto e consulta o modelo. Em seguida, extrai e retorna a resposta gerada. O loop subsequente itera pelos resultados da busca e usa a função generate_answer para gerar respostas para cada pergunta no conjunto de teste, armazenando os contextos e as respostas em listas. As perguntas usadas no loop para gerar respostas são as mesmas geradas no conjunto de teste.
Como agora você tem as respostas geradas pelo sistema RAG e as respostas de referência, vamos avaliar quão bem o sistema RAG está se saindo.
Avaliando o Sistema RAG
Por fim, avaliaremos o desempenho do nosso sistema RAG usando as métricas discutidas anteriormente:
# Ensure all lists are the same length
min_length = min(len(testset_df['question']), len(testset_df['ground_truth']), len(answers), len(contexts))
questions = testset_df['question'][:min_length]
ground_truths = testset_df['ground_truth'][:min_length]
answers = answers[:min_length]
contexts = contexts[:min_length]
# Create the dataset with correct column names
data = {
"question": questions,
"answer": answers,
"contexts": contexts,
"ground_truth": ground_truths
}
from datasets import Dataset
# Convert dict to dataset
dataset = Dataset.from_pandas(pd.DataFrame(data))
# Evaluate using RAGAS
metrics = evaluate(
dataset=dataset,
metrics=[
answer_correctness,
context_precision,
context_recall,
faithfulness,
answer_relevancy,
],
raise_exceptions=False #handle async issues
)
# Convert result to DataFrame for better readability
result_df = metrics.to_pandas()
print(result_df)
O código garante consistência no processo de avaliação ao reduzir todas as listas relevantes ao mesmo comprimento mínimo. Isso evita comprimentos incompatíveis que poderiam causar erros durante a avaliação. Em seguida, ele cria um dicionário com essas listas reduzidas e o converte em um Pandas DataFrame, que é então transformado em um Hugging Face Dataset. Esse conjunto de dados estruturado permite uma avaliação sistemática usando o framework RAGAS, que compara as respostas geradas com as verdades de referência. As métricas de avaliação (correção da resposta, precisão do contexto, recall do contexto, fidelidade e relevância da resposta) fornecem uma avaliação do desempenho do pipeline RAG.
Dê uma olhada nos resultados da avaliação abaixo:
Fig 3- Resultados da avaliação do sistema RAG com Ragas
A precisão do contexto do nosso sistema RAG e o recall são excelentes, e a relevância da resposta é louvável. Mas a correção da resposta é bastante baixa.
O lado da recuperação é bom devido ao excelente recall e à precisão do contexto. Portanto, podemos concluir que a parte de geração pode estar afetando a correção das nossas respostas. Para melhorar isso, você pode usar um modelo de geração de respostas mais poderoso, como GPT-4.
Conclusão
Avaliar e melhorar sistemas de Retrieval-Augmented Generation (RAG) é uma tarefa complexa, mas essencial no âmbito da recuperação de informações orientada por IA. Ao aproveitar uma abordagem orientada por métricas, como demonstrado por Jithin James e Shahul Es, você pode refinar sistematicamente seus sistemas RAG para garantir que eles forneçam informações precisas, relevantes e confiáveis.
Para mais detalhes sobre este tópico, assista à gravação da palestra no YouTube.
Recursos adicionais
Continue lendo

How to Build an Enterprise-Ready RAG Pipeline on AWS with Bedrock, Zilliz Cloud, and LangChain
Build production-ready enterprise RAG with AWS Bedrock, Nova models, Zilliz Cloud, and LangChain. Complete tutorial with deployable code.

Zilliz Cloud Enterprise Vector Search Powers High-Performance AI on AWS
Zilliz Cloud on AWS powers secure, scalable, ultra-fast vector search for enterprise AI apps, with BYOC, sub-10ms latency, and zero-DevOps simplicity.

Build for the Boom: Why AI Agent Startups Should Build Scalable Infrastructure Early
Explore strategies for developing AI agents that can handle rapid growth. Don't let inadequate systems undermine your success during critical breakthrough moments.


