TZ_LLM_Normalizer_v1.1.2.md Ниже даю **ТЗ на `normalizer_v1.1.2`** с комментариями — так, чтобы его можно было и отдать Codex, и потом нормально архивировать как понятный инженерный документ. --- # ТЗ: `normalizer_v1.1.2` ## Точечная доводка границы `heavy_analytical` ↔ `period_close_risk` --- ## 1. Контекст этапа На версии `normalizer_v1.1.1` удалось очень сильно улучшить рабочие свойства normalizer’а как предроутерного слоя: * `schema_validation_pass_rate = 100` * `route_hint_accuracy = 100` * `causal_flag_accuracy = 100` * `cross_entity = 100%` * `drilldown_explain = 100%` * `rule_based_account_control = 100%` * `period_close_risk = 100%` Однако при этом появился побочный перекос в taxonomy: * `intent_class_accuracy = 90` вместо `93.33` на `v1.1` * `heavy_analytical = 40%` * `high_confidence_error_rate = 3.33` вместо `0` Комментарий: Это означает, что версия `v1.1.1` **улучшила поведение normalizer’а как route/cause normalizer**, но при этом **слишком агрессивно начала относить heavy обзорные вопросы к `period_close_risk`**, если в формулировке есть слова про закрытие периода, отчётность или предзакрытие. --- ## 2. Что именно произошло Проблема локализована и понятна. ### Текущий корневой дефект В `developer prompt v1.1.1` есть правило, которое слишком жёстко задаёт: > если вопрос относится к предзакрытию, закрытию периода, сдаче отчётности, концу месяца или рискам последнего дня, primary intent должен быть `period_close_risk`, даже если требуется обзор или приоритизация. Комментарий: Это правило было добавлено, чтобы вылечить потерю `period_close_risk` внутри `heavy_analytical`. Но в текущем виде оно **перетянуло слишком много heavy overview вопросов в `period_close_risk`**. ### Дополнительный фактор В few-shot наборе есть пример на `period_close_risk`, но **нет достаточного симметричного набора примеров**, который бы показывал модели: * когда вопрос остаётся `heavy_analytical`, * даже если он сформулирован “перед закрытием периода” или “перед сдачей отчётности”. Комментарий: То есть у модели появился сильный positive-trigger на `period_close_risk`, но нет хорошего отрицательного противовеса. --- ## 3. Цель `v1.1.2` Сделать **узкий и безопасный patch**, который: 1. сохранит: * `route_hint_accuracy = 100` * `causal_flag_accuracy = 100` * `schema_validation_pass_rate = 100` * сильные результаты по `cross_entity`, `drilldown_explain`, `rule_based_account_control` 2. исправит: * taxonomy drift между `heavy_analytical` и `period_close_risk` * лишнюю high-confidence оценку на пограничных кейсах 3. не приведёт к деградации уже сильных зон. Комментарий: Это **не новый большой этап**, а именно **surgical patch**. Менять нужно **только границу intent-class**, а не общую архитектуру normalizer’а. --- ## 4. Scope этапа ### В scope входит * корректировка одного участка `developer prompt`; * добавление 2 симметричных few-shot примеров для `heavy_analytical`; * добавление 1 confidence-rule для пограничных кейсов; * очень короткий контрольный прогон на 5 кейсах. ### В scope не входит * изменение schema; * изменение route logic; * изменение cross-entity правил; * изменение drilldown правил; * изменение anomaly patch; * новый большой eval-run на 30+ кейсов; * новые данные/срезы/онтология. Комментарий: Данные и база сейчас не нужны. Проблема находится **целиком в prompt/taxonomy layer**. --- ## 5. Что именно нужно исправить --- ## 5.1. Паттерн A: `heavy_analytical` ошибочно уходит в `period_close_risk` ### Симптом На `v1.1.1` следующие кейсы получили неправильный `intent_class`: * `NQ-002` * `NQ-007` * `V11-HA-004` Во всех этих кейсах: * route правильный: `batch_refresh_then_store` * causal/requires нормальные * ошибка только в том, что `intent_class` стал `period_close_risk` вместо `heavy_analytical` ### Природа ошибки Вопросы содержат: * контекст закрытия периода, * июнь / предзакрытие / отчётность, но по сути просят: * обзор, * рейтинг, * summary, * общую картину, * концентрацию ошибок, * приоритизацию. Такие вопросы должны оставаться `heavy_analytical`. Комментарий: `period_close_risk` — это не “любой вопрос про период”, а **специальный класс про угрозу срыва закрытия**. Если в центре вопроса **обзор / рейтинг / агрегированный срез**, это должен быть `heavy_analytical`. --- ## 5.2. Паттерн B: high confidence на пограничном кейсе ### Симптом В кейсе `NQ-002`: * intent ошибочный, * route правильный, * confidence = `high` ### Природа ошибки Пограничные вопросы между: * `heavy_analytical` * `period_close_risk` не должны получать `high confidence`, если модель не различает класс уверенно. Комментарий: Даже если route совпадает, **ошибочно высокая уверенность на спорном intent — это риск для последующего управления качеством**. Эту часть нужно приглушить. --- # 6. Конкретные изменения для Codex --- ## 6.1. Изменить `developer prompt` ### Файл `prompts/developer/normalizer_v1_1_2.txt` ### Что сделать Переписать правило про `period_close_risk`. ### Текущее проблемное правило Смысл текущего правила: > если вопрос относится к предзакрытию/закрытию/отчётности/последнему дню, primary intent = `period_close_risk`, даже если нужен обзор или приоритизация. ### Новая правильная формулировка Вставить вместо него такой блок: ```text If a question is explicitly about period close risk, pre-close danger, last-day closing failure, reporting deadline risk, or threats that can break the close process itself, use `period_close_risk` as the primary intent_class. However, if the main purpose of the question is: - ranking, - top issues, - overview, - concentration of errors, - summary, - prioritized review list, - company-wide analytical review, then the primary intent_class should remain `heavy_analytical`, even if the question is phrased in the context of month-end close or reporting preparation. ``` ### Дополнительное уточнение Добавить ещё один отдельный блок: ```text `heavy_analytical` has priority over `period_close_risk` when the question asks for: - ranking, - top-N, - overview, - summary, - company-wide picture, - prioritized analytical review, even if the wording mentions closing period, reporting, or pre-close context. Use `period_close_risk` only when the core of the question is the risk of failing or destabilizing the close process itself. ``` Комментарий: Это главное исправление всей версии `v1.1.2`. Ничего сильнее менять не надо. --- ## 6.2. Добавить 2 симметричных few-shot примера ### Файл `prompts/fewshot/normalizer_fewshot_v1_1_2.txt` ### Что сделать Оставить existing few-shot на `period_close_risk`, но добавить **два примера-контрвеса**. --- ### Few-shot 1 — heavy remains heavy ```text Q: Сделай рейтинг самых рисковых хвостов перед закрытием периода за июнь. Expected: { "intent_class": "heavy_analytical", "requires": { "needs_cross_entity_join": false, "needs_causal_chain": false, "needs_exact_object_trace": false, "needs_ranking": true, "needs_anomaly_summary": false, "needs_runtime_truth": false, "needs_period_cut": true, "needs_evidence": false }, "expected_output_shape": "ranked_list", "route_hint": "batch_refresh_then_store" } ``` ### Few-shot 2 — overview remains heavy ```text Q: Дай обзорный риск-срез перед сдачей отчетности: где максимальная концентрация ошибок. Expected: { "intent_class": "heavy_analytical", "requires": { "needs_cross_entity_join": false, "needs_causal_chain": false, "needs_exact_object_trace": false, "needs_ranking": true, "needs_anomaly_summary": true, "needs_runtime_truth": false, "needs_period_cut": true, "needs_evidence": false }, "expected_output_shape": "anomaly_summary", "route_hint": "batch_refresh_then_store" } ``` ### Existing few-shot to keep Оставить пример: ```text Q: Перед закрытием периода что у нас может взорваться в последний день? Expected intent_class: period_close_risk ``` Комментарий: Эти два новых примера нужны не потому, что модель “тупая”, а потому, что в `v1.1.1` у неё был сильный пример только в одну сторону. `v1.1.2` должен сделать границу симметричной. --- ## 6.3. Добавить confidence-ограничение ### Файл `prompts/developer/normalizer_v1_1_2.txt` ### Что сделать Добавить явное правило: ```text If a question is plausibly on the boundary between `heavy_analytical` and `period_close_risk`, do not assign `confidence.overall = high`. Use `medium` unless the wording strongly and unambiguously centers on close-process failure risk rather than analytical overview. ``` Комментарий: Это страховка от кейса `NQ-002`, где route был правильный, но модель слишком самоуверенно выбрала спорный intent. --- # 7. Что нельзя менять Codex **запрещено**: 1. менять schema; 2. менять route rules; 3. трогать cross-entity prompt logic; 4. трогать drilldown prompt logic; 5. трогать anomaly/store_feature_risk patch; 6. добавлять много новых few-shot; 7. переписывать весь domain prompt; 8. делать большие prompt sweep’ы; 9. делать повторные API-запросы без необходимости. Комментарий: `v1.1.1` очень хорош по route/cause behavior. Наша задача — **не поломать working core ради косметики taxonomy**. --- # 8. Контрольный прогон ## Режим Только микро-прогон. ## Лимит * максимум **5 API-вызовов** * один кейс = один запрос * без повторов * `temperature = 0` ## Проверить только эти кейсы 1. `NQ-002` 2. `NQ-007` 3. `V11-HA-004` 4. `V11-OT-003` 5. `V11-OT-005` Комментарий: Этого достаточно. Три кейса проверяют boundary heavy/period-close. Два кейса проверяют, что `period_close_risk` мы не сломали обратно. --- # 9. Ожидаемый результат ## Минимально acceptable * `NQ-002` → `heavy_analytical` * `NQ-007` → `heavy_analytical` * `V11-HA-004` → `heavy_analytical` * `V11-OT-003` остаётся `period_close_risk` * `V11-OT-005` остаётся `period_close_risk` ## Дополнительно желательно * на пограничных кейсах confidence не `high`, а `medium` Комментарий: Если эти 5 кейсов проходят, значит `v1.1.2` делает ровно то, что нужно, и не требует нового полного 30-case eval прямо сейчас. --- # 10. Артефакты, которые должен выдать Codex 1. `docs/normalizer_v1_1_2_patch_notes.md` 2. `prompts/developer/normalizer_v1_1_2.txt` 3. `prompts/fewshot/normalizer_fewshot_v1_1_2.txt` 4. `reports/normalizer_v1_1_2_micro_eval.json` 5. `reports/normalizer_v1_1_2_micro_eval.md` --- # 11. Что должно быть в patch notes В `normalizer_v1_1_2_patch_notes.md` обязательно описать: * какая именно проблема была в `v1.1.1`; * почему она возникла; * какие prompt changes внесены; * какие few-shot added; * почему изменения безопасны; * сколько API-вызовов потрачено; * были ли ретраи; * результаты микро-прогона; * что осталось на будущее. Комментарий: Это нужно именно для архива и последующего контроля версий, чтобы потом было понятно, **почему `v1.1.2` вообще появился**. --- # 12. Приёмка этапа Этап считается принятым, если: 1. не превышен лимит в 5 API-вызовов; 2. `NQ-002`, `NQ-007`, `V11-HA-004` получают `intent_class = heavy_analytical`; 3. `V11-OT-003` и `V11-OT-005` остаются `period_close_risk`; 4. не возвращается лишний `high confidence` на пограничные heavy/period-close кейсы; 5. изменения зафиксированы прозрачно; 6. не сломаны уже сильные route/cause части normalizer’а. --- # 13. Короткий смысл этапа `v1.1.2` — это **не улучшение всей системы**, а **локальная шлифовка последнего taxonomy-boundary**. По сути задача одна: > Сохранить идеальное route/cause поведение `v1.1.1`, > но вернуть правильное именование там, где heavy overview был ошибочно засосан в period_close_risk. --- Если хочешь, я следующим сообщением сделаю ещё **ультра-короткую версию этого ТЗ для прямой вставки в Codex**, буквально как job prompt без пояснений.