Spaces:
Sleeping
Sleeping
File size: 4,765 Bytes
06f35c0 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | """
RAGAS evaluation script.
Dùng LLM-as-judge thay vì ragas library để tránh dependency conflicts.
Metrics: Faithfulness, Answer Relevancy, Context Recall
"""
print("Loading evaluate.py...")
import json
print("json ok")
import time
print("time ok")
from groq import Groq
print("groq ok")
from dotenv import load_dotenv
import os
load_dotenv()
client = Groq(api_key=os.environ["GROQ_API_KEY"])
JUDGE_MODEL = "llama-3.3-70b-versatile"
print("groq client ok")
from src.rag import answer as rag_answer
print("rag ok")
def judge(prompt: str) -> float:
"""Gọi LLM judge, trả về score 0.0-1.0."""
response = client.chat.completions.create(
model=JUDGE_MODEL,
messages=[{"role": "user", "content": prompt}],
max_tokens=10,
temperature=0.0,
)
text = response.choices[0].message.content.strip()
try:
score = float(text.split()[0])
return max(0.0, min(1.0, score))
except Exception:
return 0.5
def eval_faithfulness(question: str, answer: str, contexts: list[str]) -> float:
context_text = "\n".join(contexts)
prompt = f"""Đánh giá xem câu trả lời có trung thực với ngữ cảnh không.
Chỉ trả về một số từ 0.0 đến 1.0 (1.0 = hoàn toàn trung thực, 0.0 = bịa đặt).
Ngữ cảnh: {context_text}
Câu trả lời: {answer}
Score:"""
return judge(prompt)
def eval_answer_relevancy(question: str, answer: str) -> float:
prompt = f"""Đánh giá xem câu trả lời có liên quan đến câu hỏi không.
Chỉ trả về một số từ 0.0 đến 1.0 (1.0 = rất liên quan, 0.0 = không liên quan).
Câu hỏi: {question}
Câu trả lời: {answer}
Score:"""
return judge(prompt)
def eval_context_recall(question: str, ground_truth: str, contexts: list[str]) -> float:
context_text = "\n".join(contexts)
prompt = f"""Đánh giá xem ngữ cảnh có chứa đủ thông tin để trả lời câu hỏi theo đáp án chuẩn không.
Chỉ trả về một số từ 0.0 đến 1.0 (1.0 = đủ thông tin, 0.0 = thiếu hoàn toàn).
Câu hỏi: {question}
Đáp án chuẩn: {ground_truth}
Ngữ cảnh: {context_text}
Score:"""
return judge(prompt)
def evaluate(golden_set_path: str = "data/golden_set.json", sample: int = 20):
with open(golden_set_path, encoding="utf-8") as f:
golden = json.load(f)
# Lấy sample câu hỏi có ground_truth thực (bỏ out_of_scope)
items = [q for q in golden if q.get("type") != "out_of_scope"][:sample]
results = []
print(f"Đánh giá {len(items)} câu hỏi...\n")
for i, item in enumerate(items, 1):
question = item["question"]
ground_truth = item["answer"]
print(f"[{i}/{len(items)}] {question[:60]}...")
try:
result = rag_answer(question, top_k=5)
ans = result["answer"]
context_texts = result["contexts"]
faith = eval_faithfulness(question, ans, context_texts)
relevancy = eval_answer_relevancy(question, ans)
recall = eval_context_recall(question, ground_truth, context_texts)
results.append({
"question": question,
"ground_truth": ground_truth,
"answer": ans,
"faithfulness": faith,
"answer_relevancy": relevancy,
"context_recall": recall,
})
print(f" Faithfulness: {faith:.2f} | Relevancy: {relevancy:.2f} | Recall: {recall:.2f}")
time.sleep(2) # tránh rate limit
except Exception as e:
print(f" Lỗi: {e}")
time.sleep(5)
if results:
avg_faith = sum(r["faithfulness"] for r in results) / len(results)
avg_rel = sum(r["answer_relevancy"] for r in results) / len(results)
avg_recall = sum(r["context_recall"] for r in results) / len(results)
print(f"\n{'='*50}")
print(f"KẾT QUẢ ĐÁNH GIÁ ({len(results)} câu hỏi)")
print(f"{'='*50}")
print(f"Faithfulness: {avg_faith:.3f}")
print(f"Answer Relevancy: {avg_rel:.3f}")
print(f"Context Recall: {avg_recall:.3f}")
print(f"Average: {(avg_faith + avg_rel + avg_recall) / 3:.3f}")
with open("eval_results.json", "w", encoding="utf-8") as f:
json.dump({
"summary": {
"faithfulness": avg_faith,
"answer_relevancy": avg_rel,
"context_recall": avg_recall,
},
"details": results,
}, f, ensure_ascii=False, indent=2)
print("\nĐã lưu chi tiết vào eval_results.json")
if __name__ == "__main__":
evaluate(sample=20) |