Source code for eval_framework.contract
from abc import ABC, abstractmethod
from collections.abc import Iterable, Sequence
from enum import Enum
from typing import TYPE_CHECKING, Any
from pydantic import BaseModel, ConfigDict
from eval_framework.shared.types import BaseMetricContext, Completion
from template_formatting.formatter import BaseFormatter, Message
if TYPE_CHECKING:
from eval_framework.llm.base import BaseLLM
from eval_framework.metrics.base import BaseMetric
[docs]
class ResponseType(Enum):
COMPLETION = "completion"
LOGLIKELIHOODS = "loglikelihoods"
[docs]
class Sample(BaseModel):
model_config = ConfigDict(extra="forbid")
id: int
subject: str
messages: list[Message]
ground_truth: str | list[str] | None
possible_completions: list[str] | None
context: BaseMetricContext | list[BaseMetricContext] | None = None
[docs]
class Eval(ABC):
"""The contract a caller relies on to run an evaluation"""
[docs]
@abstractmethod
def iterate_samples(self, num_samples: int | None = None) -> Iterable[Sample]:
"""Yield the eval's samples across all subjects. ``num_samples`` caps how many are yielded PER
SUBJECT (``None`` = no cap), so a benchmark with S subjects yields up to ``S * num_samples``
samples. A sample's ``id`` is its index within its subject, restarting at 0 for each subject."""
[docs]
@abstractmethod
def generate_completions(
self,
llm: "BaseLLM",
samples: list[Sample],
stop_sequences: list[str] | None = None,
max_tokens: int | None = None,
fail_on_error: bool = True,
) -> list[Completion]:
"""Run ``llm`` over ``samples`` and return their completions."""
[docs]
@abstractmethod
def get_stop_sequences(self) -> list[str]:
"""Stop sequences the eval requests for completion generation."""
[docs]
@abstractmethod
def get_max_tokens(self) -> int | None:
"""Token limit the eval requests for completion generation, or ``None`` for no limit."""
[docs]
@abstractmethod
def get_response_type(self) -> ResponseType: ...
[docs]
@abstractmethod
def display_name(self) -> str:
"""Human-readable display name. Is allowed to have special characters and whitespaces."""
...
[docs]
class Benchmark(ABC):
"""A benchmark is used to provide means of measuring model performance in a domain.
Benchmark act as factories for `Eval`. They bind all the a prior known information and enrich it
with the arguments provided at runtime to create concrete instances of `Eval` which are used to
provide measurements of the models performance.
"""
[docs]
@abstractmethod
def id(self) -> str:
"Uniquely identifies the benchmark"
[docs]
@abstractmethod
def response_type(self) -> ResponseType:
"""The benchmark's response type"""
[docs]
@abstractmethod
def metrics(self) -> list[type["BaseMetric"]]:
"""The benchmark's metrics"""
[docs]
@abstractmethod
def subjects(self) -> list[Any]:
"""Subjects of the benchmark"""
[docs]
@abstractmethod
def display_name(self) -> str:
"""Human-readable display name. Is allowed to have special characters and whitespaces."""
[docs]
@abstractmethod
def create(
self,
num_fewshot: int,
custom_subjects: list[str] | None,
custom_hf_revision: str | None,
seed: int | None = None,
) -> Eval: ...
[docs]
@abstractmethod
def markdown_doc(self, formatters: Sequence[BaseFormatter]) -> str:
"""Render the benchmarks's documentation as markdown."""
...