Guardian of Truth: детекция галлюцинаций через hidden-state probing 🧠
Конкурсное ML-решение для определения фактологических галлюцинаций в ответах GigaChat. Детектор использует внутренние сигналы модели из одного forward pass: hidden states, contrast directions, PCA-сжатые представления и uncertainty-признаки из logits.
Результат на хакатоне: 3 место в треке Сбера. 🥉
Final/private PR-AUC: ~0.8541.
Public validation PR-AUC: 0.8493 по конфигу configs/best_config.json.
Задача состояла в том, чтобы предсказать, содержит ли ответ ai-sage/GigaChat3-10B-A1.8B-bf16 фактологическую галлюцинацию. Важным ограничением была скорость: можно было использовать forward pass самой GigaChat-модели для снятия внутренних сигналов, но нельзя было строить runtime-решение на внешних API, RAG или LLM-as-a-judge.
Финальный подход рассматривает детекцию галлюцинаций как задачу анализа внутренних представлений модели:
- снимаем hidden states с ранних и средних слоев при teacher forcing;
- считаем uncertainty-признаки по logits токенов ответа;
- строим contrast directions между корректными и галлюцинированными ответами;
- сжимаем probe-векторы через PCA;
- обучаем легкий
LogisticRegression-классификатор для быстрого inference.
-
Teacher forcing
Подаем в GigaChat паруprompt + model_answerи читаем активации на span ответа. -
Hidden-state probes
Используем слоиL3,L9иL15. Ранние слои оказались особенно полезными: рабочая гипотеза была в том, что фактологический сигнал появляется раньше, чем поздние reasoning/generation-слои успевают его исказить. -
Contrast directions
Для каждого probe-представления считаем нормированную разницу средних активаций:direction = mean(hidden_state | hallucination) - mean(hidden_state | correct)Проекция на это направление становится компактным и сильным признаком.
-
Uncertainty scalars
Добавляем 18 признаков из logits: статистики log-probability, entropy, top-k probabilities, margin, длина ответа, proxy perplexity и доля low-confidence токенов. -
Synthetic training data
Дополнительные фактологические вопросы генерировались offline, затем GigaChat отвечал на них, а разметка проверялась offline. Эти данные используются только для обучения, не для runtime-инференса. -
Lightweight classifier
Объединяем scalars, PCA-сжатые probes и contrast projections, после чего обучаемLogisticRegression.
| Эксперимент | Public PR-AUC |
|---|---|
| Baseline только на uncertainty | ~0.80 |
Late-layer probes (L20, L25) |
0.8202 |
| Contrast direction на generated data | 0.8346 |
Early/mid probes (L3, L9, L15) |
0.8493 |
| Финальный хакатонный submission | ~0.8541 private |
Подробнее про ход экспериментов: docs/experiments.md.
.
├── configs/
│ ├── best_config.json # Лучшая public-validation конфигурация
│ └── config.json # Более ранний компактный конфиг для run.py
├── data/
│ ├── README.md # Политика данных и ожидаемая структура
│ ├── bench/ # Public/private benchmark CSV
│ ├── generated/ # Offline synthetic data и labels
│ └── training/ # Labeled training splits
├── docs/
│ ├── experiments.md # История экспериментов
│ └── resume.md # Формулировки для резюме
├── features/
│ ├── README.md # Описание feature-кэшей
│ ├── train_all_layers.npz
│ ├── gen_all_layers.npz
│ └── test_all_layers.npz
├── scripts/
│ ├── install.sh
│ ├── train.sh
│ └── score_private.sh
├── src/hallucination_detector/
│ ├── classifier.py # PCA, contrast directions, обучение классификатора
│ ├── features.py # Logit и hidden-state feature extraction
│ ├── patches.py # Патчи загрузки GigaChat / DeepSeek-V3
│ └── score_private.py # End-to-end scoring entry point
├── run.py # Single-file hackathon runner
└── requirements.txt
Рекомендуется Python 3.10+ и CUDA GPU. На хакатоне использовался сервер с RTX 5090 32 GB, финальная проверка ориентировалась на A100.
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
export PYTHONPATH="$PWD/src"Если feature-кэши уже лежат в features/, можно обучить и проверить легкий классификатор без повторного снятия всех GigaChat-активаций:
bash scripts/train.shДля скоринга private benchmark:
bash scripts/score_private.shПолное пересчитывание features требует загрузки ai-sage/GigaChat3-10B-A1.8B-bf16 и достаточно тяжелого GPU-окружения. Текущий public-facing репозиторий сохраняет стабильный путь обучения/скоринга по кэшированным признакам и документирует артефакты. Перед регенерацией см. features/README.md.