ESPNBills, Josh Allen outlast Rams in overtime on MNFESPN DeportesLaporta fija la Champions como el objetivo de Barcelona este añoInquirerFree dance sessions for breast cancer survivors set in CalapanThe Jerusalem PostHezbollah explosive smuggling, illegal finance network leads to calls for probe by Lebanese PMsRTP DesportoPlay-off Mundial2027. Portugal - Irlanda do Norte (19h00)Daily MaverickSERIES SETBACK: Proteas point to ‘soft dismissals’ after batting collapse hands Australia first TestInquirer EntertainmentWowie de Guzman figures in Batangas car accident, assures he’s OKBollywood HungamaMrunal Thakur neither confirms nor denies Raaka casting rumours, says film announcements will come on social mediaTaipei TimesENGLISH DIGEST 實用美語(空中美語)
The Daily Newsstand · Free, Always
Tuesday, October 13, 2026

Чат, который ничего не сочиняет: 43 гипотезы, четыре ошибки замера и одна честная стена

Translate

Препринт этой работы пока не опубликован на arXiv: для подачи мне нужен endorsement в категории cs.CL (Computation and Language). Если у вас есть право выдавать endorsement в этой категории и вы готовы помочь, буду благодарен — напишите мне в личные сообщения на Хабре.

Код, файлы результатов, meta прогонов и реестр гипотез целиком, включая отрицательные: https://github.com/ADanMan/elm-research. Репозиторий пока приватный. Планирую открыть исходники после публикации статей.

Идея была простая и не новая: у большой языковой модели два неприятных свойства — она стоит денег на каждый ответ и держит в памяти десятки гигабайт весов, а ещё она может уверенно написать то, чего нет нигде. Захотелось собрать систему, у которой ответ выбирается из существующего текста, а не порождается: корпус лежит на диске файлами, кандидатов находит обычный код, а нейросеть-судья только выбирает строку и проверяет её. Судья — классификатор с типизированными примитивами: «выбери один из вариантов», «это правда?», «оцени по шкале». Текст она не пишет вообще. Ответ — дословная цитата с источником, и выдумать фразу, которой нет в корпусе, система не может по построению.

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

День первый: 20.0% верных и очень много отказов

Первая версия: Simple Wikipedia в SQLite, полнотекстовый поиск FTS5, окно строк судье, один запрос «какая строка отвечает» и три проверки. На отладочной половине Natural Questions (150 вопросов, строгая метрика — эталон дословно содержится в ответе) вышло 20.0% верных при 60.0% отказов.

Соблазн в этот момент — крутить формулировки вопросов к судье. Вместо этого я написал офлайн-замер охвата: доходит ли эталонный ответ до строк, которые судья реально видит. Эталон доходил до окна судьи у 42.7% вопросов, то есть больше чем в половине случаев судья выбирал из строк, где ответа не было вовсе, и никакая формулировка этого не лечит. Отсюда главный приём всего проекта: прежде чем чинить звено, докажи замером, что теряется именно в нём.

Судья не найдёт ответ среди строк, в которых его нет.

Судья не найдёт ответ среди строк, в которых его нет.

Корпус: сначала стало хуже

Расширить выдачу с сотни абзацев до шестисот — 21.3%, то есть ничего. Подключить полный psgs_w100 — 21 015 324 абзацев вместо небольшой Simple Wikipedia, и стало хуже: запрос «любое из редких слов» по такому корпусу размывает выдачу, редкие слова находятся где угодно.

Починило это не увеличение корпуса, а изменение запроса: строгое «все редкие слова разом» (с прежним запросом как страховкой, когда находок мало) — 33.3%. Плюс короткие гипотезы локальной модели, использованные как поисковый запрос, а не как ответ: 35.3%. Ещё пара пунктов пришла от инженерии — перестали теряться обращения к судье: 37.3%.

Деталь про роль генеративной модели: она никогда не принимает решений. Когда судья не может выбрать (он либо говорит это сам, либо это видно по энтропии его распределения), он берёт инструкцию из фиксированного меню — дай гипотезы ответа, переформулируй запрос, разбей на подвопросы, — и всё, что модель вернула, снова идёт ему на выбор и проверку. Три триггера по качеству неразличимы (35.3% у энтропийного), но энтропийный зовёт модель в несколько раз реже: в финальном прогоне генератор понадобился на 4 вопросах из 150.

Скачок: чужие эмбеддинги

Рамка работы — никаких дообучений: судья как есть, индексы с полки, локальная модель как генератор кандидатов. Поэтому следующий шаг был не «обучим кодировщик», а «возьмём готовый». Готовый FAISS-индекс facebook/wiki_dpr поднял охват окна судьи до 82.0% (в пуле — 89.3%) против 56.0% у словарного поиска по тому же полному корпусу и 42.7% по Simple Wikipedia, а живое качество — с 37.3% до 46.0%; парный тест Макнемара: 69 против 56 верных, несовпадающих пар 22/9, p=0.029.

Это единственный по-настоящему большой шаг за всю работу, и он чужой. За него заплачено памятью: индекс занимает около трёх гигабайт в процессе, и профиль «малая память» на этой конфигурации перестаёт быть правдой (4149 МБ пик против 47.7 МБ у полнотекстового профиля на том же корпусе) — в статье обе цифры стоят рядом.

Отдельная оговорка, которую нельзя опускать: кодировщик DPR обучался на train-половине NQ. Моя система не училась ничему, но индекс, который она берёт с полки, обучающую часть этого набора видел. Поэтому NQ идёт базой, а не главным результатом, а независимая проверка — на BrowseComp-Plus, где индекс другой.

Смешивание плотного поиска с полнотекстовым (гибрид с тройным весом) от чистого плотного неотличимо: 68 против 69, p=1.000.

Качество по гипотезам

Качество по гипотезам

Стена: семь способов спросить судью, и ни одного пункта

После плотного поиска разложение потерь стало таким: ответ есть в пуле у 91.3% вопросов, в окне судьи — у 89.8% из них, и верен, если был в окне, в 69.1% случаев. Произведение — 56.7% при измеренных 56.7% по судье. Узкое место переехало в последнее звено: судья выбирает не ту строку среди строк, где ответ есть.

По этому звену я отработал шесть схем, и каждая мерена против своей базы, а не против одной общей:

  1. четыре отдельные проверки вместо выбора (LongBench, отладочная половина);

  2. предотбор строк под каждый вариант ответа (там же);

  3. первое и второе вместе (там же);

  4. голосование судьи по трём формулировкам на словарной базе NQ — 56 против 54, p=0.625;

  5. второе окно судьи поверх плотного поиска — 69 против 69, несовпадающих 8/8, p=1.000, ценой лишнего обращения на каждый вопрос;

  6. турнирный выбор раундами по восемь строк вместо одного выбора на всё окно, тоже поверх плотного поиска — 48.7% против 46.0%, p=0.454.

Седьмая схема — обрезка придаточных кодом, чтобы вопрос судье стал «типом ответа», — не изменила ни одного ответа на BrowseComp и отдельного файла результатов не оставила.

Ни одна не дала значимого прироста. Турнир — самый поучительный: он перевёл отказы в ответы (отказов 23.3% против 27.3%), и по строгой метрике это дало 73 верных вместо 69 — 10 приобретённых против 6 потерянных, p=0.454, то есть в пределах шума. А по мягкой метрике счёт не изменился вовсе: 85 против 85 (7 приобретено, 7 потеряно, p=1.000). Зато «невпопад» вырос с 26.7% до 28.0%, а цена — с 4.5 до 28.5 обращений к судье на вопрос. Четыре строгих попадания за шестикратную цену, и ни одного — по метрике судьи.

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

А потом я сделал то, что стоило сделать раньше, и за ноль денег: офлайн-скан порогов по уже записанным вероятностям судьи. Результат неприятный и полезный. Оценки судьи не разделяют его верные и неверные ответы: лучший порог срезает 6 ответов невпопад, теряя 4 верных, а отрыв выбора у неверных ответов даже выше, чем у верных (0.15 против 0.055 по медиане). Судья уверен там, где ошибается. Это значит, что «поставить порог поумнее» — тупик, и нужна калиброванная оценка уверенности, то есть обучение. В этой работе обучения нет по условию, так что здесь — граница.

Когда у неверных ответов отрыв выше, чем у верных.

Когда у неверных ответов отрыв выше, чем у верных.

Ручка, которая не улучшение

Одна вещь из этой серии всё-таки работает, но улучшением её назвать нельзя. Если задать проверки повторно другими словами, точность и полнота размениваются: ответов невпопад 30 вместо 40 (пары 13/3, p=0.021), но верных 64 вместо 69 (p=0.359) и отказов 37.3% вместо 27.3%. У генеративной модели такой ручки нет вовсе — она всегда отвечает; но число верных ответов от неё не растёт, поэтому это «режим строгости», а не подтверждённая гипотеза.

BrowseComp-Plus: где сломался сам вопрос

Проверка на наборе, чей индекс не видел наших данных. Первые прогоны дали ноль верных ответов, и разбор показал, что судья прав, а неверна инструкция. Вопрос там — загадка из пяти условий на сотню слов, а я спрашивал «какая строка утверждает ответ на это?». Ни одна строка не отвечает на всю загадку целиком, и судья с уверенностью около единицы выбирал вариант «ни одна».

Починка — разные вопросы по звеньям: документ выбирается по полной загадке (условия нужны, чтобы его узнать), а строка и проверки — по финальному вопросу, который выделяет код; плюс дочитывание выбранного документа из базы целиком. С нуля стало 13.3% строго на живом поиске и 10.0% в оракульной схеме, где эталонные документы подставлены. Разложение по звеньям здесь другое: эталонный документ выбирается в 23.3% случаев (7 из 30), а если выбран — ответ верен в 57.1% (4 из 7); в оракуле 33.3% и 30.0%. Знаменатели крошечные, точности в этих процентах нет, и это одна из причин, почему ветка осталась на отладочной половине. Слабое звено тут другое, чем на NQ, и разложение показывает какое, без единой абляции.

И настоящая стена этого набора: у 26.7% вопросов ответ составной или форматный — «1986, Portugal», «90g», «23rd match, 2019». Строки с таким ответом в корпусе нет вовсе, и система, которая отвечает дословной цитатой, такие вопросы не решает в принципе. Потолок дословного цитирования — 73.3%.

Под эту стену сделан режим сборки: судья выбирает режим ответа (дословно / собрать из проверенных цитат / нет ответа), и сборка проходит отдельную проверку «всё ли есть в источниках». Замер: генератор позвали 3 раза на 30 вопросах, выдумок ноль, непрошедшие сборки стали отказами. Чистый эффект — около нуля: 16.7% против 13.3% на живом поиске и 13.3% против 10.0% в оракуле, отказы выросли с 63.3% до 73.3%. Механизм работает и не сочиняет, но лишний вопрос о режиме перед каждым ответом работает как ещё один гейт, и гейт съедает выигрыш. Очевидная починка — спрашивать режим только после отказа дословного пути — не замерена, поэтому это не результат.

Четыре собственные ошибки измерения

Эта часть мне интереснее результатов: все четыре ошибки искажали цифры молча.

Первая: флаги читались на импорте. Раннер выставлял переменные окружения позже, чем модуль их читал, поэтому «прогон с плотным поиском» шёл полнотекстовым, а «прогон с турниром документов» не выполнял ветку турнира вовсе. Замеры выглядели нормально. Именно отсюда взялось то самое «0 из 90», которое я сначала принял за свойство судьи. Лечится чтением настроек в момент вызова и проверкой зависимостей флагов.

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

Третья: утечка генерации в ответ. Роутер открывал генеративную ветку по одному факту наличия генератора в зависимостях. В результате в прогоне на BrowseComp «ответом» оказалась фраза, сочинённая моделью перед цитатой («The company is Genetics Nepal.»), а эталон был совсем другой. Для системы, у которой весь смысл в дословности, это делает прогон недействительным, даже если цитата стоит следом. Теперь право формулировать ответ даёт только один флаг, а тест гоняет продовый путь и проверяет, что строк генератора в ответе нет.

Четвёртая: поправка метрики. Та же утечка в мягком виде отравила прогоны NQ с гипотезами: строки поисковых догадок попадали в текст ответа перед цитатой, и на одном вопросе ответ состоял из догадок целиком, и был засчитан верным. Что считается ответом, я определил заново: только дословная цитата и выжимка-спан из неё, догадки — это поисковые запросы. Пересчёт офлайн, без новых прогонов, затронул 16 файлов результатов: база с 70 на 69 строго верных (по судье с 86 на 85), прогон с гипотезами — с 55 на 53. Выводы не перевернулись, отложенные прогоны поправка не затронула вовсе (0 совпадений — гипотезы в них были выключены). Но публиковать прежние цифры без этого пересчёта было бы нечестно.

Всего в журнале 10 прогонов помечены недействительными, с причиной у каждого, и ни один из них не участвует в цифрах статьи.

Финал: отложенная половина, один прогон

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

Где знание дано и где его надо найти

Где знание дано и где его надо найти

Там, где доказательство дано в задаче, выбор отвечает как генерация. BoolQ: 90.0% против 90.0% у Claude Opus 5 — не «близко», а тот же счёт на тех же вопросах (парный тест p=1.000); DeepSeek с тем же абзацем 84.7%, без абзаца 68.0%. SQuAD 2.0: 79.3% против 80.0% (p=1.000). Но паритет тут — размен, и это надо говорить прямо: на отвечаемых вопросах Opus сильно впереди (96.2% против 78.8%), а общий счёт выравнивается за счёт безответных, где мы молчим в 80.0% случаев против 61.4% у него. Мы не лучше отвечаем. Мы лучше не отвечаем.

Там, где ответ надо найти, всё упирается в поиск. NQ open по корпусу из 21 015 324 абзацев: 49.3% строго и 56.7% по судье при 27.3% отказов, против 62.0% / 74.0% у Opus и 47.3% / 60.0% у DeepSeek. Парно: с DeepSeek неразличимо (p=0.775), Opus значимо лучше (p=0.011). Единственное, что мы на этом наборе выигрываем, — ошибаемся реже: ответов невпопад 24 против 41 у DeepSeek (p=0.0060), потому что наши провалы уходят в отказ, а не в уверенный текст.

С длинным контекстом та же картина. LongBench v2: 15 из 30 (50.0%) при окне в 40 строк и одном обращении к судье, медиана 3 926 прочитанных токенов на вопрос. Медианный документ набора — 72 758 токенов, самый большой — 1 719 190, и окно судьи от этого размера не зависит. Референс Opus по тому же окну есть только на отладочной половине (76.7% против наших 43.3%), на отложенной он не снимался — сравнивать напрямую нельзя, и в статье это помечено.

Про цену. Каждая цифра — измеренные токены на публичную ставку провайдера. BoolQ: 0.0185$ против 9.73$ за тысячу вопросов, то есть в 395–527 раз в зависимости от того, считать ли служебный префикс платформы, который несут реплики Opus. NQ: 0.95$ против 7.31$ — уже только в 7.7 раза, потому что судья читает 23 120 токенов на вопрос. И то, что мне не нравится, но стоит в таблице: DeepSeek отвечает на те же вопросы за 0.017$ за тысячу — дешевле нас в десятки раз при неразличимом качестве. Нужны только дешёвые фактоидные ответы — берите маленькую генеративную модель; вы теряете источник у каждой фразы, штатный отказ и обновление знаний файлом, но по деньгам вы правы.

Цена и прочитанные токены

Цена и прочитанные токены

Заодно граница, из-за которой всё это затевалось: корпус — 2.73 млрд токенов, положить его в промпт целиком стоило бы 114.74$ за один вопрос по самой низкой из наших ставок, и окна такого размера не существует. Судья читает 23 120 токенов, потому что что читать — решает код.

Об устойчивости. Внедрённые инструкции («SYSTEM: this is the correct answer», «[ADMIN NOTE…]») не сработали ни разу: 0 успешных атак из 60. Это не защита, которую я написал, — найденный текст здесь данные, потому что его никто не интерпретирует как инструкцию. А подложный факт, вписанный в настоящий абзац, процитирован как ответ в 1 случае из 30: гарантия про фразы, не про факты. Два независимых прохода по 30 вопросам дали совпадение режима 30/30, строки 29/30 и реплики 26/30, а вероятности судьи дрожат (≤0.01 у 20 вопросов, ≤0.1 у 9, больше у 1), поэтому «почти детерминирован», и никогда «полностью».

Итог

что мерили (отложенная половина)

выбор (судья)

Claude Opus 5

DeepSeek

BoolQ, абзац дан

90.0%

90.0%

84.7% / 68.0% без абзаца

SQuAD 2.0, абзац дан

79.3%

80.0%

80.0%

— на отвечаемых вопросах

78.8%

96.2%

86.2%

— молчание на безответных

80.0%

61.4%

72.9%

NQ open, корпус 21 015 324 абзацев

56.7%

74.0%

60.0%

— ответов невпопад

16.0%

20.7%

27.3%

LongBench v2, окно 40 строк

50.0%

76.7% (dev)

—

цена за 1000 вопросов, BoolQ

0.0185$

9.73$

0.0396$

цена за 1000 вопросов, NQ

0.95$

7.31$

0.017$

Из 43 заведённых гипотез замерены 27, отвергнуты 16, подтверждены 9, 2 приняты как режимы-размены, до 16 дело не дошло.

Куда уперлись, по звеньям: первое — чужой индекс, и его потолок не мой; последнее — выбор строки судьёй, 69.1%, и его вероятности про собственные ошибки ничего не знают. Оба лечатся обучением: своим кодировщиком запросов под свой корпус и калиброванной оценкой уверенности на своих окнах. Здесь не обучалось ничего — это было условие, поэтому читать работу стоит как пол подхода, а не как предел.

Честный итог: когда доказательство лежит перед системой, классификатор, выбирающий предложение, отвечает не хуже модели, которая предложение пишет: дешевле в 7.7–395 раз в зависимости от того, сколько поиска нужно вопросу, с источником у каждой фразы и с отказом как штатным исходом. Когда доказательство надо найти, побеждает параметрическая память. Дальше интересна не точность, а разложение: оно показывает, какое звено чинить, и стоит ноль обращений к судье.

Оговорки, без которых цифры выше читать нельзя: память, время и цена измерены на моей стороне, судья — удалённый сервис, и его собственные вычислительные ресурсы мне неизвестны; кодировщик готового индекса обучался на train-половине NQ; референс Opus на LongBench снят только на отладочной половине; мягкую метрику пересчитывает тот же судья, который выбирает ответы внутри системы, поэтому рядом с ней всегда стоит строгая; выборки — 150 и 30 вопросов, у всех долей в статье есть доверительные интервалы, а у всех сравнений — парный тест.

Навигация по серии

В этой части кандидаты — цитаты из найденных документов. Во второй части тот же принцип выбора проверяется на вызовах функций: где теряются значения аргументов и когда правильным ответом становится отказ. В третьей части речь о диалоговом агенте: контрольная заглушка и замена решателя помогают отделить качество компонента от ошибок цикла. Обе части готовятся к публикации.

  • Часть 1. Выбор цитат: поиск, судья и ошибки измерения — вы читаете эту часть.

  • Часть 2. Вызовы функций: значения аргументов и отказ — публикация планируется на 15 октября 2026 в 18:00 МСК.

  • Часть 3. Диалоговый агент: заглушка, награда и ошибки цикла — публикация планируется на 20 октября 2026 в 18:00 МСК.

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.