Files
wehub-resource-sync 5a558eb09e
TypeScript SDK Compatibility V1.x E2E Tests / Select Node version matrix (push) Has been cancelled
TypeScript SDK Compatibility V1.x E2E Tests / TypeScript SDK Compatibility V1.x E2E Tests Node ${{matrix.node_version}} (push) Has been cancelled
TypeScript SDK E2E Tests / TypeScript SDK E2E Tests Node ${{matrix.node_version}} (push) Has been cancelled
Opik Optimizer - E2E Tests / build-opik (push) Has been cancelled
TypeScript SDK Compatibility V1.x E2E Tests / build-opik (push) Has been cancelled
Python SDK E2E Tests / Select Python version matrix (push) Has been cancelled
Python SDK E2E Tests / Python SDK E2E Tests ${{matrix.python_version}} (push) Has been cancelled
Python SDK E2E Tests / build-opik (push) Has been cancelled
Python SDK Compatibility V1.x E2E Tests / Select Python version matrix (push) Has been cancelled
Python SDK Compatibility V1.x E2E Tests / Python SDK Compatibility V1.x E2E Tests ${{matrix.python_version}} (push) Has been cancelled
Python SDK Compatibility V1.x E2E Tests / build-opik (push) Has been cancelled
TypeScript SDK E2E Tests / Select Node version matrix (push) Has been cancelled
TypeScript SDK E2E Tests / build-opik (push) Has been cancelled
Opik Optimizer - E2E Tests / Opik Optimizer E2E Tests Python ${{matrix.python_version}} (push) Has been cancelled
Opik Optimizer - E2E Tests / Opik Optimizer Integration Smoke Tests (push) Has been cancelled
🐙 Code Quality / detect (push) Has been cancelled
🐙 Code Quality / lint (${{ matrix.leg.name }}) (push) Has been cancelled
🐙 Code Quality / summary (push) Has been cancelled
TypeScript SDK Library Integration Tests / Check Secrets (push) Has been cancelled
TypeScript SDK Library Integration Tests / opik-vercel (Vercel AI SDK / eve) (push) Has been cancelled
SDK Library Integration Tests Runner / Check Secrets (push) Has been cancelled
SDK Library Integration Tests Runner / Missed OpenAI API Key Warning (push) Has been cancelled
SDK Library Integration Tests Runner / Build (push) Has been cancelled
SDK Library Integration Tests Runner / openai_tests (push) Has been cancelled
SDK Library Integration Tests Runner / langchain_tests (push) Has been cancelled
SDK Library Integration Tests Runner / langchain_legacy_tests (push) Has been cancelled
SDK Library Integration Tests Runner / llama_index_tests (push) Has been cancelled
SDK Library Integration Tests Runner / anthropic_tests (push) Has been cancelled
SDK Library Integration Tests Runner / mistral_tests (push) Has been cancelled
SDK Library Integration Tests Runner / groq_tests (push) Has been cancelled
SDK Library Integration Tests Runner / aisuite_tests (push) Has been cancelled
SDK Library Integration Tests Runner / haystack_tests (push) Has been cancelled
SDK Library Integration Tests Runner / dspy_tests (push) Has been cancelled
SDK Library Integration Tests Runner / crewai_v0_tests (push) Has been cancelled
SDK Library Integration Tests Runner / crewai_v1_tests (push) Has been cancelled
SDK Library Integration Tests Runner / genai_tests (push) Has been cancelled
SDK Library Integration Tests Runner / adk_tests (push) Has been cancelled
SDK Library Integration Tests Runner / adk_legacy_1_3_0_tests (push) Has been cancelled
SDK Library Integration Tests Runner / evaluation_metrics_tests (push) Has been cancelled
SDK Library Integration Tests Runner / bedrock_tests (push) Has been cancelled
SDK Library Integration Tests Runner / litellm_tests (push) Has been cancelled
SDK Library Integration Tests Runner / harbor_tests (push) Has been cancelled
SDK Library Integration Tests Runner / Slack Notification (push) Has been cancelled
Lint Opik Helm Chart / render-equality (push) Has been cancelled
Opik Optimizer - Unit Tests / Opik Optimizer Unit Tests Python ${{matrix.python_version}} (push) Has been cancelled
Python BE E2E Tests / Python BE E2E (push) Has been cancelled
Python Backend Tests / run-python-backend-tests (push) Has been cancelled
Python SDK Unit Tests / Python SDK Unit Tests ${{matrix.python_version}} (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
SDK E2E Libraries Integration Tests / Check Secrets (push) Has been cancelled
SDK E2E Libraries Integration Tests / Missed OpenAI API Key Warning (push) Has been cancelled
SDK E2E Libraries Integration Tests / build-opik (push) Has been cancelled
SDK E2E Libraries Integration Tests / E2E Lib Integration Python ${{matrix.python_version}} (push) Has been cancelled
TypeScript SDK Integration Build & Publish / build-and-publish (opik-gemini) (push) Has been cancelled
TypeScript SDK Integration Build & Publish / build-and-publish (opik-langchain) (push) Has been cancelled
TypeScript SDK Integration Build & Publish / build-and-publish (opik-openai) (push) Has been cancelled
TypeScript SDK Integration Build & Publish / build-and-publish (opik-otel) (push) Has been cancelled
TypeScript SDK Integration Build & Publish / build-and-publish (opik-vercel) (push) Has been cancelled
TypeScript SDK Build & Publish / build-and-publish (push) Has been cancelled
TypeScript SDK Unit Tests / Test on Node ${{ matrix.node-version }} (push) Has been cancelled
Backend Tests / discover-tests (push) Has been cancelled
Backend Tests / ${{ matrix.name }} (push) Has been cancelled
Build and Publish SDK / build-and-publish (push) Has been cancelled
Build Opik Docker Images / set-version (push) Has been cancelled
Build Opik Docker Images / build-backend (push) Has been cancelled
Build Opik Docker Images / build-sandbox-executor-python (push) Has been cancelled
Build Opik Docker Images / build-python-backend (push) Has been cancelled
Build Opik Docker Images / build-frontend (push) Has been cancelled
Build Opik Docker Images / create-git-tag (push) Has been cancelled
ClickHouse Migration Cluster Check / validate-clickhouse-migrations (push) Has been cancelled
Docs - Publish / run (push) Has been cancelled
E2E Tests - Post Merge (v2) / 🧪 E2E v2 Tests (${{ github.event.inputs.tier || 't1' }}) (push) Has been cancelled
E2E Tests - Post Merge (v2) / 📢 Slack Notification (push) Has been cancelled
Frontend Unit Tests / Test on Node 20 (push) Has been cancelled
Guardrails E2E Tests / Select Python version matrix (push) Has been cancelled
Guardrails E2E Tests / Guardrails E2E Tests ${{matrix.python_version}} (push) Has been cancelled
Guardrails E2E Tests / 📢 Slack Notification (push) Has been cancelled
Guardrails Backend Unit Tests / Guardrails Backend Unit Tests (push) Has been cancelled
Guardrails Backend Unit Tests / 📢 Slack Notification (push) Has been cancelled
Lint Opik Helm Chart / lint-helm-chart (Helm v3.21.0) (push) Has been cancelled
Lint Opik Helm Chart / lint-helm-chart (Helm v4.2.0) (push) Has been cancelled
Lint Opik Helm Chart / unittest-helm-chart (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:25:44 +08:00

298 lines
10 KiB
Python

"""
ARC-AGI metric helpers, registry, and canonical evaluation defaults.
The HRPO pipeline optimizes Python programs that solve ARC puzzles. Relying on
a single scalar obscures *why* a candidate failed, so we collect multiple
signals that describe different notions of success:
``arc_agi2_exact``
Strict, pass@1-like accuracy. Equals 1.0 only when every output grid
matches exactly. This is the primary metric reported to Opik.
``arc_agi2_approx_match``
Fraction of matching cells between predicted and gold grids; aka “likeness”.
Serves as a shaped reward so HRPO can learn even before landing on an exact
solution. It discourages degenerate strategies such as outputting all
zeros or copying the input grid.
``arc_agi2_label_iou``
Average per-label intersection-over-union. Measures whether the correct
color blobs appear in roughly the right locations—useful for rules that are
structurally right but slightly misaligned.
``arc_agi2_foreground_match``
Likeness computed only over the foreground (all cells whose gold value is
not the dominant background color). This removes large blankets of
whitespace from the equation so geometry/palette mistakes count more.
The optimizer typically samples *k* candidate programs and evaluates each one.
We default to ``pass@k = 6`` to align with the default completion count used in
the ARC-AGI HRPO entrypoint. Keep ``DEFAULT_PASS_AT_K`` in sync with
:class:`EvaluationConfig` to ensure the scoring reason text matches the reward
weighting.
:func:`build_multi_metric_objective` wires all of the above into
:class:`opik_optimizer.MultiMetricObjective` so callers can simply request
``DEFAULT_METRIC_SEQUENCE``.
"""
from __future__ import annotations
from dataclasses import dataclass
from typing import Any
from collections.abc import Callable, Iterable
import numpy as np
from opik.evaluation.metrics import score_result
from opik_optimizer import MultiMetricObjective
def approx_match_score(pred: np.ndarray, truth: np.ndarray) -> float:
"""
Compute per-pixel likeness for equally sized grids.
ARC puzzles often have failure cases where the candidate solution overlaps
the ground truth but differs in a few cells. Returning the fraction of
matching pixels lets us provide dense feedback to HRPO even when the exact
metric is zero.
"""
if pred.shape != truth.shape:
return 0.0
if truth.size == 0:
return 1.0
return float(np.mean(pred == truth))
def label_iou(pred: np.ndarray, truth: np.ndarray) -> float:
"""
Average per-label intersection-over-union.
ARC puzzles frequently rely on remembering which color blob represents a
concept. IoU captures “did you put the red blob roughly where it belongs”
even if the blob is slightly misaligned. This metric complements likeness:
likeness punishes all pixel mistakes equally, while IoU focuses on semantic
regions.
"""
if pred.shape != truth.shape or truth.size == 0:
return 0.0
labels = np.unique(truth)
if labels.size == 0:
return 0.0
ious = []
for label in labels:
pred_mask = pred == label
truth_mask = truth == label
union = np.logical_or(pred_mask, truth_mask).sum()
if union == 0:
continue
inter = np.logical_and(pred_mask, truth_mask).sum()
ious.append(inter / union)
if not ious:
return 0.0
return float(np.mean(ious))
def foreground_match_score(
pred: np.ndarray,
truth: np.ndarray,
foreground_values: set[int] | None = None,
) -> float:
"""
Compute likeness while ignoring background cells.
``foreground_values`` can be provided to explicitly specify which gold
colors count as signal. When omitted we fall back to ignoring the dominant
background color per grid (same behavior as before).
"""
if pred.shape != truth.shape:
return 0.0
flat_truth = truth.flatten()
if flat_truth.size == 0:
return 1.0
if foreground_values:
mask = np.isin(truth, list(foreground_values))
else:
values, counts = np.unique(flat_truth, return_counts=True)
background = values[np.argmax(counts)]
mask = truth != background
if not mask.any():
return 1.0
return float(np.mean(pred[mask] == truth[mask]))
@dataclass(frozen=True)
class MetricDefinition:
"""
Describes a scalar metric used inside the multi-metric objective.
Attributes
----------
name:
Identifier passed to Opik. The same name must exist in the payload
returned by :func:`evaluate_arc_response`.
extractor:
Callable that consumes the evaluator payload and returns a float. This
isolates each metric from the exact shape of the evaluation cache.
weight:
Relative contribution when the metric participates in the multi-metric
objective. We keep weights here so callers can simply ask for the
metric by name and still obtain the correct weighting.
"""
name: str
extractor: Callable[[dict[str, Any]], float]
weight: float = 1.0
def _extract(name: str) -> Callable[[dict[str, Any]], float]:
return lambda data: data["metrics"][name]
METRIC_DEFINITIONS: dict[str, MetricDefinition] = {
"arc_agi2_accuracy": MetricDefinition(
name="arc_agi2_accuracy",
extractor=lambda data: data["composite_value"],
weight=1.0,
),
"arc_agi2_exact": MetricDefinition(
name="arc_agi2_exact", extractor=_extract("arc_agi2_exact"), weight=1.0
),
"arc_agi2_approx_match": MetricDefinition(
name="arc_agi2_approx_match",
extractor=_extract("arc_agi2_approx_match"),
weight=0.2,
),
"arc_agi2_label_iou": MetricDefinition(
name="arc_agi2_label_iou",
extractor=_extract("arc_agi2_label_iou"),
weight=0.5,
),
"arc_agi2_foreground_match": MetricDefinition(
name="arc_agi2_foreground_match",
extractor=_extract("arc_agi2_foreground_match"),
weight=0.4,
),
}
# Canonical evaluation knobs shared by the HRPO entry point.
DEFAULT_METRIC_SEQUENCE: tuple[str, ...] = (
"arc_agi2_exact",
"arc_agi2_approx_match",
"arc_agi2_label_iou",
"arc_agi2_foreground_match",
)
DEFAULT_PASS_AT_K: int = 6
LIKENESS_REWARD_WEIGHT: float = METRIC_DEFINITIONS["arc_agi2_approx_match"].weight
LABEL_IOU_REWARD_WEIGHT: float = METRIC_DEFINITIONS["arc_agi2_label_iou"].weight
FOREGROUND_REWARD_WEIGHT: float = METRIC_DEFINITIONS["arc_agi2_foreground_match"].weight
def get_metric_definition(name: str) -> MetricDefinition:
return METRIC_DEFINITIONS[name]
def build_metric_function(
definition: MetricDefinition,
evaluation_fn: Callable[[dict[str, Any], str], dict[str, Any]],
handle_exception: Callable[[str, Exception], score_result.ScoreResult],
) -> Callable[[dict[str, Any], str], score_result.ScoreResult]:
"""Create a score_result-producing function for MultiMetricObjective."""
def metric(
dataset_item: dict[str, Any], llm_output: str
) -> score_result.ScoreResult:
try:
data = evaluation_fn(dataset_item, llm_output)
except Exception as exc: # pragma: no cover - delegated upstream
return handle_exception(definition.name, exc)
return score_result.ScoreResult(
name=definition.name,
value=definition.extractor(data),
scoring_failed=False,
reason=data.get("reason", ""),
metadata=data.get("metadata"),
)
return metric
def build_metric_functions(
names: Iterable[str],
evaluation_fn: Callable[[dict[str, Any], str], dict[str, Any]],
handle_exception: Callable[[str, Exception], score_result.ScoreResult],
) -> list[Callable[[dict[str, Any], str], score_result.ScoreResult]]:
return [
build_metric_function(
get_metric_definition(name), evaluation_fn, handle_exception
)
for name in names
]
def normalized_weights(names: Iterable[str]) -> list[float]:
defs = [get_metric_definition(name) for name in names]
total = sum(defn.weight for defn in defs)
return [defn.weight / total for defn in defs]
def build_multi_metric_objective(
names: Iterable[str],
evaluation_fn: Callable[[dict[str, Any], str], dict[str, Any]],
handle_exception: Callable[[str, Exception], score_result.ScoreResult],
objective_name: str = "arc_agi2_multi",
) -> MultiMetricObjective:
"""
Build the canonical ARC-AGI MultiMetric objective.
Parameters
----------
names:
Metric identifiers to include. The default call site uses
``DEFAULT_METRIC_SEQUENCE`` and mirrors the weights documented in
:data:`METRIC_DEFINITIONS`.
evaluation_fn:
Callable that executes the Python candidate, returning the evaluation
payload consumed by each metric extractor. In practice this is
:func:`evaluate_arc_response`.
handle_exception:
Callback invoked when scoring fails. This lets the orchestrator decide
whether to surface errors or treat them as a zero reward.
objective_name:
Name surfaced to Opik dashboards.
Returns
-------
MultiMetricObjective
Ready-to-use objective that automatically applies the correct weights
and reasoning metadata. Downstream callers simply pass it into HRPO.
The weights correspond to :data:`METRIC_DEFINITIONS` so updating this
registry keeps both MultiMetric and EvaluationConfig in sync.
"""
metric_functions = build_metric_functions(names, evaluation_fn, handle_exception)
weights = normalized_weights(names)
return MultiMetricObjective(
metrics=metric_functions,
weights=weights,
name=objective_name,
)
__all__ = [
"MetricDefinition",
"METRIC_DEFINITIONS",
"build_metric_function",
"build_metric_functions",
"normalized_weights",
"build_multi_metric_objective",
"DEFAULT_METRIC_SEQUENCE",
"DEFAULT_PASS_AT_K",
"LIKENESS_REWARD_WEIGHT",
"LABEL_IOU_REWARD_WEIGHT",
"FOREGROUND_REWARD_WEIGHT",
"approx_match_score",
"label_iou",
"foreground_match_score",
"get_metric_definition",
]