Skip to content
Merged
Show file tree
Hide file tree
Changes from 44 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
194964c
fix: robust judgement handling (#1134)
Froxyy-dev Jan 8, 2026
8d6458e
generation.py to respect separate server type for the client (#1135)
vmendelev Jan 9, 2026
4d058c9
added aai-omniscience as benchmark
arnavkomaragiri Jan 9, 2026
707ed78
switched omniscience to use omniscience metrics
arnavkomaragiri Jan 9, 2026
e1adc1c
renamed default omniscience file to text.jsonl
arnavkomaragiri Jan 10, 2026
443ccb0
rename changes
arnavkomaragiri Jan 10, 2026
84246e4
fixed func_timeout import error
arnavkomaragiri Jan 10, 2026
1a74320
dropped math eval from omniscience, renamed target->expected_answer, …
arnavkomaragiri Jan 10, 2026
7d0069d
added debug print
arnavkomaragiri Jan 10, 2026
cdb9a10
fixed bug with system prompt formatting
arnavkomaragiri Jan 10, 2026
33e4dde
switched perflab server type to azureopenai
arnavkomaragiri Jan 10, 2026
11d2b78
fixed bug with answer key not being set
arnavkomaragiri Jan 10, 2026
57fcdff
only checking rm score if rm score is in data
arnavkomaragiri Jan 10, 2026
3183367
added judge_omni_index to printed metrics
arnavkomaragiri Jan 10, 2026
813d792
added debug print on correctness_dict
arnavkomaragiri Jan 10, 2026
76683b1
fixed bug with judgement parsing
arnavkomaragiri Jan 10, 2026
08fc0b7
added hallucination rate computation
arnavkomaragiri Jan 10, 2026
49e937d
fixed hallucination rate impl, refactored to track more metrics
arnavkomaragiri Jan 10, 2026
16c0d7b
fixed bugs
arnavkomaragiri Jan 10, 2026
0b87a57
fixed bugs with metric return
arnavkomaragiri Jan 10, 2026
07956c2
added debug print on agg_metric_dict
arnavkomaragiri Jan 10, 2026
1259a26
rescaled omni index and hallucination rate to 0-100
arnavkomaragiri Jan 10, 2026
3f0d6cd
cleaned up impl
arnavkomaragiri Jan 10, 2026
d6cc9d1
Add compute eval (#1158)
blahblahasdf Jan 10, 2026
723a1fc
add musan dataset (#1139)
Jorjeous Jan 12, 2026
4843d71
switched off perflab, added license to prepare.py, fixed bugs with me…
arnavkomaragiri Jan 12, 2026
6e599e6
corrected licenses, dockerfiles
arnavkomaragiri Jan 13, 2026
18ce92d
removed debugging fiddle
arnavkomaragiri Jan 13, 2026
e0e107a
fixed whitespace on omni judge prompt
arnavkomaragiri Jan 13, 2026
48bf2b0
added omniscience to docs on other benchmarks
arnavkomaragiri Jan 13, 2026
55ac14a
Update nemo_skills/evaluation/metrics/omni_metrics.py
arnavkomaragiri Jan 13, 2026
858ad2b
Merge branch 'main' into akomaragiri/aai_omniscience
arnavkomaragiri Jan 13, 2026
9529381
fixed whitespace on omni metrics
arnavkomaragiri Jan 13, 2026
9a30970
Merge branch 'akomaragiri/aai_omniscience' of github.com:NVIDIA-NeMo/…
arnavkomaragiri Jan 13, 2026
32160a9
updated omni_index and omni_hallucination to work with pass@k
arnavkomaragiri Jan 13, 2026
d08edbe
added workaround for premature pct conversion
arnavkomaragiri Jan 13, 2026
10492a4
fixed bug in pct workaround
arnavkomaragiri Jan 13, 2026
6ac32db
Merge branch 'main' into akomaragiri/aai_omniscience
arnavkomaragiri Jan 13, 2026
86dc189
added debug logging for other omniscience fields
arnavkomaragiri Jan 14, 2026
e805cd8
cleaned up formatting issue with docs
arnavkomaragiri Jan 14, 2026
46235f4
fixed bug where judgement may contain whitespace
arnavkomaragiri Jan 15, 2026
20a2c84
cleaned up logs, updated docs with eval setup
arnavkomaragiri Jan 16, 2026
838d182
Merge branch 'akomaragiri/aai_omniscience' of github.com:NVIDIA-NeMo/…
arnavkomaragiri Jan 16, 2026
d1c2fbf
Merge branch 'main' into akomaragiri/aai_omniscience
arnavkomaragiri Jan 16, 2026
774aa1b
added parse_reasoning to config
arnavkomaragiri Jan 16, 2026
9efc5c5
added eval results on qwen3-8b to docs
arnavkomaragiri Jan 16, 2026
019a8f9
Merge branch 'akomaragiri/aai_omniscience' of github.com:NVIDIA-NeMo/…
arnavkomaragiri Jan 16, 2026
29ffea6
switched docs to qwen3-8b from gpt-oss-20b
arnavkomaragiri Jan 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions docs/evaluation/other-benchmarks.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,71 @@ More details are coming soon!

- Benchmark is defined in [`nemo_skills/dataset/arena-hard/__init__.py`](https://github.com/NVIDIA-NeMo/Skills/blob/main/nemo_skills/dataset/arena-hard/__init__.py)
- Original benchmark source is [here](https://github.com/lmarena/arena-hard-auto).

### AA-Omniscience

This is a benchmark developed by AA to measure hallucinations in LLMs and penalize confidently-false answers.

- Benchmark is defined in [`nemo_skills/dataset/omniscience/__init__.py`](https://github.com/NVIDIA-NeMo/Skills/blob/main/nemo_skills/dataset/omniscience/__init__.py)
- Original benchmark and leaderboard are defined [here](https://artificialanalysis.ai/evaluations/omniscience), and data is [here](https://huggingface.co/datasets/ArtificialAnalysis/AA-Omniscience-Public)

#### Notes:
- Note that this benchmark can be quite sensitive to temperature and other sampling parameters, so make sure your settings align well with downstream conditions.
- Also note that there still may be some variance between the public set and the full dataset; however, this set may be used as a way to compare hallucination rates between different checkpoints/models.

#### Configuration: gpt-oss-20b with default judge (gemini-2.5-flash-preview-09-2025)
- Make sure to set `DEFAULT_REASONING_EFFORT_HIGH_THINKING_BUDGET=24576` in your environment variables and nemo-skills config to max judge reasoning when using reasoning_effort='high'.

```python
from nemo_skills.pipeline.cli import wrap_arguments, eval

eval(
ctx=wrap_arguments(
f"++inference.temperature=0.6 "
f"++inference.top_p=1.0 "
f"++inference.top_k=-1 "
f"++inference.tokens_to_generate=131072 "
f"++inference.reasoning_effort='high' "
),
cluster="slurm",
expname="aa-omniscience-eval",
model="openai/gpt-oss-20b",
server_gpus=8,
server_nodes=1,
server_type="vllm",
server_args="--async-scheduling",
benchmarks="omniscience",
output_dir="/workspace/experiments/aa-omniscience-eval",
data_dir="/workspace/data_dir",
extra_judge_args="++inference.reasoning_effort='high' ++inference.temperature=1.0 ++inference.top_p=0.95 ++inference.top_k=64 " # set max reasoning effort and default temp for judge
)
```

#### Configuration: gpt-oss-20b with custom judge (gpt-oss-120b)
```python
from nemo_skills.pipeline.cli import wrap_arguments, eval

eval(
ctx=wrap_arguments(
f"++inference.temperature=0.6 "
f"++inference.top_p=1.0 "
f"++inference.top_k=-1 "
f"++inference.tokens_to_generate=131072 "
f"++inference.reasoning_effort='high' "
),
cluster="slurm",
expname="aa-omniscience-eval",
model="openai/gpt-oss-20b",
server_gpus=8,
server_nodes=1,
server_type="vllm",
server_args="--async-scheduling",
judge_model="openai/gpt-oss-120b",
judge_server_type="vllm",
judge_server_gpus=8,
judge_server_args="--async-scheduling --reasoning-parser GptOss",
benchmarks="omniscience",
output_dir="/workspace/experiments/aa-omniscience-eval",
data_dir="/workspace/data_dir"
)
```
26 changes: 26 additions & 0 deletions nemo_skills/dataset/omniscience/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copyright year is 2026 (future year)

Suggested change
# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved.
# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copyright year is 2026

Suggested change
# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved.
# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copyright year is 2026 instead of 2025

Suggested change
# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved.
# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copyright year is 2026, should be 2025

Suggested change
# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved.
# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

copyright year is 2026 but should be 2025

#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# settings that define how evaluation should be done by default (all can be changed from cmdline)
DATASET_GROUP = "math"

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.

is this the right group?

METRICS_TYPE = "omniscience"
GENERATION_ARGS = "++prompt_config=eval/aai/omni"
EVAL_SPLIT = "text"

JUDGE_PIPELINE_ARGS = {
"model": "gemini-2.5-flash-preview-09-2025",
"server_type": "gemini",
"server_address": "https://generativelanguage.googleapis.com",
}
Comment on lines +21 to +25

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Gemini 2.5 flash model versions January 2026 availability

💡 Result:

Short answer — as of January 13, 2026:

  • Gemini 2.5 Flash (gemini-2.5-flash) — GA, available in the Gemini app, Google AI Studio and Vertex AI (launched June 17, 2025; scheduled retirement listed as June 17, 2026). [1][2]
  • Gemini 2.5 Flash‑Lite (gemini-2.5-flash-lite) — GA, available to developers (released July 22, 2025; earliest retirement July 22, 2026). [2][3]
  • Gemini 2.5 Flash‑Image (gemini-2.5-flash-image) — available (released Oct 2, 2025). [2][3]
  • Live / native‑audio variants — there were preview/live variants (e.g., gemini-live-2.5-flash and native‑audio preview) that were preview/private GA; some Live preview model IDs were shut down or replaced in Dec 2025, and newer Gemini 3 Flash rollout is superseding parts of the 2.5 Flash lineup. Check the Gemini API changelog and Vertex AI model pages for exact model IDs and shutdown dates. [1][2][4]

Sources: Google blog & Gemini changelog / Vertex AI docs and recent coverage. [1][2][3][4]

References
[1] Google blog (Gemini updates).
[2] Vertex AI — Gemini 2.5 Flash model page.
[3] Vertex AI — model versions & lifecycle.
[4] Gemini API changelog / deprecations.


Replace with stable GA model version.

The model "gemini-2.5-flash-preview-09-2025" is a preview variant. As of January 2026, preview Gemini 2.5 variants were shut down or replaced in December 2025. Use the stable GA version "gemini-2.5-flash" instead (available through June 17, 2026).

🤖 Prompt for AI Agents
In @nemo_skills/dataset/omniscience/__init__.py around lines 21 - 25,
JUDGE_PIPELINE_ARGS currently sets the model to the preview variant
"gemini-2.5-flash-preview-09-2025"; update the "model" value in the
JUDGE_PIPELINE_ARGS dict to the stable GA name "gemini-2.5-flash" (leave other
keys like "server_type" and "server_address" unchanged) so the code uses the
supported GA model.

JUDGE_ARGS = "++prompt_config=judge/aa-omni-judge ++generation_key=judgement ++add_generation_stats=False"
80 changes: 80 additions & 0 deletions nemo_skills/dataset/omniscience/prepare.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copyright year is 2026 (future year)

Suggested change
# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved.
# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copyright year is 2026

Suggested change
# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved.
# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copyright year is 2026 instead of 2025

Suggested change
# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved.
# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copyright year is 2026, should be 2025

Suggested change
# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved.
# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

copyright year is 2026 but should be 2025

#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import argparse
import json
from pathlib import Path

from datasets import load_dataset
from tqdm import tqdm

TOPIC_TO_SPLIT_MAP = {
"Humanities and Social Sciences": "humanities",
"Health": "health",
"Software Engineering": "swe",
"Science Engineering and Mathematics": "stem",
"Law": "law",
"Finance": "finance",
}


def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser()
parser.add_argument(
"-s",
"--splits",
default=["text", "humanities", "health", "swe", "stem", "law", "finance"],
nargs="+",
choices=["text", "humanities", "health", "swe", "stem", "law", "finance"],
)
return parser.parse_args()


def format_entry(entry) -> dict:
return {
"id": entry["question_id"],
"domain": entry["domain"],
"topic": entry["topic"],
"question": entry["question"],
"expected_answer": entry["answer"],
}


def write_jsonl(data: list[dict], path: str):
with open(path, "w", encoding="utf-8") as f:
for d in data:
f.write(json.dumps(d) + "\n")


if __name__ == "__main__":
args = parse_args()

dataset = load_dataset("ArtificialAnalysis/AA-Omniscience-Public", split="train")
jsonl_data = [format_entry(d) for d in dataset]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

jsonl_data variable is unused

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

jsonl_data variable is assigned but never used - can be removed

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

jsonl_data is created but never used

Comment on lines +63 to +64

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Variable jsonl_data is created but never used

Comment on lines +63 to +64

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

style: jsonl_data created but never used - can be removed

Suggested change
dataset = load_dataset("ArtificialAnalysis/AA-Omniscience-Public", split="train")
jsonl_data = [format_entry(d) for d in dataset]
dataset = load_dataset("ArtificialAnalysis/AA-Omniscience-Public", split="train")

output_dir = Path(__file__).absolute().parent

split_set = set(args.splits)
splits = {
"text": dataset,
**{
TOPIC_TO_SPLIT_MAP.get(t, str(t).lower()): dataset.filter(lambda x: x["domain"] == t)
for t in dataset.unique("domain")
},
}
splits = {k: v for k, v in splits.items() if k in split_set}

for split, data in tqdm(splits.items(), total=len(splits)):
output_file = output_dir / f"{split}.jsonl"
formatted_data = [format_entry(entry) for entry in data]
write_jsonl(formatted_data, output_file)
2 changes: 2 additions & 0 deletions nemo_skills/evaluation/metrics/map_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
from nemo_skills.evaluation.metrics.math_metrics import MathMetrics
from nemo_skills.evaluation.metrics.mmau_pro_metrics import MMAUProMetrics
from nemo_skills.evaluation.metrics.mrcr_metrics import MRCRMetrics
from nemo_skills.evaluation.metrics.omni_metrics import OmniMetrics
from nemo_skills.evaluation.metrics.ruler_metrics import RulerMetrics
from nemo_skills.evaluation.metrics.simpleqa_metrics import SimpleQAMetrics
from nemo_skills.evaluation.metrics.translation_metrics import TranslationMetrics
Expand Down Expand Up @@ -72,6 +73,7 @@
"mmau_pro_closed_form": MMAUProMetrics,
"mmau_pro_open_ended": MMAUProMetrics,
"mmau_pro_instruction_following": MMAUProMetrics,
"omniscience": OmniMetrics,
"compute-eval": ComputeEvalMetrics,
}

Expand Down
142 changes: 142 additions & 0 deletions nemo_skills/evaluation/metrics/omni_metrics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copyright year is 2026 (future year)

Suggested change
# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved.
# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copyright year is 2026

Suggested change
# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved.
# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copyright year is 2026 instead of 2025

Suggested change
# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved.
# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copyright year is 2026, should be 2025

Suggested change
# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved.
# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

copyright year is 2026 but should be 2025

#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from collections import defaultdict

from nemo_skills.evaluation.metrics.math_metrics import BaseMetrics, as_int, as_percentage


class OmniMetrics(BaseMetrics):
def __init__(self, compute_no_answer: bool = True, answer_key: str = "generation"):
super().__init__(compute_no_answer=compute_no_answer)
self.answer_key = answer_key

# use same RM code as MathMetrics
def _compute_reward_at_k(self, predictions: list[dict]):

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.

Is this function required for all datasets? Seems like math has it but most of the datasets don't

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.

I don't think it's required, but I figured it might be helpful since a reward model could serve as a proxy for a judge model and may be useful for the downstream task. It's not critical to the benchmark itself though, so we can drop if need be.

score_dicts = [self._get_score_dict(pred) for pred in predictions]

for k in range(1, len(predictions) + 1):
for score_method in score_dicts[0].keys():
Comment on lines +29 to +30

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

will crash with IndexError if score_dicts is empty (when all predictions have no judgement field) - add guard: if not score_dicts or not score_dicts[0]: continue

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

logic: IndexError if all predictions have no judgement field - score_dicts will be a list of empty dicts, and score_dicts[0].keys() will be empty, but attempting to iterate over it will still try to access score_dicts[0] when it doesn't exist if predictions list is empty

Suggested change
for score_method in score_dicts[0].keys():
if not score_dicts or not score_dicts[0]:
continue
for score_method in score_dicts[0].keys():

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

logic: KeyError if score_dicts is empty (when all predictions lack judgement field) - trying to access .keys() on empty list's first element

Suggested change
for score_method in score_dicts[0].keys():
if not score_dicts or not score_dicts[0]:
continue
for score_method in score_dicts[0].keys():

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

logic: IndexError if all predictions lack judgement field - score_dicts will be a list of empty dicts, causing score_dicts[0].keys() to fail when trying to iterate

Suggested change
for score_method in score_dicts[0].keys():
if not score_dicts or not score_dicts[0]:
continue
for score_method in score_dicts[0].keys():

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

logic: IndexError if predictions is empty - accessing score_dicts[0] without checking length

Suggested change
for score_method in score_dicts[0].keys():
for score_method in (score_dicts[0].keys() if score_dicts else []):

# Get valid answers and their results for this field
valid_answers_and_results = [
(elem[self.answer_key], correctness_dict[score_method], elem["reward_model_score"])
for elem, correctness_dict in zip(predictions[:k], score_dicts[:k])
if elem[self.answer_key] is not None
]

# If no valid answers, it's incorrect
if not valid_answers_and_results:
is_correct = False

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

is_correct variable is assigned but never used

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

is_correct variable is assigned but never used - can be removed

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

is_correct is assigned but never used in the branch where valid_answers_and_results is empty

Comment on lines +36 to +40

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

variable is_correct is assigned but never used - this dead code should be removed

else:
is_correct_best = sorted(valid_answers_and_results, key=lambda x: x[2], reverse=True)[0][1]
self.eval_dict[f"rm_best@{k}"][score_method] += is_correct_best

answer_to_score_dict = defaultdict(float)
answer_to_correctness_dict = {}
for predicted_answer, is_correct, reward_score in valid_answers_and_results:
answer_to_score_dict[predicted_answer] += reward_score
answer_to_correctness_dict[predicted_answer] = is_correct

top_cum_reward_answer = sorted(
list(answer_to_score_dict.items()), key=lambda x: x[1], reverse=True
)[0][0]
is_correct_majority = answer_to_correctness_dict[top_cum_reward_answer]
self.eval_dict[f"rm_majority@{k}"][score_method] += is_correct_majority

no_answer = all(elem[self.answer_key] is None for elem in predictions[:k])
self.eval_dict[f"rm_best@{k}"]["no_answer"] += no_answer
self.eval_dict[f"rm_majority@{k}"]["no_answer"] += no_answer
Comment on lines +26 to +59

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Multiple issues in _compute_reward_at_k.

  1. Potential IndexError (Line 30): If predictions is empty, score_dicts will be empty and score_dicts[0].keys() will raise IndexError.

  2. Dead code (Line 40): is_correct = False is assigned but never used.

  3. Variable shadowing (Line 47): Loop variable is_correct shadows the outer is_correct from line 40, causing confusion.

  4. Missing strict= on zip (Line 34): Per static analysis, adding strict=True would catch length mismatches.

Suggested fix
 def _compute_reward_at_k(self, predictions: list[dict]):
+    if not predictions:
+        return
+
     score_dicts = [self._get_score_dict(pred) for pred in predictions]
+    if not score_dicts or not score_dicts[0]:
+        return

     for k in range(1, len(predictions) + 1):
         for score_method in score_dicts[0].keys():
             # Get valid answers and their results for this field
             valid_answers_and_results = [
                 (elem[self.answer_key], correctness_dict[score_method], elem["reward_model_score"])
-                for elem, correctness_dict in zip(predictions[:k], score_dicts[:k])
+                for elem, correctness_dict in zip(predictions[:k], score_dicts[:k], strict=True)
                 if elem[self.answer_key] is not None
             ]

             # If no valid answers, it's incorrect
             if not valid_answers_and_results:
-                is_correct = False
+                pass  # No valid answers to process
             else:
                 is_correct_best = sorted(valid_answers_and_results, key=lambda x: x[2], reverse=True)[0][1]
                 self.eval_dict[f"rm_best@{k}"][score_method] += is_correct_best

                 answer_to_score_dict = defaultdict(float)
                 answer_to_correctness_dict = {}
-                for predicted_answer, is_correct, reward_score in valid_answers_and_results:
+                for predicted_answer, correctness, reward_score in valid_answers_and_results:
                     answer_to_score_dict[predicted_answer] += reward_score
-                    answer_to_correctness_dict[predicted_answer] = is_correct
+                    answer_to_correctness_dict[predicted_answer] = correctness
🧰 Tools
🪛 Ruff (0.14.11)

34-34: zip() without an explicit strict= parameter

Add explicit value for parameter strict=

(B905)


def _get_score_dict(self, prediction: dict) -> dict[str, bool | int | float]:
correctness_dict = {}
if "judgement" in prediction:
judgement = prediction["judgement"].strip()
correctness_dict["judge_correct"] = int(judgement.lower() == "a")
correctness_dict["judge_incorrect"] = -int(
judgement.lower() == "b"
) # negate incorrect so pass@k minimizes it
correctness_dict["judge_partially_correct"] = int(judgement.lower() == "c")
correctness_dict["judge_abstained"] = int(judgement.lower() == "d")

# keep counter of all entries where no answer is correct
correctness_dict["non_correct"] = -int(judgement.lower() in ["b", "c", "d"])
return correctness_dict
Comment on lines +61 to +74

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, let's find the file and understand its structure
fd -p omni_metrics.py

Repository: NVIDIA-NeMo/Skills

Length of output: 108


🏁 Script executed:

# Read the omni_metrics.py file to see the full context
wc -l nemo_skills/evaluation/metrics/omni_metrics.py

Repository: NVIDIA-NeMo/Skills

Length of output: 112


🏁 Script executed:

# Read relevant sections of the file
head -150 nemo_skills/evaluation/metrics/omni_metrics.py | tail -100

Repository: NVIDIA-NeMo/Skills

Length of output: 4822


🏁 Script executed:

# Look at the _compute_reward_at_k method around line 30
sed -n '20,50p' nemo_skills/evaluation/metrics/omni_metrics.py

Repository: NVIDIA-NeMo/Skills

Length of output: 1678


🏁 Script executed:

# Check the full structure of the class and find base class
sed -n '1,100p' nemo_skills/evaluation/metrics/omni_metrics.py

Repository: NVIDIA-NeMo/Skills

Length of output: 4883


🏁 Script executed:

# Search for _compute_pass_at_k in the file
grep -n "_compute_pass_at_k\|_compute_reward_at_k" nemo_skills/evaluation/metrics/omni_metrics.py

Repository: NVIDIA-NeMo/Skills

Length of output: 246


🏁 Script executed:

# Find BaseMetrics class
fd -p math_metrics.py

Repository: NVIDIA-NeMo/Skills

Length of output: 108


🏁 Script executed:

# Check the BaseMetrics class and _compute_pass_at_k method
cat nemo_skills/evaluation/metrics/math_metrics.py | head -200

Repository: NVIDIA-NeMo/Skills

Length of output: 6732


🏁 Script executed:

# Find and read the base metrics class
fd -p base.py | grep evaluation

Repository: NVIDIA-NeMo/Skills

Length of output: 141


🏁 Script executed:

# Read the base metrics file
cat nemo_skills/evaluation/metrics/base.py | head -250

Repository: NVIDIA-NeMo/Skills

Length of output: 10587


🏁 Script executed:

# Search for _compute_pass_at_k implementation
grep -n "_compute_pass_at_k" nemo_skills/evaluation/metrics/base.py

Repository: NVIDIA-NeMo/Skills

Length of output: 624


🏁 Script executed:

# Read more of base.py to find _compute_pass_at_k
wc -l nemo_skills/evaluation/metrics/base.py

Repository: NVIDIA-NeMo/Skills

Length of output: 104


🏁 Script executed:

# Read the _compute_pass_at_k method from base.py
sed -n '200,350p' nemo_skills/evaluation/metrics/base.py

Repository: NVIDIA-NeMo/Skills

Length of output: 6200


🏁 Script executed:

# Read the _compute_pass_at_k method
sed -n '352,420p' nemo_skills/evaluation/metrics/base.py

Repository: NVIDIA-NeMo/Skills

Length of output: 3433


🏁 Script executed:

# Verify the get_metrics method and understand the issue better
sed -n '73,85p' nemo_skills/evaluation/metrics/omni_metrics.py

Repository: NVIDIA-NeMo/Skills

Length of output: 717


🏁 Script executed:

# Check if there's any initialization or default values in eval_dict
grep -A 10 "def __init__" nemo_skills/evaluation/metrics/omni_metrics.py

Repository: NVIDIA-NeMo/Skills

Length of output: 597


🏁 Script executed:

# Check the base class initialization
sed -n '25,35p' nemo_skills/evaluation/metrics/base.py

Repository: NVIDIA-NeMo/Skills

Length of output: 525


🏁 Script executed:

# Check the reset method to see how eval_dict is initialized
sed -n '435,445p' nemo_skills/evaluation/metrics/base.py

Repository: NVIDIA-NeMo/Skills

Length of output: 591


🏁 Script executed:

# Let's trace through exactly what happens - check how metrics are accessed
# Check if get_metrics handles missing keys gracefully
sed -n '35,55p' nemo_skills/evaluation/metrics/base.py

Repository: NVIDIA-NeMo/Skills

Length of output: 1050


🏁 Script executed:

# Let's verify the actual flow by checking OmniMetrics.update() completely
sed -n '94,102p' nemo_skills/evaluation/metrics/omni_metrics.py

Repository: NVIDIA-NeMo/Skills

Length of output: 448


🏁 Script executed:

# Check what happens with defaultdict when accessing missing keys
python3 << 'EOF'
from collections import defaultdict

# This is how eval_dict is structured
eval_dict = defaultdict(lambda: defaultdict(float))

# Simulate what happens when no metrics are added
score_dicts = [{}]  # Empty score dict

# This loop doesn't execute
for score_method in score_dicts[0].keys():
    eval_dict[f"pass@1"]["method"] += 1

# Now try to access keys like get_metrics does
print("Keys in eval_dict:", dict(eval_dict))
print("Keys in eval_dict['pass@1']:", dict(eval_dict["pass@1"]))

# Check if accessing missing key raises error or returns default
try:
    value = eval_dict["pass@1"]["judge_correct"]
    print(f"Value for judge_correct: {value}")
except KeyError as e:
    print(f"KeyError: {e}")
EOF

Repository: NVIDIA-NeMo/Skills

Length of output: 144


🏁 Script executed:

# Let's test what happens in the actual OmniMetrics.get_metrics() flow
python3 << 'EOF'
from collections import defaultdict

# Simulate the flow
eval_dict = defaultdict(lambda: defaultdict(float))

# When no metrics are computed (empty score dicts), nothing is added
# Simulate calling get_metrics from base class
metrics_dict = {}
for agg_mode, agg_metric_dict in eval_dict.items():
    metrics_dict[agg_mode] = {}
    for metric_key, metric_value in agg_metric_dict.items():
        if isinstance(metric_value, float):
            metrics_dict[agg_mode][metric_key] = 100.0 * metric_value / 1  # assume total=1

print("After base get_metrics:", metrics_dict)

# Now OmniMetrics.get_metrics() tries to access keys
if metrics_dict:  # Only if there are entries
    for agg_method, agg_metric_dict in metrics_dict.items():
        try:
            correct = agg_metric_dict["judge_correct"]
            print(f"Got judge_correct: {correct}")
        except KeyError as e:
            print(f"KeyError accessing judge_correct: {e}")
else:
    print("metrics_dict is empty, so the loop won't even execute")
EOF

Repository: NVIDIA-NeMo/Skills

Length of output: 142


🏁 Script executed:

# Let's check if there's always at least one agg_mode in eval_dict
grep -n "eval_dict\[" nemo_skills/evaluation/metrics/base.py | head -20

Repository: NVIDIA-NeMo/Skills

Length of output: 614


🏁 Script executed:

# Let's trace through a realistic scenario - when _compute_pass_at_k is called with None predicted_answers
python3 << 'EOF'
from collections import defaultdict

# Simulate OmniMetrics scenario
eval_dict = defaultdict(lambda: defaultdict(float))

# Simulate _compute_pass_at_k with empty score_dicts[0] and predicted_answers=None
score_dicts = [{}]  # Empty because no "judgement" field
predicted_answers = None
compute_no_answer = True

# The loop that depends on score_dicts[0]
for score_method in score_dicts[0].keys():
    # This doesn't execute
    eval_dict[f"pass@1"]["method"] += 1
    pass

# The no_answer logic
for k in range(1, 2):
    if predicted_answers is not None and compute_no_answer:
        # This condition is False because predicted_answers is None
        eval_dict[f"pass@{k}"]["no_answer"] += True
    pass

# Check what's in eval_dict
print("eval_dict after _compute_pass_at_k:", dict(eval_dict))
print("Is eval_dict empty?", len(eval_dict) == 0)

# Now simulate get_metrics flow
metrics_dict = {}
for agg_mode, agg_metric_dict in eval_dict.items():
    metrics_dict[agg_mode] = dict(agg_metric_dict)

print("metrics_dict from base get_metrics:", metrics_dict)

# Now OmniMetrics.get_metrics() tries to access
print("\nWould OmniMetrics.get_metrics() be called?")
if metrics_dict:
    print("  Yes, and it would try to access judge_correct, judge_incorrect, etc.")
    for agg_method, agg_metric_dict in metrics_dict.items():
        try:
            val = agg_metric_dict["judge_correct"]
            print(f"  Got {val}")
        except KeyError as e:
            print(f"  KeyError: {e}")
else:
    print("  No, metrics_dict is empty so the loop doesn't execute")
EOF

Repository: NVIDIA-NeMo/Skills

Length of output: 264


🏁 Script executed:

# Test the actual problematic scenario - mixed predictions with and without "judgement"
python3 << 'EOF'
from collections import defaultdict

# Simulate mixed case - some predictions have judgement, others don't
def _get_score_dict_omni(prediction):
    correctness_dict = {}
    if "judgement" in prediction:
        judgement = prediction["judgement"]
        correctness_dict["judge_correct"] = int(judgement.lower() == "a")
        correctness_dict["judge_incorrect"] = int(judgement.lower() == "b")
        correctness_dict["judge_partially_correct"] = int(judgement.lower() == "c")
        correctness_dict["judge_abstained"] = int(judgement.lower() == "d")
    return correctness_dict

# Test scenario: some predictions have judgement, others don't
predictions = [
    {"judgement": "A", "generation": "answer1"},
    {"generation": "answer2"},  # Missing judgement
]

score_dicts = [_get_score_dict_omni(pred) for pred in predictions]
print("score_dicts:", score_dicts)

# Now try _compute_pass_at_k logic
try:
    for score_method in score_dicts[0].keys():
        print(f"Processing score_method: {score_method}")
        # This is line 369 in _compute_pass_at_k
        scores_list = [correctness_dict[score_method] for correctness_dict in score_dicts]
        print(f"  scores_list: {scores_list}")
except KeyError as e:
    print(f"KeyError: {e}")
    print(f"Trying to access '{e.args[0]}' in one of the score_dicts")
EOF

Repository: NVIDIA-NeMo/Skills

Length of output: 299


🏁 Script executed:

# Check the update() method to see if there are any guards
sed -n '94,102p' nemo_skills/evaluation/metrics/omni_metrics.py

Repository: NVIDIA-NeMo/Skills

Length of output: 448


🏁 Script executed:

# Also check if OmniMetrics is used with consistent data
grep -r "OmniMetrics" nemo_skills/evaluation/ | grep -v ".pyc" | head -10

Repository: NVIDIA-NeMo/Skills

Length of output: 332


🏁 Script executed:

# Check if there's any validation or guarantee that all predictions have consistent structure
grep -B 5 -A 10 "def _compute_pass_at_k" nemo_skills/evaluation/metrics/base.py | head -25

Repository: NVIDIA-NeMo/Skills

Length of output: 799


🏁 Script executed:

# Test the exact error scenario again with the actual code
python3 << 'EOF'
# Reproduce the exact crash with line numbers from base.py
import math
from collections import defaultdict

# Simulate BaseMetrics._compute_pass_at_k
def _get_score_dict(prediction):
    """OmniMetrics version"""
    correctness_dict = {}
    if "judgement" in prediction:
        judgement = prediction["judgement"]
        correctness_dict["judge_correct"] = int(judgement.lower() == "a")
        correctness_dict["judge_incorrect"] = int(judgement.lower() == "b")
        correctness_dict["judge_partially_correct"] = int(judgement.lower() == "c")
        correctness_dict["judge_abstained"] = int(judgement.lower() == "d")
    return correctness_dict

def test_crash():
    predictions = [
        {"judgement": "A", "generation": "answer1"},
        {"generation": "answer2"},  # Missing judgement - will cause crash
    ]
    
    eval_dict = defaultdict(lambda: defaultdict(float))
    score_dicts = [_get_score_dict(pred) for pred in predictions]
    
    print(f"score_dicts = {score_dicts}")
    print(f"score_dicts[0].keys() = {list(score_dicts[0].keys())}")
    
    try:
        # This is line 368 in base.py _compute_pass_at_k
        for score_method in score_dicts[0].keys():
            # This is line 369 in base.py
            scores_list = [correctness_dict[score_method] for correctness_dict in score_dicts]
            print(f"Success: {score_method} = {scores_list}")
    except KeyError as e:
        print(f"CRASH at line 369: KeyError accessing '{e.args[0]}' in score_dicts[1]")
        return False
    return True

test_crash()
EOF

Repository: NVIDIA-NeMo/Skills

Length of output: 355


KeyError crash when predictions have inconsistent "judgement" field.

When some (but not all) predictions lack the "judgement" field, _get_score_dict returns an empty dict for those predictions. This causes a KeyError crash in _compute_pass_at_k (base.py line 369) when trying to build scores_list:

scores_list = [correctness_dict[score_method] for correctness_dict in score_dicts]

If score_dicts[0] has keys like "judge_correct" but score_dicts[i] is empty, accessing score_dicts[i]["judge_correct"] raises KeyError.

Validate that all predictions in a batch contain the "judgement" field, or ensure _get_score_dict returns consistent keys across all predictions (e.g., with default values).


def get_metrics(self):
metrics = super().get_metrics()

for agg_method, agg_metric_dict in metrics.items():
correct, incorrect, part_correct, abstained = (
agg_metric_dict["judge_correct"],
-agg_metric_dict["judge_incorrect"], # multiply negated judge_incorrect to get minimized incorrect pct
agg_metric_dict["judge_partially_correct"],
agg_metric_dict["judge_abstained"],
)
non_correct = -agg_metric_dict["non_correct"]

# convert pcts back to counts
if isinstance(correct, float):
correct *= self.total / 100
if isinstance(incorrect, float):
incorrect *= self.total / 100
if isinstance(part_correct, float):
part_correct *= self.total / 100
if isinstance(abstained, float):
abstained *= self.total / 100
if isinstance(non_correct, float):
non_correct *= self.total / 100

# compute omni index between max correct and min incorrect (for pass@k)
metrics[agg_method]["judge_omni_index"] = 100 * (correct - incorrect) / self.total if self.total > 0 else 0

# compute hallucination rate with min incorrect and min non_correct
metrics[agg_method]["judge_omni_hallucination"] = 100 * incorrect / non_correct if non_correct > 0 else 0
return metrics
Comment on lines +76 to +105

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Potential ZeroDivisionError in metric calculations.

Two division operations can fail:

  1. Line 82-83: (correct + incorrect + part_correct + abstained) equals zero if no judgements exist.
  2. Line 84: (incorrect + part_correct + abstained) equals zero when all responses are judge_correct (judgement "A").

This will crash metrics computation in edge cases (empty data or perfect scores).

Suggested fix with guards
     def get_metrics(self):
         metrics = super().get_metrics()

         for agg_method, agg_metric_dict in metrics.items():
             correct, incorrect, part_correct, abstained = (
                 agg_metric_dict["judge_correct"],
                 agg_metric_dict["judge_incorrect"],
                 agg_metric_dict["judge_partially_correct"],
                 agg_metric_dict["judge_abstained"],
             )
-            metrics[agg_method]["judge_omni_index"] = (
-                100 * (correct - incorrect) / (correct + incorrect + part_correct + abstained)
-            )
-            metrics[agg_method]["judge_omni_hallucination"] = 100 * incorrect / (incorrect + part_correct + abstained)
+            total = correct + incorrect + part_correct + abstained
+            non_correct_total = incorrect + part_correct + abstained
+            
+            metrics[agg_method]["judge_omni_index"] = (
+                100 * (correct - incorrect) / total if total > 0 else 0.0
+            )
+            metrics[agg_method]["judge_omni_hallucination"] = (
+                100 * incorrect / non_correct_total if non_correct_total > 0 else 0.0
+            )
         return metrics


def get_incorrect_sample(self, prediction: dict) -> dict:
copy_prediction = prediction.copy()
if "judgement" in prediction:
copy_prediction["judgement"] = "B"
copy_prediction["judge_correct"] = 0
copy_prediction["judge_incorrect"] = -1
copy_prediction["judge_partially_correct"] = 0
copy_prediction["judge_abstained"] = 0
copy_prediction["non_correct"] = -1
return copy_prediction

def update(self, predictions):
super().update(predictions)
self._compute_pass_at_k(predictions, None)
if "reward_model_score" in predictions[0]:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

logic: IndexError if predictions list is empty - accessing predictions[0] without checking if list is non-empty

Suggested change
if "reward_model_score" in predictions[0]:
if predictions and "reward_model_score" in predictions[0]:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

logic: IndexError if predictions is empty - accessing predictions[0] without checking length

Suggested change
if "reward_model_score" in predictions[0]:
if predictions and "reward_model_score" in predictions[0]:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

logic: IndexError if predictions is empty - accessing predictions[0] without checking length first

Suggested change
if "reward_model_score" in predictions[0]:
if predictions and "reward_model_score" in predictions[0]:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

logic: IndexError if predictions list is empty - accessing predictions[0] without checking length first

Suggested change
if "reward_model_score" in predictions[0]:
if predictions and "reward_model_score" in predictions[0]:

self._compute_reward_at_k(predictions=predictions)
Comment on lines +118 to +122

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

IndexError risk with empty predictions.

Line 99 accesses predictions[0] without checking if predictions is non-empty. If update is called with an empty list, this will raise IndexError.

Suggested fix
 def update(self, predictions):
     super().update(predictions)
+    if not predictions:
+        return
     self._compute_pass_at_k(predictions, None)
     if "reward_model_score" in predictions[0]:
         self._compute_reward_at_k(predictions=predictions)
🤖 Prompt for AI Agents
In @nemo_skills/evaluation/metrics/omni_metrics.py around lines 96 - 100, The
update method accesses predictions[0] without checking for an empty list,
risking IndexError; after calling super().update(predictions) add a guard like
"if not predictions: return" to avoid further processing on an empty list, or at
minimum change the reward-model check to "if predictions and
'reward_model_score' in predictions[0]:"; ensure this guard is applied before
calling _compute_pass_at_k and _compute_reward_at_k so both methods aren't
invoked with an empty predictions list (refer to the update method and helpers
_compute_pass_at_k and _compute_reward_at_k).


# print the same evaluations/metrics as math but ignoring majority/rm since that doesn't really exist with omniscience
def evaluations_to_print(self):
return [
f"pass@1[avg-of-{self.max_k}]",
f"pass@{self.max_k}",
]

def metrics_to_print(self):
metrics_to_print = {
"num_entries": as_int,
"avg_tokens": as_int,
"gen_seconds": as_int,
"judge_correct": as_percentage,
"judge_omni_index": as_percentage,
"judge_omni_hallucination": as_percentage,
}
if self.compute_no_answer:
metrics_to_print["no_answer"] = as_percentage
return metrics_to_print
7 changes: 7 additions & 0 deletions nemo_skills/prompt/config/eval/aai/omni.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# https://huggingface.co/datasets/ArtificialAnalysis/AA-Omniscience-Public

system: |-
You are answering questions about {domain}, and in particular {topic}. You will be given a question, answer with JUST the answer (no explanation). If you do not know the answer, or you need more context or tools to answer the question, be clear about this - it is better that you say this than get the wrong answer.

user: |-
{question}
Loading