Correct the Gemini thinking-knob and billing notes against vendor docs and ping the orchestrator about the engine losing the glossary on Gemini hops

This commit is contained in:
Claude (backend session) 2026-08-22 01:03:20 +03:00
parent 70966c219f
commit 29338dfbd3
4 changed files with 53 additions and 9 deletions

View file

@ -280,6 +280,36 @@
## Полигон ## Полигон
**⛔⛔ ПИНГ ОРКЕСТРАТОРА №19 — 22.08. ЖИВОЙ ДЕФЕКТ ДВИЖКА: эскалация на Gemini ТИХО ТЕРЯЕТ ГЛОССАРИЙ.**
Найдено полигоном живой пробой, подтверждено вендор-докой. **OpenAI-совместимый слой Gemini принимает
РОВНО ОДНО системное сообщение; лишние выбрасываются молча, без ошибки.** Механизм назван вендором:
в нативном API `systemInstruction` — один объект `Content` (`ai.google.dev/api/generate-content`),
поэтому уход на нативный API проблемы НЕ решает — склеивать надо в любом случае.
Замер (один и тот же системный текст 7970 знаков): одним сообщением → `prompt_tokens` **2994**, маркерная
инструкция ИСПОЛНЕНА; двумя → **535** токенов и инструкция НЕ исполнена, при `finish=stop` и внешне
правильном переводе. Отказа нет — есть тихая потеря промта, невидимая гейтам годности.
**Почему это ваша зона, а не наша.** `backend/internal/pipeline/render.go:256-258` штатно строит ВТОРОЕ
системное сообщение — инъекцию банка памяти (глоссарий/STM); `backend/internal/llm/httpllm.go:517-522`
(`toOpenAIMessages`) копирует сообщения дословно; склейки под Gemini нет нигде. При этом
`gemini-3.1-pro-preview` стоит в ратифицированной цепочке эскалации во ВСЕХ арм-конфигах
(`backend/configs/pipeline-c1.yaml:129`, `pipeline-arm-glm.yaml:61`, `pipeline-arm-deepseek-pro.yaml:62`,
`pipeline-arm-mistral.yaml:61`). ⇒ **любой эскалационный хоп на Gemini при непустой инъекции теряет
глоссарий, и книга едет без канона имён.** Оговорка D22.3 «экспозиция Ф1 нулевая» держится только на том,
что до Gemini в дефолте не доходят — то есть на маршруте, а не на коде.
⚠ Класс в проекте УЖЕ решён рядом: `backend/internal/llm/provider_anthropic.go:169-179` сворачивает
ведущий system-префикс в одно поле и падает громко на system посреди диалога. Не обобщено на Gemini.
Полигон у себя починил склейкой по вендору (`eval/dovodka/rol.py` `ONE_SYSTEM`/`fit_msgs`); в бэкенд
рукой не лезу. Квирк записан в `00-provider-quirks.md` (наша зона) с механизмом и ссылками.
**Тем же касанием — две поправки в квирках, обе наши прежние ошибки, уже внесены нами:**
(1) форма `extra_body.google.thinking_config...` в бюллетене НЕ доезжает через openai-SDK: вендорская
форма несёт ключ `extra_body` на верхнем уровне тела (`extra_body={'extra_body': {'google': …}}`), а один
уровень даёт HTTP 400 «Unknown name "google"». Из-за этой ошибки `eval/providers.json:59` объявил рабочую
форму багом, и проект три недели считал, что ручки размышления у Gemini нет. (2) `reasoning_tokens=0` у
Gemini — НОРМА слоя, а не измерение: вывод «размышление выключено» из этого поля недействителен, считать
надо `total prompt completion`. У серии Gemini 3 размышление вообще невыключаемо (вендор, 17.08.2026).
**⚠ Пинг оркестратора №18 — 20.08 (протухшие цены в квирках, чинить вашей рукой).** `docs/experiments/00-provider-quirks.md` до сих пор утверждает, что цены после катовера НЕ изменились («flash $0.14/$0.28»). Это опровергнуто пере-пином 1315.08 (D39.137): таблица запинена ПИКОМ — flash 0.44/1.32 при кэш-хите **0.014**, pro 1.32/3.96 при кэш-хите **0.044** за 1M (⚠ испр. 20.08: первая редакция пинга приписала flash кэш-хит pro — ошибка ×3.1 ровно в той клетке, ради которой пинг и писался; сверено с `backend/configs/models.yaml:167,183` и телом D39.137 §2а), и счёт шиппинга = 100% DeepSeek ⇒ ×4.24.4 в пике. Квирки — ваша зона, рукой не трогаю; поправьте при ближайшем касании, потому что по ним считают деньги проб. Тем же касанием сверьте пункт «возражение Sol по проходу `tier`»: шапка держит его на владельце, а ваша секция пишет, что оно снято и причина названа — один из двух носителей неверен. **⚠ Пинг оркестратора №18 — 20.08 (протухшие цены в квирках, чинить вашей рукой).** `docs/experiments/00-provider-quirks.md` до сих пор утверждает, что цены после катовера НЕ изменились («flash $0.14/$0.28»). Это опровергнуто пере-пином 1315.08 (D39.137): таблица запинена ПИКОМ — flash 0.44/1.32 при кэш-хите **0.014**, pro 1.32/3.96 при кэш-хите **0.044** за 1M (⚠ испр. 20.08: первая редакция пинга приписала flash кэш-хит pro — ошибка ×3.1 ровно в той клетке, ради которой пинг и писался; сверено с `backend/configs/models.yaml:167,183` и телом D39.137 §2а), и счёт шиппинга = 100% DeepSeek ⇒ ×4.24.4 в пике. Квирки — ваша зона, рукой не трогаю; поправьте при ближайшем касании, потому что по ним считают деньги проб. Тем же касанием сверьте пункт «возражение Sol по проходу `tier`»: шапка держит его на владельце, а ваша секция пишет, что оно снято и причина названа — один из двух носителей неверен.
**ФАЗА Д — СТАТУС НА ВЕЧЕР 10.08 (сессия передана, хендофф `/home/ubuntu/CONTINUATION_PROMPT.md`).** ⚠ **Запись ПРОТУХЛА трижды и её надо срезать при лендинге петель** (свип доков 20.08): статус «на вечер 10.08» лежит поверх записей от 15.08, хендофф указывает ВНЕ репозитория (файл на месте, но от 10.08 и вне git — то есть не переживёт машину), а в дереве с 16.08 живёт незадокументированная работа (`eval/dovodka/PLAN-16-08.md`, `PLAN-17-08.md`, `HANDOFF-21-08.md`, `ja6.py`, `naklon.py`), которой в этой секции нет вовсе. Три поколения записей в одном месте — именно то, из-за чего состояние фазы Д сегодня нельзя прочитать. **ФАЗА Д — СТАТУС НА ВЕЧЕР 10.08 (сессия передана, хендофф `/home/ubuntu/CONTINUATION_PROMPT.md`).** ⚠ **Запись ПРОТУХЛА трижды и её надо срезать при лендинге петель** (свип доков 20.08): статус «на вечер 10.08» лежит поверх записей от 15.08, хендофф указывает ВНЕ репозитория (файл на месте, но от 10.08 и вне git — то есть не переживёт машину), а в дереве с 16.08 живёт незадокументированная работа (`eval/dovodka/PLAN-16-08.md`, `PLAN-17-08.md`, `HANDOFF-21-08.md`, `ja6.py`, `naklon.py`), которой в этой секции нет вовсе. Три поколения записей в одном месте — именно то, из-за чего состояние фазы Д сегодня нельзя прочитать.

View file

@ -51,8 +51,8 @@
| **DeepSeek v4-flash** | гибридная reasoning-модель, thinking ON по умолчанию | **Управление (официальные доки, api-docs.deepseek.com/guides/thinking_mode, проверено 04.07): в body `extra_body={"thinking":{"type":"enabled"\|"disabled"}}`** (дефолт enabled). Т.е. выключить МОЖНО, параметр есть. НО для роли ПЕРЕВОДЧИКА не выключать: `disabled`→non-thinking режим, который на плотном CJK **ЭХАЕТ исходник**. Оставлять thinking ВКЛ; reasoning→`reasoning_content`, `content` чистый; ~~`max_tokens` ≥8000~~ **→ см. строку 0731 ниже: флор 8000 ПРОБИТ**. ⚠ **thinking-режим НЕ поддерживает `temperature`/`top_p`/penalties** (шлём — молча игнорируются). ~~`reasoning_effort`: только `high`/`max` (low/medium→high, xhigh→max)~~ **→ УСТАРЕЛО, см. строку 0731**; `none` в OpenAI-формате НЕ существует → 400. Для дешёвой роли ЭКСТРАКЦИИ (не перевод) thinking можно выключить — echo бьёт по переводу, не по JSON-выводу (перепроверить). | | **DeepSeek v4-flash** | гибридная reasoning-модель, thinking ON по умолчанию | **Управление (официальные доки, api-docs.deepseek.com/guides/thinking_mode, проверено 04.07): в body `extra_body={"thinking":{"type":"enabled"\|"disabled"}}`** (дефолт enabled). Т.е. выключить МОЖНО, параметр есть. НО для роли ПЕРЕВОДЧИКА не выключать: `disabled`→non-thinking режим, который на плотном CJK **ЭХАЕТ исходник**. Оставлять thinking ВКЛ; reasoning→`reasoning_content`, `content` чистый; ~~`max_tokens` ≥8000~~ **→ см. строку 0731 ниже: флор 8000 ПРОБИТ**. ⚠ **thinking-режим НЕ поддерживает `temperature`/`top_p`/penalties** (шлём — молча игнорируются). ~~`reasoning_effort`: только `high`/`max` (low/medium→high, xhigh→max)~~ **→ УСТАРЕЛО, см. строку 0731**; `none` в OpenAI-формате НЕ существует → 400. Для дешёвой роли ЭКСТРАКЦИИ (не перевод) thinking можно выключить — echo бьёт по переводу, не по JSON-выводу (перепроверить). |
| GLM-4.5-air / 4.6 | thinking ON, не влезал в 180с | отключить: `extra_body: {"thinking": {"type": "disabled"}}` | | GLM-4.5-air / 4.6 | thinking ON, не влезал в 180с | отключить: `extra_body: {"thinking": {"type": "disabled"}}` |
| **glm-5** | thinking ON по умолчанию | гасится тем же `extra_body: {"thinking": {"type": "disabled"}}` — подтверждено живыми армами эксп-18/21 (арм B шёл thinking-OFF; провод-факт эксп-21 §8) | | **glm-5** | thinking ON по умолчанию | гасится тем же `extra_body: {"thinking": {"type": "disabled"}}` — подтверждено живыми армами эксп-18/21 (арм B шёл thinking-OFF; провод-факт эксп-21 §8) |
| Gemini 2.5 Flash | thinking ON, съедал `max_tokens`, **молча обрезал перевод** | отключить: `extra_body.google.thinking_config.thinking_budget: 0` | | Gemini 2.5 Flash | thinking ON, съедал `max_tokens`, **молча обрезал перевод** | **ФОРМА, КАК ОНА ЗДЕСЬ СТОЯЛА, НА ПРОВОД НЕ ДОЕЗЖАЕТ** (поймано полигоном 22.08). Проводное тело несёт ключ `extra_body` **НА ВЕРХНЕМ УРОВНЕ**: `{"extra_body":{"google":{"thinking_config":{…}}}}`; в Python-SDK это `extra_body={'extra_body': {'google': {…}}}` (вендор-сэмпл ai.google.dev/gemini-api/docs/openai, 17.08.2026). Один уровень вложенности → HTTP 400 «Unknown name "google"» — это НАША ошибка, а не отказ вендора. Штатный off-switch для серии 2.5 — плоский `reasoning_effort:"none"` |
| **Gemini 3.1 Pro** | thinking **обязателен** | `thinking_budget:0` → HTTP 400 «only works in thinking mode». НЕ отключать; дать большой `max_tokens` (≥8000) | | **Gemini 3.x и 2.5 Pro** | thinking **невыключаем У ВСЕЙ СЕРИИ** | дословно вендор (17.08.2026): «Reasoning cannot be turned off for Gemini 2.5 Pro or 3 models». Дефолт `gemini-3.1-pro-preview`**On (high)**. У 3.x ручка — `thinking_level` (minimal/low/medium/high), у 2.5 — `thinking_budget`; через OpenAI-слой обе задаются как `reasoning_effort`, и **вместе с `thinking_level`/`thinking_budget` слать нельзя**. ⚠ Для `gemini-3.1-flash-lite` строки в вендорской таблице дефолтов НЕТ**дефолтный уровень НЕ УСТАНОВЛЕН**, писать «не установлено», а не «выключено». НЕ отключать; дать большой `max_tokens` (≥8000) |
| gpt-5-mini (reasoning) | reasoning ON, выжигал бюджет → пустой ответ | `reasoning_effort: "minimal"`; **без `temperature`**; `max_completion_tokens` вместо `max_tokens` | | gpt-5-mini (reasoning) | reasoning ON, выжигал бюджет → пустой ответ | `reasoning_effort: "minimal"`; **без `temperature`**; `max_completion_tokens` вместо `max_tokens` |
| **gpt-5.4 (reasoning)** | ⚠ **`reasoning_effort:"medium"` РЕПРОДУЦИРУЕМО ОБРЕЗАЕТ ВЫВОД на длинной редактуре** (exp14b: reasoning съел бюджет → `content` 223 out-ток ≈ 602 симв из ~5000, `finish=stop` — выглядит как валидный короткий ответ, НЕ length-обрыв → тихо портит результат) | В роли РЕДАКТОРА/переводчика (длинный выход) слать **`reasoning_effort:"low"`** (exp14b: тот же чанк → 5137 симв, полный); `max_completion_tokens` (не `max_tokens`), без `temperature`. reasoning⊆completion (subset-биллинг). Слаг live-фактчек 2026-07-11: `gpt-5.4-2026-03-05`. *(Верифицировано span-читкой D38; self-review полигона поймал живьём.)* | | **gpt-5.4 (reasoning)** | ⚠ **`reasoning_effort:"medium"` РЕПРОДУЦИРУЕМО ОБРЕЗАЕТ ВЫВОД на длинной редактуре** (exp14b: reasoning съел бюджет → `content` 223 out-ток ≈ 602 симв из ~5000, `finish=stop` — выглядит как валидный короткий ответ, НЕ length-обрыв → тихо портит результат) | В роли РЕДАКТОРА/переводчика (длинный выход) слать **`reasoning_effort:"low"`** (exp14b: тот же чанк → 5137 симв, полный); `max_completion_tokens` (не `max_tokens`), без `temperature`. reasoning⊆completion (subset-биллинг). Слаг live-фактчек 2026-07-11: `gpt-5.4-2026-03-05`. *(Верифицировано span-читкой D38; self-review полигона поймал живьём.)* |
| **gpt-5.6-luna (reasoning)** | reasoning ON; **без явной ручки эффорта выжигает бюджет на рассуждение и отдаёт ПУСТОЙ `content`** (провод-факт эксп-21 §8) | слать явный `reasoning_effort` (`low` для перевода/редактуры); `max_completion_tokens`; пустой `content` при `finish=length` — оплаченный брак, гейтить приёмом ответа | | **gpt-5.6-luna (reasoning)** | reasoning ON; **без явной ручки эффорта выжигает бюджет на рассуждение и отдаёт ПУСТОЙ `content`** (провод-факт эксп-21 §8) | слать явный `reasoning_effort` (`low` для перевода/редактуры); `max_completion_tokens`; пустой `content` при `finish=length` — оплаченный брак, гейтить приёмом ответа |
@ -154,8 +154,9 @@
## Контент-фильтры / safety ## Контент-фильтры / safety
- ⛔⛔ **Gemini, ДВА СИСТЕМНЫХ СООБЩЕНИЯ = ПРОМТ ТЕРЯЕТСЯ МОЛЧА (полигон 22.08, живая проба `eval/dovodka/proba_gemini.py`).** Слой OpenAI у Gemini принимает ОДНО системное сообщение; при двух и более лишние выбрасываются без ошибки. Замер на одном и том же системном тексте в 7970 знаков: ОДНИМ сообщением → `prompt_tokens` 2994 и маркерная инструкция ИСПОЛНЕНА; ДВУМЯ → **535 токенов (это размер одного user-сообщения) и инструкция НЕ исполнена**. Ответ приходит с `finish=stop` и выглядит правильным переводом — отказа нет, есть тихая потеря инструкции, невидимая всем гейтам годности. ⚠ Так были куплены 16 клеток арма `RE` (промт-роль на gemini): они переведены ВООБЩЕ БЕЗ ИНСТРУКЦИИ, и вердикт о переносимости из них был бы ложным. Лечение: склеивать системные в одно ДЛЯ ЭТОГО ВЕНДОРА (`rol.ONE_SYSTEM`/`fit_msgs`) — общая склейка сменила бы форму запроса у всех моделей и рассогласовала бы уже купленные клетки. ⚠ Проверено, что у `deepseek-v4-pro`, `gpt-5.6-luna`, `glm-5` и `grok-4.3` два системных доезжают целиком. - ⛔⛔ **Gemini, ДВА СИСТЕМНЫХ СООБЩЕНИЯ = ПРОМТ ТЕРЯЕТСЯ МОЛЧА (полигон 22.08, живая проба `eval/dovodka/proba_gemini.py`).** **МЕХАНИЗМ НАЗВАН** (вендор-дока `ai.google.dev/api/generate-content`): в нативном API `systemInstruction` — это ОДИН объект `Content`, поэтому слой ФИЗИЧЕСКИ не может пронести больше одного системного, и уход на нативный API проблемы НЕ решает — там пришлось бы склеивать так же. При двух и более лишние выбрасываются без ошибки. ⚠ КАКОЕ именно выживает — НЕ УСТАНОВЛЕНО: форум Google (discuss.ai.google.dev/t/86097, 30.05.2025) сообщает «выживает последнее», а наш замер даёт 535 токенов ≈ размер одного user-сообщения, то есть не выжило НИ ОДНО. Расхождение открыто. Документированного вендором ограничения в разделе «Current limitations» НЕТ. Замер на одном и том же системном тексте в 7970 знаков: ОДНИМ сообщением → `prompt_tokens` 2994 и маркерная инструкция ИСПОЛНЕНА; ДВУМЯ → **535 токенов (это размер одного user-сообщения) и инструкция НЕ исполнена**. Ответ приходит с `finish=stop` и выглядит правильным переводом — отказа нет, есть тихая потеря инструкции, невидимая всем гейтам годности. ⚠ Так были куплены 16 клеток арма `RE` (промт-роль на gemini): они переведены ВООБЩЕ БЕЗ ИНСТРУКЦИИ, и вердикт о переносимости из них был бы ложным. Лечение: склеивать системные в одно ДЛЯ ЭТОГО ВЕНДОРА (`rol.ONE_SYSTEM`/`fit_msgs`) — общая склейка сменила бы форму запроса у всех моделей и рассогласовала бы уже купленные клетки. ⚠ Проверено, что у `deepseek-v4-pro`, `gpt-5.6-luna`, `glm-5` и `grok-4.3` два системных доезжают целиком.
- **Gemini**: `safety_settings` через OpenAI-совместимый слой **не передаются** (HTTP 400 «Unknown name safety_settings»). Дефолт фильтров у 2.5/3 — OFF (gap-2). Для явного контроля фильтров (роль судьи 18+) нужен **нативный** Gemini API, не OpenAI-слой. ⚠ **D22.6: на ГРАФИЧНОЙ эротике Gemini 3.x fail-closed `PROHIBITED_CONTENT` (8× wire-verified, exp11) — фильтр НЕконфигурируем, нативный API не спасает; судья эротики — только Grok. На violence/SFW Gemini-судья жив.** `finish_reason` приходит СОСТАВНОЙ строкой `'content_filter: PROHIBITED_CONTENT'` (точные матчеры мертвы — D22.8а). Биллинг Gemini: thinking ТОЛЬКО в `total_tokens``reasoning: additive_total`, иначе недоучёт 146×/вызов (D22.3). ⚠ **В роли редактора Gemini течёт сервис-преамбулой в выход («Вот отредактированный…», 6/6 чанков — exp12) → за output-санитайзером D30.3.****Дополнение эксп-21 (08.08):** fail-closed ответ OpenAI-слоя приходит вовсе БЕЗ объекта `message` (не с пустым `content`) — парсер обязан переживать его отсутствие; на вебновелльном violence-материале срабатывания массовые (10 клеток судейского прогона с `content_filter: PROHIBITED_CONTENT`) ⇒ оговорка «на violence/SFW Gemini-судья жив» целиком НЕ держится — Gemini непригоден как ЕДИНСТВЕННЫЙ второй контур на этом материале (эксп-21 §1/§8). - ⛔⛔ **ТОТ ЖЕ ДЕФЕКТ ЖИВЁТ В ДВИЖКЕ, А НЕ ТОЛЬКО В ПОЛИГОНЕ (аудит 22.08).** `backend/internal/pipeline/render.go:256-258` штатно строит ВТОРОЕ системное сообщение — инъекцию банка памяти (глоссарий/STM), `backend/internal/llm/httpllm.go:517-522` копирует сообщения дословно, склейки под Gemini нет нигде, а `gemini-3.1-pro-preview` стоит в ратифицированной цепочке эскалации во ВСЕХ арм-конфигах (`pipeline-c1.yaml:129`, `pipeline-arm-glm.yaml:61`, `pipeline-arm-deepseek-pro.yaml:62`, `pipeline-arm-mistral.yaml:61`). ⇒ **любой эскалационный хоп на Gemini при непустой инъекции ТИХО теряет глоссарий.** Оговорка D22.3 «экспозиция Ф1 нулевая» держится только на том, что до Gemini в дефолте не доходят. ⚠ Класс в проекте уже был решён рядом: `backend/internal/llm/provider_anthropic.go:169-179` сворачивает ведущий system-префикс в одно поле и падает громко на system посреди диалога — просто не обобщён на Gemini. **Зона бэкенда, пинг оркестратору отправлен.**
- **Gemini**: `safety_settings` через OpenAI-совместимый слой **не передаются** (HTTP 400 «Unknown name safety_settings»). Дефолт фильтров у 2.5/3 — OFF (gap-2). Для явного контроля фильтров (роль судьи 18+) нужен **нативный** Gemini API, не OpenAI-слой. ⚠ **D22.6: на ГРАФИЧНОЙ эротике Gemini 3.x fail-closed `PROHIBITED_CONTENT` (8× wire-verified, exp11) — фильтр НЕконфигурируем, нативный API не спасает; судья эротики — только Grok. На violence/SFW Gemini-судья жив.** `finish_reason` приходит СОСТАВНОЙ строкой `'content_filter: PROHIBITED_CONTENT'` (точные матчеры мертвы — D22.8а). Биллинг Gemini: thinking ТОЛЬКО в `total_tokens``reasoning: additive_total`, иначе недоучёт 146×/вызов (D22.3). Нативное имя поля — `usageMetadata.thoughtsTokenCount`; слой AI-Studio `completion_tokens_details.reasoning_tokens` не отдаёт ВОВСЕ, тогда как Vertex AI то же поле отдаёт (форум 15.01.2026) — при переезде на Vertex учёт менять. ⚠⚠ **`reasoning_tokens=0` у Gemini — НОРМА, а не измерение: вывод «размышление выключено» из этого поля НЕДЕЙСТВИТЕЛЕН.** Полигон 22.08 на этом и поскользнулся, объявив «вендор-дефолт flash-lite = размышление ВЫКЛ (замерено)»; считать надо `total prompt completion`. ⚠ **В роли редактора Gemini течёт сервис-преамбулой в выход («Вот отредактированный…», 6/6 чанков — exp12) → за output-санитайзером D30.3.****Дополнение эксп-21 (08.08):** fail-closed ответ OpenAI-слоя приходит вовсе БЕЗ объекта `message` (не с пустым `content`) — парсер обязан переживать его отсутствие; на вебновелльном violence-материале срабатывания массовые (10 клеток судейского прогона с `content_filter: PROHIBITED_CONTENT`) ⇒ оговорка «на violence/SFW Gemini-судья жив» целиком НЕ держится — Gemini непригоден как ЕДИНСТВЕННЫЙ второй контур на этом материале (эксп-21 §1/§8).
- **Qwen Model Studio**: внешний фильтр `data_inspection_failed` на вход/выход, неотключаем (риск молчаливых вырезаний) — не тестировано (нет ключа). - **Qwen Model Studio**: внешний фильтр `data_inspection_failed` на вход/выход, неотключаем (риск молчаливых вырезаний) — не тестировано (нет ключа).
- Детект отказов/вырезаний — см. `eval/refusal_bench.py` (паттерны soft-отказа + coverage-гейт по len_ratio/sent_cov, пороги в эксп. 02). - Детект отказов/вырезаний — см. `eval/refusal_bench.py` (паттерны soft-отказа + coverage-гейт по len_ratio/sent_cov, пороги в эксп. 02).

View file

@ -463,7 +463,11 @@ THINK_LEVEL: dict = {
"RK": "low", # grok на вендор-дефолте — ровно так и куплен, теперь это НАПИСАНО "RK": "low", # grok на вендор-дефолте — ровно так и куплен, теперь это НАПИСАНО
"RKT": "high", # grok с настоящим размышлением — клетка Б6, не куплена "RKT": "high", # grok с настоящим размышлением — клетка Б6, не куплена
"RL": "vendor", # gpt-5.6-luna: ростер пинит `low`, снимаем (В22) "RL": "vendor", # gpt-5.6-luna: ростер пинит `low`, снимаем (В22)
"RE": "vendor", # gemini-3.1-flash-lite: вендор-дефолт = размышление ВЫКЛ (замерено, 0 ток.) "RE": "vendor", # gemini-3.1-flash-lite: ВЕНДОР-ДЕФОЛТ. ⛔ НЕ «выключено»: у серии Gemini 3
# размышление вообще невыключаемо (вендор-дока 17.08.2026), а поле
# `reasoning_tokens` у Gemini ВСЕГДА 0 по построению слоя — считать надо
# `total prompt completion`. Прежний комментарий «замерено, 0 ток.»
# читал ровно то поле, которое наш же бюллетень объявил всегда нулевым.
"RET": "budget", # он же с размышлением: у Gemini своя ручка `thinking_budget`, не `effort` "RET": "budget", # он же с размышлением: у Gemini своя ручка `thinking_budget`, не `effort`
} }
@ -508,9 +512,18 @@ def call_kwargs(model: str, msgs: list[dict], arm: str = "") -> dict:
if lvl == "budget": if lvl == "budget":
# ⚠ У Gemini уровень задаётся БЮДЖЕТОМ, а не словом: `thinking_budget` в google-секции # ⚠ У Gemini уровень задаётся БЮДЖЕТОМ, а не словом: `thinking_budget` в google-секции
# (квирк-бюллетень :54). `-1` — динамический бюджет, то есть «думай сколько нужно». # (квирк-бюллетень :54). `-1` — динамический бюджет, то есть «думай сколько нужно».
# ⚠ Форма `extra_body.google.thinking_config.thinking_budget` (квирк-бюллетень :54) вендором # ⛔ ПОПРАВКА 22.08 ПОСЛЕ СВЕРКИ С ВЕНДОР-ДОКОЙ. Прежний комментарий здесь утверждал, что
# ОТВЕРГНУТА 22.08: HTTP 400 «Unknown name "google"» — тот же класс, что отказ на # вендор ОТВЕРГ google-секцию. Неверно: секция работает, а 400 «Unknown name "google"» был
# `safety_settings`. Пробуем стандартную для OpenAI-слоя ручку. # НАШЕЙ ошибкой вложенности — Python-SDK раскладывает `extra_body` в верхний уровень тела,
# поэтому вендорская форма требует ДВОЙНОГО ключа: `extra_body={'extra_body': {'google': …}}`.
# Рабочая форма лежала в репозитории (`eval/adaptive_probe.py:71`), но была объявлена багом
# в `eval/providers.json:59`, и ошибка размножилась оттуда.
# ⇒ Здесь оставлена ПЛОСКАЯ `reasoning_effort` — она документирована вендором для 3.x
# (маппится в `thinking_level`) и проверена живой пробой: 4068 токенов размышления в
# `total_tokens`. Слать её ВМЕСТЕ с `thinking_level`/`thinking_budget` вендор запрещает.
# ⚠ `high` — ВЕРХНЯЯ ступень. Для роли переводчика аналог того, что мы шлём другим вендорам,
# это `low`/`minimal`; контраст `RE`/`RET` читать как «вендор-дефолт против high», НЕ как
# «выключено против включено».
eb["reasoning_effort"] = "high" eb["reasoning_effort"] = "high"
elif lvl == "vendor": elif lvl == "vendor":
# снимаем ЛЮБОЕ наше подавление: у Z.ai это `thinking.disabled`, у OpenAI — `effort: low` # снимаем ЛЮБОЕ наше подавление: у Z.ai это `thinking.disabled`, у OpenAI — `effort: low`

View file

@ -56,7 +56,7 @@
"api_key_env": "GEMINI_API_KEY", "api_key_env": "GEMINI_API_KEY",
"rps_delay": 1.0, "rps_delay": 1.0,
"max_tokens": 8000, "max_tokens": 8000,
"_comment": "МИГРИРОВАН 2026-07-10 (D21.9): gemini-2.5-flash EOL 16.10.2026 + интермиттентный 404-флейк → gemini-3.1-flash-lite (вендор-замена 2.5-flash-lite; НЕ 3.5-flash — та даёт 503 high-demand, проба research/15 + live-смоук 07-10). Live-смоук 07-10: finish=stop, thinking не съедает бюджет на коротком выходе → thinking_config НЕ нужен (прежний extra_body был ДВОЙНО ВЛОЖЕН extra_body.extra_body.google — на провод не уходил, баг убран). safety_settings через OpenAI-слой НЕ передаются (400 Unknown name); дефолт фильтров 3.x зависит от класса: SAFETY конфигурируем, PROHIBITED_CONTENT — НЕТ (00-provider-quirks). Для явного контроля фильтров судьи 18+ → нативный Gemini API." "_comment": "МИГРИРОВАН 2026-07-10 (D21.9): gemini-2.5-flash EOL 16.10.2026 + интермиттентный 404-флейк → gemini-3.1-flash-lite (вендор-замена 2.5-flash-lite; НЕ 3.5-flash — та даёт 503 high-demand, проба research/15 + live-смоук 07-10). Live-смоук 07-10: finish=stop, thinking не съедает бюджет на коротком выходе → thinking_config НЕ нужен ⛔ ПОПРАВКА 22.08: фраза «прежний extra_body был ДВОЙНО ВЛОЖЕН … баг убран» БЫЛА НЕВЕРНА — двойной ключ это и есть ВЕНДОРСКАЯ форма (ai.google.dev/gemini-api/docs/openai, 17.08.2026): Python-SDK раскладывает extra_body в верхний уровень тела, поэтому google-секция требует extra_body={'extra_body': {'google': …}}. Из этой ошибки выросло убеждение, что ручки размышления у Gemini нет; она есть. Штатная форма через слой — плоский reasoning_effort (у 3.x маппится в thinking_level). safety_settings через OpenAI-слой НЕ передаются (400 Unknown name); дефолт фильтров 3.x зависит от класса: SAFETY конфигурируем, PROHIBITED_CONTENT — НЕТ (00-provider-quirks). Для явного контроля фильтров судьи 18+ → нативный Gemini API."
}, },
{ {
"name": "openai", "name": "openai",