# Анатомия потолка Этот документ отвечает на один вопрос: **почему пайплайн стоит там, где стоит, и что именно мешает ему подняться.** Он состоит в основном из отрицательных результатов — это и есть его содержание. Все числа здесь пересчитаны из сырых отчётов (`eval/reports/`), а не перенесены из прошлых редакций; команды воспроизведения — в конце. Короткий ответ: **из всего, что мы пробовали, работает ровно одна ось — сила генератора.** Всё остальное — вмешательства в промпт, контекст, отбор примеров, ансамбли, дообучение своей модели — на этом стеке либо не двигает метрику, либо вредит. А сама метрика гораздо шумнее, чем выглядит. --- ## 1. Сначала о метрике: половину пути мы мерили внутри шума Execution Accuracy на BIRD выглядит как объективное число. Это не так. Jin et al. ([arXiv:2601.08778](https://arxiv.org/abs/2601.08778)) проверили разметку BIRD Mini-Dev и обнаружили ошибки аннотации примерно у половины вопросов. Их исправленный gold (вариант `sql_only` — переписан только SQL, вопрос тот же) даёт возможность измерить собственный шум бенчмарка: прогнать одни и те же предсказания против двух разметок, отвечающих на **один и тот же вопрос**, и посмотреть, где вердикт меняется. Для продуктового прогона (codestral, n=200, 199 сопоставимых вопросов): | | Вопросов | Доля | |---|---:|---:| | Верно при **обеих** разметках | 105 | 52.8% | | Неверно при **обеих** | 61 | 30.7% | | **Вердикт зависит от разметки** | **33** | **16.6%** | То есть «61.5%» — одна точка в коридоре **[52.8%, 69.3%]**, ширину которого задаёт разногласие аннотаторов, а не качество пайплайна. Практическое следствие оказалось неприятным. Порог «живого рычага», по которому проект полгода принимал решения, был ±1.5 п.п. (три вопроса) — **в одиннадцать раз тоньше собственного шума бенчмарка**. Восемь измеренных до этого «паритетов» не были опровергнуты; они просто **неинформативны**: измерение шло внутри шума. ### Метрика, которой можно пользоваться Вместо голого EA мы судим по «бесспорной земле» — по вопросам, где разметка не решает исход: - **чинит** — сколько из **61** вопроса, который бейслайн проваливает при обеих разметках, претендент решает **при обеих**; - **ломает** — сколько из **105** вопросов, которые бейслайн берёт при обеих, претендент теряет **при обеих**; - **net = чинит − ломает.** Требование «при обеих» существенно и применяется к претенденту тоже. Более мягкий вариант — засчитывать починку по одной лишь оригинальной разметке — возвращает в счёт ровно ту лотерею аннотаций, ради исключения которой метрика и заводилась, и завышает «чинит» на 3–4 вопроса у большинства моделей. --- ## 2. Единственный живой рычаг — генератор Все прогоны: одна конфигурация (`config E`, `n=200`, `seed=0`), один продуктовый промпт, меняется только модель-генератор. | Генератор | Доступ | EA (оригинальный gold) | чинит /61 | ломает /105 | net | |---|---|---:|---:|---:|---:| | `claude-opus-4-8`, effort=max | подписка | **79.5%** | **31** | **1** | **+30** | | `claude-sonnet-5` | подписка | 71.5% | 22 | 6 | +16 | | `grok-composer-2.5-fast` | подписка | 70.0% | 23 | 3 | +20 | | **`mimo-v2.5-free`** | **бесплатно** | **68.5%** | 22 | 5 | **+17** | | `big-pickle` (тот же MiMo) | бесплатно | 66.0% | 19 | 6 | +13 | | `nemotron-3-ultra-free` | бесплатно | 63.5% | 20 | 9 | +11 | | `grok-build` | подписка | 62.5% | — | — | — | | `deepseek-v4-flash-free` | бесплатно | 62.5% | — | — | — | | **codestral (бейслайн)** | free API | **61.5%** | — | — | — | | `north-mini-code-free` | бесплатно | 60.5% | — | — | — | Три наблюдения важнее самих чисел. **Разрыв реален и крупнее шума.** Лучший бесплатный генератор чинит 22 из 61 бесспорного промаха бейслайна, ломая 5 из 105. Это не переливание одного класса ошибок в другой — это движение. **Сильному генератору не нужны костыли пайплайна.** Доля вопросов, где сработал repair: codestral **16/200**, mimo-free 3/200, Sonnet 1/200, Opus **0/200**. Механизм починки невалидного SQL, на который потрачено заметное время, у сильной модели просто не вызывается. **Рост идёт туда, где пайплайн был слабее всего.** По тирам сложности: codestral 76.1 / 58.6 / **41.2**, mimo-free 77.6 / 66.7 / **55.9**, Opus 88.1 / 77.8 / **67.6** (simple / moderate / challenging). --- ## 3. На исправленном gold порядок моделей сжимается Тот же набор предсказаний, судимый по исправленной разметке Arcwise `sql_only` (n=199): | Генератор | Оригинальный gold | Исправленный gold | Δ | |---|---:|---:|---:| | `claude-opus-4-8` max | 79.4% | **73.9%** | **−5.5** | | `grok-composer-2.5-fast` | 69.8% | 72.9% | +3.0 | | `mimo-v2.5-free` | 68.3% | 71.9% | +3.5 | | `big-pickle` | 65.8% | 69.8% | +4.0 | | `nemotron-3-ultra-free` | 63.8% | 69.8% | +6.0 | | `claude-sonnet-5` | 71.4% | 68.8% | −2.5 | | codestral | 61.8% | 60.3% | −1.5 | (Проценты в этой таблице считаются по 199 сопоставимым вопросам, поэтому на десятые расходятся с таблицей §2, где знаменатель 200.) **Модели расходятся в разные стороны, и это не случайность.** Бесплатные модели на исправленной разметке растут, а те, что лучше всех на оригинальной, — падают. Падение означает, что модель хорошо ловит конвенции конкретной аннотации: few-shot-примеры взяты из того же корпуса, и модель, которая их лучше усваивает, лучше отвечает «как размечено», а не «как правильно». Практический вывод: **на исправленном gold вся верхушка помещается в 68.8–73.9%.** Разрыв между лучшей платной моделью и лучшей бесплатной — **2.0 п.п.** вместо 11.0 п.п., которые показывает оригинальная разметка. Ось «сильнее модель» жива, но её масштаб зависит от того, какой разметке верить, и честная оценка масштаба заметно скромнее. При этом на бесспорной земле (§1) Opus всё равно первый: 31 починенных против 1 сломанного. Оба факта верны одновременно — он действительно лучший, и он же сильнее всех подстраивается под оригинальные конвенции. --- ## 4. Что не сработало: шесть литературных рычагов подряд Все шесть реализованы по опубликованным работам, каждый измерен отдельным прогоном n=200 на лучшем бесплатном генераторе (чистый `mimo-v2.5-free` = 68.5%), каждый спрятан за флагом и по итогу **выключен**. | Рычаг | Источник идеи | EA | Δ | |---|---|---:|---:| | Value retrieval (поиск значений в БД) | CHESS | 68.0% | −0.5 | | Микропромпты классов ошибок | — | 67.5% | −1.0 | | DAIL-отбор few-shot по маскированному вопросу | DAIL-SQL / MCS | 67.0% | −1.5 | | Целевые описания колонок | — | 65.5% | −3.0 | | Обогащение вопроса в явную спецификацию | E-SQL | 63.0% | −5.5 | | Синтетические few-shot под целевую схему | CHASE-SQL | 59.0% | −9.5 | Ни один не дал плюса. Разброс — от «в пределах шума, но со знаком минус» до −9.5 п.п. Отдельно показателен последний: техника, у авторов дающая +9.3 п.п., на нашем стеке обрушила сложный тир до уровня бейслайна. Раньше тем же способом умерли: декомпозиция запроса (**−6.5**), M-Schema (**−2.0**), компактный промпт на бейслайне (**−3.5**). Без пересчёта в этой редакции, поэтому без чисел: self-consistency, сужение схемы, межмодельное голосование двух и трёх моделей, судья-селектор поверх кандидатов, LLM-верификатор покрытия условий — все дали ноль или шум (детали — в [`docs/03_eval_methodology.md`](03_eval_methodology.md) и [`docs/BACKLOG.md`](BACKLOG.md)). **Обобщение, ради которого этот раздел написан:** чистая конфигурация оказалась локальным оптимумом. Любое добавление контекста или структуры в промпт на нём вредит, а литературные приёмы не переносятся систематически, а не разово. Мы получили шесть независимых подтверждений подряд. --- ## 5. Стена: 32 вопроса, которых не берёт никто Возьмём пять моделей разных семейств (Anthropic ×2, xAI, Xiaomi, NVIDIA) и посмотрим на исправленном gold, что они решают (n=199): | | Вопросов | Доля | |---|---:|---:| | Решают все пять | 112 | 56.3% | | Решает хотя бы одна (оракул) | 167 | **83.9%** | | **Не решает ни одна** | **32** | **16.1%** | Интересна не величина стены, а её устройство. Из 32 вопросов **15 — это случаи, где все модели дают ОДИН И ТОТ ЖЕ ответ, и он расходится с gold.** Пять независимых семейств не галлюцинируют одинаково. Когда они согласны между собой и не согласны с разметкой, подозреваемый — не модель. Разбор формы ответа, на котором модели сошлись: **12 — семантика**, 2 — верная форма при неверной кардинальности, 1 — недостающая колонка. По сложности стена растёт, но присутствует везде: она забирает **11.9%** простых вопросов (8 из 67), **16.3%** средних (16 из 98) и **23.5%** сложных (8 из 34). То есть это не просто «самые трудные вопросы» — четверть стены стоит на простом тире, где генератор в среднем даёт 76–88%. Отдельный класс, найденный при разборе руками, стоит назвать прямо: **бенчмарк местами противоречит собственной подсказке.** В поле `evidence` лежит готовая формула, а gold-SQL считает по другой — например, `evidence` предписывает делить сумму значений, а gold делит количество строк. Инвариант нашего промпта (вопрос и `evidence` — в начале) прямо учит модель доверять подсказке, и на таких вопросах послушание гарантирует промах. Ни один генератор их не возьмёт, пока следует инструкции. Исправленный gold чинит SQL, но `evidence` не трогает — противоречие уцелело и там. Вывод, который стоил разбора: **дешёвых рычагов в стене нет.** Класс «недостающая колонка» лечится правилом в промпте и стоит порядка одного вопроса. Всё остальное — либо семантика, которую чинит только более сильная модель, либо вопросы, у которых нет единственного правильного прочтения. --- ## 6. Своя дообученная модель бейслайн не догоняет Отдельная проверка гипотезы «дообучим свою маленькую модель под эти данные». Qwen2.5-Coder-7B в 4 битах, QLoRA на train-части BIRD (8468 примеров; шаблон промпта — продуктовый, но блок схемы при обучении собран из сырого DDL, а на измерении приходит retrieval-карточками с примерами значений — известный зазор этой версии датасета), измерение тем же харнессом. | | EA (n=200) | чинит /61 | ломает /105 | net | |---|---:|---:|---:|---:| | База (без дообучения) | 50.0% | 12 | 30 | −18 | | После дообучения | 53.0% | 12 | 28 | −16 | Парное сравнение на 199 вопросах, отвеченных обеими версиями: **50.3% → 53.3%, +3.0 п.п.**, починено 25 / сломано 19, точный критерий Макнемара **p = 0.451**. То есть дообучение не дало статистически значимого выигрыша даже над собственной базой, а до продуктовых 61.5% не дотянулось на 8.5 п.п. По тирам выигрыш есть на простом и среднем и **отрицателен на сложном** (−2.9 п.п.). Методическая деталь, которая тут важнее результата: промежуточная оценка на 153 из 200 вопросов давала «+7.2 п.п., p = 0.099». После добивки оставшихся 46 эффект **ужался вдвое, а значимость исчезла** — пропущенные вопросы систематически играли за базовую модель. Знак устоял, но вывод «эффект крепнет с выборкой» оказался артефактом дыр в прогоне. --- ## 7. Что из этого следует 1. **Метрику нельзя читать одним числом.** У EA на оригинальной разметке BIRD коридор ±16.6 п.п. Сравнения тоньше этого — не результаты. Судить надо по бесспорной земле. 2. **Работает только смена генератора.** Все прочие оси — промпт, контекст, отбор примеров, ансамбли, отбор кандидатов без gold, собственное дообучение — на этом стеке мертвы, и это проверено, а не предположено. 3. **Масштаб этого рычага зависит от разметки.** На оригинальном gold он выглядит как +18.0 п.п., на исправленном — как +11.6 п.п. до бесплатной модели и +2.0 п.п. дальше. 4. **Потолок структурный, а не вычислительный.** Верхняя граница отбора из пяти моделей — 83.9%, но все механизмы выбора лучшего кандидата без доступа к gold в этом проекте умирали шесть раз. А часть остатка недостижима в принципе: там бенчмарк противоречит сам себе. 5. **Литературные приёмы не переносятся.** Шесть подряд отрицательных результатов на техниках из статей — достаточное основание проверять их у себя прежде, чем закладывать в план. --- ## Как воспроизвести ```bash # прогон генератора (config E, n=200, seed=0) python scripts/eval_baseline.py --config E --n 200 \ --provider zen --sql-model mimo-v2.5-free --explain-provider mistral \ --report-suffix zen-mimo # пересчёт того же прогона против исправленного gold python scripts/rescore_arcwise.py \ --report eval/reports/<дата>/<отчёт>.json \ --sql-only data/arcwise_plat_sql_only.json \ --full data/arcwise_plat_full.json \ --out eval/reports/arcwise_rescored_<имя>.json ``` Коридор разметки и разбиение 105/61/33 считаются из выхода `rescore_arcwise.py` по полям `original_match` и `sql_only_match`. **Важно при чтении отчётов:** имя файла отчёта не содержит времени, поэтому два прогона с одним суффиксом пишут в один файл. Прежде чем назвать число — убедиться, что процесс прогона завершён, и сверить время изменения отчёта; а пересчёт против исправленного gold имеет смысл только если он новее самого отчёта. ## Источники - Jin et al. Аудит разметки BIRD Mini-Dev — [arXiv:2601.08778](https://arxiv.org/abs/2601.08778). Исправленные артефакты: `data/arcwise_plat_sql_only.json`, `data/arcwise_plat_full.json`. - Разбор техник и обзор литературы — [`docs/quality_levers_research_2026-07.md`](quality_levers_research_2026-07.md). - Методология измерения — [`docs/03_eval_methodology.md`](03_eval_methodology.md). - Сравнение на исправленном gold — [`docs/corrected_gold_evaluation.md`](corrected_gold_evaluation.md).