diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index 04ba3ac..29d1e23 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -204,6 +204,29 @@ read-пути `report`. Фикс: строки материализуются п Уже решено (не пере-обсуждаем): премиум-бюджет (формула Р5 + $5/$30), ключ TM (консервативный), стриминг keep-alive (Ф1–2), инъекция глоссария (`selective`), пороги coverage (полигон), epub v1 (текст по spine). +> **Ответ оркестратора на все [НУЖНО РЕШЕНИЕ] + Q3/Q4 (04.07) → полный контракт в [architecture/05-decisions-log.md](architecture/05-decisions-log.md).** +> Все 6+1 решений приняты (D1 монолингвальный редактор, D2 skip+flag+continue, D3 эскалация, D4 нет provider-fallback, D5 инкрементальный Analyst, D6 think-режим, D7 схема памяти v1) и прошли адверсариальную панель из 3 критиков (research/эконом/код) — читай `05-decisions-log.md` целиком перед Фазой 1, там уточнения меняют реализацию. Самое важное для тебя: +> 1. **`snapshotID` расширить memory-state + context-assembly hash ДО инъекции памяти** (D5.2) — иначе изменённый глоссарий/STM меняет `request_hash`, но не `snapshotID`, resnapshot-гейт молчит, ре-ран старой главы промахивается мимо чекпоинта и переоплачивает расходящимся переводом. Это общий гейт, держит D1 и D5. +> 2. **Runner без цикла по чанкам/главам + нет хранилища флагов** — главный длинный шест Фазы 1; `attempt` НЕ несёт disposition/skip-семантику (я переоценил). Строить цикл + таблицу флагов + `flag_reason` первым. +> 3. **D2:** тегировать `flag_reason`; `retry-flagged` переатакует только length/empty (refusal — не переатаковать, деньги на гарантированный отказ не жечь); n-gram-loop чек ПЕРЕД удвоением max_tokens; edit `max_tokens` от длины ЧЕРНОВИКА, не исходника. +> 4. **D3:** завести провайдеры gemini/xai/**openai**/deepseek-v4-pro/glm-5.1 в `models.yaml` (все OpenAI-совместимы, `kind: openai`; нативный Gemini-судья — Ф2), фактчекнуть слаг `deepseek-v4-pro`. Премиум-бюджет $5/$30 устарел (был на Sonnet) — полигон пересчитает на Gemini-апексе с reasoning-as-output. +> 5. **D1:** убрать `{{text}}` из editor.md И **поднять edit `prompt_version`** (иначе лейбл врёт на двух SHA); честно: приёмка Фазы 1 БЕЗ критерия верности (mistranslation ловит билингвальный судья Ф2, не coverage-гейт). +> 6. **D6:** дефолт think off/**minimal** (операционно), но пилот Ф2.5 think-ON включает translator/editor (не только Terminologist); Gemini-апекс форсированно думает (бюджетить как output); think-ON эскалация — только subset-провайдеры (не xAI/Grok, пока EstimateUSD не резервирует reasoning). +> 7. Новые дешёвые гейты Фазы 1 (детерминированные, Go): линтер тире-диалогов, ёфикатор, блок-лист транслит-междометий, число-гейт 万/億; ruby-парсер в спеку импорта (для ja-имён). +> +> **ПОПРАВКА ВЛАДЕЛЬЦА (04.07): удалён только Anthropic (за дороговизну), OpenAI ОСТАЁТСЯ.** Живой набор ключей у бэкенда и полигона: `DEEPSEEK_API_KEY`, `ZAI_API_KEY`, `KIMI_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, `XAI_API_KEY`. → Вернуть провайдер `openai` в `models.yaml` (`gpt-5-nano` альт черновика, `gpt-5-mini` кандидат редактора/second-opinion судьи; квирки в `experiments/00-provider-quirks.md`: reasoning_effort minimal, без temperature, `max_completion_tokens`). Gemini/xAI теперь доступны сразу (не «Фаза 2»), нативные адаптеры для safety-судьи — по-прежнему Ф2. Р4 в `01-decisions.md` обновлён. **xAI/Grok НЕ выведен** (уточнение владельца): Grok 4.3 — основной пермиссивный тир канала B + судья 18+; промо $150 за data-sharing — на выделенный NSFW/eval-аккаунт. + +> **Ответ оркестратора на два флага + вопрос «план vs старт» (04.07).** Оба флага верные, приняты: +> 1. **Рассинхрон quirks — исправил** (`experiments/00-provider-quirks.md`: строка про OpenAI была устаревшей). Источник истины по стеку — `05-decisions-log.md` D3 + Р4. +> 2. **Capability-слой — принял как корректировку D3.1** (записано в `05-decisions-log.md`): «без новых адаптеров» было оптимистично. Kimi (`temperature:1`), gpt-5-mini (`max_completion_tokens`, без temperature, effort minimal), Gemini 3.1 Pro (thinking обязателен) → текущий `openAIRequest` даст 400. И это **раньше D3**: Kimi — уже альт-редактор, edit temp 0.4 упрётся. Форма — декларативные capabilities per-модель в `models.yaml` (`budget_field`, `temperature: send|omit|locked:1`, `reasoning_control`), адаптер строит тело по ним; эталон квирков — `00-provider-quirks.md`. +> **Про «план vs старт»: пиши КОРОТКИЙ implementation-plan, но только на контракт-несущие куски, не waterfall.** Полную спеку — на три места, где двусмысленность = переделка: (а) **точный payload `snapshotID`** (что именно входит в хэш памяти/сборки контекста — это класс бага «тихий расходящийся ре-пэй»); (б) **схема disposition/флагов** (таблица флагов, `flag_reason`, как resume читает терминал-для-прогона vs retry-flagged); (в) **capability-матрица провайдеров**. Чанкер/импорт/гейты — механика, их в план не разворачивай. Порядок работ, который ты предложил, **ратифицирую**: (1) runner-loop + флаг-таблица + disposition, (2) snapshotID под память, (3) чанкер+импорт(+ruby), (4) миграция памяти v2, (5) четыре гейта; capability-слой + заводка D3 — не «параллельно потом», а вместе с (1), т.к. Kimi-редактор упрётся сразу. Стартуй с (1)+(2) — они держат всё остальное. `deepseek-v4-pro` слаг фактчекни на api-docs.deepseek.com перед wiring эскалации (не блокирует фундамент). + +> **Ответ оркестратора на readiness-вердикт + флаг git (04.07).** Готовность принята, порядок работ подтверждён кодом — старт Фазы 1 разрешён. +> 1. **Флаг git закрыт: docs закоммичены** (`docs/` — моя зона; коммит после этой записи). Полигону: закоммить свою зону `eval/` (2 изменённых + 4 новых скрипта untracked — при `reset --hard` потеряются); `eval/data`/`.venv`/токенизаторы в .gitignore, коммить только код. +> 2. **Дефолт редактора Фазы 1 = `grok-4.3`** (эксп.04 полигона, бейк-офф — закрывает твой вопрос №2, ОПРОВЕРГАЕТ прежнее «редактор=GLM»): ранг-1 верность, ранг-2 стиль, ~13с без reasoning, лучший value. Премиум-эскалация редактора — `gemini-3.1-pro`. GLM/Kimi сняты с дефолта. В `pipeline-c1.yaml` edit-стадию перевести на grok-4.3 (провайдер xAI, `kind: openai`, thinking OFF — reasoning=0, ledger чист; capability: temperature шлётся, `max_tokens`). Провизорно (LLM-судьи, короткие фрагменты) — финал на пилоте Ф2.5. Р4/`05-decisions-log` обновлены. +> 3. Следствие: grok-4.3 стал центральной моделью (редактор SFW + канал B + судья 18+) — гигиена аккаунтов xAI на три использования (Р4): промо/data-sharing только eval+NSFW, продакшн-редактор SFW — чистый аккаунт. +> 4. ⚠ **DeepSeek-черновик «эхал» оригинал** на высоко-CJK фрагменте (эксп.04, 3/3) — тихий отказ = оригинал вместо перевода. CJK-гейт Фазы 1 обязан это ловить (уже в плане); плюс фолбэк-черновик как у полигона. + ## Полигон (секция параллельной сессии — записи добавлять сюда) @@ -231,7 +254,12 @@ keep-alive (Ф1–2), инъекция глоссария (`selective`), пор - **Справочник провайдерских граблей** → [experiments/00-provider-quirks.md](experiments/00-provider-quirks.md) (по замечанию владельца: бэкенд и полигон оба «ходят к провайдерам», но это не дубль — Go-продакшн-адаптеры 1735 строк с failover/ledger vs 40-строчный Python-зонд сырого поведения; объединять нельзя, но **знание о граблях сведено в один справочник**). Собраны: thinking-управление (GLM/Gemini/gpt-5/Qwen — у каждого по-своему!), Kimi только temp=1, Gemini 3.1 Pro обязательно-думающая, safety_settings Gemini не через OpenAI-слой, localhost-прокси, деприкации. **Бэкенду: читать при правке адаптеров `internal/llm`.** +- **Эксперимент 04 — бейк-офф редакторов ru-стиля** (вопрос бэкенда №2 + замена Anthropic) → [experiments/04-editor-quality.md](experiments/04-editor-quality.md). Метод: DeepSeek-черновик → 4 редактора (glm-4.6/kimi-k2.6/gemini-3.1-pro/grok-4.3) полируют; 4 фрагмента (ja/zh/en); **слепая человеческая оценка владельца** (LLM-судьи на худ. качестве ненадёжны). Артефакт для оценки: https://claude.ai/code/artifact/25394796-96f0-4f3f-b8d0-de000d415472. **Объективно уже видно:** grok-4.3 — быстрый/дешёвый (~13с, без reasoning); **kimi-k2.6 дорогой** (~11k reasoning-токенов на абзац → биллятся как выход); gemini-3.1-pro обязательно-думающая. Цена входит в решение наравне со стилем. **Оценка стиля — на владельце (ожидает).** Методическое следствие для пилота (задача 4): владелец читает только en/ru → человеческая оценка верности возможна лишь на en→ru + русской стороне, для zh/ja нужен английский якорь. + +**Эксперимент 04 — РЕЗУЛЬТАТ (04.07):** слепую оценку сделали два фронтир-судьи (GPT + Opus 4.8), сверяясь с **каноническими переводами** (Фельдман/Рогов/Морозов), **сошлись независимо**. Ключ: A=grok-4.3, B=glm-4.6, C=gemini-3.1-pro, D=kimi-k2.6. Итог: стиль **gemini > grok > kimi > glm**; верность **grok > gemini > glm > kimi**; value **grok ≫ gemini > glm > kimi**. **Рекомендация дефолта редактора Фазы 1: `grok-4.3`** (лучший баланс качество/цена, надёжен по смыслу, ~13с/без reasoning), **премиум-эскалация `gemini-3.1-pro`** (лучшая проза, культурные узлы на уровне канона). **GLM-4.6 (текущее допущение Р4 «редактор=GLM») эмпирически слабейший — снять с дефолта; Kimi убрать (худший value: 11k reasoning/абзац, последний по верности).** → **оркестратору: правка Р4** (полигон архдоки не трогает). Полный разбор — [04-editor-quality.md](experiments/04-editor-quality.md). + ### Следующие шаги полигона +- [x] Эксперимент 04 (редактор) — оценён (grok-4.3 дефолт, gemini-3.1-pro премиум; GLM/Kimi не дефолт); правка Р4 на оркестраторе. - [x] Прогон refusal-бенчмарка (SFW/L1/L2-violence часть) — 66/66 ok, пороги в 02; explicit-часть ждёт фрагментов владельца. - [x] Эталон DeepSeek для сравнения черновиков — в 03. - [x] llama.cpp `--n-cpu-moe` для 30b-a3b — перемерено (потолок 13.5 tok/s, см. выше). @@ -240,3 +268,11 @@ keep-alive (Ф1–2), инъекция глоссария (`selective`), пор - [ ] Довалидация калибровки на 3–5 главах реальных вебновелл (файлы владельца → `eval/data/samples/` + manifest). - [ ] Задача 4: протокол BWS + панель LLM-судей (LAIT/JP-TL-Bench), харнесс `eval/pilot/`. - [ ] Задача 5: bge-m3 vs Qwen3-Embedding-0.6B vs LaBSE на retrieval глоссария (bge-m3 скачан). + +> **Задачи от оркестратора (04.07, из журнала решений [architecture/05-decisions-log.md](architecture/05-decisions-log.md)):** +> 1. **Пересчитать премиум-бюджет** на Sonnet-free стеке: апекс — Gemini 3.1 Pro ($2/$12 ≤200k) с **обязательным thinking** (reasoning биллится как output $12/M — учесть, это класс недоучёта vojo 30–44%); batch −50% только на судью/QA, НЕ на inline-эскалацию (последовательна из-за STM); эскалированный чанк платит Gemini дважды (перевод+ре-джадж). Дефолты $5/$30 — заглушка до твоего пересчёта. +> 2. **Замерить, эмитят ли DeepSeek/GLM/Kimi `finish_reason=content_filter`** (D2.4): бэкенд ветвит диспозицию по нему, но OpenAI-совместимый слой отдаёт finish_reason сырым — если провайдеры его не шлют, реальная страховка только refusal-blacklist. Дешёвый зонд на отказном фрагменте. +> 3. **Think-ON vs OFF по КАЧЕСТВУ на облачных translator/editor** (DeepSeek/GLM/Kimi — subset-billing, безопасно по потолку): гипотеза владельца про reasoning частично подтвердилась локально (羅生門→Радзёмон), DRT (arXiv:2412.17498) подтверждает для роли переводчика. Это ключевой вход в пилот Ф2.5 — мерить именно translator/editor, не только Terminologist. +> 4. Проброс cache-hit/batch RU-агрегаторами (уже в бэклоге) гейтит достоверность всего премиум-бюджета — приоритет поднять. +> 5. **Ключевой набор расширен:** теперь живы и `OPENAI_API_KEY`, и `GEMINI_API_KEY`, и `XAI_API_KEY` — Gemini-судья и Grok-канал-B можно гонять в евалах сразу. +> 6. **xAI/Grok НЕ выведен** (уточнение владельца): ретайрнулся только дешёвый Grok 4.1 Fast, сам провайдер жив. Роли Grok — переводчик канала B **и судья 18+** (не отказывается оценивать explicit). У xAI **промо $150 за data-sharing** — бери на выделенный NSFW-аккаунт: этим разблокируется висящая 18+ часть refusal-бенчмарка (эксп.02) и 18+ плечо пилота. Гони на промо-кредитах: (а) 18+ refusal/excision на Grok/DeepSeek/локальной abliterated; (б) Grok в роли 18+-судьи — качество оценки explicit-сцен. Data-sharing только PD/тест-корпус, реальные книги через него не гнать. Grok в евалах — thinking OFF (reasoning аддитивный). diff --git a/docs/architecture/01-decisions.md b/docs/architecture/01-decisions.md index 6cdffb2..b4fcb0d 100644 --- a/docs/architecture/01-decisions.md +++ b/docs/architecture/01-decisions.md @@ -44,18 +44,21 @@ Из [04](../research/04-api-providers.md), [09](../research/09-cost-model.md), [11-gap-1](../research/11-gap-1.md), [11-gap-2](../research/11-gap-2.md) (актуально на 2026-07-04, пересматривать ежеквартально): +> **Решение владельца (04.07): удалён только Anthropic — за ДОРОГОВИЗНУ** (git `c7f8a95`, `85f24fb`), не за недоступность: флагманы Claude в любом контуре съедают маржу per-book (Р5), а роль судьи закрывает Gemini. Нативный Anthropic-адаптер в коде помечен DEPRECATED (не удалён — референс для нативного Gemini-адаптера). **OpenAI остаётся** (у владельца есть ключ). Живой набор ключей у бэкенда и полигона (04.07): `DEEPSEEK_API_KEY`, `ZAI_API_KEY`, `KIMI_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, `XAI_API_KEY` — то есть Gemini (судья/апекс) и xAI (канал B) доступны сразу, а не «в Фазе 2» (нативные адаптеры для safety-контроля судьи — всё ещё Фаза 2, но OpenAI-совместимый слой работает уже сейчас). Эскалационные развязки — см. [05-decisions-log.md](05-decisions-log.md) D3. + | Роль | Основная модель | Альтернативы/эскалация | |---|---|---| -| Черновик | DeepSeek V4 Flash ($0.14/$0.28; cache-hit input $0.0028; лучший zh-токенизатор) | Qwen-Flash, GPT-5 nano | -| Редактор (ru-стиль) | GLM-5 / Kimi K2.6 (доступны из РФ напрямую) | Claude Sonnet 5 (промо $2/$10 до 31.08.2026) — только в контуре прямых ключей | -| Судья | Gemini 3.1 Pro (batch −50%) | Claude Opus 4.8 (адресно, только канал A и прямые ключи), локальный POLLUX-judge-7B как бесплатный гейт | +| Черновик | DeepSeek V4 Flash ($0.14/$0.28; cache-hit input $0.0028; лучший zh-токенизатор) | GPT-5 nano ($0.05/$0.40), Qwen-Flash. ⚠ эксп.04: DeepSeek «эхал» оригинал на высоко-CJK фрагменте (82% CJK, 3/3) → тихий отказ = оригинал вместо перевода; ловит CJK-гейт + фолбэк-черновик | +| **Редактор (ru-стиль) — эмпирический дефолт (эксп.04)** | **grok-4.3** (слепой бейк-офф, 2 фронтир-судьи: ранг-1 верность, ранг-2 стиль, самый дешёвый+быстрый ~13с без reasoning) | премиум-эскалация **gemini-3.1-pro** (лучшая проза, дорогая/медленная, иногда дописывает). GLM/Kimi сняты с дефолта (GLM-4.6 слабейший — перемерить при GLM-5; Kimi худший value: ~11k reasoning-ток./абзац). *Провизорно: LLM-судьи на коротких фрагментах; финал — человеческий пилот Ф2.5* | +| Эскалация канал A (по сигналу гейта) | DeepSeek V4 Pro → gemini-3.1-pro (премиум-проза) | нативный Gemini-адаптер для safety-судьи — Ф2 | +| Судья | Gemini 3.1 Pro (для явного safety-контроля — нативный API, Ф2) | GPT-5 mini — second-opinion судья чужого семейства; **Grok 4.3 — судья 18+** (не отказывается оценивать explicit, в отличие от Gemini/Claude); локальный POLLUX-judge-7B — бесплатный гейт | | Эмбеддинги/скрининг/экстракция терминов | локально: bge-m3, Qwen3.5-9B | Qwen3-Embedding-0.6B | -| 18+ (канал B) | Интерим до Фазы 2: DeepSeek офиц. API + локальная abliterated Qwen3.5 | open-weights через OpenRouter (Chutes/Venice); Grok 4.3 — дорогая эскалация. ⚠ Grok 4.1 Fast retired 15.05.2026, слаги молча редиректят на grok-4.3 с ценой ×9 (фактчек бэкенд-сессии) — перевыбор дешёвой модели канала B по итогам refusal-бенчмарка полигона | +| 18+ (канал B) | **Grok 4.3** ($1.25/$2.50 — средний тир, самый пермиссивный крупный API) + DeepSeek офиц. + локальная abliterated Qwen3.5 | open-weights через OpenRouter (Chutes/Venice). ⚠ Grok 4.1 Fast (дешёвый тир) retired 15.05.2026 — слаги редиректят на grok-4.3; сам xAI НЕ выведен. reasoning xAI **аддитивный** → канал B с thinking OFF (EstimateUSD не резервирует reasoning). Промо xAI $150 за data-sharing — брать на выделенный NSFW/eval-аккаунт (PD/тест-корпус), НЕ на продакшн клиентских книг | Контент-роутинг ([11-gap-2](../research/11-gap-2.md)): - Локальный классификатор «горячести» 0–3. Уровни 0–1 → канал A. Уровень 2 → канал B (пермиссивный). Уровень 3 (несовершеннолетние в сексуальном контексте) — **жёсткий отказ на уровне чанка**: чанк не переводится, помечается в отчёте, глава и книга продолжают обрабатываться (ложное срабатывание классификатора не должно убивать многочасовую оплаченную джобу). -- **Эскалация channel-aware**: для чанков канала B дорогая эскалация — Grok 4.3 / Gemini (safety off) / крупные open-weights; **Anthropic исключён структурно** из канала B, включая эскалации. OpenAI в NSFW-канал не включать (adult mode заморожен бессрочно, к API не применялся). Anthropic — только стерильные уровни 0–1 с refusal-мониторингом и автопереносом чанка в канал B. -- Гигиена аккаунтов: выделенный xAI-аккаунт под NSFW, отдельный биллинг на канал. +- **Эскалация channel-aware**: для чанков канала B дорогая эскалация — Grok 4.3 / Gemini (safety off) / крупные open-weights; канал A — DeepSeek V4 Pro / GLM-5.1 / Gemini 3.1 Pro. Anthropic из роутинга исключён (дорого); OpenAI остаётся, но **в канал B не включать** (политика 18+ строгая, adult mode заморожен — как и раньше). При подключении failover (Фаза 2) пара primary/fallback канала B — только пермиссивные провайдеры (xAI/DeepSeek/local/open-weights) или fail loudly (иначе пустой ответ local-abliterated молча уйдёт в непермиссивную облачную ногу — дыра D3 ревью бэкенда). +- Гигиена аккаунтов xAI (Grok теперь центральная модель — дефолт-редактор SFW + канал B + судья 18+): **три раздельных использования одного провайдера** — (1) промо/data-sharing аккаунт только под eval и NSFW-тесты (PD/тест-корпус); (2) продакшн-редактор SFW — **чистый аккаунт без data-sharing** (реальные/конфиденциальные книги через data-sharing нельзя, research/08); (3) NSFW-продакшн — отдельный биллинг. Концентрация ролей на xAI — риск: провайдер лёг → редактор-роль пауза→resume (D4, не сайлент-своп). Reasoning xAI аддитивный, но дефолт-редактор работает с thinking OFF (reasoning=0) → ledger чист; think-ON на Grok — только после reasoning-буфера в EstimateUSD (D6.2). - Обязателен **детектор молчаливых вырезаний** (сверка покрытия предложений вход↔выход) — Qwen-подобные внешние фильтры молча портят перевод. - Внутренний refusal/excision-бенчмарк (50–100 фрагментов), прогонять при каждой смене версии модели. - Для политически чувствительных zh-текстов — не полагаться на китайские API (цензура в весах), фолбэк на западные/локальные. @@ -71,12 +74,12 @@ | Контур | Модели | Cache/Batch | COGS тома ранобэ | |---|---|---|---| | Прямые ключи (наш зарубежный контур, «позже»; DeepSeek/GLM/Kimi — доступны и из РФ) | весь стек Р4 | да / да | стандарт на DeepSeek ~$0.25–0.6; премиум-микс ~$4 (batch ~$2) | -| RU-агрегаторы (ProxyAPI/VseGPT/AITunnel), наш ключ | дешёвые модели ×1.2–1.3; флагманы ×2–6 (**Sonnet-редактор в ru-контуре экономически недоступен** — премиум-микс через агрегатора ≈ съедает всю маржу per-book $99) | неизвестно — **эмпирически проверить в Фазе 0–1** (скорее всего cache/batch не пробрасываются) | стандарт ~$0.3–0.8; премиум — только точечные вызовы | +| RU-агрегаторы (ProxyAPI/VseGPT/AITunnel), наш ключ | дешёвые модели ×1.2–1.3; флагманы ×2–6 (западные премиум-модели через агрегатора ≈ съедают всю маржу per-book $99 — одна из причин удаления Anthropic из стека, Р4) | неизвестно — **эмпирически проверить** (задача полигона; скорее всего cache/batch не пробрасываются) | стандарт ~$0.3–0.8; премиум — только точечные вызовы | | BYOK (ключ пользователя) | что настроит пользователь | его тарифы | COGS токенов — не наш; мы продаём софт; в UI — оценка стоимости по тарифам его провайдера | - **Prompt caching — главный рычаг**, и раскладка промпта фиксируется под него (разрешение конфликта Р3↔Р5 из ревью): **стабильный кэшируемый префикс** = системный промпт роли + book brief + style sheet + резюме книги/арок (меняется редко, раз в главу-арку); **волатильный хвост после кэш-брейкпоинта** = селективный глоссарий + STM + чанк. На стадии edit кэшу ловить почти нечего (уникальный черновик в промпте) — ожидаемый cache-hit считать по стадиям, а не «≥50% в среднем». Альтернатива для DeepSeek (cache-hit $0.0028/M): полный глоссарий в стабильном префиксе может оказаться дешевле селективной инъекции по miss-тарифу — решить расчётом на прототипе, обе схемы поддержать конфигом. - **Батчуемость — свойство стадии**: Analyst, Terminologist, судья/оценки, книжный QA — батчуемы (−50%); черновик и редактура чанков — последовательны (STM/резюме создают зависимость, DelTA-паттерн). «С batch ≈$2» относится только к батчуемым стадиям. Batch API — Фаза 2 (к судье), не Фаза 0. -- **Бюджет премиум-токенов на книгу**: одиночный полный Sonnet-проход 500-главной вебновеллы ~$92 — впритык к якорю GlobeScribe $100 и выходит за него с буфером +25%; двойной ~$185 — ломает экономику. Отсюда: дорогая модель — только адресно по сигналу судьи/гейтов, бюджет ≤2× input-объёма книги по премиум-тарифам. +- **Бюджет премиум-токенов на книгу**: полный проход премиум-моделью (историческая калибровка на Sonnet до его удаления: ~$92 за 500-главную вебновеллу, впритык к якорю GlobeScribe $100; двойной ~$185 — ломает экономику) не должен идти сплошняком. Принцип сохраняется для любой премиум-эскалации (Gemini 3.1 Pro): дорогая модель — только адресно по сигналу судьи/гейтов, в пределах $-потолка (формула ниже). - **Формула премиум-бюджета** (уточнение по запросу бэкенд-сессии, заменяет эвристику «≤2×»): в коде — конфигурируемый $-потолок на книгу, `premium_budget_usd = clamp(price_target × (1 − target_margin) − est_base_cogs, 0, hard_cap)`; для локального режима без прайса — дефолты $5/том ранобэ, $30/вебновелла-500. «≤2× input-объёма» остаётся прикидочной эвристикой в доках, не контрактом кода. - ⚠ **Абсолютные COGS этого раздела устарели после токен-калибровки** (эксперимент 01 полигона): zh→ru дороже в ~1.4–1.75 раза (премиум-микс вебновеллы ≈$49, с batch ≈$26; ранобэ ja→ru, наоборот, дешевле — ≈$3.1). Структура выводов не меняется; актуальные множители — `docs/experiments/01-token-calibration.md`. - Буфер +25% к расчётному COGS (ретраи, глоссарий-строительство, регенерации). Цены/имена моделей — только в конфиге с датой проверки. Миграция deepseek-chat → deepseek-v4-flash до 24.07.2026. Для DeepSeek — планировщик внепиковых часов (надбавка ×2 в пик; сам планировщик — Фаза 3, до тех пор — просто не гнать массовые прогоны в пик). diff --git a/docs/architecture/05-decisions-log.md b/docs/architecture/05-decisions-log.md new file mode 100644 index 0000000..b077389 --- /dev/null +++ b/docs/architecture/05-decisions-log.md @@ -0,0 +1,101 @@ +# Журнал решений оркестратора — развязки перед Фазой 1 (2026-07-04) + +Ответ на вопросы бэкенд-сессии (PROGRESS §«Вопросы от бэкенда», §«[НУЖНО РЕШЕНИЕ] перед Фазой 1») и полигона (think-режим). Каждое решение прошло адверсариальную панель из 3 критиков (research / экономика / исполнимость в коде Фазы 0); ни одно не отклонено, все уточнены. Это **контракт Фазы 1** — бэкенд исполняет отсюда; при конфликте с буквой 01-decisions/02-mvp-plan — источник истины здесь (потом сольём в основные доки). + +Статусы: ✅ принято · ✅+ принято с уточнением панели. + +--- + +## D1. Редактор C1 — монолингвальный. ✅+ + +**Решение:** редактор Фазы 1 видит только черновик + одобренный глоссарий (dst-термины как target-констрейнты), **не** исходник. Убрать `{{text}}` из `prompts/editor.md`. + +**Обоснование:** издательская норма (редактор не знает язык оригинала — research/07); билингвальный редактор в zh→ru якорится к исходнику и плодит кальки (главная translationese-болезнь); монолингвальный редактор к тому же дешевле (исходник не сидит на входе каждого edit-вызова). + +**Уточнения панели (обязательны):** +1. **Честно: coverage-гейт НЕ контролирует верность.** Он ловит только omission/дописывание по длине; same-length mistranslation (свап рода, «кто кого», неверная полисемия) проходит насквозь. Значит в Фазе 1 верность после черновика **не контролирует ничто** до билингвального судьи Фазы 2. Это допустимо (Фаза 1 — инфраструктурная веха), но записать прямо: **приёмка Фазы 1 не содержит критерия верности** — не маскировать это coverage-гейтом. +2. Пилот Ф2.5: плечо C1 (draft→editor) меряется на win-rate **только вместе с живым билингвальным судьёй** — иначе C1 по собственному признанию полирует неверное в «гладко-неверное». +3. **Код:** убрать `{{text}}` меняет SHA256 шаблона → resnapshot-гейт сработает громко (хорошо), но `prompt_version: "v0-draft"` в `pipeline-c1.yaml` станет врать (тот же лейбл на двух SHA). **Поднять edit `prompt_version` при этой правке.** + +## D2. Диспозиция плохого чанка — skip+flag+continue. ✅+ + +**Решение:** `finish=length` → ретрай с бо́льшим max_tokens до капа, потом флаг; hard refusal/`content_filter` → флаг+продолжить; пустой оплаченный → skip+flag (не падение прогона); soft refusal (blacklist) → флаг. Флагнутый чанк не коммитит мусор/пустоту в TM. + +**Уточнения панели (обязательны):** +1. **`attempt` этого НЕ несёт** (переоценка в моём ответе). В коде Фазы 0 нет ни цикла по чанкам (chapter=1/chunk=0 захардкожены, `runner.go:235`), ни хранилища флагов, ни статуса «skipped/flagged»; любой ненормальный путь сейчас = `SetJobStatus(failed)+return`. Механика skip+flag+continue — **net-new работа Фазы 1** (цикл + таблица флагов + колонка disposition, читаемая resume-путём). `attempt` — необходим, но не достаточен. +2. **Тегировать `flag_reason`.** `retry-flagged` переатакует **только** `length`/`empty` на той же модели; `content_filter`/refusal детерминирован per-модель/канал — повтор на том же SFW-канале снова откажет и снова спишет деньги. В Фазе 1 refusal-флаги просто **не переатаковать** (деньги на гарантированный отказ не жечь); маршрутизация в канал B/эскалацию — Фаза 2. +3. **Детектор вырождения перед удвоением max_tokens.** У дешёвого черновика `finish=length` чаще всего — repetition-loop; бо́льший max_tokens лишь оплачивает больше повтора (усугубляется неидемпотентными ретраями F3). Дешёвый n-gram-loop чек ПЕРЕД удвоением → при вырождении сразу флаг, без оплаты цикла. +4. **`content_filter` ненадёжен как ветка:** OpenAI-совместимый адаптер отдаёт `finish_reason` сырым (`httpllm.go`), пробрасывают ли его DeepSeek/GLM/Kimi — не проверено. Реальная страховка — **refusal-blacklist гейт**, а не ветка по finish_reason. Полигону: замерить, эмитят ли провайдеры `content_filter`. +5. **Edit `max_tokens` считать от длины ЧЕРНОВИКА, не исходника** (`runner.go:283-287` сейчас от source). Для монолингвального редактора (D1), чей вход/выход ≈ русский черновик (~1.9× токенов исходника zh→ru), оценка от source мис-сайзит бюджет и ложно триггерит length-ретрай. + +## D3. Эскалация. ✅+ + +**Решение:** канал A — DeepSeek V4 Pro → GLM-5.1 → апекс Gemini 3.1 Pro; канал B (18+) — **Grok 4.3 основной пермиссивный тир** + DeepSeek офиц. + локальная abliterated. Sonnet удалён (Anthropic — дорого); OpenAI остаётся (ключ есть) — GPT-5 nano альт черновика, GPT-5 mini кандидат в редакторы/second-opinion судьи. + +**Правка по xAI (04.07, вопрос владельца — xAI НЕ выведен):** ретайрнулся только дешёвый Grok 4.1 Fast; сам провайдер жив, ключ есть. grok-4.3 ($1.25/$2.50) — средний тир, не «дорогой крайний». Роли Grok: (а) **переводчик канала B** (самый пермиссивный крупный API — стандарт R-rated); (б) **судья/QA 18+ контента** — не отказывается оценивать explicit, в отличие от Gemini (нужен нативный safety-off) и Claude (отказ). Ограничения: reasoning xAI **аддитивный** → канал B с thinking OFF, а think-ON на Grok — только после reasoning-буфера в `EstimateUSD` (D6.2). Промо xAI **$150 за data-sharing**: брать на выделенный NSFW/eval-аккаунт для PD/тест-корпуса и refusal/18+-бенчмарка (разблокирует висящую 18+ часть эксп.02) — но **не гнать через data-sharing реальные/конфиденциальные клиентские книги** (конфликт с ToS-гарантией и zero-retention режимом B2B, research/08). + +**Правка редактора (04.07, эксп.04 полигона — бейк-офф): дефолт-редактор Фазы 1 = `grok-4.3`.** Слепой бейк-офф glm-4.6 / kimi-k2.6 / gemini-3.1-pro / grok-4.3 на 4 фрагментах (2 фронтир-судьи, сверка с каноническими ru-переводами, согласие независимо): **grok-4.3** — ранг-1 верность, ранг-2 стиль, самый дешёвый+быстрый (~13с без reasoning) → лучший value «одной модели на роль». **gemini-3.1-pro** — лучшая проза → премиум-эскалация редактора. **GLM-4.6 слабейший** (опровергает допущение Р4 «редактор=GLM»; перемерить при GLM-5), **Kimi худший value** (~11k reasoning-ток./абзац, ранг-последний по верности) → оба сняты с дефолта редактора. Это **закрывает вопрос бэкенда №2** (дефолт редактора). Оговорка: LLM-судьи на коротких фрагментах — провизорный дефолт Фазы 1; финальный выбор редактора/ядра — человеческий пилот Ф2.5. Р4 обновлён. Следствие: grok-4.3 стал центральной моделью (редактор SFW + канал B + судья 18+) — гигиена аккаунтов xAI на три использования (Р4), редактор с thinking OFF (ledger чист). + +**Уточнения панели (обязательны):** +1. **Модели ОТСУТСТВУЮТ в конфиге.** `models.yaml` знает только `deepseek-v4-flash`/`glm-5`/`kimi-k2.6`/`local`; `deepseek-v4-pro`/`glm-5.1`/`gemini-3.1-pro`/`grok-4.3` и провайдеры `gemini`/`xai`/`openai` — **не заведены**, цепочки эскалации всё ещё `[kimi-k2.6]`-заглушки. Задача бэкенда: завести провайдеры+модели+цены, **фактчекнуть слаг `deepseek-v4-pro`** перед wiring (иначе 4xx). + - **ПОПРАВКА (принял корректировку бэкенда): «без новых адаптеров» было оптимистично.** Провайдеры OpenAI-совместимы по эндпоинту, но не по телу запроса: текущий `openAIRequest` всегда шлёт `temperature` + `max_tokens`, а Kimi требует `temperature: 1` (иначе 400), gpt-5-mini — `max_completion_tokens` без temperature + `reasoning_effort: minimal`, Gemini 3.1 Pro — обязательный thinking (`thinking_budget: 0` → 400). Это **не строчка в yaml, а per-model capability-слой** в адаптере, и он нужен **раньше D3**: Kimi — уже альтернативный редактор Р4, edit-стадия на temp 0.4 даст 400 на первом вызове. → Capability-слой — фундаментальный элемент Фазы 1. Форма (согласована с принципом «модели/цены только в конфиге», Р4): каждая модель в `models.yaml` декларирует возможности — `budget_field: max_tokens|max_completion_tokens`, `temperature: send|omit|locked:1`, `reasoning_control: none|extra_body_disable|effort_minimal|mandatory`; адаптер строит тело запроса по ним. `experiments/00-provider-quirks.md` — эталонная таблица квирков. +2. **Премиум-бюджет $5/$30 УСТАРЕЛ** — выведен из калибровки на Sonnet $3/$15. Апекс теперь Gemini 3.1 Pro ($2/$12 ≤200k) с **обязательным thinking** (reasoning биллится как output $12/M — тот же класс недоучёта, что сжёг vojo 30–44%). Плюс `batch −50%` к inline-эскалации неприменим (последовательна из-за STM), только к судье/QA. Плюс Gemini = и апекс, и судья → эскалированный чанк платит Gemini дважды (перевод+ре-джадж), оба с форсированным reasoning. **Полигону: пересчитать бюджет на фактическом Sonnet-free стеке с reasoning-as-output, batch только на судью.** До пересчёта — $-потолок конфигурируемый (D-эконом ниже), дефолты $5/$30 держим как консервативную заглушку. + +## D4. Provider-fallback — НЕ добавлять для облачных draft/edit. ✅+ + +**Решение:** авто-кросс-провайдерного фоллбека для облачных ролей нет (фоллбек драфта = разный стиль/термины по чанкам + `model_id` в ключе TM обнулит хиты на ре-ране). Провайдер лёг → durable pause → resume. Локальный→облако failover из vojo — только для local-ролей, channel-aware. Ночь — супервизор перезапускает `tmctl`. + +**Уточнения панели (обязательны):** +1. **Channel-aware изоляция в коде НЕ обеспечена** (дыра). `FailoverConfig` не имеет поля канала/пермиссивности — изоляция сейчас лишь doc-comment для вызывающего; сам failover в Фазе 0 не подключён. Хуже: ветка «fallback отсутствует → fail loud» **сделает nil-panic** (нет nil-guard, `c.fallback.Complete` разыменует nil), а путь «пустой local-контент → облако» — ровно тот сайлент-шип, о котором предупреждает заголовок, без guard. **При подключении failover (Фаза 2): изоляцию канала B делать типом (поле permissive/channel) или явной fail-loud веткой на nil-fallback, а не комментарием.** +2. Формулировка «resume бесплатен» переусилена: техдолг F3 — retryable-но-оплаченные вызовы не идемпотентны, resume может переплатить прерванный in-flight (до `MaxAttempts−1`). Точнее: «resume переоплачивает максимум прерванный in-flight, всё равно кратно дешевле mixed-model failover». +3. Local→cloud failover для local-ролей канала A (экстракция глоссария, дешёвый судья-гейт) при OOM 8GB GPU молча превращает $0-вызовы в платные облачные — **un-budgeted; пометить** (телеметрия должна показывать, когда local-роль ушла в облако). + +## D5. Онгоинг Analyst — инкрементально. ✅+ + +**Решение:** book-brief заморожен; новые главы — Analyst инкрементально расширяет резюме и ищет новые термины; approved-глоссарий/series-bible наследуются read-only, новые термины append, approved не ревизуются молча (research/07); разрешение gender=hidden-твиста — ручное событие. + +**Уточнения панели (обязательны):** +1. **Проактивная эвристика `gender=hidden`.** Онгоинг структурно теряет преимущество «книга целиком видит твист заранее»: инкрементальный Analyst не видит ещё не загруженных глав, поздний реверс-трап (女扮男装) → уже вмороженные главы закоммитили род. Митигация: когда Analyst в **загруженных** главах видит намеренную неоднозначность (омофонное ta / pro-drop без дизамбигуации), ставить `gender=hidden` и гнать безродовые конструкции (гайд ООН) **до** раскрытия, а не дефолтить в мужской (TACL-биас). Плюс ретро-патч-протокол «с тома N — так» с показом стоимости пере-перевода вмороженных глав, которые твист фальсифицировал. +2. **КРИТИЧНО (impl): `snapshotID` не покрывает память и сборку контекста.** Сейчас хэширует только brief_hash + план стадий + defaults, **не** context-assembly (`glossary_injection`/`stm_depth`/`overlap`) и **не** инъектированный глоссарий/резюме/series-bible. Как только Фаза 1 начнёт инъектить память в `msgs`: изменённая память меняет `request_hash` (msgs в нём), но `snapshotID` не меняется → resnapshot-гейт **не сработает** → ре-ран старой главы молча промахивается мимо чекпоинта и переоплачивает **расходящимся** переводом — ломается сам инвариант Р6, на который D5 опирается. **Свернуть memory-state + context-assembly hash в `snapshotID` ДО того, как приедет инъекция Фазы 1.** Это общий гейт Фазы 1 — держит и D1 (глоссарий редактору), и D5. + +## D6. Think-режим — не глобальный дефолт, но пилотить на переводчике. ✅+ (существенно переписано) + +**Решение:** `reasoning_effort` per-роль, дефолт **off/minimal** для draft/edit — но **по операционным причинам** (эмпирика полигона: GLM ×3 таймауты, Gemini жрёт max_tokens, gpt-5-mini выжигает бюджет — `00-provider-quirks`), НЕ потому что «reasoning вредит переводу». + +**Переписанное обоснование (панель отозвала мою посылку):** прежняя «think ломает роль переводчика — пустой вывод» — **отозванная находка**: PROGRESS:230 исправляет её («пустота — артефакт тесного контекста, не зависание; с ctx 16k think завершается и реально чинит реалии: 羅生門→Радзёмон, чтение 朱雀»). DRT (research/03, arXiv:2412.17498) независимо показывает: long-CoT над метафорами/сравнениями **поднимает литперевод** — это роль ПЕРЕВОДЧИКА. Владелец был прав в гипотезе. + +**Уточнения (обязательны):** +1. **Пилот Ф2.5 think-ON vs OFF по качеству включает draft/translator и editor** (не только Terminologist+эскалацию, как я ошибочно сузил) — именно туда указывают и полигон, и DRT. Дефолт-off остаётся до результатов пилота. +2. **Скоуп think-ON эскалации — только subset-billing провайдеры** (deepseek/zai/kimi, где reasoning ⊆ completion ≤ maxTokens, `EstimateUSD` покрывает). **xAI/Grok исключить из think-ON** пока `EstimateUSD` не резервирует явный reasoning-бюджет (additive reasoning xAI → «потолок пробьётся» ровно на премиум-пути канала B). +3. **Gemini-апекс/судья — форсированный think-ON** (не чтит `reasoning='off'` → HTTP 400). Заложить его в бюджет как reasoning-as-output ($12/M), а не как opt-in. `runner.go` шлёт `st.Reasoning` — адаптеру Gemini `off` придётся молча глотать; этот кейс назвать явно. +4. «×2–3 COGS» занижает многословных ризонеров: Kimi-k2.6 ~11k reasoning-ток./абзац = ×4…×20 на output этой роли — учесть в бюджете эскалации. + +--- + +## D7. Схема банка памяти v1 — скоуп. ✅+ + +**Решение (подтверждаю рекомендацию бэкенда с двумя правками):** +- **v1 (store v2-миграция):** база Р3 (`src, dst, type, aliases, gender, speech, decl, since_ch/until_ch, status, note`) + **alias-граф** (типы: имя/цзы/хао/прозвище/титул) + `gender=hidden(until_ch)` + `translit_policy` (западные имена через катакану — `04-unhappy §9`) + `first_person` + **series-bible-lite = gender + ты/вы**. +- **Правка 1 (панель D5):** ты/вы в series-bible-lite — **журнал событий переходов**, а не статичная матрица пар (переход ты↔вы — сюжетное событие, `12-ru-target §2`). Поле `gender` — с проактивной установкой `hidden` Analyst-ом на неоднозначности (D5.1). +- **Правка 2:** `nickname_translation` **оставить в v1** (это одна колонка + лок «перевести раз навсегда», `04-unhappy §1` относит в Фазу 1); дорогая только логика первичного перевода сильной моделью — её можно отложить, но поле держать. +- **Отложить в v1.1:** `ranked-set` (инъективность ступеней), словарь эвфемизмов, число-словарь мер/разрядов (сам число-**гейт** — Фаза 1, а словарь конвертаций — v1.1). +- **Обязательно:** сверка с «Следствиями для плана» `04-unhappy-paths`; и `snapshotID` покрывает состояние памяти (D5.2) — иначе схема памяти без хеша в снапшоте молча ломает resume. + +## Q3/Q4 бэкенда — прямые ответы + +- **Q3 (эскалационный дефолт RU-контура):** см. D3 — не-Anthropic, дёшево-первым (DeepSeek Pro/GLM-5.1), апекс Gemini; Sonnet не дефолт (удалён). В будущем зарубежном контуре премиум-эскалация опциональна, но не сейчас. +- **Q4 (per-role provider-fallback):** см. D4 — **нет** для облачных draft/edit; pause/resume; local→cloud только для local-ролей, channel-aware типом. + +## Требования Фазы 1, не покрытые 6 решениями (из «missed» панели) — в скоуп + +1. **Runner без цикла по чанкам/главам — главный длинный шест** (chapter/chunk захардкожены). Цикл + хранилище флагов + disposition-колонка — фундамент, на который опираются D2, D5, гейты, эскалация. Строить первым. +2. **`snapshotID` расширить** memory-state + context-assembly hash ДО инъекции (см. D5.2) — общий гейт. +3. **ruby/фуригана-парсер в спеку импорта Фазы 1** (детерминированная часть, `04-unhappy-paths §4`). Противоречие с планом:25 («epub v1 фуригану не сохраняет») разрешить: для ja→ru фуригана несёт авторские чтения имён → глоссарий-лок; молчаливая потеря подрывает приёмку ≥98% консистентности ja-книг. Извлекать чтения на инжесте (не сохранять инлайн-разметку, а **выхватить ruby в глоссарий**). +4. **Дешёвые детерминированные гейты Фазы 1** (были в `04-unhappy-paths §6/§9`, но выпали из плана): линтер тире-диалогов (Розенталь §47–52), ёфикатор, блок-лист транслит-междометий, число-гейт разрядов 万/億. Самый дешёвый и заметный читателю класс — «максимум воспринимаемого качества за минимум денег». Морфозависимые (канцелярит) остаются Фазой 2 (Python-сайдкар); эти четыре — детерминированные, Go, Фаза 1. +5. **Экономика инвалидации TM** (`[НУЖНО РЕШЕНИЕ] п.2в`): смена параметров чанкера = полная инвалидация «как смена brief» с показом стоимости — **да, подтверждаю** (ключ TM от src-чанка, перечанкование by design инвалидирует; пользователю показывать $ пере-перевода). prompt_version и model_id в ключе (уже зафиксировано Р6) означают: правка промпта обнуляет TM-библиотеку, эскалация пишет новую запись — это осознанная плата за корректность, не баг. + +## Экономические открытые пункты (полигону, гейтят достоверность бюджета) + +- Пересчёт премиум-бюджета на Sonnet-free стеке с reasoning-as-output (D3.2). +- Проброс cache-hit/batch RU-агрегаторами (уже в бэклоге полигона) — вся premium/cache-экономика посчитана для прямых ключей; в RU-контуре главный рычаг Р5 может испариться. +- `budget_usd: 0` в `pipeline-c1.yaml` — заглушка; $-потолок владелец задаёт по ценовому намерению, дефолты $5/$30 держим до пересчёта. diff --git a/docs/experiments/00-provider-quirks.md b/docs/experiments/00-provider-quirks.md new file mode 100644 index 0000000..fd94a60 --- /dev/null +++ b/docs/experiments/00-provider-quirks.md @@ -0,0 +1,67 @@ +# 00. Провайдерские грабли — справочник для адаптеров + +Назначение: единый список практических особенностей LLM-провайдеров, найденных полигоном при живых вызовах. **Бэкенд-сессия читает это напрямую** при написании/правке адаптеров `internal/llm`, чтобы не переоткрывать в Go то, что уже поймано в Python. Дата: 2026-07-04, проверять при смене версий моделей. + +Разделение ролей: полигон (`eval/`, Python) — тупой замерочный зонд, характеризует **сырое поведение** провайдера (отказ/качество/латентность); бэкенд (`backend/internal/llm`, Go) — продакшн-адаптеры (retry/failover/ledger). Код не общий (разные языки) и не должен быть — но знание о граблях общее и живёт здесь. + +## Эндпоинты и модели (OpenAI-совместимые, если не указано иное) + +| Провайдер | base_url | Модель (на 2026-07-04) | env-ключ | +|---|---|---|---| +| DeepSeek | `https://api.deepseek.com/v1` | `deepseek-chat` → `deepseek-v4-flash` (деприкация 24.07.2026) | `DEEPSEEK_API_KEY` | +| xAI Grok | `https://api.x.ai/v1` | `grok-4-fast`, `grok-4.3` (флагман) | `XAI_API_KEY` | +| GLM (Z.ai) | `https://api.z.ai/api/paas/v4` | `glm-4.6` | `ZAI_API_KEY` | +| Gemini | `https://generativelanguage.googleapis.com/v1beta/openai` | `gemini-2.5-flash`, `gemini-2.5-pro`, `gemini-3.1-pro-preview` | `GEMINI_API_KEY` | +| Kimi (Moonshot) | `https://api.moonshot.ai/v1` (intl, **не** `.cn`) | `kimi-k2.6` (доступны k2.5, k2.7-code) | `KIMI_API_KEY` | +| OpenAI | `https://api.openai.com/v1` | `gpt-5-mini` | `OPENAI_API_KEY` | +| Qwen (DashScope intl) | `https://dashscope-intl.aliyuncs.com/compatible-mode/v1` | `qwen-flash` | `DASHSCOPE_API_KEY` | +| OpenRouter | `https://openrouter.ai/api/v1` | зависит от хостера | `OPENROUTER_API_KEY` | +| Локаль (ollama) | `http://localhost:11434/v1` (chat) или `/api/generate` | тег модели | не нужен | + +## Thinking / reasoning — главный источник граблей + +У всех современных моделей режим «размышления» включён по умолчанию и **ломает роль переводчика**: рассуждения съедают бюджет вывода → перевод обрезается или пустой, латентность ×3–5. **Для роли переводчика/редактора reasoning обязателен к управлению.** Как — зависит от провайдера: + +| Провайдер | Поведение по умолчанию | Как управлять (для перевода) | +|---|---|---| +| GLM-4.6 | thinking ON, не влезал в 180с | отключить: `extra_body: {"thinking": {"type": "disabled"}}` | +| Gemini 2.5 Flash | thinking ON, съедал `max_tokens`, **молча обрезал перевод** | отключить: `extra_body.google.thinking_config.thinking_budget: 0` | +| **Gemini 3.1 Pro** | thinking **обязателен** | `thinking_budget:0` → HTTP 400 «only works in thinking mode». НЕ отключать; дать большой `max_tokens` (≥8000) | +| gpt-5-mini (reasoning) | reasoning ON, выжигал бюджет → пустой ответ | `reasoning_effort: "minimal"`; **без `temperature`**; `max_completion_tokens` вместо `max_tokens` | +| **Kimi K2.6** | думающая, **очень многословная**: ~11k reasoning-токенов на абзац; reasoning в `reasoning_content`, ответ в `content`; при малом бюджете reasoning съедает лимит → `content` **пуст** (finish=length, не ошибка!) | дать `max_tokens` ≥16000; ответ из `content`. **Дорогой в роли редактора** — reasoning биллится как выход | +| Qwen3.5 / локальные | thinking ON | ollama: `think: false` + `num_predict` cap. Иначе рассуждения (в поле `thinking`, не `response`) забивают контекст | + +**Находка (эксп. 03):** reasoning реально улучшает реалии/имена в переводе (羅生門: «Радзёмон»→«Рашо-мон»), но локально нежизнеспособен (8.6 мин/фрагмент). **Открытый вопрос для бэкенда: проверить think-ON на быстром облачном черновике/редакторе как рычаг качества.** + +## Параметры сэмплинга + +| Провайдер | Грабля | +|---|---| +| **Kimi K2.6** | принимает **только `temperature: 1`**; иное → HTTP 400 «only 1 is allowed for this model» | +| gpt-5-mini | `temperature` не принимается вовсе (см. выше) | +| Локаль (ollama `/v1`) | `top_k`/`min_p`/`repeat_penalty` **не пробрасываются** (ollama issue #11325) → запекать в Modelfile (паттерн `qwen3-vojo`). Для llama-server — расширить запрос этими полями | +| Локаль (ollama) | `max_tokens`/`num_predict` покрывает **thinking + ответ вместе** (в отличие от xAI, где thinking сверх лимита) | + +## Контент-фильтры / safety + +- **Gemini**: `safety_settings` через OpenAI-совместимый слой **не передаются** (HTTP 400 «Unknown name safety_settings»). Дефолт фильтров у 2.5/3 — OFF (gap-2). Для явного контроля фильтров (роль судьи 18+) нужен **нативный** Gemini API, не OpenAI-слой. +- **Qwen Model Studio**: внешний фильтр `data_inspection_failed` на вход/выход, неотключаем (риск молчаливых вырезаний) — не тестировано (нет ключа). +- Детект отказов/вырезаний — см. `eval/refusal_bench.py` (паттерны soft-отказа + coverage-гейт по len_ratio/sent_cov, пороги в эксп. 02). + +## Транспорт / инфраструктура + +- **Прокси на localhost**: в env стенда webshare-прокси, `NO_PROXY=` — WinINET-нотация, которую curl/urllib/Go **не понимают** → запрос к 127.0.0.1 уходит на прокси и получает **403**. Лечение: явный `NO_PROXY="localhost,127.0.0.1,0.0.0.0,::1"` + в коде обходить прокси для loopback/172.x (бэкенд: local-адаптер с no-proxy транспортом — уже сделано). +- **DeepSeek cache-поля**: в `usage` два варианта именования (бэкенд обрабатывает оба). +- **«Эхо» черновика (тихий отказ)**: deepseek-chat на плотной CJK-прозе **воспроизводимо** (3 из 3 ретраев на zh-фрагменте Лу Синя «祝福») возвращает **оригинал вместо перевода** (82% CJK в «переводе»). Не ошибка API — валидный ответ с неправильным содержимым; ретраи не помогают (детерминировано для фрагмента). Митигация в `eval/editor_bench.py`: детектор доли CJK (порог 15%) → фолбэк на другого провайдера (GLM перевёл тот же текст чисто). **Бэкенд/гейт: детектор CJK-артефактов в русском выходе обязателен** (смыкается с anti-omission coverage-гейтом Р7 и уже запланированным «детектором CJK-артефактов» — 7 из 18 моделей грешат); эскалация на другого провайдера, а не ретрай. NB: проверено на deepseek-chat; актуальную роль-модель `deepseek-v4-flash` перепроверить. +- **Таймауты**: книжные чанки на локали занимают **63–278 с** (не 45 с как в чат-vojo). Нужен per-роль лег-таймаут ~300–600 с + стриминг как keep-alive. Донорский транспорт vojo имел скрытый per-attempt потолок 60 с. + +## Календарь деприкаций / цен (мониторить ежеквартально) + +- `deepseek-chat` → `deepseek-v4-flash` к **24.07.2026**. +- **Grok 4.1 Fast retired 15.05.2026** → слаги молча редиректят на `grok-4.3` (цена ×9). Ретайрнулся дешёвый тир, НЕ сам xAI: grok-4.3 остаётся основным пермиссивным тиром канала B. +- Claude Sonnet 5 промо $2/$10 до **31.08.2026** (не закладывать в долгий прайс). +- **ПОПРАВКА (04.07, владелец): удалён только Anthropic (за дороговизну). OpenAI ОСТАЁТСЯ** (ключ есть — GPT-5 nano/mini). Живой набор ключей у бэкенда и полигона: DEEPSEEK, ZAI, KIMI, OPENAI, GEMINI, XAI. Источник истины по стеку — `architecture/05-decisions-log.md` (D3) и Р4. Ранее эта строка ошибочно исключала OpenAI — исправлено оркестратором. + +## Провенанс + +Кто что нашёл: эндпоинты/thinking/temp/safety — полигон (эксп. 02, 03, 04, живые вызовы); Grok-retired/cache-write Anthropic/per-attempt-60с — бэкенд (шаг 0 валидации); localhost-прокси — оба стенда независимо. diff --git a/docs/experiments/03-local-stand.md b/docs/experiments/03-local-stand.md index 2a28037..b7e5cd0 100644 --- a/docs/experiments/03-local-stand.md +++ b/docs/experiments/03-local-stand.md @@ -75,9 +75,20 @@ MoE-модель 30B-A3B (18 ГБ весов, 3B активных) — по ра ### Влияние thinking-режима на качество -Гипотеза: reasoning может починить именно понимание (реалии, длинные конструкции). Проверка — те же фрагменты на qwen3.5:9b и abliterated с включённым thinking и достаточным бюджетом вывода (6000 токенов). +Гипотеза (владельца): reasoning может починить понимание — реалии, длинные конструкции. Проверка на qwen3.5:9b (ja→ru, «Расёмон»). -> _РЕЗУЛЬТАТ БУДЕТ ВПИСАН ПОСЛЕ ПРОГОНА (идёт)._ +**Мешает тесный контекст, не «зависание».** При `num_ctx 8192` (temp 0.3 и 0.6) think уходит в развёрнутый мета-анализ задачи (~7000 токенов рассуждений на английском: «Analyze the Request: Role… Task…»), забивает всё окно и обрывается по `length` **до перевода** — `response` пуст (детектор видел «0 символов»). Рассуждения при этом реально пишутся — просто ollama кладёт их в отдельное поле `thinking`. + +**С достаточным контекстом think завершается и улучшает реалии.** `num_ctx 16384`, temp 0.6: 518 с, ~11k токенов рассуждений (39к символов) → перевод получен (2605 симв), `done_reason: stop`. Качество реалий заметно выше, чем без think: + +| Реалия | без think | с think | эталон DeepSeek | +|---|---|---|---| +| 羅生門 | «Радзёмон» | **«Рашо-мон»** (узнаваемо) | «Расёмон» | +| 朱雀大路 | «улица Чжуцзянь» (кит. чтение) | **«улица Сёкаку»** (яп. чтение) | «улица Судзаку» | + +Reasoning вытащил модель из грубых ошибок (унрекогнайзабл-транслит, китайское чтение кандзи) — **гипотеза частично подтвердилась: think трогает реалии.** Но: (1) даже с think локаль ниже API («Рашо-мон/Сёкаку» ≠ «Расёмон/Судзаку»); (2) цена запретительна — **8,6 мин и ~11k токенов рассуждений на 1400-знаковый фрагмент** (вебновелла 500 глав ≈ 200 ч локального счёта против 15 с/$0.0005 у DeepSeek за более точный результат). **Вывод: локально think для перевода нежизнеспособен по латентности.** + +**Проброс гипотезы в облако (новая проверка для бэклога):** раз reasoning чинит реалии, включить think на быстрых облачных черновике/редакторе (DeepSeek/GLM, где это секунды) может поднять качество — проверить thinking-ON vs OFF по качеству (не только скорости) на облачном контуре. ## Сравнение пула dense-моделей diff --git a/docs/experiments/04-editor-quality.md b/docs/experiments/04-editor-quality.md new file mode 100644 index 0000000..0d23790 --- /dev/null +++ b/docs/experiments/04-editor-quality.md @@ -0,0 +1,68 @@ +# Эксперимент 04. Качество редактора ru-стиля (бейк-офф) + +Дата: 2026-07-04. Отвечает на вопрос бэкенда №2 (дефолт редактора для Фазы 1) и решение владельца заменить Anthropic. Скрипт: `eval/editor_bench.py`; сравнение: `eval/build_editor_artifact.py` → артефакт. + +## Метод + +Пайплайн как в продукте: **DeepSeek делает черновой перевод → редактор-кандидат полирует** его в живую художественную прозу (чек-лист Норы Галь: канцелярит, кальки, синтаксис), сохраняя смысл и все предложения. Каждый редактор получает **оригинал + черновик**. + +- Кандидаты (дорогой тир, без Anthropic/OpenAI по решению владельца): **glm-4.6, kimi-k2.6, gemini-3.1-pro-preview, grok-4.3**. +- 4 фрагмента: Расёмон (ja), А-Кью (zh), Беги Мелос (ja), Машина времени (en — владелец судит и стиль, и верность напрямую). +- Для ja/zh — английский эталон смысла (владелец читает en/ru, не ja/zh) как якорь верности. +- **Оценка — человеческая, слепая** (A/B/C/D): худ. качество ru — единственная надёжная метрика человек, LLM-судьи расходятся с людьми (LAIT, research/03). Артефакт: слепые версии, ключ и цена скрыты до вынесения оценки. + +## Объективные находки (не зависят от стиля) + +Латентность и цена на один абзац (для роли, вызываемой на каждый чанк книги, — решающе): + +| Редактор | Латентность | Особенность цены | +|---|---|---| +| **grok-4.3** | ~13 с | без «размышлений» — самый быстрый и дешёвый | +| **glm-4.6** | ~105 с | thinking off (иначе таймаут) | +| **gemini-3.1-pro** | ~60–86 с | thinking **не отключить** (обязателен), нужен `max_tokens` ≥16k | +| **kimi-k2.6** | ~150 с | **~11 000 токенов «размышлений» на абзац** — биллятся как выход → самый дорогой | + +**Вывод по цене:** Kimi как редактор экономически тяжёлый (11k reasoning-токенов × output-тариф на каждый чанк книги — это сотни тысяч токенов на том). Grok-4.3 — противоположный полюс (быстрый, без reasoning). Если человеческая оценка стиля не покажет явного превосходства Kimi, его цена его дисквалифицирует. Это входит в решение наравне со стилем. + +## Провайдерские грабли, найденные по пути + +Все — в [00-provider-quirks.md](00-provider-quirks.md): Kimi только `temp=1` + reasoning в `reasoning_content` (нужен бюджет ≥16k); Gemini 3.1 Pro обязательно-думающая; **DeepSeek «эхал» оригинал на zh-фрагменте Лу Синя «祝福»** (82% CJK, воспроизводимо 3/3) → пришлось сменить zh-фрагмент на А-Кью и добавить фолбэк-черновик (GLM) + детектор CJK-эха. Последнее — реальный класс дефекта для черновой стадии бэкенда (тихий отказ = оригинал вместо перевода). + +## Оценка (слепая) — выполнена двумя фронтир-судьями + +Артефакт: https://claude.ai/code/artifact/25394796-96f0-4f3f-b8d0-de000d415472. Владелец отдал слепую оценку **двум независимым судьям (GPT-фронтир + Opus 4.8)**, которые сверялись не только с английским якорем, но и с **каноническими русскими переводами** (Н. Фельдман — Расёмон, В. Рогов — А-Кью, С. Смоляков/канон — Мелос, К. Морозов — Машина времени) и оригиналами. Оба судьи **сошлись независимо** — высокая уверенность. + +**Ключ слепой разметки:** A = grok-4.3, B = glm-4.6, C = gemini-3.1-pro, D = kimi-k2.6. + +### Свод (оба судьи согласны) + +| Ось | Ранжирование | +|---|---| +| **Стиль** (живость ru, без канцелярита/калек) | **C (gemini) > A (grok) > D (kimi) > B (glm)** | +| **Верность** (без потерь и отсебятины) | **A (grok) > C (gemini) > B (glm) > D (kimi)** | +| **Value** (качество / цена+скорость) | **A (grok) ≫ C (gemini) > B (glm) > D (kimi)** | + +Ключевые наблюдения судей: +- **A = grok-4.3 — лучший value с огромным отрывом**: ранг-1 по верности, ранг-2 по стилю, при **самой низкой цене и в разы быстрее** думающих (~13 с, без reasoning). Оба судьи независимо назвали его лучшим выбором «одной модели на роль». +- **C = gemini-3.1-pro — лучшая проза**: сильнейший художественный русский, эталонно решает культурные узлы (каламбур заглавия 正传 у Лу Синя, глосса к имени А-гуй — и это **не отсебятина**, а ровно приём канонического Рогова). Иногда переусиливает/дописывает. Выбор, когда литературность важнее цены и текст потом вычитывает редактор. +- **B = glm-4.6 — слабейший**: площе всех, кальки, пара опечаток, при этом ~105 с. Плохой value. +- **D = kimi-k2.6 — худший value**: дороже и медленнее всех (~150 с, ~11k reasoning-токенов/абзац), а по верности — последний (чаще всех подменяет детали). Лишние «размышления» точность не купили. Колоритен на Дадзае, но нестабилен. + +### Рекомендация дефолта редактора (Фаза 1) + +1. **Дефолт: `grok-4.3`** — лучший баланс качество/цена, надёжен по смыслу «из коробки». Закрывает вопрос бэкенда №2. +2. **Премиум-эскалация: `gemini-3.1-pro`** — на дорогих книгах / по сигналу судьи, где нужна максимальная проза и есть человеческая вычитка. +3. **GLM-4.6 — снять с роли дефолтного редактора** (был допущением Р4 «редактор = GLM», эмпирически слабейший). NB: тестировали glm-4.6; при появлении GLM-5 можно перемерить. +4. **Kimi — из кандидатов в редакторы убрать** (цена+скорость+риск верности). + +**Следствие для архитектуры (→ оркестратору):** правка Р4 — редактор ru-стиля по умолчанию `grok-4.3`, премиум `gemini-3.1-pro`; GLM/Kimi не дефолт. Нюанс контуров: grok/gemini — Западный/прямых-ключей контур; в ru-BYOK экономика иная, но по качеству+цене grok-4.3 выигрывает и дёшев. Полигон архитектурные доки не редактирует — решение вносит оркестратор. + +### Оговорки + +- **Короткие фрагменты** (по одному отрывку) — срез, не приговор моделям в целом; полный выбор ядра пайплайна — пилот Фазы 2.5 (задача 4). +- Судьи поймали реальный дефект данных: версия C (Gemini) на «Мелосе» была **обрезана** (бюджет 8k при обязательном thinking) — **исправлено** после оценки (перегенерирована с 16k, артефакт обновлён); вывод по «Мелосу» (лидер A) от этого не меняется. +- «Якорь ≠ эталон»: оба судьи отметили места, где английский якорь сам упрощает оригинал (напр. оттенок «жалостливо усмехнуться» у Дадзая) — подтверждает методическое следствие ниже. + +## Методическое следствие (важно для пилота, задача 4) + +Владелец читает только **en и ru**. Прямая человеческая оценка **верности** доступна лишь на en→ru и на русской стороне; для zh/ja→ru нужен английский эталон-якорь (или метрики+глоссарий). Заложить в протокол пилота: не строить человеческую оценку верности на языках, которых судья не читает.