Initial import NDC_1C

This commit is contained in:
2026-03-26 10:38:25 +03:00
commit a162d77ef7
2943 changed files with 3615871 additions and 0 deletions
+772
View File
@@ -0,0 +1,772 @@
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 получал нормальный предметный профиль даже из кривого человеческого запроса.