Coverage for /home/admin/Documents/AI/applications/lexigram-dev/lexigram/experimental/ai/lexigram-ai-rag/src/lexigram/ai/rag/evaluation/evaluator.py: 95%
40 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-25 07:19 +0800
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-25 07:19 +0800
1"""Main RAG evaluation orchestrator."""
3from __future__ import annotations
5from typing import Any
7from lexigram.ai.rag.evaluation.base import EvaluatorBase
8from lexigram.ai.rag.evaluation.types import (
9 EvaluationResult,
10 MetricType,
11 RAGEvaluationReport,
12)
15class RAGEvaluator:
16 """Comprehensive RAG evaluation orchestrator.
18 Coordinates multiple evaluators to produce a complete evaluation report.
19 """
21 def __init__(
22 self,
23 evaluators: list[EvaluatorBase] | None = None,
24 weights: dict[MetricType, float] | None = None,
25 ):
26 """Initialize RAG evaluator.
28 Args:
29 evaluators: List of evaluators to use.
30 weights: Optional weights for computing overall score.
31 """
32 self.evaluators = evaluators or []
33 self.weights = weights or {}
35 def add_evaluator(self, evaluator: EvaluatorBase) -> Any:
36 """Add an evaluator.
38 Args:
39 evaluator: Evaluator to add.
40 """
41 self.evaluators.append(evaluator)
43 async def evaluate(
44 self,
45 query: str,
46 retrieved_docs: list[Any],
47 generated_answer: str,
48 reference_answer: str | None = None,
49 **kwargs,
50 ) -> RAGEvaluationReport:
51 """Run all evaluators and produce a report.
53 Args:
54 query: The query.
55 retrieved_docs: Retrieved documents.
56 generated_answer: Generated answer.
57 reference_answer: Optional ground truth.
58 **kwargs: Additional parameters for evaluators.
60 Returns:
61 Complete evaluation report.
62 """
63 results = []
65 # Run all evaluators
66 for evaluator in self.evaluators:
67 result = await evaluator.evaluate(
68 query=query,
69 retrieved_docs=retrieved_docs,
70 generated_answer=generated_answer,
71 reference_answer=reference_answer,
72 **kwargs,
73 )
74 results.append(result)
76 # Calculate overall score
77 overall_score = self._calculate_overall_score(results)
79 return RAGEvaluationReport(
80 query=query,
81 retrieved_docs=retrieved_docs,
82 generated_answer=generated_answer,
83 reference_answer=reference_answer,
84 results=results,
85 overall_score=overall_score,
86 metadata=kwargs.get("metadata", {}),
87 )
89 def _calculate_overall_score(self, results: list[EvaluationResult]) -> float:
90 """Calculate weighted overall score.
92 Args:
93 results: Individual evaluation results.
95 Returns:
96 Overall score (0.0 to 1.0).
97 """
98 if not results:
99 return 0.0
101 # If no weights specified, use equal weights
102 if not self.weights:
103 # Invert hallucination rate (lower is better)
104 total = 0.0
105 count = 0
106 for result in results:
107 if result.metric_type == MetricType.HALLUCINATION_RATE:
108 total += 1.0 - result.score # Invert
109 else:
110 total += result.score
111 count += 1
112 return total / count if count > 0 else 0.0
114 # Use weighted average
115 weighted_sum = 0.0
116 total_weight = 0.0
118 for result in results:
119 weight = self.weights.get(result.metric_type, 0.0)
120 if weight > 0:
121 score = result.score
122 # Invert hallucination rate
123 if result.metric_type == MetricType.HALLUCINATION_RATE:
124 score = 1.0 - score
125 weighted_sum += score * weight
126 total_weight += weight
128 return weighted_sum / total_weight if total_weight > 0 else 0.0