NODEDC_1C/docs/ADDRESS/tz/рекомендации_после_первых_д...

14 KiB
Raw Blame History

рекомендации после первых двух этапов.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. Для 510 ключевых сценариев собрать 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-рецептам.