# Query Recipes V1 (Address Query) Дата: 2026-03-29 Контур: Stage 4, отдельная ветка `question_mode=address_query` ## 1) Safe Access Contract Цепочка должна быть строго управляемой: `intent -> filters -> recipe -> MCP -> factual result` Ограничения: - LLM не генерирует произвольный SQL/1C-запрос. - LLM выбирает только `recipe_id` из каталога и заполняет параметры. - Любой нераспознанный или рискованный случай возвращается как `LIMITED_WITH_REASON` или уходит в deep-analysis. ## 2) Entity Catalog (P0 for address-query) Базовые семейства для V1: - `ACCOUNTING_REGISTER` (`AccountingRegister_Хозрасчетный*`) - `DOCUMENT` (`СписаниеСРасчетногоСчета`, `ПоступлениеНаРасчетныйСчет`, `АктСверкиВзаиморасчетов`, документные линии) - `DOCUMENT_JOURNAL` (`ДокументыПоставщиков`, `ДокументыПокупателей`, `БанковскиеВыписки`) - `NSI_CATALOG` (`ДоговорыКонтрагентов`, плюс фильтровые справочники) - `CHART_OF_ACCOUNTS` (`Хозрасчетный`) ## 3) Filter Catalog | filter | type | required_when | notes | |---|---|---|---| | `period_from` | date (`YYYY-MM-DD`) | turnover/list-by-period intents | начало периода | | `period_to` | date (`YYYY-MM-DD`) | turnover/list-by-period intents | конец периода | | `as_of_date` | date (`YYYY-MM-DD`) | balance/open-items intents | срез на дату | | `organization` | string/guid | optional | если не задано, берется default company scope | | `counterparty` | string/guid | required for by-counterparty intents | допускается name->id resolver | | `contract` | string/guid | required for by-contract intents | допускается number/name->id resolver | | `account` | string (`60`, `62.01`, ...) | required for account intents | только validated account tokens | | `document_type` | enum/string | required for list-by-type | белый список типов | | `document_ref` | guid/string | required for document drilldown | точечный lookup | | `status` | enum (`open`, `closed`, `all`) | optional | для open/closed срезов | | `limit` | int (1..200) | optional | default 50 | | `sort` | enum (`date_desc`, `amount_desc`, `name_asc`) | optional | default recipe-specific | ## 4) Query Recipe Catalog V1 | recipe_id | purpose | required_params | optional_params | expected_output_schema | sort/limit rules | drilldown_targets | |---|---|---|---|---|---|---| | `address.open_contracts.by_asof` | Незакрытые договоры на дату | `as_of_date` | `organization`, `counterparty`, `limit`, `sort` | `contract_ref`, `contract_name`, `counterparty_ref`, `debit`, `credit`, `saldo`, `as_of_date` | default `saldo_desc`, `limit=50` | `address.open_items.by_contract` | | `address.payables.counterparty_totals` | Кому должны мы | `as_of_date` | `organization`, `account`, `limit` | `counterparty_ref`, `counterparty_name`, `payable_amount`, `doc_count`, `as_of_date` | default `payable_amount_desc`, `limit=50` | `address.open_items.by_counterparty` | | `address.receivables.counterparty_totals` | Кто должен нам | `as_of_date` | `organization`, `account`, `limit` | `counterparty_ref`, `counterparty_name`, `receivable_amount`, `doc_count`, `as_of_date` | default `receivable_amount_desc`, `limit=50` | `address.open_items.by_counterparty` | | `address.account.balance_snapshot` | Остаток по счету на дату | `account`, `as_of_date` | `organization`, `limit` | `account`, `debit_balance`, `credit_balance`, `net_balance`, `as_of_date` | default `account_asc`, `limit=20` | `address.balance.drilldown_documents` | | `address.open_items.by_counterparty` | Открытые позиции по контрагенту | `counterparty`, `as_of_date` | `organization`, `contract`, `account`, `limit` | `document_ref`, `document_type`, `document_date`, `contract_ref`, `debit`, `credit`, `open_amount` | default `document_date_desc`, `limit=100` | `address.documents.by_contract` | | `address.open_items.by_contract` | Открытые позиции по договору | `contract`, `as_of_date` | `organization`, `counterparty`, `account`, `limit` | `document_ref`, `document_type`, `document_date`, `counterparty_ref`, `debit`, `credit`, `open_amount` | default `document_date_desc`, `limit=100` | `address.documents.by_contract` | | `address.documents.by_counterparty` | Документы контрагента за период | `counterparty`, `period_from`, `period_to` | `organization`, `document_type`, `limit`, `sort` | `document_ref`, `document_type`, `number`, `date`, `amount`, `posted` | default `date_desc`, `limit=100` | `address.documents.by_contract` | | `address.bank_ops.by_counterparty` | Банковские операции по контрагенту | `counterparty` | `period_from`, `period_to`, `organization`, `limit`, `sort` | `document_ref`, `document_type`, `number`, `date`, `amount`, `posted`, `bank_account_hint` | default `date_desc`, `limit=100` | `address.documents.by_counterparty` | | `address.documents.by_contract` | Документы договора за период | `contract`, `period_from`, `period_to` | `organization`, `document_type`, `limit`, `sort` | `document_ref`, `document_type`, `number`, `date`, `amount`, `posted` | default `date_desc`, `limit=100` | `address.balance.drilldown_documents` | | `address.balance.drilldown_documents` | Расшифровка остатка до документов | `account`, `as_of_date` | `organization`, `counterparty`, `contract`, `limit` | `document_ref`, `document_type`, `number`, `date`, `debit`, `credit`, `delta` | default `date_desc`, `limit=150` | `address.documents.by_counterparty` | ## 5) Result Schema (Unified) ```json { "question_mode": "address_query", "intent": "list_payables_counterparties", "recipe_id": "address.payables.counterparty_totals", "filters": { "as_of_date": "2026-03-29", "organization": "", "limit": 50 }, "result_mode": "FACTUAL_SUMMARY", "summary": { "rows": 12, "total_amount": 1543200.50, "currency": "RUB" }, "rows": [ { "counterparty_name": "ООО Альфа", "payable_amount": 450000.00, "doc_count": 7 } ], "limitations": [] } ``` ## 6) Answer Contract - `FACTUAL_LIST`: короткий вывод + список строк + totals. - `FACTUAL_SUMMARY`: агрегат + top строки + предложение уточнить фильтр при большом объеме. - `LIMITED_WITH_REASON`: честная причина ограничения (`missing_required_filters`, `live_unavailable`, `no_matches_for_filters`, `unsupported_for_address_query_v1`). ## 7) MCP Execution Notes - Runtime вызывает MCP proxy (`/api/execute_query`) только с query-template из recipe и параметрами после валидации. - Для V1 все recipe выполняются в `read-only` режиме. - Ограничения на выборку (`limit`) и сортировки фиксируются recipe-контрактом, а не свободным текстом вопроса. ## 8) Account Scope Strategy (M2.3b) - `account_balance_snapshot` and `documents_forming_balance` use `strict` account scope. - counterparty-oriented recipes use `preferred` account scope with runtime fallback to raw rows when scope gives zero rows. - this keeps account-intent precision while preventing blind row loss on party intents.