TZ_LLM_Normalizer_v2.0.2.md Ниже даю **ТЗ на новый вариант — `Normalizer v2.0.2`**. Это уже не про “ещё лучше понять бухгалтерию”, а про **доводку устойчивости исполнения** после последнего жирного прогона. --- # ТЗ: `Normalizer v2.0.2` ## Stability / No-Route / Schema Hardening --- ## 1. Контекст этапа После перехода на `v2.0.1` система показала правильный вектор: * `schema_validation_pass_rate = 96.15` * `scope_in_scope_rate = 92.31` * `clarification_required_rate = 15.38` * `out_of_scope` отрабатывается * нормальные in-scope вопросы в большинстве случаев проходят без лишнего clarification Комментарий: Это уже лучше, чем бесконечный prompt-tuning `v1.x`, потому что новая схема стала: * устойчивее к новым формулировкам; * лучше разделять допустимый/недопустимый контур; * меньше душить нормальные вопросы уточнениями. Но после жирного прогона видны три конкретные проблемы: 1. `schema_validation_pass_rate` упала с 100 до 96.15 2. `no_route_fragment_rate = 20.69` — слишком много 3. часть внутренних состояний (`fallback_type`, `execution_readiness`, `soft_assumptions`) согласованы неидеально --- ## 2. Цель этапа Довести `v2.0.1` до более устойчивой рабочей версии `v2.0.2`, не меняя базовую архитектуру. Цели: * вернуть `schema_validation_pass_rate` к `100` * разобраться с природой `no_route` * сделать внутреннюю policy-логику согласованной * не сломать уже хорошие свойства: * scope gating * out-of-scope filtering * умеренный clarification rate * decomposition-first подход --- ## 3. Главный принцип этапа На этом этапе **не надо**: * снова тюнить под конкретные 26 вопросов; * переписывать всю prompt-логику; * возвращаться к `v1.x`; * пытаться “угадать всё лучше через ещё один prompt”. Нужно: * сделать систему **строже и честнее на уровне исполнения**; * понять, где `no_route` правильный, а где это недонастроенный mapping; * сделать output pipeline согласованным и стабильным. Комментарий: Это уже этап **операционной жёсткости**, а не “семантической магии”. --- # 4. Что именно надо чинить --- ## 4.1. Проблема A: schema validation не 100 ### Симптом В последнем прогоне: * `schema_validation_pass_rate = 96.15` * кейс `BQ-001` не прошёл валидацию * был retry (`request_count_for_case = 2`) ### Требование Нужно вернуть: * `schema_validation_pass_rate = 100` ### Что сделать 1. Разобрать `BQ-001` целиком: * raw question * raw model output * parsed object * validation error * retry output 2. Выявить точную причину: * field missing * wrong enum * wrong nested type * prompt overflow / malformed json * parser inconsistency 3. Исправить причину на системном уровне, а не точечно под кейс. ### Ожидаемый артефакт Файл: `docs/v2_0_2_schema_forensic.md` Комментарий: Schema loss даже в одном кейсе — это нельзя игнорировать. Это технический риск уровня “сломается в проде в неожиданный момент”. --- ## 4.2. Проблема B: слишком много `no_route` ### Симптом * `no_route_fragment_rate = 20.69` * `route_distribution.no_route = 6` ### Требование Разделить все `no_route` случаи на две категории: ### A. Legit no-route Когда реально нельзя безопасно отправить дальше: * fragment out-of-scope; * fragment слишком неопределённый; * fragment требует clarification; * fragment семантически распознан, но не относится к исполняемому бухгалтерскому действию. ### B. Missing route mapping Когда fragment уже in-scope и достаточно понятен, но код не умеет подобрать маршрут. ### Что сделать 1. Выгрузить все fragments с `no_route` 2. Для каждого сделать ручную классификацию: * `legit_no_route` * `missing_mapping` 3. Если это `missing_mapping`, добавить deterministic mapping rule 4. Если это `legit_no_route`, зафиксировать policy явно ### Ожидаемый артефакт Файл: `docs/v2_0_2_no_route_audit.md` Комментарий: Сейчас `no_route` — это ещё слишком “чёрный ящик”. Нужно сделать так, чтобы каждый такой случай был объясним. --- ## 4.3. Проблема C: несогласованность execution state ### Симптом Есть кейсы, где: * `fallback_type = none` * `predicted_clarification_required = false` * но `executable_with_soft_assumptions_fragments = 0` Например: * `BQ-007` * `BQ-024` ### Что это значит Внутренняя state machine не полностью согласована. ### Требование Согласовать следующие статусы между собой: * `domain_relevance` * `execution_readiness` * `predicted_clarification_required` * `fallback_type` * `route_decision` * `soft_assumption_used` ### Целевая логика Если fragment: * in-scope * не clarification * не out-of-scope * и route выбран то должно быть явно видно: * либо `execution_readiness = executable` * либо `execution_readiness = executable_with_soft_assumptions` Не должно быть “исполняем, но readiness не поднят”. ### Ожидаемый артефакт Файл: `docs/v2_0_2_execution_state_machine.md` --- # 5. Что изменить в схеме ## 5.1. Явно ввести `execution_readiness` Если ещё не введено как обязательное поле — сделать обязательным. ```json id="mgbtkn" { "execution_readiness": "executable | executable_with_soft_assumptions | needs_clarification | no_route" } ``` ## 5.2. Явно ввести `route_status` ```json id="6sdd3j" { "route_status": "routed | no_route" } ``` ## 5.3. Явно ввести `no_route_reason` Если `route_status = no_route`, обязателен reason: ```json id="y0eqbg" { "no_route_reason": "out_of_scope | insufficient_specificity | missing_mapping | unsupported_fragment_type" } ``` Комментарий: Это очень важно. Без этого вы будете бесконечно смотреть на `no_route` как на аморфную массу. --- # 6. Что изменить в коде --- ## 6.1. Добавить post-normalization state resolver Сделать отдельный кодовый слой после ответа LLM: ```text id="kcynfd" resolve_fragment_execution_state(fragment, session_context) -> resolved_fragment ``` Он должен: 1. нормализовать readiness; 2. нормализовать route_status; 3. ставить `no_route_reason`; 4. приводить `fallback_type` в согласованное состояние. --- ## 6.2. Ввести deterministic `no_route` policy Если fragment: * in-scope * и не clarification * и есть достаточно route-critical flags то `no_route` запрещён. В таком случае должен выбираться маршрут. `no_route` разрешён только если: * fragment реально вне контура; * fragment реально недостаточно определён; * fragment unsupported by current route map. --- ## 6.3. Добавить trace completeness check Сейчас у вас раньше был кейс с пустым trace view. Нужно проверить, что для каждого run сохраняется: * raw input * raw model output * parsed fragments * resolved execution state * final route per fragment Если trace неполный — логировать это как системную ошибку. --- # 7. Что изменить в prompt’ах На этом этапе prompt менять минимально. Нужно только: * добавить требование, чтобы fragment-level output был полным и непротиворечивым; * не трогать общий semantic слой без нужды. ### Добавить в developer prompt ```text id="xlg5ut" Every in-scope fragment must produce a consistent execution state. If a fragment is routable, mark it as executable or executable_with_soft_assumptions. Do not leave routable fragments in an unresolved execution state. If a fragment cannot be routed, provide an explicit no_route_reason. ``` Комментарий: Это не semantic tuning, а дисциплина output’а. --- # 8. Новый eval для `v2.0.2` Нужен уже не просто набор “сложных вопросов”, а **размеченный eval по policy**. ## 8.1. Состав eval Собрать 20 кейсов: ### Блок A — routable in-scope 8 кейсов Ожидание: * in-scope * no clarification * route selected * no `no_route` ### Блок B — legit clarification 4 кейса Ожидание: * in-scope * clarification needed ### Блок C — out-of-scope 4 кейса Ожидание: * out-of-scope * no route * fallback out_of_scope ### Блок D — borderline / soft assumptions 4 кейса Ожидание: * in-scope * executable_with_soft_assumptions * route selected --- ## 8.2. Новые метрики Обязательно считать: * `schema_validation_pass_rate` * `scope_detection_accuracy` * `route_resolution_accuracy` * `no_route_precision` * `false_no_route_rate` * `execution_state_consistency_rate` * `clarification_precision` * `clarification_recall` --- # 9. Целевые показатели Минимально приемлемо: * `schema_validation_pass_rate = 100` * `execution_state_consistency_rate >= 95` * `false_no_route_rate <= 10` * `route_resolution_accuracy` заметно выше текущего * `clarification_required_rate` не выше текущего на in-scope одноходовых кейсах Хорошо: * `false_no_route_rate <= 5` * `execution_state_consistency_rate = 100` --- # 10. Что нельзя делать Codex запрещено: 1. снова возвращать один главный `intent_class` как основу всего; 2. снова лечить всё через few-shot под эти 26 вопросов; 3. занижать `no_route` искусственно, просто проставляя маршрут куда угодно; 4. выключать fallback/out-of-scope; 5. игнорировать единичный schema fail как “неважный”. --- # 11. Артефакты Codex должен выдать: 1. `docs/v2_0_2_schema_forensic.md` 2. `docs/v2_0_2_no_route_audit.md` 3. `docs/v2_0_2_execution_state_machine.md` 4. `schemas/normalized_query_v2_0_2.json` 5. `prompts/developer/normalizer_v2_0_2.txt` 6. `reports/v2_0_2_eval_plan.md` --- # 12. Короткий смысл этапа `v2.0.2` — это версия не про “лучше понимать язык”, а про: * **не ломать схему** * **не терять route без объяснения** * **сделать внутренние состояния честными и жёсткими** * **перестать иметь серые зоны между clarification / no-route / executable** --- # 13. Практический итог После `v2.0.2` вы должны получить систему, где для каждого fragment всегда понятно: * он в контуре или нет; * он исполним или нет; * если не исполним — почему; * если исполним — с какими допущениями; * какой route выбран; * если route не выбран — по какой строго указанной причине. Это уже будет нормальный инженерный фундамент, а не “LLM что-то там решила”. ---