grantforge-api / backend /scripts /evaluate_ragas.py
GrantForge Bot
Deploy to Hugging Face
afd56bc
# ruff: noqa: E402
import os
import json
import logging
from datasets import Dataset
from dotenv import load_dotenv
load_dotenv()
# Konfiguracja logowania
logging.basicConfig(level=logging.INFO, format="%(name)s - %(levelname)s - %(message)s")
logger = logging.getLogger(__name__)
# Pobranie naszych domyślnych modułów
from core.llm_router import get_llm
from rag_pipeline.hybrid_retriever import get_hybrid_retriever
from rag_pipeline.retriever import generate_answer
from langchain_google_genai import GoogleGenerativeAIEmbeddings
try:
from ragas import evaluate
from ragas.metrics import (
context_precision,
faithfulness,
answer_relevancy,
context_recall,
)
from ragas.llms.prompt import LangchainLLMWrapper
from ragas.embeddings.base import LangchainEmbeddingsWrapper
except ImportError:
logger.error(
"Brak zainstalowanych bibliotek 'ragas' / 'datasets'. Zainstaluj środowisko testowe."
)
exit(1)
def run_evaluation():
dataset_path = os.path.join(
os.path.dirname(__file__), "..", "tests", "golden_dataset.json"
)
if not os.path.exists(dataset_path):
logger.error(f"Nie znaleziono pliku {dataset_path}")
return
with open(dataset_path, "r", encoding="utf-8") as f:
golden_data = json.load(f)
logger.info(f"Loaded {len(golden_data)} pytań z Golden Dataset.")
# Inicjalizacja retrievera i łańcucha RAG do generowania odpowiedzi bieżącego systemu
retriever = get_hybrid_retriever()
if not retriever:
logger.error(
"Nie znaleziono funkcjonującego wektora w systemie. Uruchom najpierw ingest."
)
return
questions = []
answers = []
contexts = []
ground_truths = []
logger.info("🛠️ Trwa generowanie odpowiedzi RAG celem poddania ewaluacji...")
for idx, item in enumerate(golden_data):
q = item["question"]
gt = item["ground_truth_answer"]
docs = retriever.invoke(q)
retrieved_texts = [d.page_content for d in docs]
# Generowanie używając naszego agenta
answer = generate_answer(q, docs)
questions.append(q)
answers.append(answer)
contexts.append(retrieved_texts)
# Ragas < 0.2 używa ground_truths, Ragas >= 0.2 używa ground_truth, dodajmy format listowy, standardowy dla starszych
# Jeśli użyjemy Ragas >= 0.2.x, ground_truth powinno być typu string. Dopasujmy do nowszego RAGAS:
ground_truths.append(gt)
data = {
"question": questions,
"answer": answers,
"contexts": contexts,
"ground_truth": ground_truths,
}
dataset = Dataset.from_dict(data)
# Skonfigurowanie RAGAS jako evaluatora używającego Google Gemini z naszego routera (unikanie kosztów OpenAI)
logger.info(
"📊 Rozpoczynam ocenę metryk (RAGAS). Używam LLM od Google via LangChainWrapper..."
)
eval_llm = get_llm(task_type="critical")
eval_embeddings = GoogleGenerativeAIEmbeddings(
model="text-embedding-004", google_api_key=os.environ.get("GOOGLE_API_KEY")
)
try:
ragas_eval_llm = LangchainLLMWrapper(eval_llm)
ragas_eval_emb = LangchainEmbeddingsWrapper(eval_embeddings)
result = evaluate(
dataset=dataset,
metrics=[context_precision, faithfulness, answer_relevancy, context_recall],
llm=ragas_eval_llm,
embeddings=ragas_eval_emb,
)
print("\n\n=== 🏆 WYNIKI EWALUACJI RAGAS ===")
print(result)
import datetime
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
# Safe format for json
result_dict = result.to_pandas().to_dict(orient="records")
out_json = f"rag_evaluation_results_{timestamp}.json"
with open(out_json, "w", encoding="utf-8") as f:
json.dump(result_dict, f, ensure_ascii=False, indent=2)
out_csv = f"rag_evaluation_results_{timestamp}.csv"
df = result.to_pandas()
df.to_csv(out_csv, index=False)
print(
f"💡 Analiza szczegółowa została zapisana w lokalizacji: {out_json} oraz {out_csv}"
)
except Exception as e:
logger.error(f"Nie udało się zakończyć ewaluacji: {e}")
if __name__ == "__main__":
run_evaluation()