Skip to content

Add meta evaluation task - #76

Open
ErlisLushtaku wants to merge 8 commits into
mainfrom
erlislushtaku/feat/add-meta-eval
Open

Add meta evaluation task#76
ErlisLushtaku wants to merge 8 commits into
mainfrom
erlislushtaku/feat/add-meta-eval

Conversation

@ErlisLushtaku

@ErlisLushtaku ErlisLushtaku commented Jul 18, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Add --task meta-eval for evaluating judge models against human-labeled arena battles.
  • Support deterministic sampling, language filtering, four named prompt modes, and optional swapped-order judging.
  • Report agreement, ranking, ELO, bootstrap uncertainty, ELO-gap, token, and cost metrics.
  • Save auditable per-pass annotations, summaries, results, and run metadata.
  • Package prompt resources and integrate meta-eval with the hierarchical RunConfig CLI.

Usage

judgearena \
  --task meta-eval \
  --judge.model OpenRouter/deepseek/deepseek-v3.2 \
  --meta_eval.reference_arena LMArena-140k \
  --meta_eval.prompt_mode standard \
  --meta_eval.languages '["en", "es"]' \
  --meta_eval.top_models 20 \
  --meta_eval.battles_per_model 50 \
  --meta_eval.n_bootstraps 1000 \
  --run.seed 0

Outputs

Runs produce:

  • annotations.parquet
  • results.json
  • summary.csv
  • args.json
  • run-metadata.v1.json

With --judge.swap_mode both, annotations contain one row per judge pass with normalized model ordering and an orientation column.

Cache note

Meta-eval temporarily retains the existing per-battle SQLite WAL cache. It should be used from a single host and not concurrently across NFS-mounted compute nodes. Cache unification remains deferred to the dedicated caching work.

@ErlisLushtaku ErlisLushtaku changed the title Erlislushtaku/feat/add meta eval Add meta evaluation task Jul 18, 2026
@ErlisLushtaku
ErlisLushtaku marked this pull request as ready for review July 20, 2026 11:37

def parse_pairscore_pref(judge_completion: str, *, temperature: float) -> float:
score = pair_score_parser(temperature).parse_model_raw(judge_completion)
if score is None or np.isnan(score):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why we return tie=0.5 for parsing errors? We have to make sure this does not change the Cohen's Kappa or any accuracy

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, malformed outputs become ties and therefore affect accuracy and the Cohen kappa score. This matches the reference implementation here. I kept this behavior to match the reference results, since dropping them or adding an invalid label would change the reported metrics. Let me know if you think we should intentionally diverge.

replace=False,
random_state=int(rng.integers(0, 2**32 - 1)),
)
if exclude_ties:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sampling num_battles row then excluding tie means that our battles will have n <= num_battles

@ErlisLushtaku ErlisLushtaku Aug 6, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

num_battles is the annotation budget for this analysis. The reference samples that many annotations and then drops tie predictions here, so the Bradley-Terry fit can use fewer decisive rows. I kept this behavior and clarified it here.

args.prompt_mode,
provide_explanation=args.provide_explanation,
)
judge_chat_model = make_model(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we call build_default_judge_model_kwargs before? Or this is already enough

@ErlisLushtaku ErlisLushtaku Aug 6, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added it here.

annotation_cache: AnnotationCache | None = None,
) -> pd.DataFrame:
n_total = len(df_sample)
n_batches = (n_total + args.batch_size - 1) // args.batch_size

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not so problematic but we never check args.batch_size > 0. It can raise division by zero by mistake.

@ErlisLushtaku ErlisLushtaku Aug 6, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, added the validation here.

@kargibora

Copy link
Copy Markdown
Collaborator

Apart from these I feel like there are some duplications:

(1)
compute_soft_bradley_terry() reimplements most of fit_bradley_terry().

The existing function already supports continuous preferences:

  fit_bradley_terry(df, pref_col="pref_llm")

(2)

The PR introduces:

  PromptModeSpec
  resolve_prompt_mode()
  _read_prompt()

JudgeArena already has:

  JudgePromptPreset
  ResolvedJudgePrompt
  resolve_judge_prompt()

Are these exchangable or we are required to implement this specifically?

@ErlisLushtaku

ErlisLushtaku commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator Author

@kargibora Regarding each point:

compute_soft_bradley_terry() reimplements most of fit_bradley_terry().

Good point, I removed it and now use fit_bradley_terry(..., pref_col="pref_llm") here.

Are these exchangable or we are required to implement this specifically?

standard already delegates to resolve_judge_prompt(). The remaining modes are not fully exchangeable atm because the shared registry only supports PairScore with parser_mode="score", while Arena-Hard and AlpacaEval need their own verdict parsers. I kept the small meta-eval resolver for these protocol-specific modes.

Introduce the core judge meta-evaluation building blocks and package
prompt resources so later CLI wiring can reuse them unchanged.
Add the annotation orchestration path and expose meta-eval as a flat
--task route alongside generate+judge and ELO workflows.
Add unit/integration coverage for meta-eval behavior and ensure
prompt resources remain loadable from wheel and sdist installs.
Describe the new meta-eval CLI path, prompt modes, swap-mode semantics,
and temporary SQLite cache limitations for operators.
Store rendered prompt text rather than LangChain prompt objects so SQLite-backed meta-eval runs complete after annotation.

Includes-AI-Code: true
Reuse shared Bradley-Terry and judge defaults, and reject invalid annotation batch sizes.

Includes-AI-Code: true
Keep the meta-eval tests aligned with the hierarchical RunConfig interface retained from main.

Includes-AI-Code: true
@ErlisLushtaku
ErlisLushtaku force-pushed the erlislushtaku/feat/add-meta-eval branch from 56949c0 to 340fffd Compare August 6, 2026 17:53
@ErlisLushtaku
ErlisLushtaku requested a review from kargibora August 6, 2026 23:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants