Архитектура

Эта страница — для тех, кто хочет заглянуть внутрь: разработчиков и тех, кто думает дополнять бенчмарк. Нужна просто методика — она на странице Как это работает.

Карта проекта

Бенчмарк построен на одном правиле: определение живёт в данных, харнесс их исполняет. Что считается верным решением, как наблюдение переводится в балл и в каких условиях испытывали модель — это задают файлы в metrics/, tasks/, generation/ и editions/. Код в harness/ таких решений не принимает: он читает правила, запускает код кандидата в песочнице и записывает результат. Поэтому смена правила оценки — это правка YAML и пересчёт, а не правка скорера.

flowchart TB
    subgraph DEF["Определение бенчмарка · данные"]
        direction LR
        METRICS["metrics/<br/>конституция · протоколы"]
        TASKS["tasks/<br/>условие · тесты · эталон"]
        GENCAT["generation/<br/>модели · промпты · прайс"]
        EDIT["editions/<br/>профили прогона"]
    end

    subgraph HARNESS["Харнесс · harness/"]
        direction LR
        GEN["generate<br/>адаптеры моделей"]
        EXEC["execute<br/>песочницы"]
        SCORE["score<br/>S · M · O · P → Q"]
        GEN --> EXEC --> SCORE
    end

    subgraph RES["Результаты · results/"]
        direction LR
        RAW["experiment_*.json<br/>ответы моделей"]
        AUTO["auto/*.json<br/>оценки L1"]
        CACHE[".measure_cache/<br/>сырьё прогонов"]
    end

    subgraph PUB["Публикация"]
        direction LR
        SITE["сайт и docs/"]
        SUBM["submissions/<br/>compat_hash"]
        DATA["датасет"]
    end

    GATES["prism check · prism audit<br/>гейт определения · гейт результатов"]
    L2["Уровень L2<br/>экспертная разметка"]

    DEF --> HARNESS --> RES --> PUB
    DEF -.-> GATES
    RES -.-> GATES
    RES -.-> L2

    classDef planned stroke-dasharray:5 5,color:#888;
    class L2 planned;

Гейтов на схеме два, и они проверяют разное. prism check отвечает за определение бенчмарка: задачи, эталоны, контракты, наличие инструментов. prism audit отвечает за полученные результаты: инварианты поверх готовых оценок. Пунктиром — Уровень 2, экспертная разметка: она опирается на ту же конституцию и те же ответы моделей, но пока в планах.

Дальше эта карта разобрана по слоям: данные и код, метрика, устройство задачи, каталог моделей, издания, поток данных и состав results/.

Данные и код

Репозиторий делится на данные (правда о том, что и как мы меряем) и код (инструмент, который это исполняет).

Данные — что и как оценивать:

КаталогЧто лежит
metrics/правила метрики SMOP: общие определения осей (конституция) + как их считает машина и как ставит эксперт (два протокола)
tasks/сами задания: условие, скрытые тесты, эталон; для платформенных — ещё и описание синтетической базы
editions/профили прогона: какие оси считать и в каких условиях решала модель
generation/с какими моделями работаем: каталог моделей, их числовые параметры, системные промпты, таблица цен

Код — чем оценивать (папка harness/):

МодульЗа что отвечает
generate/модели пишут код по задачам: адаптеры провайдеров, агентный сбор метаданных (категория B), чекпойнт/--resume, ретраи, учёт бюджета, офлайновая имитация --mock
score/оценка кода по осям S · M · O · P и общий балл Q (по модулю на ось)
execute/запуск кода в песочнице: OneScript (категория A), headless-1С (B), BSL LS (оси S/O), сборка синтетической базы из описания
stats/сводная статистика (среднее, медиана, σ, доверительный интервал), срезы по тегам, воронка отказов
report/генерация таблиц лидерборда и банка задач (prism docs, prism tasks)
preflight, submitпредполётные проверки (doctor, ping) и упаковка прогона для шеринга (submit)

Сверху — тонкая обвязка: cli (разбор команд), orchestrate (прогон оценки), check (целостность), loaders/settings (чтение данных и ключей). Логики в диспетчере нет — он только связывает слои.

Метрика: одна конституция, два протокола

Сердце бенчмарка — каталог metrics/:

  • smop.yaml — конституция. Определяет сами оси (S, M, O, P), шкалу баллов и правило общего балла Q. Это «что мы меряем» — менять осознанно, это затрагивает все результаты.
  • smop_l1_auto.yaml — протокол Уровня 1 (машина). Как из запуска кода получается балл: пороги, банды, белые списки. Скореры в harness/score/ читают пороги отсюда, не хардкодят.
  • smop_l2_expert.yaml — протокол Уровня 2 (эксперт). Как тот же набор осей оценивает живой человек.
  • error_taxonomy.yaml — словарь ошибок. Маркеры платформенной ошибки, подклассы маркера «Ошибка при вызове метода контекста», поле вины (model / task / harness / infra). Списки живут в данных, а не в коде раннера: скорер, воронка и аудит читают их оттуда же, откуда читаются пороги. Уточнить словарь можно правкой YAML, не трогая код.

Ключевая идея: оба уровня меряют одно и то же (по одной конституции) — различаются только протоколы. Поэтому их оценки сравнимы, и главный научный результат проекта — согласие L1 с L2 (каппа Коэна).

Задача = условие + скрытая проверка + эталон

Каждая задача — самодостаточный каталог. Состав зависит от категории:

ФайлКатегория A (алгоритмика)Категория B (платформа)
task.yamlусловие, точка входа, тегиусловие, паттерны функции, ожидаемые объекты, теги
тестыtests.yaml (скрытые кейсы)tests.bsl (проверки на BSL)
эталонcanonical.bslcanonical.bsl
оптимальностьperf.yaml (генератор растущего входа)perf.yaml (спека роста БАЗЫ, поле grow; есть у части задач)
синтетическая база—config_spec.yaml + fixtures.yaml (конфигурация и данные)

Инвариант: эталон обязан проходить свои скрытые тесты на 100% — иначе сломаны тесты или эталон. Это и гейтит prism check. Для категории B база целиком воссоздаётся из config_spec.yaml + fixtures.yaml при каждом прогоне (в репозиторий база не попадает).

Каталог моделей и адаптеры

Модель — это факты, канал доступа — отдельно. В generation/models.yaml модель описана фактами: id, вендор, возможности (окно контекста, поддержка инструментов). А как до неё достучаться — поле access.adapter: один и тот же вендор может идти разными каналами (Claude через OpenRouter, Qwen — локально через Ollama).

  • models.yaml — каталог моделей (факты);
  • params.yaml — числовые параметры прогона (temperature, число прогонов) по модели;
  • prompts.yaml — системные промпты по категории;
  • pricing.yaml — датированная таблица цен (волатильна, поэтому отдельно от каталога).

Добавить нового провайдера = один файл-адаптер в harness/generate/adapters/ плюс запись в каталоге. Остальной код не трогается.

Издания — «в каких условиях испытывали»

Издание (editions/) — профиль прогона: какие оси считаем и при каких условиях модель решала задачу. Один и тот же набор задач можно прогнать по-разному:

  • core (есть сейчас) — модель получает задание и пишет код; для платформенных задач сама собирает нужные сведения о базе (метаданные) вызовами инструментов;
  • agent (в планах) — полный агентный цикл: модель не просто пишет код, а сама правит конфигурацию инструментами и проверяет результат.

Издание отвечает на вопрос «в каких условиях испытывали», а не «кто проверил результат». «Проверено экспертом» (Verified) — это отдельное измерение, не издание.

Поток данных: от задачи до оценки

flowchart TD
    IN["Задания · модели · издание"]
    GEN["generate<br/>модель пишет код"]
    EXP["Код-кандидаты<br/>experiment_*.json"]
    SCORE["score<br/>запуск в песочнице"]
    AUTO["Оценка S·M·O·P + Q<br/>auto_l1.json"]
    LB["leaderboard / docs<br/>рейтинг — L1, машина"]
    SUB["submit<br/>пакет с compat_hash"]
    AUD["audit<br/>инварианты поверх оценок"]
    L2["Уровень 2 — эксперт<br/>(в планах)"]
    VER["Verified<br/>согласие L1 и L2"]

    IN --> GEN --> EXP --> SCORE --> AUTO
    AUTO --> AUD
    AUTO --> LB --> SUB
    AUTO -.-> L2 -.-> VER

    classDef planned stroke-dasharray:5 5,fill:#f6f6f6,color:#777;
    class L2,VER planned;

Пунктиром — Уровень 2 (эксперт): он пока в планах. Категория B перед генерацией сама собирает метаданные базы; подробности по шагам — в разделах выше.

Ветка на audit стоит в стороне не случайно: эта команда ничего не считает и ничего не меняет, она проверяет уже готовые оценки инвариантами (сироты и дубли, ось с баллом там, где замера не было, инфраструктурный сбой под видом дефекта модели, задачи-выбросы, дрейф к снимку). Разделение простое: prism check проверяет определение бенчмарка, prism audit его результаты.

Где исполняется код: docker и local

Код кандидата нужно запустить, и есть два режима:

  • docker (по умолчанию) — код запускается в изолированном контейнере: без доступа к сети, с лимитами по памяти и времени, файлы только для чтения. Это дефолт, потому что код от нейросети недоверенный — ему не место на хосте без песочницы. Так же гоняется и в CI.
  • local — инструменты стоят на твоём компьютере. Быстрее, удобно для своей разработки; включается явно (--runner local / --bsl local или PRISM_RUNNER=local).

Важно: способ запуска на оценку не влияет — инструмент той же версии, балл тот же. Поэтому режим это инфраструктура, а не часть результата (не входит в «версия × издание × конфиг»).

Правило держится на том, как считаются лимиты. Бюджет исполнения измеряется процессорным временем (cpu_limit_s в протоколе), поэтому загрузка машины на балл не влияет: решение тратит свой бюджет независимо от того, что ещё стоит в очереди. Сторож по стенным часам тоже есть, он впятеро больше и означает не «медленно», а «не измерено»: это сбой окружения, а не свойство кода. Выбор — через PRISM_RUNNER / PRISM_BSL (по умолчанию docker).

Что сохраняется в results/

  • experiment_*.json — сырые ответы моделей (что именно сгенерировала каждая модель на каждой задаче), с хешами для анализа воспроизводимости. Каноничны, идут в репозиторий.
  • auto/*_auto_l1.json — авто-оценки Уровня 1: производная из сырых ответов + протокола. Воспроизводимы пересчётом (prism score), поэтому кэш-снимки в репозиторий не идут. Но канонические снимки (текущий прогон A и B плюс site_data.json) коммитятся намеренно — белый список в .gitignore: чтобы prism leaderboard и подстановка чисел в README работали сразу после клона, без пересчёта.
  • .measure_cache/ — сырые замеры песочницы, сложенные по содержимому входа (текст скрипта плюс версия инструмента). В репозиторий не идут. Это не только ускорение пересчёта: ключ прогона сохраняется в самой оценке (detail.M.run_key), и prism artifacts разворачивает запись обратно в логи 1С, как они были. Почистить кэш значит потерять сырьё, по которому балл можно перепроверить руками.
  • auto/snapshots/ — замороженные снимки корпуса с контрольными суммами и составом. Это база сравнения: prism audit --baseline считает к ней дрейф оценок, запись за записью.
  • submissions/ — упакованные прогоны для шеринга (prism submit): оценки + compat_hash (отпечаток версии бенчмарка — метрика и набор задач). Хеш гарантирует, что чужой прогон получен на той же версии и его цифры сравнимы.

Документация — производные данные

Таблицы лидерборда и счётные бейджи в README и на сайте — не пишутся руками. Их источник правды — results/auto/*_auto_l1.json; prism docs подменяет помеченные регионы между <!-- prism:KEY --> свежими данными. Так проза и числа не разъезжаются.

Операционная надёжность ⟂ метрика

Чекпойнт/--resume, ретраи при сбоях сети, учёт стоимости, параллельный запуск — всё это нужно для больших прогонов, но на баллы SMOP не влияет: балл считается из ответа модели, а не из того, как и почём он получен. Параллельный скоринг (PRISM_CONCURRENCY) проверен бит-в-бит против последовательного — баллы совпадают.

Дальше