textmachine/docs/experiments/06-local-extraction.md

9.3 KiB
Raw Permalink Blame History

Эксперимент 06. Экстракция терминов: локаль vs облако (write-path банка памяти)

Дата: 2026-07-04. Закрывает дыру G1 реестра рисков (architecture/06: «качество популяции глоссария не измерено»). Скрипт: eval/extract_bench.py; сырьё: eval/data/extract_bench/results.json.

Зачем. Горячий путь банка памяти модель НЕ использует (детерминированный матч). Локаль касается банка в 2 точках: эмбеддинги (exp там же → bge-m3) и экстракция кандидатов в глоссарий из сырого текста (bootstrap write-path). Полигон exp03 мерил локаль как ПЕРЕВОДЧИКА (вердикт: не годится). Экстракция — другая, более лёгкая задача; здесь меряем её отдельно и верифицированно.

Метод (в ответ на «сделай нормально, не обрывочно»):

  • 13 моделей: 6 локальных (qwen3-abliterated:8b/9b, qwen3:8b, qwen3-vojo, ruadapt-qwen3:8b, qwen3-abliterated:30b-a3b) + 7 облачных (deepseek-v4-flash, grok-4.20-non-reasoning, glm-4.5-air, kimi-k2.6, gemini-2.5-flash, gpt-5-mini, + deepseek-nothink как дешёвый вариант без reasoning).
  • 12 кейсов, 3 языка, эдж-кейсы: zh (имена+реалии 送灶/祝福/秀才, алиас 王癞胡=王胡), ja (羅生門/朱雀大路, западные имена через катакану メロス→Мелос / セリヌンティウス→Селинунтий, буддийское 禅智内供 по эталону Стругацкого), en (Джон Картер/Конан/Филби — эдж на транскрипцию). Gold — сущности + канонический RU (accept-регэксп: Палладий/Поливанов/устоявшиеся).
  • Запросы — через рабочий refusal_bench.call_provider + канонический providers.json (квирки уже верны: deepseek thinking-ON+max_tokens 8000 — иначе reasoning съедает бюджет и content пуст; kimi temp=1/24k; gpt-5-mini max_completion_tokens+no-temp; gemini/glm thinking-off). Управление thinking у DeepSeek — extra_body={"thinking":{"type":"..."}} (офиц. доки, см. 00-provider-quirks).
  • Каждый ответ верифицируется на здоровость (пустой/echo/http/unparseable → ретрай с бо́льшим бюджетом → явный HEALTH=failed, НЕ засчитывается как recall 0 — урок прошлого обрывочного прогона). Метрики детерминированные, без судьи.

Результаты

Агрегат по health==ok (recall = спот сущностей; render = доля найденных с каноническим RU; halluc = извлечённое, чего нет в тексте):

Модель тип recall render halluc n сек ok/all
qwen3-abliterated:8b local 0.98 0.48 0.0 3.9 5.1 12/12
qwen3.5-abliterated:9b local 1.00 0.54 0.0 3.2 6.6 12/12
qwen3:8b local 0.98 0.49 0.0 3.8 4.9 12/12
qwen3-vojo local 0.98 0.51 0.0 3.4 3.4 12/12
qwen3-abliterated:30b-a3b local 0.91 0.55 0.0 3.1 13.5 12/12
ruadapt-qwen3:8b local 1.00 0.72 0.07 3.6 3.7 5/12
deepseek-v4-flash cloud 0.97 0.85 0.0 3.3 8.9 12/12
grok-4.20-non-reasoning cloud 0.98 0.69 0.0 3.2 1.1 12/12
glm-4.5-air cloud 0.98 0.68 0.0 3.2 1.9 12/12
kimi-k2.6 cloud 1.00 0.96 0.0 3.5 38.2 12/12
gemini-2.5-flash cloud 0.97 0.92 0.0 3.4 1.4 12/12
gpt-5-mini cloud 0.95 0.67 0.0 4.4 2.5 12/12
deepseek-nothink cloud 0.98 0.58 0.0 3.5 1.6 12/12

Ключевая разбивка — render по языку (пул из 5 локальных dense/MoE vs топ-3 облака deepseek/kimi/gemini):

Группа zh ja en
локаль (пул) 0.26 0.53 0.82
облако-топ 0.75 0.98 1.00

Recall по языку у всех ~0.951.0 (спот не зависит от языка).

Выводы (верифицированные)

  1. СПОТ сущностей — решённая задача для ВСЕХ, локаль включительно (recall 0.951.0 на zh/ja/en). Кандидат-споттинг write-path можно гнать на дешёвой локальной 8b. Даже 0 галлюцинаций (кроме ruadapt).
  2. РЕНДЕР канонического RU — вот где разрыв, и он с крутым ЯЗЫКОВЫМ градиентом у локали: en 0.82 (западные имена локаль транскрибирует нормально — Джон Картер/Конан), ja 0.53 (средне), zh 0.26 (локаль проваливается). Облако-топ сильно везде (zh 0.75, ja 0.98, en 1.0).
  3. Провалы локали на zh — это прямая нонконформность стандарту Палладия (реестр B6, эмпирически подтверждён): 阿Q→«Ах-Чу», 赵太爷→«Тяо Тай-Я», 祥林嫂→«Сяньлинсяо», 送灶→«Сув-цзя», 祝福→«Бэ-цзю», 羅生門→«Ро-сёмон», 朱雀大路→«Чжу-сюкэ-дайро» — фонетический мусор вместо Палладий-канона («А-кью», «Чжао»). Локаль не знает системы транскрипции zh→ru; это не «плохой перевод», а систематически неверная по стандарту транслитерация.
  4. Бо́льшая локаль НЕ помогает: 30b-a3b render 0.55 ≈ 8b (0.480.55), но в 34× медленнее (13.5с vs 35с) и recall даже ниже (0.91). Для спота брать дешёвую 8b, не 30b.
  5. deepseek: thinking ПОМОГАЕТ рендеру (0.85 с thinking vs 0.58 без) — reasoning вытаскивает канон реалий (согласуется с exp03). Но thinking-off deepseek на экстракции здоров (12/12, echo бьёт перевод, не JSON-вывод) — просто рендерит хуже (≈уровень локали).
  6. Лучший рендер-value — gemini-2.5-flash (render 0.92 за 1.4с); kimi лучший по качеству (0.96), но 38с/дорого; deepseek-think 0.85/8.9с. grok/glm/gpt-5-mini слабее по рендеру (0.670.69).
  7. ruadapt-qwen3 — ненадёжен (5/12 health, единственный с галлюцинациями) — как и предупреждал exp03 «понимание разрушено ru-адаптацией».

Следствие для дизайна (write-path, уточняет Р4/G1)

Экстракцию разбить на две подзадачи, и разбивка язык-зависима:

  • (а) СПОТ кандидатов-спанов — локальная 8b (recall ~0.98 на всех языках, дёшево/быстро, 0 галлюцинаций). Это дешёвый пре-пасс NER.
  • (б) РЕНДЕР dst — зависит от языка источника: для zh — обязательно облако/человек + детерминированная таблица Палладия (локаль даёт мусор 0.26; даже облако лишь 0.75 — часть zh→ru реалий не имеет единого канона, нужен словарь B6); для ja — облако (локаль 0.53); для en/западных имён — локаль потянет (0.82), облако для надёжности. Рендер-модель по value — gemini-2.5-flash.
  • Промоушен auto→approvedс человеком/судьёй (G1), особенно на zh, где даже сильная модель не гарантирует Палладий.

Ограничения

12 кейсов (умеренно, не сотни), 1 прогон на ячейку (temp низкая), gold-render = мой набор accept-регэкспов канона (для спорных реалий — 送灶/洛中 — канон нестрогий, render занижен честно). Render — объективно более трудная для авто-оценки ось, чем recall; человеческая сверка на выборке усилит. Но языковой град**иент (zh≪ja≪en у локали) устойчив и с этим N.

Провенанс: eval/extract_bench.py (переиспользует refusal_bench.call_provider + providers.json), results.json с per-кейс records. Реальные PD-тексты eval/data/samples.