File size: 2,365 Bytes
9c84f9d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
from typing import Any

from solar_eval.evaluators.base import BaseEvaluator
from solar_eval.models.sample import EvalSample
from solar_eval.providers.base import BaseProvider


class CompositeEvaluator(BaseEvaluator):
    """Combines multiple evaluators with weights.

    Example: 50% LLM Judge + 50% Rule-based for title evaluation.
    """

    def __init__(self, components: list[dict[str, Any]]) -> None:
        """Components: [{evaluator: BaseEvaluator, weight: float}]"""
        self.components = components

    @property
    def required_fields(self) -> frozenset[str]:
        """κ΅¬μ„±λœ ν•˜μœ„ 평가기 μš”κ΅¬ ν•„λ“œμ˜ ν•©μ§‘ν•©.

        `components` λŠ” μΈμŠ€ν„΄μŠ€λ§ˆλ‹€ λ‹€λ₯΄κ²Œ κ΅¬μ„±λ˜λ―€λ‘œ(μƒμ„±μž 인자) κ³ μ •λœ
        클래슀 μ†μ„±μœΌλ‘œλŠ” ν‘œν˜„ν•  수 μ—†λ‹€ -- `BaseEvaluator.required_fields`
        λ₯Ό `@property` 둜 μ˜€λ²„λΌμ΄λ“œν•΄ 맀번 ν•˜μœ„ ν‰κ°€κΈ°μ—μ„œ 합쳐낸닀.
        """
        fields: frozenset[str] = frozenset()
        for comp in self.components:
            fields |= comp["evaluator"].required_fields
        return fields

    async def evaluate(
        self,
        sample: EvalSample,
        provider: BaseProvider | None = None,
        judge_model: str = "gpt-4o",
    ) -> dict[str, Any]:
        component_results = []
        weighted_score = 0.0

        for comp in self.components:
            evaluator = comp["evaluator"]
            weight = comp["weight"]
            result = await evaluator.evaluate(
                sample=sample,
                provider=provider,
                judge_model=judge_model,
            )
            weighted_score += result["score"] * weight
            component_results.append(
                {
                    "weight": weight,
                    "score": result["score"],
                    "details": result.get("details", {}),
                }
            )

        return {
            "score": weighted_score,
            "components": component_results,
            "details": {"components": component_results},
        }

    def aggregate(self, results: list[dict[str, Any]]) -> dict[str, Any]:
        if not results:
            return {"overall_score": 0.0, "scores": {}}

        overall = sum(r["score"] for r in results) / len(results)
        return {"overall_score": overall, "num_samples": len(results)}