TZ_Assistant_Mode_retrievalLAYER.md Да. Ниже даю **расширенный набор правил для retrieval/execution layer** именно под бухгалтерский контекст, чтобы `executeHybrid` и соседние executors не жили на одном `GUID` и одном `account_hint`, а реально тащили **избыточный набор ограничений и признаков**. Это прямо ложится на ваш текущий контур `route-specific retrieval` и `unified result schema`, который уже зафиксирован в vNext ТЗ. Это не замена normalizer, а **расширение retrieval contract**: LLM/normalizer должен отдавать не только route, но и плотный набор бухгалтерских ограничителей, а retrieval обязан их исполнять. --- # Расширение правил retrieval-слоя под бухгалтерский контекст ## 1. Главный принцип Для бухгалтерского ассистента **нельзя** строить retrieval только по: * `guid` * `account_hint` * общему route * одной сущности верхнего уровня Retrieval должен работать по **многослойному бухгалтерскому профилю запроса**. Минимальный обязательный набор слоёв: 1. **счета / субсчета** 2. **тип участка учёта** 3. **тип документов** 4. **тип движения** 5. **тип связи между сущностями** 6. **тип аномалии / конфликта** 7. **период** 8. **контрагент / договор / объект / номенклатура / ОС / статья / подразделение** 9. **стадия жизненного цикла** 10. **исключающие условия** 11. **приоритет ранжирования** 12. **ожидаемый тип объяснения** --- ## 2. Новый обязательный retrieval contract Каждый routed fragment должен передаваться в executor не в виде “route + hints”, а в виде расширенного `semantic_retrieval_profile`. Примерно так: ```json { "fragment_id": "F1", "route": "hybrid_store_plus_live", "query_subject": "bank_settlement_mismatch", "account_scope": ["51", "60"], "subaccount_scope": [], "domain_scope": ["bank", "settlements", "supplier_payments"], "document_types": ["bank_statement", "payment_order", "receipt", "settlement_document"], "entity_types": ["counterparty", "contract", "document", "posting"], "period_scope": { "from": null, "to": null, "granularity": "month" }, "relation_patterns": [ "document_to_posting", "payment_to_settlement", "statement_to_document" ], "lifecycle_stage_filters": [ "created", "posted", "closed", "reconciled" ], "anomaly_patterns": [ "missing_link", "wrong_document_type", "broken_closure", "posting_mismatch" ], "ranking_basis": [ "financial_impact", "repeatability", "closure_risk" ], "excluded_interpretations": [ "simple_payment_delay", "amount_only_anomaly" ], "explanation_focus": [ "why_selected", "where_chain_breaks", "what_business_risk" ] } ``` --- ## 3. Общие правила для всех retrieval executor’ов ## 3.1. Поиск всегда строится не по одному измерению, а по пересечению признаков Использовать одновременно: * счёт * тип документа * статус документа * связанную проводку * период * предметную область * relation pattern * anomaly pattern Недопустимо: если нет `guid`, снимать ограничения и лить в ответ весь массив. Если `guid` нет, retrieval должен переходить на **semantic narrowing**, а не на `full scan without accounting discrimination`. --- ## 3.2. Любой account hint должен разворачиваться в бухгалтерский контекст Если в вопросе или normalizer output есть `51`, этого недостаточно. Нужно автоматически достраивать: * bank domain * возможные документы: выписка, платежное поручение, списание с р/с, поступление на р/с * возможные связи: банк → документ → проводка → расчётный контур * возможные конфликты: документ есть / нет, проводка есть / нет, не тот тип документа, неверный контур закрытия То есть `51` — это не фильтр, а **семантический вход в набор поисковых правил**. --- ## 3.3. Если вопрос про аномалию, нельзя ранжировать только по сумме Если пользователь не просил explicitly “самые большие суммы”, то anomaly retrieval обязан учитывать не только money magnitude, но и: * отсутствие связанной записи; * рассогласование между документом и проводкой; * нарушение жизненного цикла; * повторяемость отклонения; * влияние на закрытие периода; * несоответствие карточки и движения; * конфликт между участками учёта. --- ## 3.4. Если вопрос про цепочку, retrieval должен искать разрыв, а не просто соседние документы Для `hybrid_store_plus_live` поиск обязан различать: * наличие документов в цепочке; * корректность связей между ними; * полноту прохождения этапов; * расхождение статусов; * конфликт проводки и первички; * отсутствие ожидаемого продолжения; * наличие “ложного закрытия” не тем документом. Это соответствует самой идее `hybrid_store_plus_live` в вашем vNext ТЗ: causal / cross-entity / chain queries должны возвращать связи, документы, оплаты, проводки и признаки разрыва цепочки. --- # 4. Расширенные бухгалтерские измерения для retrieval ## 4.1. Слой счетов Нужно учитывать не только основной счёт, но и: * корреспондирующие счета; * типовой соседний контур; * признак “счёт упомянут явно” vs “счёт выведен косвенно”; * приоритет основного счёта; * исключённые счета. ### Примеры: * `51` → банк, движения ДС, документы банка, платежи, выписки * `60` → поставщики, расчёты, закрытие обязательств * `62` → покупатели, выручка, оплаты, задолженность * `76` → прочие расчёты, подвешенные взаимосвязи, нестандартные хвосты * `97` → расходы будущих периодов, сроки списания, график, корректность продолжения жизненного цикла * `01/02/08` → ОС, ввод в эксплуатацию, амортизация, капитальные вложения, карточка объекта * `19/68` → НДС, принятие к вычету, книга покупок/продаж, закрытие налогового контура * `10/41/43` → ТМЦ, товар, выпуск, остатки, движение запасов * `20/23/25/26/44` → затраты, распределение, закрытие, себестоимость --- ## 4.2. Слой участков учёта Для каждого запроса нужно фиксировать `domain_scope`: * банк * поставщики * покупатели * склад / запасы * ОС * НМА * РБП * НДС * зарплата * затраты * закрытие периода * прочие расчёты * договорной контур * авансы * налоги * денежные документы * касса * производство Это нужно, чтобы один и тот же счёт не тянул нерелевантный участок. --- ## 4.3. Слой документов Retrieval обязан учитывать тип документа как first-class filter. Категории: * банковская выписка * платежное поручение * поступление товаров/услуг * реализация * счет-фактура * корректировка * акт сверки * авансовый отчет * кассовый ордер * ввод в эксплуатацию ОС * принятие к учету ОС * начисление амортизации * списание РБП * закрытие месяца * регламентная операция * ручная операция * корректировка долга * перемещение / списание / оприходование ТМЦ Если пользователь спрашивает про “не тем документом закрыто”, retrieval обязан искать **ошибочный тип документа в ожидаемой цепочке**, а не просто все связанные документы. --- ## 4.4. Слой сущностей Поддерживать entity filters: * контрагент * договор * организация * документ * проводка * номенклатура * склад * подразделение * сотрудник * объект ОС * статья затрат * проект * заказ * налоговая запись * регистр/движение * период закрытия Если вопрос multi-entity, retrieval обязан различать **главную сущность** и **подтверждающие сущности**. --- ## 4.5. Слой жизненного цикла Очень важный слой. Почти все хорошие бухгалтерские аномалии — это не “не та сумма”, а **сломанный lifecycle**. Для каждой сущности retrieval должен пытаться определить стадию: * создан * проведён * не проведён * частично связан * закрыт * не закрыт * сторнирован * отменён * завис * повторён * перенесён * закрыт не тем документом * есть продолжение / нет продолжения * цепочка оборвана * финальный статус противоречит промежуточным движениям Это особенно критично для: * 97 * ОС * поставщики/авансы * НДС * закрытие периода * расчёты по 60/62/76 --- # 5. Набор anomaly patterns, которые надо заложить в retrieval Ниже даю именно как **словарь аномалий**, который можно использовать в `semantic_retrieval_profile.anomaly_patterns`. ## 5.1. Missing link Ожидаемая связь между сущностями отсутствует. Примеры: * документ есть, проводки нет; * платёж есть, закрывающего документа нет; * ОС есть, начисления есть/нет, но карточка не бьётся; * запись в одном контуре есть, в смежном нет. ## 5.2. Wrong document type Закрытие, отражение или продолжение прошло не тем типом документа. ## 5.3. Broken lifecycle Объект застрял между стадиями. ## 5.4. Posting mismatch Проводка не соответствует документу, счёту, участку или ожидаемому направлению движения. ## 5.5. Cross-domain inconsistency Один участок говорит одно, другой — другое. Примеры: * банк подтверждает движение, расчётный контур не закрылся; * документ прихода есть, складское движение не совпадает; * ОС в карточке в одном статусе, амортизационный контур в другом. ## 5.6. Closure risk Запись влияет на корректность закрытия периода. ## 5.7. Repeated anomaly Одна и та же проблема повторяется серийно. ## 5.8. Silent orphan Запись выглядит спокойной по сумме, но сиротская по связям и жизненному циклу. ## 5.9. Amount-independent risk Риск не по величине суммы, а по структуре нарушения. ## 5.10. Manual intervention suspicion Есть признаки ручной коррекции, нестандартной операции или обходного закрытия. --- # 6. Правила дифференциации по ключевым бухгалтерским зонам ## 6.1. Банк / 51 Если запрос касается 51, retrieval должен автоматически учитывать: * банковские документы; * платежные поручения; * выписки; * приход/расход ДС; * связанный расчётный контур; * закрытие обязательства; * аванс / оплата / зачет; * корреспондирующие счета; * совпадение назначения платежа и учетного отражения; * факт отражения в выписке; * факт проведения документа; * разрыв между движением денег и закрытием расчета. ### Специальные паттерны: * оплата есть, закрытия обязательства нет; * выписка есть, документ-основание не найден; * движение пошло не в тот договор / не в того контрагента; * банк закрылся, а расчеты зависли; * проблема не в платеже, а в документе, который интерпретировал платёж. --- ## 6.2. Поставщики / 60 Учитывать: * контрагент; * договор; * документ поступления; * оплата; * зачет аванса; * закрытие обязательства; * просроченный хвост; * расхождение по актам/счётам/поступлению/оплате; * зависшие незакрытые позиции; * повторяемость по контрагенту; * влияние на закрытие периода. ### Специальные паттерны: * хвост без движения после оплаты; * поступление есть, расчёт не закрылся; * аванс есть, поставка не бьётся; * несколько документов спорят за одну оплату; * один контрагент серийно создаёт одинаковый дефект. --- ## 6.3. Покупатели / 62 Учитывать: * реализация; * оплата; * аванс; * зачет; * дебиторка; * договор; * закрытие выручки; * документ основания; * банковое подтверждение; * НДС-связка. ### Паттерны: * оплата есть, реализация не закрылась; * аванс завис; * дебиторка выглядит искусственно живой; * проводка есть, но цепочка первички неполна. --- ## 6.4. Прочие расчёты / 76 Зона повышенного риска. Retrieval должен относиться к 76 как к зоне, где часто лежат: * нестандартные хвосты; * временные костыли; * переходные записи; * плохо закрытые взаимосвязи. Нужны более жёсткие правила на: * давность; * отсутствие продолжения; * слабую связанность; * нетипичный тип документа; * ручные операции; * странные корреспонденции. --- ## 6.5. РБП / 97 Если запрос про 97, retrieval обязан смотреть не только остаток и сумму, но и: * дату возникновения; * срок списания; * график списания; * факт начала списания; * факт завершения списания; * разрыв между сроком и поведением записи; * документ-источник; * связанный объект/основание; * продолжение жизненного цикла. ### Паттерны: * запись давно живёт, но логика списания не выполняется; * срок наступил, движения нет; * объект уже должен был перейти в другой статус; * карточка/основание есть, но дальше жизни нет; * запись выглядит закрытой формально, но по связанным движениям не завершена. --- ## 6.6. ОС / 01 / 02 / 08 Retrieval обязан учитывать: * карточку ОС; * документ принятия к учету; * ввод в эксплуатацию; * инвентарный объект; * амортизацию; * счет 08 как источник; * корректность перехода 08 → 01; * статус эксплуатации; * списание/выбытие; * соответствие карточки и начислений. ### Паттерны: * объект заведен, но lifecycle не доведён; * амортизация идет/не идет в противоречии со статусом; * карточка есть, движений недостаточно; * ввод в эксплуатацию и отражение по счетам не совпадают; * объект сиротский по связям. --- ## 6.7. НДС / 19 / 68 Учитывать: * счёт-фактура; * поступление/реализация; * принятие к вычету; * книга покупок/продаж; * период вычета; * отражение в налоговом контуре; * связь с первичкой; * расхождение между бухгалтерским и налоговым отражением. ### Паттерны: * НДС висит без нормального продолжения; * документ есть, вычет не бьётся; * вычет попал не в тот период; * запись живёт без подтверждающей цепочки; * топ по НДС не должен подменять вопросы про ОС или банк. --- ## 6.8. Закрытие периода Если пользователь спрашивает о проблемах, “ломающих период”, retrieval должен повышать вес признаков: * незакрытый хвост; * конфликт между участками; * документ/движение в граничных датах; * сиротские остатки; * серия однотипных нарушений; * объекты, затрагивающие регламентные операции; * следы ручных коррекций; * зависшие авансы/расчёты/РБП/ОС. --- # 7. Правила relation patterns для hybrid / chain retrieval Для `executeHybrid` нужны предопределённые relation patterns. ## 7.1. payment_to_settlement Платёж ↔ расчёт ↔ закрытие обязательства ## 7.2. document_to_posting Документ ↔ проводка ## 7.3. statement_to_document Банковская выписка ↔ внутренний документ ## 7.4. asset_card_to_depreciation Карточка ОС ↔ начисление амортизации ## 7.5. deferred_expense_to_writeoff РБП ↔ график/списание ## 7.6. invoice_to_vat Первичка ↔ счёт-фактура ↔ НДС ## 7.7. receipt_to_stock_movement Поступление ↔ складское движение ## 7.8. contract_to_documents Договор ↔ серия документов / хвостов / закрытий Если route chain-based, executor должен явно понимать, **какой relation pattern проверяет**, а не просто тянуть “всё около темы”. --- # 8. Правила ранжирования Нужен не один ranking score, а составной. ## 8.1. Базовые факторы ранжирования * финансовое влияние * давность * повторяемость * степень незавершённости lifecycle * количество сломанных связей * влияние на закрытие периода * пересечение с несколькими участками учёта * типовая/нетиповая проводка * ручное вмешательство * наличие противоречащих документов * отсутствие ожидаемого продолжения ## 8.2. Важное правило Если пользователь спрашивает “не по сумме, а по риску”, то фактор суммы не должен быть доминирующим. --- # 9. Excluded interpretations — обязательный блок Очень полезный слой. Чтобы retrieval не ехал в ближайшую похожую тему, надо явно передавать, **что нельзя считать ответом**. Примеры: * не считать любую большую сумму аномалией; * не сводить вопрос про ОС к НДС; * не сводить вопрос про 51 к рейтингу контрагентов вообще; * не считать любой незакрытый документ доказательством хвоста без проверки связи; * не отвечать на вопрос про lifecycle просто списком документов; * не подменять “не тем документом закрыто” на “есть документы по контрагенту”. --- # 10. Что добавить в executeHybrid прямо практически Ниже уже почти как техзадание на реализацию. ## 10.1. Если GUID нет, не брать весь набор данных Вместо этого строить фильтрацию по пересечению: * `account_scope` * `domain_scope` * `document_types` * `entity_types` * `relation_patterns` * `anomaly_patterns` * `period_scope` * `excluded_interpretations` ## 10.2. Ввести `query_subject` Категории верхнего уровня, например: * `bank_settlement_mismatch` * `supplier_tail_analysis` * `customer_closure_gap` * `deferred_expense_lifecycle_anomaly` * `fixed_asset_card_mismatch` * `vat_chain_conflict` * `period_closure_risk` * `cross_entity_breakage` * `document_posting_conflict` ## 10.3. Ввести `explanation_focus` Чтобы retrieval сразу собирал evidence под тип ответа: * `why_selected` * `where_chain_breaks` * `why_risky` * `why_not_closed` * `why_ranked_high` * `what_conflicts_with_what` ## 10.4. Ввести `evidence pack` На каждый top item возвращать не только сущность, но и: * ключевой счёт * документ * статус * связанная проводка * отсутствующая связь * lifecycle gap * period impact * selection_reason * business_interpretation --- # 11. Что добавить в result schema Расширить unified result schema, чтобы answer composer мог собирать нормальный ответ по сути, а не по name/count/id. Это согласуется с вашим целевым слоем `Result normalization` и `Final Answer Composer`. ```json { "fragment_id": "F1", "route": "hybrid_store_plus_live", "status": "ok", "result_type": "chain", "items": [ { "entity_type": "counterparty", "entity_id": "....", "label": "ООО ...", "account_context": ["51", "60"], "document_context": ["bank_statement", "payment_order"], "selection_reason": [ "оплата отражена", "закрывающий документ не подтвержден", "цепочка расчета оборвана" ], "risk_factors": [ "broken_lifecycle", "missing_link", "closure_risk" ], "business_interpretation": "деньги прошли, но обязательство не закрылось корректно", "evidence": [], "confidence": "medium" } ], "summary": { "ranking_basis": ["closure_risk", "repeatability", "financial_impact"] }, "errors": [] } ``` --- # 12. Минимальный набор бухгалтерских правил, который я бы считал must-have Если прямо урезать до ядра, то retrieval должен обязательно учитывать: 1. `account_scope` 2. `domain_scope` 3. `document_types` 4. `entity_types` 5. `relation_patterns` 6. `anomaly_patterns` 7. `lifecycle_stage_filters` 8. `period_scope` 9. `excluded_interpretations` 10. `ranking_basis` 11. `explanation_focus` Без этого вы снова получите: нормализатор понял вопрос, route выбрали правильно, а retrieval принёс один и тот же массив “вокруг темы”. --- # 13. Короткая формулировка для команды Если тебе нужен короткий месседж в работу, то вот он: **Нужно расширить executeHybrid и соседние retrieval executors от модели “GUID-or-full-scan” к модели “semantic retrieval profile”. Фильтрация должна строиться не только по счету, но и по участку учёта, типам документов, типам сущностей, relation patterns, lifecycle stage, anomaly patterns, excluded interpretations и ranking basis. Если GUID отсутствует, executor не имеет права брать весь датасет; он обязан делать semantic narrowing по бухгалтерскому профилю запроса.** --- # 14. Что я бы добавил ещё сверх этого Отдельно заложить в retrieval слой: * транслит-нормализацию бухгалтерских терминов до исполнения; * словарь синонимов по участкам учёта; * бухгалтерские alias-паттерны: “хвост”, “зависло”, “не бьётся”, “не тем закрылось”, “жизни не случилось”, “сломало период”, “сирота”, “висит”, “криво пошло”; * map “бытовой язык → retrieval constraints”. Это уже не про answer composer, а про то, чтобы retrieval получал нормальный предметный профиль даже из кривого человеческого запроса.