File size: 1,482 Bytes
f868144
8521f60
 
f868144
8521f60
 
 
79bdbbe
8521f60
 
 
4dc151e
 
 
 
 
8521f60
 
4dc151e
 
 
 
 
f868144
4dc151e
f868144
4dc151e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""Composite RAG metrics combining retrieval + generation (single‐mapping version)."""

from __future__ import annotations
from typing import Mapping
import math


def harmonic_mean(scores: Mapping[str, float]) -> float:
    """Compute the harmonic mean of positive scores."""
    if not scores:
        return 0.0
    if any(v <= 0 for v in scores.values()):
        return 0.0
    else:
        inv_sum = sum(1.0 / (v) for v in scores.values())
        return len(scores) / inv_sum if inv_sum and inv_sum != 0 else 0.0


def rag_score(
    scores: Mapping[str, float],
    *,
    alpha: float = 0.5,
) -> float:
    """
    Combine retrieval & generation sub-scores (0-1) via weighted HM.
    """
    # Split the incoming flat mapping into two maps: retrieval vs generation
    retr_map: dict[str, float] = {}
    gen_map: dict[str, float] = {}
    for k, v in scores.items():
        if k.startswith("retrieval_"):
            retr_map[k[len("retrieval_"):]] = v
        elif k.startswith("generation_"):
            gen_map[k[len("generation_"):]] = v
        else:
            # ignore any key that doesn't start with 'retrieval_' or 'generation_'
            pass

    # If either side is empty, we cannot score
    if not retr_map or not gen_map:
        return 0.0

    retr_score = harmonic_mean(retr_map)
    gen_score = harmonic_mean(gen_map)

    if retr_score == 0 or gen_score == 0:
        return 0.0

    return 1.0 / (alpha / retr_score + (1 - alpha) / gen_score)