Checklist OAI 2025 Stage I · Task 2
Hallucination Detection
Polish title: Wykrywanie Halucynacji
Predict whether a language model's answer to a factual question is correct, using the answer, its tokens and four higher-temperature alternative answers with token probabilities.
The task
Language models can produce answers that sound plausible but are wrong; such answers are called hallucinations. The task is to detect hallucinations in answers to factual questions generated by a large language model.
Each example contains the question, the model's main answer, the tokens of that answer, four alternative answers generated by the same model at a higher temperature, their tokens and token probabilities, and the label is_correct stating whether the main answer is correct according to a trusted source. The questions and answers themselves are in English.
The contestant implements predict_hallucinations(sample), which returns a probability for each example; a model or algorithm may be built from the training data.
Abridged and translated by SOTA from the official Polish materials. The official statement has the exact rules, and it wins wherever this summary differs.
In English
This task was published in Polish. SOTA translated its 2 files into English on 16 September 2026. Only the words changed in the notebooks: markdown, code comments, messages and printed output. The code, file names and paths are the original's, so a translated notebook runs with the original data.
- Task notebook Polish original of Task notebook
- Official solution Polish original of Official solution
Read the task notebook in English
Hallucination Detection
Image generated using the DALL-E model.
Introduction
Language models help us with everyday tasks such as proofreading texts, writing code or answering questions. They are also increasingly used in fields such as medicine and education.
But how can we know whether the answers they generate are correct? Language models do not always have complete knowledge of a given topic, and yet they can formulate answers that sound credible but are in fact misleading. We call such incorrect answers hallucinations.
Task
In this task you will tackle the detection of hallucinations in answers to factual questions generated by large language models (LLMs). You will analyse a dataset that will help to assess whether the answers generated by a language model are actually correct or contain hallucinations.
Each example in the dataset contains:
- A question, e.g. "What is the main responsibility of the US Department of Defense?"
- The language model's answer, e.g. "The main responsibility is the defence of the country."
- Tokens associated with generating the answer.
- Four alternative answers generated by the same model at a higher temperature.
- Tokens of the alternative answers generated by the same model at a higher temperature.
- Probabilities of the alternative answers generated by the same model at a higher temperature.
- A label (
is_correct) indicating whether the main answer is correct according to a trusted source.
Example:
[
{
"question_id": 34,
"question": "What is the name of the low-cost carrier that operates as a wholly owned subsidiary of Singapore Airlines?",
"answer": "Scoot is the low-cost carrier that operates as a wholly owned subsidiary of Singapore Airlines.",
"tokens": [" Sco", "ot", " is", ..., " Airlines", ".", "\n"],
"supporting_answers": [
"As a wholly owned subsidiary of Singapore Airlines, <answer> Scoot </answer> stands as a low-cost carrier that revolutionized air travel in the region.",
"Scoot, a subsidiary of <answer> Singapore Airlines </answer> , is the low-cost carrier that operates under the same brand.",
"<answer> Scoot </answer> is the low-cost carrier that operates as a wholly owned subsidiary of Singapore Airlines.",
"Singapore Airlines operates a low-cost subsidiary named <answer> Scoot </answer> , offering affordable and efficient air travel options to passengers."
],
"supporting_tokens": [
[" As", " a", ..., ".", "<answer>"],
[" Sco", "ot", ..., " brand", ".", "\n"],
["<answer>", " Sco", ..., ".", "\n"],
[" Singapore", " Airlines", ..., ".", "\n"]
],
"supporting_probabilities": [
[0.0029233775567263365, 0.8621460795402527, ..., 0.018515007570385933],
[0.42073577642440796, 0.9999748468399048, ..., 0.9166142344474792],
[0.3258324861526489, 0.9969879984855652, ..., 0.921079695224762],
[0.11142394691705704, 0.960810661315918, ..., 0.9557166695594788]
],
"is_correct": true
},
.
.
.
]
Data
The data available to you in this task are:
train.json- a dataset containing 2967 questions and answers.valid.json- 990 additional questions.
Scoring Criterion
ROC AUC (Receiver Operating Characteristic Area Under Curve) is a measure of the quality of a binary classifier. It shows the model's ability to distinguish between two classes - here, a hallucination (false) and a correct answer (true).
- ROC (Receiver Operating Characteristic): A plot showing the relationship between the True Positive Rate (sensitivity) and the False Positive Rate (1 - specificity) at various decision thresholds.
- AUC (Area Under Curve): The area under the ROC curve, which takes values from 0 to 1:
- 1.0: A perfect model.
- 0.5: A random model (no ability to distinguish between the classes).
The higher the AUC value, the better the model performs at classification.
You can score between 0 and 100 points for this task. The score will be scaled linearly depending on the ROC AUC value:
- ROC AUC ≤ 0.7: 0 points.
- ROC AUC ≥ 0.82: 100 points.
- Values between 0.7 and 0.82: scaled linearly.
Scoring formula:
Constraints
- Your solution will be tested on the Contest Platform without internet access and in an environment without a GPU.
- The evaluation of your final solution on the Contest Platform must not take longer than 5 minutes without a GPU.
- List of permitted libraries:
xgboost,scikit-learn,numpy,pandas,matplotlib.
Submission Files
This notebook, completed with your solution (see the predict_hallucinations function).
Evaluation
Remember that during checking the FINAL_EVALUATION_MODE flag will be set to True.
You can score between 0 and 100 points for this task. The number of points you receive will be calculated on the (secret) test set on the Contest Platform using the formula given above, rounded to an integer. If your solution does not meet the above criteria or does not run correctly, you will receive 0 points for the task.
Starter Code
In this section we initialise the environment by importing the required libraries and functions. The prepared code will make it easier for you to work with the data efficiently and to build a proper solution.
######################### DO NOT CHANGE THIS CELL WHEN SUBMITTING ##########################
FINAL_EVALUATION_MODE = False # While checking your solution, we will change this value to True
import os
import json
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import sklearn as sk
from sklearn.metrics import roc_auc_score
import xgboost as xgb
import shutil
def download_data(train=("1TGEDaxw4GKfSq0fpqSk0wRpUSc8GgZN0", "train.json"),
valid=("1qrr7bZk6Uct8DeC-V8Bc1qD5su56ryFd", "valid.json")):
"""Downloads the dataset from Google Drive and saves it in the 'data' folder."""
import gdown
# Create or reset the 'data' folder
if not os.path.exists('data'):
os.makedirs('data')
else:
shutil.rmtree('data')
os.makedirs('data')
GDRIVE_DATA = [train, valid]
for file_id, file_name in GDRIVE_DATA:
# Download the file from Google Drive and save it in the 'data' folder
url = f'https://drive.google.com/uc?id={file_id}'
output = f'data/{file_name}'
gdown.download(url, output, quiet=False)
print(f"Downloaded: {file_name}")
# Download the data only if you are not in FINAL_EVALUATION_MODE
if not FINAL_EVALUATION_MODE:
download_data()
Loading the Data
The code below will load the data and prepare it appropriately.
######################### DO NOT CHANGE THIS CELL WHEN SUBMITTING ##########################
def load_data(folder='data'):
# Load the data from the files
train_path = os.path.join(folder, 'train.json')
valid_path = os.path.join(folder, 'valid.json')
with open(train_path, 'r') as f:
train = json.load(f)
with open(valid_path, 'r') as f:
valid = json.load(f)
return train, valid
train, valid = load_data("data")
print(json.dumps(train[0], indent=2))
print(f"\nTotal training examples: {len(train)}")
print(f"Total validation examples: {len(valid)}")
Scoring Criterion Code
Code similar to the code below will be used to evaluate the solution on the test set.
######################### DO NOT CHANGE THIS CELL WHEN SUBMITTING ##########################
def compute_score(roc_auc: float) -> float:
"""
Computes the score in points from the ROC AUC value.
:param roc_auc: A float value in the range [0.0, 1.0]
:return: The score in points according to the specified function
"""
if roc_auc <= 0.7:
return 0
elif 0.7 < roc_auc < 0.82:
return int(round(100 * (roc_auc - 0.7) / (0.82 - 0.7)))
else:
return 100
def evaluate_algorithm(dataset, algorithm, verbose=False):
"""
Evaluates a hallucination detection algorithm on the given dataset.
Parameters
----------
dataset : list
A labelled dataset, where each element is a dictionary containing the key 'is_correct'.
algorithm : callable
A function that takes a single example (a dictionary) and returns the probability of a hallucination.
verbose : bool
If True, prints additional information for each example and a summary.
Returns
-------
roc_auc : float
The area under the ROC curve (ROC AUC) for the predictions.
"""
predicted_ys = [] # List storing the predicted hallucination probabilities
for i, entry in enumerate(dataset):
# Create a copy of the sample and remove the label to obtain unlabelled input data
sample_unlabeled = dict(entry)
sample_unlabeled.pop('is_correct', None)
try:
# Predict the probability for a single sample
pred_prob = algorithm(sample_unlabeled)
predicted_ys.append(pred_prob)
except Exception as e:
# If an error occurs, we set the probability to 0.5 by default
predicted_ys.append(0.5)
if verbose:
print(f"Sample {i} => Error: {e}")
predicted_ys = np.array(predicted_ys, dtype=np.float32)
ys = []
for entry in dataset:
ys.append(1 if entry.get('is_correct') else 0)
ys = np.array(ys, dtype=np.int32)
# Compute the ROC AUC metric
roc_auc = roc_auc_score(ys, predicted_ys)
# Compute the final score from the ROC AUC
points = compute_score(roc_auc)
if verbose:
print(f"\nNumber of samples: {len(dataset)}")
print(f"ROC AUC: {roc_auc:.4f}")
print(f"Score in points: {points}")
return points
Your Solution
Place your solution in this section. Make changes only here!
# TODO: Use the training data to create a model or algorithm here.
def predict_hallucinations(sample):
# TODO: Run your model or algorithm on this dataset.
# TODO: Return a list of probabilities for each example in the dataset.
prediction = 0.5
return prediction
Evaluation
Running the cell below will let you check how many points your solution would score on the validation data. Before submitting, make sure that the whole notebook runs from start to finish without errors and without any user intervention after choosing the "Run All" option.
if not FINAL_EVALUATION_MODE:
roc_auc = evaluate_algorithm(valid, predict_hallucinations, verbose=True)
During checking, the model will be saved as your_model.pkl and evaluated on the test set.
######################### DO NOT CHANGE THIS CELL WHEN SUBMITTING ##########################
if FINAL_EVALUATION_MODE:
import cloudpickle
OUTPUT_PATH = "file_output"
FUNCTION_FILENAME = "your_model.pkl"
FUNCTION_OUTPUT_PATH = os.path.join(OUTPUT_PATH, FUNCTION_FILENAME)
if not os.path.exists(OUTPUT_PATH):
os.makedirs(OUTPUT_PATH)
with open(FUNCTION_OUTPUT_PATH, "wb") as f:
cloudpickle.dump(predict_hallucinations, f)
Translated by SOTA. The Polish original is the official version and wins wherever the two differ. The dataset itself is in English. In the official solution, the saved plot images still show the original Polish titles and axis labels; the plotting code has been translated, so re-running it produces English labels. If you organise this olympiad and would like the translation removed, email [email protected] and we will take it down.
At a glance
- You get
train.json(2,967 questions with answers) andvalid.json(990 questions), downloaded from Google Drive.- You submit
- This notebook with
predict_hallucinations; during checking it is saved toyour_model.pkland evaluated on the test set. - Scoring
- ROC AUC. Points = 0 for ROC AUC ≤ 0.7, 100 for ROC AUC ≥ 0.82, 100 × (ROC AUC − 0.7) / (0.82 − 0.7) in between.
- Rules
- Tested without Internet access and without a GPU.
- Evaluation must take at most 5 minutes without a GPU.
- Allowed libraries: xgboost, scikit-learn, numpy, pandas, matplotlib.
- Format
- Stage I (online), 17 February – 22 March 2025; up to 100 points per task (500 in total). Evaluated automatically on the Competition Platform (Platforma Konkursowa) on a hidden test set; points are rounded to an integer, and a notebook that fails the requirements or does not run scores 0.