Spaces:
Sleeping
Sleeping
Download evaluate.py from thaidinhz1/rag-vietnamese: direct link, hf CLI and curl.
- Browser
- Download file 4.95 kB
-
https://huggingface.co/spaces/thaidinhz1/rag-vietnamese/resolve/9e7ded3dd31be325a258cd2b19fbc3441d5fe4f5/evaluate.py
- Command line
-
hf download hf://spaces/thaidinhz1/rag-vietnamese@9e7ded3dd31be325a258cd2b19fbc3441d5fe4f5/evaluate.py
-
curl -L -o evaluate.py https://huggingface.co/spaces/thaidinhz1/rag-vietnamese/resolve/9e7ded3dd31be325a258cd2b19fbc3441d5fe4f5/evaluate.py
4.95 kB
| """ | |
| 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__": | |
| import sys | |
| golden_path = sys.argv[1] if len(sys.argv) > 1 else "data/golden_set.json" | |
| sample = int(sys.argv[2]) if len(sys.argv) > 2 else 20 | |
| evaluate(golden_set_path=golden_path, sample=sample) |