АДРЕСНЫЙ РЕЖИМ - M2.3b тюнинг account-scope и диагностика стадий адресного рантайма
This commit is contained in:
@@ -0,0 +1,701 @@
|
||||
TZ_address_query_runtime_V1_MCP.md
|
||||
|
||||
## Project Sync Override (2026-03-29)
|
||||
|
||||
Этот документ используется в связке с:
|
||||
|
||||
- `docs/ADDRESS/tz/TZ_address_query_runtime_V1_MCP_SYNC_2026-03-29.md`
|
||||
|
||||
Критичная фиксация для текущего проекта:
|
||||
|
||||
- мобильный интерфейс **не входит** в scope реализации;
|
||||
- диалог ведется через существующую оболочку ассистента;
|
||||
- поддерживаются короткие разговорные формулировки, но без отдельной mobile UI ветки.
|
||||
|
||||
## Контекст
|
||||
|
||||
По проекту уже подготовлен bootstrap-пакет в `docs/ADDRESS`:
|
||||
|
||||
* карта сущностей по snapshot 2020;
|
||||
* матрица address-сценариев;
|
||||
* каталог фильтров и recipe draft;
|
||||
* план интеграции `question_mode=address_query`;
|
||||
* сводный bootstrap report.
|
||||
|
||||
Этот пакет считается baseline и **не переписывается с нуля**.
|
||||
Новая задача — перейти от проектного пакета к **реальному внедрению runtime-слоя**.
|
||||
|
||||
---
|
||||
|
||||
## Ключевая архитектурная идея
|
||||
|
||||
Нужно реализовать **не изолированный address-остров**, а **общий semantic/query foundation layer**, который включает:
|
||||
|
||||
1. каталог сущностей;
|
||||
2. каталог фильтров;
|
||||
3. нормализацию пользовательских названий;
|
||||
4. resolver’ы name -> id / alias -> canonical entity;
|
||||
5. whitelist query recipes;
|
||||
6. общий result contract.
|
||||
|
||||
На первом этапе этот foundation layer используется для `question_mode=address_query`.
|
||||
|
||||
В будущем этот же слой должен быть пригоден для:
|
||||
|
||||
* deep-analysis маршрутов,
|
||||
* controlled drilldown,
|
||||
* guided factual reasoning поверх live/MCP.
|
||||
|
||||
---
|
||||
|
||||
## Главная цель этапа
|
||||
|
||||
Реализовать V1 отдельного runtime-контура для быстрых адресных вопросов к 1С через MCP, при этом:
|
||||
|
||||
* **не ломать** существующий deep-analysis pipeline;
|
||||
* **не дублировать** сущностную модель в двух местах;
|
||||
* **не открывать** свободный natural-language query builder;
|
||||
* дать пользователю в текущей оболочке ассистента возможность задавать короткие поисковые вопросы типа:
|
||||
|
||||
* “кто должен нам на сегодня”
|
||||
* “покажи хвосты по альфе”
|
||||
* “найди платежи по договору такому-то”
|
||||
* “проверь, какие документы формируют остаток”
|
||||
* “по 60 счету что висит на текущую дату”
|
||||
|
||||
---
|
||||
|
||||
## Что уже считать входными материалами
|
||||
|
||||
Перед началом реализации использовать как source of truth следующие документы из `docs/ADDRESS/address_query/`:
|
||||
|
||||
* `entity_map_1c_2020.md`
|
||||
* `address_scenario_matrix.md`
|
||||
* `query_recipes_v1.md`
|
||||
* `runtime_integration_plan.md`
|
||||
* `address_query_bootstrap_report_2026-03-29.md`
|
||||
|
||||
Нужно опираться на них, а не проектировать заново поверх пустого места.
|
||||
|
||||
---
|
||||
|
||||
# 1. Что нужно реализовать
|
||||
|
||||
## 1.1. Общий semantic/query foundation layer
|
||||
|
||||
Нужно ввести общий слой, который станет основой для address-runtime.
|
||||
|
||||
### В состав foundation layer должны войти:
|
||||
|
||||
#### A. Entity Registry
|
||||
|
||||
Единый реестр сущностей, доступных для запроса.
|
||||
|
||||
Для каждой сущности:
|
||||
|
||||
* `entity_family`
|
||||
* `entity_name`
|
||||
* `business_label`
|
||||
* `description`
|
||||
* `priority`
|
||||
* `query_suitability`
|
||||
* `key_fields`
|
||||
* `filterable_fields`
|
||||
* `relations`
|
||||
* `readiness`
|
||||
* `source_origin`
|
||||
|
||||
#### B. Alias / Label Normalization Layer
|
||||
|
||||
Нужно предусмотреть слой нормализации пользовательских названий.
|
||||
|
||||
Например:
|
||||
|
||||
* “контрагент”
|
||||
* “договор”
|
||||
* “60 счет”
|
||||
* “реализация”
|
||||
* “платежка”
|
||||
* “банковская выписка”
|
||||
* “хвосты”
|
||||
* “долг”
|
||||
* “дебиторка”
|
||||
* “кредиторка”
|
||||
|
||||
Должны приводиться к каноническим сущностям / filter tokens / intents.
|
||||
|
||||
Отдельно учесть:
|
||||
|
||||
* декодирование mojibake-labels из snapshot mapping;
|
||||
* синонимы;
|
||||
* бухгалтерские разговорные формулировки;
|
||||
* краткие разговорные запросы без строгой терминологии.
|
||||
|
||||
#### C. Resolver Layer
|
||||
|
||||
Нужны resolver’ы, которые переводят слова пользователя в реальные объекты.
|
||||
|
||||
Минимально:
|
||||
|
||||
* `counterpartyResolver`
|
||||
* `contractResolver`
|
||||
* `organizationResolver`
|
||||
* `accountResolver`
|
||||
* `documentTypeResolver`
|
||||
* `bankAccountResolver`
|
||||
|
||||
Выход:
|
||||
|
||||
* `resolved_value`
|
||||
* `resolved_id/ref`
|
||||
* `confidence`
|
||||
* `ambiguous_candidates[]`
|
||||
|
||||
#### D. Filter Catalog
|
||||
|
||||
Единый каталог поддерживаемых фильтров.
|
||||
|
||||
Минимум:
|
||||
|
||||
* `as_of_date`
|
||||
* `period_from`
|
||||
* `period_to`
|
||||
* `organization`
|
||||
* `counterparty`
|
||||
* `contract`
|
||||
* `account`
|
||||
* `document_type`
|
||||
* `document_ref`
|
||||
* `bank_account`
|
||||
* `posted`
|
||||
* `status`
|
||||
* `limit`
|
||||
* `sort`
|
||||
|
||||
#### E. Recipe Catalog
|
||||
|
||||
Только whitelist recipes.
|
||||
|
||||
Для каждого recipe:
|
||||
|
||||
* `recipe_id`
|
||||
* `intent`
|
||||
* `purpose`
|
||||
* `required_filters`
|
||||
* `optional_filters`
|
||||
* `resolver_dependencies`
|
||||
* `result_schema`
|
||||
* `sort_rules`
|
||||
* `limit_rules`
|
||||
* `drilldown_targets`
|
||||
* `mcp_template_id`
|
||||
|
||||
#### F. Unified Result Contract
|
||||
|
||||
Единый контракт ответа:
|
||||
|
||||
* `FACTUAL_LIST`
|
||||
* `FACTUAL_SUMMARY`
|
||||
* `LIMITED_WITH_REASON`
|
||||
|
||||
---
|
||||
|
||||
# 2. Что нужно реализовать в runtime
|
||||
|
||||
## 2.1. Отдельный `question_mode=address_query`
|
||||
|
||||
В текущий assistant pipeline добавить ранний mode-routing:
|
||||
|
||||
* `address_query`
|
||||
* `deep_analysis`
|
||||
* `unsupported`
|
||||
|
||||
### Правило
|
||||
|
||||
Если вопрос относится к поисковому factual lookup, он должен идти в `address_query`.
|
||||
|
||||
Если вопрос требует объяснения причин, доказательства, анализа ошибок учета или длинного reasoning — он должен уходить в deep-path.
|
||||
|
||||
---
|
||||
|
||||
## 2.2. Address intent resolver
|
||||
|
||||
Нужно реализовать определение address-intent.
|
||||
|
||||
### P0 intents
|
||||
|
||||
* `list_open_contracts`
|
||||
* `list_payables_counterparties`
|
||||
* `list_receivables_counterparties`
|
||||
* `account_balance_snapshot`
|
||||
* `open_items_by_counterparty_or_contract`
|
||||
|
||||
### P1 intents
|
||||
|
||||
* `list_documents_by_counterparty`
|
||||
* `list_documents_by_contract`
|
||||
* `documents_forming_balance`
|
||||
* `bank_operations_by_counterparty`
|
||||
* `bank_operations_by_contract`
|
||||
* `documents_by_period`
|
||||
* `account_turnover_snapshot`
|
||||
* `document_lookup_by_number_or_date`
|
||||
|
||||
---
|
||||
|
||||
## 2.3. Multi-query decomposition
|
||||
|
||||
Нужно учитывать, что пользователь может писать составные запросы в свободной разговорной форме.
|
||||
|
||||
Примеры:
|
||||
|
||||
* “покажи хвосты по альфе и отдельно по бете”
|
||||
* “найди долг по договору 15 и покажи документы”
|
||||
* “что по 60 счету и какие контрагенты там висят”
|
||||
* “проверь оплаты за март и какие из них без договора”
|
||||
* “по поставщикам кто должен и что формирует остаток”
|
||||
|
||||
Нужен `addressQueryDecomposer`, который умеет:
|
||||
|
||||
1. определить, что вопрос составной;
|
||||
2. разбить его на подзапросы;
|
||||
3. проверить, что все части остаются в factual-search зоне;
|
||||
4. выполнить их последовательно;
|
||||
5. склеить ответ в один компактный output.
|
||||
|
||||
Для V1 достаточно baseline-режима:
|
||||
|
||||
* максимум 2 подзапроса;
|
||||
* без сложной межподзапросной оркестрации;
|
||||
* без скрытого перехода в reasoning-chain.
|
||||
|
||||
Расширенная decomposition-логика фиксируется как V1.1.
|
||||
|
||||
### Важно
|
||||
|
||||
Если составной вопрос требует уже reasoning-связки, а не просто нескольких factual lookup, нужно:
|
||||
|
||||
* либо честно ограничить ответ;
|
||||
* либо переводить его в deep-path с явной пометкой.
|
||||
|
||||
---
|
||||
|
||||
## 2.4. Filter extraction + validation
|
||||
|
||||
Нужно выделять:
|
||||
|
||||
* явные фильтры;
|
||||
* подразумеваемые фильтры;
|
||||
* отсутствующие обязательные фильтры.
|
||||
|
||||
Например:
|
||||
|
||||
* “кто должен нам” -> нужен `as_of_date`, можно подставить `today` по умолчанию;
|
||||
* “остаток по 60 за март” -> `account=60`, `period_from`, `period_to`;
|
||||
* “документы по альфе” -> нужен resolver контрагента;
|
||||
* “покажи хвосты” -> недостаточно фильтров, нужен scope.
|
||||
|
||||
---
|
||||
|
||||
## 2.5. MCP execution layer
|
||||
|
||||
Нужен выделенный `addressMcpExecutor`.
|
||||
|
||||
### Правила:
|
||||
|
||||
* только whitelist recipes;
|
||||
* read-only;
|
||||
* fixed sorting profiles;
|
||||
* limit controlled by recipe, а не свободным текстом;
|
||||
* live-first;
|
||||
* snapshot fallback только как explicit controlled mode, не silent.
|
||||
|
||||
---
|
||||
|
||||
## 2.6. Answer composer под короткий factual-формат оболочки
|
||||
|
||||
Нужно сделать composer, ориентированный на компактный factual-ответ в текущей оболочке ассистента.
|
||||
|
||||
### Формат ответа должен уметь:
|
||||
|
||||
#### A. Короткий итог
|
||||
|
||||
Например:
|
||||
|
||||
* “На сегодня найдено 12 контрагентов с дебиторкой, общий объем 1.54 млн ₽.”
|
||||
* “По договору найдено 7 открытых позиций на 430 тыс. ₽.”
|
||||
|
||||
#### B. Список top-строк
|
||||
|
||||
Например:
|
||||
|
||||
* контрагент
|
||||
* сумма
|
||||
* число документов
|
||||
|
||||
#### C. Что можно уточнить дальше
|
||||
|
||||
Например:
|
||||
|
||||
* “Можно показать документы по каждому контрагенту.”
|
||||
* “Можно раскрыть остаток по документам.”
|
||||
* “Можно отфильтровать по организации или периоду.”
|
||||
|
||||
#### D. Honest limitation
|
||||
|
||||
Если фильтров не хватает:
|
||||
|
||||
* “Недостаточно данных для точного поиска: не указан контрагент / договор / счет.”
|
||||
* “Найдено несколько договоров с похожим названием, нужно уточнение.”
|
||||
|
||||
---
|
||||
|
||||
# 3. Важное архитектурное требование
|
||||
|
||||
## Не делать “отдельные сущности” только под address-runtime
|
||||
|
||||
Вместо этого нужно:
|
||||
|
||||
* создать **единый semantic layer**;
|
||||
* использовать его первым потребителем в `address_query`;
|
||||
* оставить возможность потом подключить deep-path к тем же registry/resolver/filter primitives.
|
||||
|
||||
Иными словами:
|
||||
|
||||
**address-query — это первый runtime-потребитель общего semantic/query слоя, а не отдельная параллельная модель мира.**
|
||||
|
||||
---
|
||||
|
||||
# 4. Список пользовательских вопросов, который нужно заложить в проект
|
||||
|
||||
Нужно не просто реализовать intents, а подготовить **question bank**.
|
||||
|
||||
Создать отдельный файл, например:
|
||||
|
||||
* `docs/ADDRESS/address_query/question_bank_v1.md`
|
||||
|
||||
В нем нужно разложить реальные пользовательские формулировки.
|
||||
|
||||
---
|
||||
|
||||
## 4.1. Группа A — задолженность и хвосты
|
||||
|
||||
Примеры:
|
||||
|
||||
* кто должен нам на сегодня
|
||||
* кому должны мы на сегодня
|
||||
* какие хвосты висят
|
||||
* покажи хвосты по контрагентам
|
||||
* покажи хвосты по договору
|
||||
* какие незакрытые позиции по альфе
|
||||
* где висит дебиторка
|
||||
* где висит кредиторка
|
||||
* по каким контрагентам есть долг
|
||||
* по каким договорам есть незакрытые расчеты
|
||||
* какие открытые взаиморасчеты на текущую дату
|
||||
* у кого самый большой долг перед нами
|
||||
* кому больше всего должны мы
|
||||
|
||||
---
|
||||
|
||||
## 4.2. Группа B — счета и остатки
|
||||
|
||||
Примеры:
|
||||
|
||||
* какой остаток по 60 счету
|
||||
* какой остаток по 62 на дату
|
||||
* покажи остаток по счету 76
|
||||
* что висит на 60 счете
|
||||
* что висит на 62 счете
|
||||
* какие контрагенты формируют остаток по 60
|
||||
* какие документы формируют остаток по 62
|
||||
* оборот по 60 за март
|
||||
* оборот по 62 за период
|
||||
* по какому договору висит остаток на счете 60
|
||||
|
||||
---
|
||||
|
||||
## 4.3. Группа C — договоры
|
||||
|
||||
Примеры:
|
||||
|
||||
* какие договоры не закрыты
|
||||
* покажи незакрытые договоры
|
||||
* что по договору 15/24
|
||||
* какие хвосты по договору номер 15
|
||||
* есть ли долг по договору с альфой
|
||||
* покажи открытые позиции по договору
|
||||
* какие документы связаны с этим договором
|
||||
* какие платежи были по договору
|
||||
* что осталось незакрытым по договору
|
||||
|
||||
---
|
||||
|
||||
## 4.4. Группа D — документы
|
||||
|
||||
Примеры:
|
||||
|
||||
* найди документы по контрагенту альфа
|
||||
* покажи документы по договору
|
||||
* покажи платежки по альфе
|
||||
* найди реализации за март
|
||||
* найди поступления за февраль
|
||||
* покажи списания с расчетного счета по контрагенту
|
||||
* покажи поступления на расчетный счет по договору
|
||||
* найди документ по номеру
|
||||
* какие документы были 15 марта
|
||||
* покажи последние документы по поставщику
|
||||
* покажи неоплаченные документы
|
||||
* покажи проведенные документы по организации
|
||||
|
||||
---
|
||||
|
||||
## 4.5. Группа E — bank / payment lookup
|
||||
|
||||
Примеры:
|
||||
|
||||
* какие платежи были по альфе
|
||||
* какие списания были по договору
|
||||
* были ли поступления от беты
|
||||
* покажи банковские операции за неделю
|
||||
* какие платежи ушли без договора
|
||||
* какие поступления пришли по этому контрагенту
|
||||
* найди оплату на сумму 150 тысяч
|
||||
* покажи платежи по статье ддс
|
||||
|
||||
---
|
||||
|
||||
## 4.6. Группа F — drilldown от агрегата к деталям
|
||||
|
||||
Примеры:
|
||||
|
||||
* кто должен нам и какие документы это формируют
|
||||
* что висит по альфе и покажи документы
|
||||
* по 60 счету что висит и раскрой по документам
|
||||
* покажи остаток по договору и документы под ним
|
||||
* найди дебиторку и раскрой по договорам
|
||||
* покажи кредиторку и раскрой по контрагентам
|
||||
|
||||
---
|
||||
|
||||
## 4.7. Группа G — составные поисковые вопросы
|
||||
|
||||
Примеры:
|
||||
|
||||
* покажи хвосты по альфе и бете
|
||||
* найди долг по договору и покажи документы
|
||||
* кто должен нам и отдельно кому должны мы
|
||||
* покажи остаток по 60 и кто его формирует
|
||||
* найди платежи по альфе за март и отдельно поступления от нее
|
||||
* покажи незакрытые договоры и по каждому сумму хвоста
|
||||
* по контрагенту альфа покажи долг, договоры и последние документы
|
||||
|
||||
---
|
||||
|
||||
## 4.8. Группа H — check / verify формулировки, но still factual
|
||||
|
||||
Нужно предусмотреть вопросы вида “проверь”, если они остаются в lookup-логике.
|
||||
|
||||
Примеры:
|
||||
|
||||
* проверь, есть ли долг по альфе
|
||||
* проверь, есть ли незакрытые документы
|
||||
* проверь, были ли платежи в марте
|
||||
* проверь, что висит на 60 счете
|
||||
* проверь, есть ли оплаты по договору
|
||||
* проверь, какие документы формируют остаток
|
||||
|
||||
### Важно
|
||||
|
||||
Если “проверь” означает именно factual lookup — это address.
|
||||
Если “проверь, правильно ли…” — это уже не address, а deeper reasoning.
|
||||
|
||||
---
|
||||
|
||||
# 5. Что нужно реализовать в коде
|
||||
|
||||
## 5.1. Новые/обновляемые модули
|
||||
|
||||
Ожидаемый набор:
|
||||
|
||||
* `addressQueryService.ts`
|
||||
* `addressModeClassifier.ts`
|
||||
* `addressIntentResolver.ts`
|
||||
* `addressQueryDecomposer.ts`
|
||||
* `addressFilterExtractor.ts`
|
||||
* `addressFilterValidator.ts`
|
||||
* `addressRecipeCatalog.ts`
|
||||
* `addressRecipeSelector.ts`
|
||||
* `addressMcpExecutor.ts`
|
||||
* `addressResultMaterializer.ts`
|
||||
* `addressAnswerComposer.ts`
|
||||
|
||||
### Shared foundation
|
||||
|
||||
* `semanticEntityRegistry.ts`
|
||||
* `semanticAliasMap.ts`
|
||||
* `semanticResolvers/`
|
||||
* `semanticFilterCatalog.ts`
|
||||
|
||||
---
|
||||
|
||||
## 5.2. Нормализованный debug contract
|
||||
|
||||
Минимальный debug payload:
|
||||
|
||||
* `question_mode`
|
||||
* `address_intent`
|
||||
* `is_compound_query`
|
||||
* `subqueries_count`
|
||||
* `resolved_entities`
|
||||
* `resolved_filters`
|
||||
* `missing_filters`
|
||||
* `selected_recipe_ids`
|
||||
* `mcp_call_status`
|
||||
* `rows_fetched`
|
||||
* `response_type`
|
||||
* `fallback_reason`
|
||||
|
||||
---
|
||||
|
||||
## 5.3. Тесты
|
||||
|
||||
Нужны тесты не только на intent, но и на разбор живых пользовательских формулировок.
|
||||
|
||||
### Минимум:
|
||||
|
||||
* 20 single-query tests
|
||||
* 15 filter extraction tests
|
||||
* 10 resolver ambiguity tests
|
||||
* 10 compound-query decomposition tests
|
||||
* 10 composer response tests
|
||||
* 5 negative tests на unsafe/free-form query behavior
|
||||
|
||||
---
|
||||
|
||||
# 6. Что нужно создать в docs
|
||||
|
||||
Нужно дополнить пакет следующими файлами:
|
||||
|
||||
* `question_bank_v1.md`
|
||||
* `semantic_layer_design.md`
|
||||
* `address_runtime_contracts.md`
|
||||
* `address_v1_acceptance_pack.md`
|
||||
|
||||
---
|
||||
|
||||
# 7. Очередность выполнения
|
||||
|
||||
## M0 — Contracts and Foundation Skeleton
|
||||
|
||||
На базе уже собранных docs оформить и завести в коде минимальные контракты:
|
||||
|
||||
* `question_mode` / `address_intent`;
|
||||
* filter schema;
|
||||
* recipe schema;
|
||||
* debug contract;
|
||||
* P0 foundation skeleton (без поведенческих переключений).
|
||||
|
||||
## M1 — Classifier + Intent + Filter Pipeline
|
||||
|
||||
Реализовать:
|
||||
|
||||
* mode classifier;
|
||||
* intent resolver для P0;
|
||||
* filter extraction + validation;
|
||||
* baseline compound decomposition (как указано в 2.3).
|
||||
|
||||
## M2 — Recipe Selection + MCP Executor
|
||||
|
||||
Реализовать **recipe selection + MCP executor** для P0 с live-first политикой.
|
||||
|
||||
## M3 — Factual Composer + Debug
|
||||
|
||||
Реализовать **answer composer** под factual/shell-friendly output и стабилизировать debug payload.
|
||||
|
||||
## M4 — Live Acceptance Pack
|
||||
|
||||
Сделать **acceptance pack**:
|
||||
|
||||
* реальные тестовые вопросы;
|
||||
* debug traces;
|
||||
* примерные ответы;
|
||||
* список ограничений.
|
||||
|
||||
---
|
||||
|
||||
# 8. Что не входит в V1
|
||||
|
||||
Не делать на этом этапе:
|
||||
|
||||
* свободный query builder от LLM;
|
||||
* доказательный бухгалтерский reasoning;
|
||||
* объяснение причин расхождений;
|
||||
* поиск ошибок учета;
|
||||
* автоматическую интерпретацию НДС-логики;
|
||||
* “универсальный доступ ко всем сущностям” без recipe/guardrails;
|
||||
* silent fallback между snapshot/live.
|
||||
|
||||
---
|
||||
|
||||
# 9. Критерии приемки
|
||||
|
||||
Задача считается выполненной, если:
|
||||
|
||||
### Архитектурно
|
||||
|
||||
* `address_query` внедрен как отдельный runtime lane;
|
||||
* deep-analysis path не деградировал;
|
||||
* сущностная модель не продублирована в отдельный address-only мир;
|
||||
* общий semantic/query foundation layer создан.
|
||||
|
||||
### Функционально
|
||||
|
||||
* P0 intents работают через MCP/live-first;
|
||||
* resolver’ы умеют базово разруливать контрагентов/договоры/счета;
|
||||
* составные factual-запросы поддержаны хотя бы в базовом виде;
|
||||
* ответы укладываются в единый factual contract.
|
||||
|
||||
### UX
|
||||
|
||||
* короткие разговорные запросы разбираются стабильно;
|
||||
* при нехватке фильтров система не фантазирует, а честно просит уточнение или возвращает `LIMITED_WITH_REASON`;
|
||||
* ответ читабелен в текущей оболочке ассистента.
|
||||
|
||||
### Безопасность
|
||||
|
||||
* только whitelist recipes;
|
||||
* read-only MCP;
|
||||
* никакой генерации свободного запроса LLM’ом.
|
||||
|
||||
---
|
||||
|
||||
# 10. Что должно быть в финальном отчете по задаче
|
||||
|
||||
В конце работы нужно явно показать:
|
||||
|
||||
1. какие модули добавлены;
|
||||
2. какие контракты введены;
|
||||
3. какие P0 и P1 intents реально поддержаны;
|
||||
4. какие resolver’ы готовы;
|
||||
5. как обрабатываются составные вопросы;
|
||||
6. какие ограничения остались;
|
||||
7. какие следующие шаги нужны для V1.1.
|
||||
|
||||
---
|
||||
|
||||
# 11. Дополнительное указание
|
||||
|
||||
При проектировании ориентироваться не только на “идеальные бухгалтерские формулировки”, но и на реальную разговорную подачу пользователя:
|
||||
|
||||
* коротко;
|
||||
* обрывочно;
|
||||
* без строгих терминов;
|
||||
* с бытовыми словами;
|
||||
* с запросами в стиле “найди”, “проверь”, “что висит”, “что по договору”, “покажи остаток”.
|
||||
|
||||
Нужно проектировать слой так, чтобы он был полезен в простом повседневном интерфейсе, а не только в аналитическом desktop-flow.
|
||||
|
||||
---
|
||||
|
||||
Если нужно, следующим сообщением я могу сразу собрать это в ещё более прикладной вид: **короткий production-prompt для Codex** без объяснений, чтобы его можно было просто вставить в задачу.
|
||||
@@ -0,0 +1,91 @@
|
||||
# TZ Sync Note — Address Query Runtime V1 MCP (Project-Aligned)
|
||||
|
||||
Дата: 2026-03-29
|
||||
Источник: `docs/ADDRESS/tz/TZ_address_query_runtime_V1_MCP.md`
|
||||
Статус: `SYNCED_WITH_PROJECT_ARCHITECTURE`
|
||||
|
||||
## 1) Что синхронизировано без изменений
|
||||
|
||||
Эти части полностью совпадают с нашим курсом и сохраняются:
|
||||
|
||||
- отдельный runtime-режим `question_mode=address_query`;
|
||||
- MCP/live-first для address lane;
|
||||
- whitelist recipe-модель (`intent -> filters -> recipe -> MCP -> factual result`);
|
||||
- запрет free-form query generation от LLM;
|
||||
- явный fallback и честный `LIMITED_WITH_REASON`;
|
||||
- сохранение existing deep-analysis path без ломки.
|
||||
|
||||
## 2) Что скорректировано под реальный проект
|
||||
|
||||
### 2.1 Mobile interface — исключен из scope
|
||||
|
||||
В исходном ТЗ есть акцент на “телефонный интерфейс/мобильный UX”.
|
||||
|
||||
В проекте фиксируем:
|
||||
|
||||
- **мобильный интерфейс не реализуем**;
|
||||
- **единый канал взаимодействия — текущая оболочка ассистента** (наш existing dialogue shell);
|
||||
- поддерживаем короткие, разговорные и обрывочные формулировки как NL-вход, но без отдельной mobile UI ветки.
|
||||
|
||||
### 2.2 Compound decomposition — не blocker для V1 core
|
||||
|
||||
`addressQueryDecomposer` оставляем как важную capability, но:
|
||||
|
||||
- для V1 core делаем базовую поддержку составных factual-запросов;
|
||||
- advanced decomposition (многосвязная склейка и сложный orchestration) переносим в V1.1.
|
||||
|
||||
### 2.3 Foundation layer — вводим поэтапно, без big-bang
|
||||
|
||||
Семантический слой (registry/aliases/resolvers/filter catalog) внедряем итеративно:
|
||||
|
||||
- сначала минимальный P0 registry + resolver subset;
|
||||
- затем расширение на P1 intents.
|
||||
|
||||
Никакого “одним большим неразмеченным рефактором”.
|
||||
|
||||
### 2.4 Acceptance — staged
|
||||
|
||||
Стадии приемки:
|
||||
|
||||
- `M0` contracts ready;
|
||||
- `M1` classifier+intent+filters;
|
||||
- `M2` MCP executor + P0 recipes;
|
||||
- `M3` factual composer + debug;
|
||||
- `M4` live acceptance run.
|
||||
|
||||
## 3) Синхронизированный scope V1
|
||||
|
||||
### In scope (V1)
|
||||
|
||||
- mode-classifier (`address_query` / `deep_analysis` / `unsupported`);
|
||||
- P0 intents;
|
||||
- filter extraction + validation;
|
||||
- resolver subset: counterparty/contract/account/document_type/organization;
|
||||
- recipe whitelist;
|
||||
- MCP live-first execution;
|
||||
- factual answer contract;
|
||||
- debug contract for address lane;
|
||||
- acceptance pack в `docs/ADDRESS/runs/...`.
|
||||
|
||||
### Out of scope (V1)
|
||||
|
||||
- mobile UI/mobile-specific rendering;
|
||||
- full proof reasoning;
|
||||
- universal free-form access ко всем сущностям;
|
||||
- deep-path redesign;
|
||||
- advanced compound orchestration beyond baseline.
|
||||
|
||||
## 4) Runtime compatibility points (код-база)
|
||||
|
||||
Синк с текущей архитектурой:
|
||||
|
||||
- early mode branching в `assistantService.ts`;
|
||||
- classifier/routing integration рядом с `routeHintAdapter.ts`;
|
||||
- отдельный `addressQueryService.ts` и специализированные address-модули;
|
||||
- текущий deep chain (claim-bound/evidence/admissibility/eligibility) не трогаем как default path.
|
||||
|
||||
## 5) Вердикт синка
|
||||
|
||||
`TZ_V1_MCP_IS_VALID_AFTER_PROJECT_SYNC`
|
||||
|
||||
Главная поправка: **убрать мобильный интерфейс из требований реализации и оставить только поддержку коротких разговорных формулировок в существующей оболочке.**
|
||||
@@ -0,0 +1,397 @@
|
||||
рекомендации после первых двух этапов.md
|
||||
|
||||
## Что видно по текущему состоянию
|
||||
|
||||
Не похоже, что у вас основная проблема в том, что “ассистент не понимает вопрос”.
|
||||
|
||||
По текущим run-артефактам картина такая:
|
||||
|
||||
* `address lane` **включается корректно**;
|
||||
* ранняя ветка в `AssistantService` **срабатывает правильно**;
|
||||
* `intent resolver` после перевода на token-based стал **стабильнее**;
|
||||
* `false factual rate = 0` — это хорошо.
|
||||
|
||||
Но дальше почти все упирается в другое:
|
||||
|
||||
* `mcp_call_status=empty`, либо
|
||||
* `no_contract_anchors_in_live_rows`, либо
|
||||
* controlled `LIMITED_WITH_REASON`.
|
||||
|
||||
То есть **верхний слой уже более-менее жив**, а основной потолок сейчас — это **небогатый live-result на уровне рецептов и materialization**.
|
||||
|
||||
---
|
||||
|
||||
## Глобальный вывод
|
||||
|
||||
Сейчас у вас смешались **два разных понятия готовности**:
|
||||
|
||||
### 1. “Сущность видна в snapshot”
|
||||
|
||||
Это значит:
|
||||
|
||||
* она существует в 2020 corpus;
|
||||
* у нее есть поля;
|
||||
* есть связи;
|
||||
* она красиво выглядит в entity map.
|
||||
|
||||
### 2. “По этой сущности можно стабильно отвечать в runtime через текущий live recipe”
|
||||
|
||||
Это уже совсем другое:
|
||||
|
||||
* есть нужные якоря в live-строках;
|
||||
* эти якоря доезжают до MCP-ответа;
|
||||
* по ним можно собрать уверенный factual answer.
|
||||
|
||||
И вот по артефактам видно, что у вас **эти две вещи пока переоценены как будто они одинаковые**.
|
||||
|
||||
А они не одинаковые.
|
||||
|
||||
---
|
||||
|
||||
## Самый важный сигнал из ваших документов
|
||||
|
||||
В inventory у вас формально много P0-сущностей, но по факту:
|
||||
|
||||
* для `account_balances` опора есть;
|
||||
* для `counterparties/contracts` картина значительно слабее;
|
||||
* `open_contracts` и часть `open_items` уже сейчас честно уходят в limited, потому что **в live rows не хватает договорных якорей**.
|
||||
|
||||
Это очень хороший симптом с точки зрения честности системы.
|
||||
Но одновременно это показывает, что:
|
||||
|
||||
**entity map сейчас структурно сильнее, чем runtime-ready model.**
|
||||
|
||||
---
|
||||
|
||||
# Что я бы улучшал уже сейчас
|
||||
|
||||
## 1. Развести два уровня readiness
|
||||
|
||||
Сейчас у вас полезно ввести не один `priority/readiness`, а два.
|
||||
|
||||
### A. Structural readiness
|
||||
|
||||
Сущность:
|
||||
|
||||
* есть в snapshot;
|
||||
* понятны поля;
|
||||
* понятны связи;
|
||||
* можно проектировать recipes.
|
||||
|
||||
### B. Runtime readiness
|
||||
|
||||
Сущность:
|
||||
|
||||
* реально доступна через текущий MCP/live маршрут;
|
||||
* по ней есть достаточные якоря;
|
||||
* можно собрать factual answer без натяжки.
|
||||
|
||||
### Практически
|
||||
|
||||
Добавьте для каждой сущности и/или сценария отдельный статус:
|
||||
|
||||
* `STRUCTURALLY_VISIBLE`
|
||||
* `LIVE_QUERYABLE`
|
||||
* `LIVE_QUERYABLE_WITH_LIMITS`
|
||||
* `REQUIRES_SPECIALIZED_RECIPE`
|
||||
* `DEEP_ONLY`
|
||||
|
||||
Это сразу уберет ложное ощущение, что “раз сущность в P0, значит можно уже уверенно спрашивать”.
|
||||
|
||||
---
|
||||
|
||||
## 2. Перестать пытаться вытащить `open_contracts` из одного movement-среза
|
||||
|
||||
Вот это сейчас, по-моему, ключевой архитектурный затык.
|
||||
|
||||
Для:
|
||||
|
||||
* `list_open_contracts`
|
||||
* `open_items_by_contract`
|
||||
* часть `open_items_by_counterparty_or_contract`
|
||||
|
||||
движений из `Хозрасчетный` **недостаточно**, если в live строках не приезжает нормальный contract anchor.
|
||||
|
||||
### Что делать
|
||||
|
||||
Для этих сценариев нужны **специализированные recipes**, а не просто еще одна вариация movement-query.
|
||||
|
||||
Минимум отдельные live-рецепты на базе:
|
||||
|
||||
* документов поставщиков,
|
||||
* документов покупателей,
|
||||
* банковских выписок,
|
||||
* договорных реквизитов документных линий,
|
||||
* актов сверки,
|
||||
* возможно, отдельных регистров взаиморасчетов, если через MCP они доступны лучше, чем бухрегистр.
|
||||
|
||||
То есть:
|
||||
|
||||
**для balances movement-рецепт ок,
|
||||
для contracts/open items нужен object-aware recipe.**
|
||||
|
||||
---
|
||||
|
||||
## 3. Ввести двухшаговый execution вместо одного прямого
|
||||
|
||||
Сейчас у вас, судя по артефактам, часто логика такая:
|
||||
|
||||
`intent -> recipe -> empty -> LIMITED`
|
||||
|
||||
Это честно, но слишком грубо.
|
||||
|
||||
Я бы сделал для части сценариев **controlled two-step plan**.
|
||||
|
||||
### Пример
|
||||
|
||||
Для вопроса:
|
||||
“какие хвосты по договору X”
|
||||
|
||||
не сразу идти в movement summary, а:
|
||||
|
||||
#### Шаг 1. Anchor resolution
|
||||
|
||||
* найти договор;
|
||||
* понять контрагента;
|
||||
* понять связанные документы/тип маршрута.
|
||||
|
||||
#### Шаг 2. Focused recipe
|
||||
|
||||
* уже по найденному anchor выполнять узкий live query.
|
||||
|
||||
Это особенно важно для:
|
||||
|
||||
* `by_contract`
|
||||
* `documents_forming_balance`
|
||||
* `bank_operations_by_contract`
|
||||
* `open_items_by_counterparty_or_contract`
|
||||
|
||||
---
|
||||
|
||||
## 4. Разделить `empty`, `blind`, `missing_anchor`
|
||||
|
||||
Сейчас у вас многие ответы схлопываются в один limited-мод.
|
||||
|
||||
А на деле это три разных случая:
|
||||
|
||||
### A. `EMPTY`
|
||||
|
||||
Данные действительно не найдены по фильтру.
|
||||
|
||||
### B. `BLIND_RECIPE`
|
||||
|
||||
Данные, возможно, есть, но текущий recipe их не видит.
|
||||
|
||||
### C. `MISSING_ANCHOR`
|
||||
|
||||
Нет достаточного ключа для точного запроса.
|
||||
|
||||
Это суперважно, потому что сейчас пользователь может видеть одинаковый ограниченный ответ, но причины там разные.
|
||||
|
||||
### Что это даст
|
||||
|
||||
Тогда limited-ответ станет полезнее:
|
||||
|
||||
* “По указанному фильтру данные не найдены.”
|
||||
* “Текущий live-рецепт не возвращает договорную аналитику для этого сценария.”
|
||||
* “Нужно уточнить договор или контрагента.”
|
||||
|
||||
Это уже не просто safety, а нормальный рабочий UX.
|
||||
|
||||
---
|
||||
|
||||
## 5. Усилить слой anchor-first resolution раньше intent
|
||||
|
||||
Сейчас вы уже улучшили token-based intent resolver — это хорошо.
|
||||
Но на раннем этапе я бы вообще сделал акцент не на intent-first, а на:
|
||||
|
||||
**anchor-first + intent-second**
|
||||
|
||||
То есть сначала пытаться вытащить:
|
||||
|
||||
* счет,
|
||||
* контрагента,
|
||||
* договор,
|
||||
* тип документа,
|
||||
* период,
|
||||
* дату среза,
|
||||
|
||||
а уже потом выбирать intent.
|
||||
|
||||
Потому что в реальной короткой подаче пользователь часто говорит не “тип запроса”, а якорь:
|
||||
|
||||
* “по альфе что висит”
|
||||
* “по договору 15 покажи хвост”
|
||||
* “60 счет на сегодня”
|
||||
* “платежки по бете за март”
|
||||
|
||||
Именно anchor здесь важнее красивой intent-классификации.
|
||||
|
||||
---
|
||||
|
||||
## 6. Добавить `query shape classification`
|
||||
|
||||
Нужно разделить не только по intent, но и по форме вопроса.
|
||||
|
||||
Например:
|
||||
|
||||
* `AGGREGATE_LOOKUP`
|
||||
* `OBJECT_LOOKUP`
|
||||
* `DOCUMENT_LIST`
|
||||
* `DRILLDOWN_REQUEST`
|
||||
* `COMPOUND_FACTUAL_QUERY`
|
||||
* `VERIFY_FACTUAL`
|
||||
* `EXPLAIN_OR_REASON`
|
||||
|
||||
Это сильно поможет на раннем этапе, потому что многие “многочастные” вопросы на самом деле нормально раскладываются не через “один сложный intent”, а через форму запроса.
|
||||
|
||||
---
|
||||
|
||||
## 7. Для composer: limited-ответы сделать намного полезнее
|
||||
|
||||
Сейчас safety у вас честная, но UX можно усилить.
|
||||
|
||||
Когда система не может дать factual result, она уже сейчас должна возвращать не просто ограничение, а **полезный следующий шаг**.
|
||||
|
||||
### Например:
|
||||
|
||||
вместо
|
||||
|
||||
* “не найдено”
|
||||
|
||||
лучше:
|
||||
|
||||
* “Текущий маршрут не видит договорную аналитику в live-строках. Можно продолжить по одному из вариантов: по контрагенту, по счету 60/62/76 или по документам за период.”
|
||||
|
||||
или
|
||||
|
||||
* “Для точного поиска не хватает якоря. Можно уточнить контрагента, договор или дату.”
|
||||
|
||||
То есть limited-mode должен стать **операционным**, а не просто защитным.
|
||||
|
||||
---
|
||||
|
||||
# Что, скорее всего, “глобально происходит” на текущих двух этапах
|
||||
|
||||
Если упрощенно, то так:
|
||||
|
||||
## Верхний этап
|
||||
|
||||
Работает уже лучше, чем кажется:
|
||||
|
||||
* классификация,
|
||||
* заход в address lane,
|
||||
* базовый intent/filter layer.
|
||||
|
||||
## Нижний этап
|
||||
|
||||
Не дотягивает по фактической выразительности live-data:
|
||||
|
||||
* текущие рецепты слишком общие,
|
||||
* movement layer беден для contract-aware сценариев,
|
||||
* многие кейсы рано упираются в `empty/limited`.
|
||||
|
||||
То есть у вас сейчас проблема не “LLM тупой”, а **семантический слой уже обогнал реальную мощность live recipe layer**.
|
||||
|
||||
Это нормальная ранняя стадия.
|
||||
Просто теперь нужно не бесконечно шлифовать классификатор, а **сильно усилить слой address recipes и anchor resolution**.
|
||||
|
||||
---
|
||||
|
||||
# Что бы я делал следующим коротким шагом
|
||||
|
||||
## Sprint A — не расширение фич, а прояснение runtime-реальности
|
||||
|
||||
### 1. Ввести отдельную матрицу:
|
||||
|
||||
`scenario -> structural readiness -> runtime readiness -> blocker`
|
||||
|
||||
Для каждого P0/P1 сценария явно указать:
|
||||
|
||||
* видна ли сущность в snapshot;
|
||||
* видна ли она через текущий live recipe;
|
||||
* чего не хватает;
|
||||
* нужен ли новый recipe.
|
||||
|
||||
### 2. Добавить 3 статуса failure mode:
|
||||
|
||||
* `empty_match`
|
||||
* `missing_anchor`
|
||||
* `recipe_visibility_gap`
|
||||
|
||||
### 3. Для 5–10 ключевых сценариев собрать live evidence pack
|
||||
|
||||
Не просто “PASS/limited”, а:
|
||||
|
||||
* какой recipe вызывался,
|
||||
* какие поля реально вернулись,
|
||||
* каких anchors не хватило,
|
||||
* на каком шаге потерялась сущность.
|
||||
|
||||
Это сразу покажет, что именно ломается.
|
||||
|
||||
---
|
||||
|
||||
## Sprint B — минимальное усиление без раздувания системы
|
||||
|
||||
### Приоритетно добавить:
|
||||
|
||||
1. `documents_by_counterparty`
|
||||
2. `documents_by_contract`
|
||||
3. `bank_operations_by_counterparty`
|
||||
4. `bank_operations_by_contract`
|
||||
5. `documents_forming_balance`
|
||||
|
||||
Потому что эти маршруты обычно лучше дают якоря, чем голый movement slice.
|
||||
|
||||
---
|
||||
|
||||
## Sprint C — небольшой апгрейд NLU, но без фанатизма
|
||||
|
||||
### Что стоит сделать
|
||||
|
||||
* account token extractor (`60`, `62`, `76`, `60.01`, `62.02`);
|
||||
* contract number recognizer;
|
||||
* counterparty fuzzy resolver;
|
||||
* short mobile phrase normalization:
|
||||
|
||||
* “что висит”
|
||||
* “хвосты”
|
||||
* “по альфе”
|
||||
* “на сегодня”
|
||||
* “за март”
|
||||
* “проверь оплаты”
|
||||
|
||||
### Что пока не надо делать
|
||||
|
||||
* тяжелую многошаговую reasoning-логику;
|
||||
* сложный free-form planner;
|
||||
* глубокий unified-intelligence слой.
|
||||
|
||||
Рано.
|
||||
|
||||
---
|
||||
|
||||
# Мой короткий вывод
|
||||
|
||||
Сейчас у вас ситуация на самом деле хорошая.
|
||||
|
||||
Потому что:
|
||||
|
||||
* lane уже заведен;
|
||||
* deep-path не сломан;
|
||||
* false factual не генерируется;
|
||||
* система честно ограничивается там, где live-слой не тянет.
|
||||
|
||||
Главное, что я бы зафиксировал:
|
||||
|
||||
**узкое место сейчас не в понимании вопроса, а в несоответствии между “сущность есть в inventory” и “по ней можно стабильно ответить текущим live recipe”.**
|
||||
|
||||
То есть следующий шаг — это не столько “еще умнее классификатор”, сколько:
|
||||
|
||||
* отдельный runtime-readiness слой,
|
||||
* richer anchor resolution,
|
||||
* specialized recipes вместо общих movement-срезов,
|
||||
* и более полезный limited-mode.
|
||||
|
||||
Если хочешь, следующим сообщением я могу собрать тебе уже **конкретное ТЗ для Codex на M2.1/M2.2**, именно на усиление runtime-ready слоя и evidence pack по live-рецептам.
|
||||
Reference in New Issue
Block a user