Реализовать synthetic benchmark генератор
ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Реализовать synthetic benchmark генератор
1. Цель задачи
Разработать автоматическую систему, которая еженедельно создаёт новый набор тестовых примеров (вопросов/задач) с помощью LLM. Генерация должна быть контролируемой по тематике, сложности и формату, а ключевым требованием является отсутствие контаминации: сгенерированные задачи не должны пересекаться с известными публичными бенчмарками (MMLU, HumanEval, MATH и др.) и с ранее сгенерированными пулами. Система автономна, логирует метаданные и может быть запущена по расписанию.
Ключевой результат каждую неделю автоматически формируется валидный набор тестов (≥200 задач), прошедших проверку на пересечение с эталонными бенчмарками и с предыдущими выпусками.
2. Исходные данные
| Что нужно | Откуда взять |
|---|---|
| API LLM (генерация) | OpenAI / Anthropic / локальная модель (через LocalAI) |
| Эталонные бенчмарки (MMLU, HumanEval, GSM8K, MATH, BigBench) | Открытые датасеты (Hugging Face datasets) |
| Описание предметной области и требований к задачам | От заказчика / из ТЗ на продукт |
| Схема хранения предыдущих выпусков | Разработать самостоятельно: SQLite или CSV |
| Шаблоны промптов для генерации | Создать на основе анализа существующих бенчмарков |
Если нет реального инструмента — симулируем:
- Использовать open‑source модель (например, microsoft/phi-3-mini-4k-instruct) через библиотеку transformers с кэшированием ответов.
- Эталонные бенчмарки загрузить с Hugging Face один раз и сохранить локально в FAISS‑индекс для быстрого поиска дубликатов.
- Расписание реализовать через cron (или Task Scheduler) — запуск
main.pyс флагом--week N.
3. Технологический стек
| Компонент | Инструменты | Назначение |
|---|---|---|
| Генерация текста | OpenAI API / local‑модель (transformers, vLLM) | Создание вопросов, эталонных ответов |
| Оркестрация пайплайна | Python 3.11, Typer (CLI), schedule | Управление шагами, запуск по расписанию |
| Детекция контаминации | FAISS (cosine similarity), sentence‑transformers (all‑MiniLM‑L6‑v2) | Векторный поиск дубликатов среди эталонов |
| Хранение метаданных | SQLite (через SQLAlchemy) | Логирование каждого вопроса, хэша, темы, недели |
| Версионирование и CI | Git, GitHub Actions (ежедневный запуск при пушах в main) | Управление кодом, автоматический прогон |
| Тестирование | pytest, pytest‑cov | Юнит‑тесты компонентов |
| Мониторинг | Prometheus + Grafana (опционально) / просто текстовые логи | Сбор метрик: количество сгенерированных, процент контаминации |
4. Этапы выполнения
Этап 1: Проектирование архитектуры (4 часа)
Действия
- Определить формат одной задачи: JSON с полями
id,question,expected_answer,source_benchmark(null), topic,difficulty, keywords,creation_week,hash_question. - Спроектировать схему БД: таблица
generated_questions+ таблицаcontamination_log. Создать SQLAlchemy модели. - Выбрать метрику детекции контаминации: cos_sim > 0.85 между эмбеддингами сгенерированного вопроса и эталонными вопросами.
- Набросать высокоуровневую диаграмму компонентов в Mermaid (опционально, включить в README).
Ожидаемый результат этапа документ ARCHITECTURE.md с описанием схемы данных, потока работы и критериев дубликата.
Этап 2: Реализация генератора вопросов (12 часов)
Действия
- Написать функцию generate_batch(topic: str, n: int) -> list[dict]:
- Реализовать управление seed‑темами (берём из topics.yaml или аргумента командной строки).
- Добавить retry‑логику с exponential backoff при ошибках API.
- Написать юнит‑тест: моковый ответ LLM, проверка количества и структуры.
# example/generator.py
import hashlib, json
from openai import OpenAI
SYSTEM_PROMPT = """Ты генератор тестовых вопросов.
Отвечай ТОЛЬКО JSON-массивом объектов с ключами: question, expected_answer, topic, difficulty.
Не используй задачи из публичных бенчмарков (MMLU, HumanEval, GSM8K, MATH, BigBench)!"""
def generate_questions(client, topic: str, n: int) -> list[dict]:
resp = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": f"Тема: {topic}, сгенерируй {n} задач."}
],
temperature=0.8,
response_format={"type": "json_object"}
)
raw = resp.choices[0].message.content
questions = json.loads(raw) # ожидаем массив или объект с массивом
for q in questions:
q["hash"] = hashlib.sha256(q["question"].encode()).hexdigest()
return questions
Ожидаемый результат этапа стабильный модуль generator.py, проходящий 5+ юнит‑тестов и генерирующий 100 задач за < 2 минут (с эмуляцией API).
Этап 3: Реализация детектора контаминации (8 часов)
Действия
- Загрузить эталонные бенчмарки из Hugging Face: mmlu, gsm8k, math,
hendrycks_test. Взять по 1000 вопросов из каждого (случайная подвыборка). - Вычислить эмбеддинги для эталонных и сгенерированных вопросов через sentence-transformers/all-MiniLM-L6-v2.
- Построить FAISS‑индекс по эталонным векторам.
- Для каждого сгенерированного вопроса:
- Получить top‑1 ближайший эталон.
- Если cos_sim ≥ 0.85 → mark as
contaminated = True.
- Сохранить результат в таблицу
contamination_log. - Написать тест на симулированных дубликатах (взять один эталонный вопрос и слегка перефразировать – должно быть обнаружено).
# example/detector.py
from sentence_transformers import SentenceTransformer
import faiss
import numpy as np
class ContaminationDetector:
def __init__(self, reference_texts: list[str]):
self.model = SentenceTransformer("all-MiniLM-L6-v2")
ref_emb = self.model.encode(reference_texts, show_progress_bar=False)
self.index = faiss.IndexFlatIP(ref_emb.shape[1])
self.index.add(np.array(ref_emb, dtype=np.float32))
self.ref_texts = reference_texts
self.threshold = 0.85
def check(self, question_text: str) -> tuple[bool, float]:
emb = self.model.encode([question_text], show_progress_bar=False)
scores, idxs = self.index.search(np.array(emb, dtype=np.float32), 1)
score = float(scores[0][0])
return (score >= self.threshold), score
Ожидаемый результат этапа модуль detector.py с FAISS‑индексом, точность обнаружения явных дубликатов > 95%.
Этап 4: Интеграция и еженедельный запуск (6 часов)
Действия
- Написать главный скрипт pipeline.py:
- Получает аргумент
--week(дефолт – вычисляется из даты). - Выбирает 5 тем из topics.yaml (random или по очереди).
- Для каждой темы вызывает generator (n=40 → 200 задач всего).
- Прогоняет все через
detector. - Отбрасывает контаминированные.
- Дополняет выборку до 200 повторной генерацией (если менее 200 чистых).
- Сохраняет чистые вопросы в SQLite (и CSV‑дамп для использования).
- Пишет лог: сколько сгенерировано, сколько отброшено, метрики по темам.
- Получает аргумент
- Настроить cron (каждую пятницу в 02:00) или GitHub Actions workflow с триггером
schedule. - Добавить оповещение в Telegram/email при успехе или ошибке (через python-telegram-bot или просто write‑to‑file).
Ожидаемый результат этапа работающий пайплайн, который можно запустить командой python pipeline.py --week 12 и получать чистый дамп benchmark_week12.json.
Этап 5: Валидация и мониторинг (6 часов)
Действия
- Разработать тесты на полную интеграцию (mock‑LLM и mock‑FAISS): проверить, что pipeline не падает и генерирует ≥200 чистых вопросов.
- Выполнить ручную валидацию на 100 вопросах: выбрать 10 случайных, проверить качество (осмысленность, корректность ответа), отсутствие явных копий из MMLU (human check).
- Добавить скрипт
report.py, который выдаёт статистику по всем неделям: общее количество, динамика контаминации, распределение тем. - Задокументировать инструкцию по запуску и добавлению новых тем.
Ожидаемый результат этапа отчёт о валидации, документация README.md, репозиторий готов к деплою.
5. Критерии приемки (Definition of Done)
- 1. Система еженедельно генерирует ≥200 уникальных вопросов (без дублей внутри одного выпуска).
- 2. Контаминация с эталонными бенчмарками не превышает 1% от всего выпуска (т.е. допускается ≤2 совпадения).
- 3. Контаминация с предыдущими выпусками (все недели) ≤ 1% (проверка по хэшу).
- 4. Вопросы имеют структурированный JSON-формат с полями
question,expected_answer,topic,difficulty,creation_week. - 5. Система автоматически запускается по расписанию (cron/GitHub Actions) без ручного вмешательства.
- 6. Все ошибки генерации/детекции логируются, пайплайн не завершается аварийно при временных сбоях (retry).
- 7. Код покрыт юнит-тестами (минимум 10 тестов, покрытие ≥70%).
- 8. Приложена документация по запуску, настройке и добавлению новых тем/бенчмарков.
6. Ожидаемый результат
Основной артефакт репозиторий с кодом, содержащий:
pipeline.py– точка входа.generator.py,detector.py,models.py,config.py.benchmarks/– папка с еженедельными дампами (начиная с недели 1).tests/– 10+ тестов.README.mdс описанием и инструкцией.
Содержимое финального выпуска (benchmark_week12.json):
[
{
"id": "W12_001",
"question": "Вычислите двойной интеграл ∫∫_D x^2 y dxdy, где D – треугольник с вершинами (0,0), (1,0), (0,1).",
"expected_answer": "1/12",
"topic": "математический анализ",
"difficulty": "средний",
"creation_week": 12,
"hash": "a1b2c3d4...",
"contamination_check_passed": true
}
]
Опционально дашборд с метриками (Grafana) или простой HTML-отчёт.
7. Возможные сложности и их решение
| Сложность | Решение |
|---|---|
| LLM повторно генерирует задачи из своих тренировочных данных (даже если запретить в промпте) | Систематически проверять через детектор контаминации; если процент >5% – менять промпт (добавлять few-shot с «непохожими» примерами) или использовать более новую модель. |
| Дрейф домена со временем (темы надоедают) | Ротация тем на основе рейтинга: меньше всего использованные по истории – приоритет. Добавить возможность автоматического расширения тем через LLM. |
| Ложные срабатывания детектора (cos_sim >0.85, но задачи разные) | Оптимизировать порог (подобрать на валидации) или добавить второй проход: проверка n-грамм. |
| Сбой API на этапе генерации | Retry до 3 раз с увеличением задержки; если всё равно ошибка – пропустить тему и записать в лог. |
| Увеличение размера FAISS-индекса (сотни тысяч эталонов) | Использовать IVF-индекс (квантование) или подгружать только релевантный поднабор по теме. |
8. Бюджет времени (оценка)
| Этап | Оценка (часы) |
|---|---|
| Этап 1: Проектирование архитектуры | 4 |
| Этап 2: Реализация генератора вопросов | 12 |
| Этап 3: Реализация детектора контаминации | 8 |
| Этап 4: Интеграция и еженедельный запуск | 6 |
| Этап 5: Валидация и мониторинг | 6 |
| Итого | 36 |
Примечание для первого раза (из‑за настройки окружения, загрузки моделей) время можно увеличить на 20–30%.
9. Связанные вопросы из базы знаний
| Вопрос | Тема |
|---|---|
| 12 | Методы оценки качества LLM |
| 47 | Понятие контаминации тестовых данных |
| 103 | Синтетические датасеты: генерация и валидация |
| 215 | Использование sentence-transformers для поиска дубликатов |
| 324 | FAISS: построение индексов и поиск по сходству |
| 401 | Распределённая генерация задач через LLM (промпт-инжиниринг) |
| 512 | CI/CD для ML-пайплайнов (GitHub Actions) |
| 678 | Параметризованные юнит-тесты с mock-объектами |
| 789 | Хранение метаданных экспериментов (SQLite vs MLflow) |
| 890 | Оценка дрейфа данных при генерации |
10. Чек-лист самопроверки
- Я проверил, что пайплайн запускается без ошибок и генерирует 200 задач за один прогон.
- Я убедился, что ни одна из сгенерированных задач не совпала с эталонными бенчмарками (cos_sim < 0.85).
- Я проверил, что логи контаминации записываются в БД и содержат понятный уровень детализации.
- Я добавил тест на случай контаминации (внёс заведомо похожий вопрос) и убедился, что детектор его отбрасывает.
- Я задокументировал в README инструкцию по добавлению новой темы и запуску «вручную».