# 5 - Assistant Mode Architecture Report (2026-03-24) ## 1. Статус этапа Дата фиксации: **24 марта 2026**. На текущем этапе реализован рабочий `Assistant Mode` поверх существующего `Decomposition` контура: - decomposition/debug режим сохранен и не удален; - добавлен отдельный backend endpoint для assistant-loop; - добавлен слой `answer_composer` (human-readable ответ); - добавлена session-scoped история диалога (in-memory); - добавлен debug drawer в GUI по каждому assistant ответу; - единый pipeline нормализации/маршрутизации используется для обоих режимов. --- ## 2. Что входит в текущую архитектуру ## 2.1 Backend Ключевые узлы: - `llm_normalizer/backend/src/routes/assistant.ts` - `llm_normalizer/backend/src/services/assistantService.ts` - `llm_normalizer/backend/src/services/answerComposer.ts` - `llm_normalizer/backend/src/services/assistantSessionStore.ts` - `llm_normalizer/backend/src/types/assistant.ts` - `llm_normalizer/backend/src/services/routeHintAdapter.ts` (общий deterministic routing) - `llm_normalizer/backend/src/services/normalizerService.ts` (общий normalizer pipeline) Подключение в сервер: - `llm_normalizer/backend/src/server.ts` - `llm_normalizer/backend/src/serverContext.ts` ## 2.2 Frontend Ключевые узлы: - `llm_normalizer/frontend/src/App.tsx` (mode switch + orchestration) - `llm_normalizer/frontend/src/components/AssistantPanel.tsx` - `llm_normalizer/frontend/src/api/client.ts` (assistant API methods) - `llm_normalizer/frontend/src/state/types.ts` (assistant типы состояния) - `llm_normalizer/frontend/src/styles.css` (assistant/mode switch UI стиль) --- ## 3. Backend: функциональная архитектура ## 3.1 Endpoint’ы ### 3.1.1 POST `/api/assistant/message` Назначение: - принять user message; - прогнать через normalizer pipeline; - определить route/fallback; - собрать human-readable assistant reply; - вернуть reply + debug + session conversation snapshot. Проверки: - `user_message` обязателен; - при пустом сообщении возвращается `INVALID_ASSISTANT_MESSAGE` (HTTP 400). ### 3.1.2 GET `/api/assistant/session/:session_id` Назначение: - вернуть текущую историю сессии из in-memory store. Поведение: - если сессия отсутствует: `ASSISTANT_SESSION_NOT_FOUND` (HTTP 404). --- ## 3.2 Контракт данных Assistant Mode Типы заданы в: - `llm_normalizer/backend/src/types/assistant.ts` Ключевые сущности: - `AssistantMessageRequestPayload` - `AssistantDebugPayload` - `AssistantConversationItem` - `AssistantMessageResponsePayload` `fallback_type` (жестко зафиксированный набор): - `none` - `out_of_scope` - `clarification` - `partial` - `unknown` --- ## 3.3 Session memory Реализовано в: - `llm_normalizer/backend/src/services/assistantSessionStore.ts` Характеристики: - хранилище: in-memory `Map`; - auto-create сессии при первом сообщении; - ограничение длины: `MAX_ITEMS_PER_SESSION = 200`; - хранение только в рамках текущего backend процесса; - при рестарте backend память очищается. Это deliberate решение текущего этапа (sandbox/stage), без persistent storage. --- ## 3.4 Assistant pipeline (внутренний flow) Реализовано в: - `llm_normalizer/backend/src/services/assistantService.ts` Порядок выполнения: 1. `ensureSession` -> получаем/создаем `session_id`. 2. Сохраняем user message как conversation item (`role=user`). 3. Формируем `NormalizeRequestPayload` с: - `promptVersion` по умолчанию `normalizer_v2_0_2`, - connection/prompt/context/useMock из запроса. 4. Вызываем `normalizerService.normalize(...)`. 5. По `route_hint_summary` строим retrieval plan (`buildRetrievalPlan`). 6. Передаем данные в `composeAssistantAnswer(...)`. 7. Формируем `debug` payload: - `trace_id`, - `route_summary`, - `fragments`, - `retrieval`, - `normalized`. 8. Сохраняем assistant message как conversation item (`role=assistant`). 9. Логируем structured event `assistant_message_processed`. 10. Возвращаем: - `assistant_reply`, - `conversation_item`, - `debug`, - `conversation`. --- ## 3.5 Routing rules (общий deterministic v2 engine) Основные правила маршрутизации берутся из: - `llm_normalizer/backend/src/services/routeHintAdapter.ts` Правила выбора маршрута: 1. `live_mcp_drilldown` - если `asks_for_exact_object_trace = true`. 2. `batch_refresh_then_store` - если `asks_for_ranking_or_top = true` **или** `asks_for_period_summary = true`. 3. `hybrid_store_plus_live` - если `has_multi_entity_scope = true` и `asks_for_chain_explanation = true`. 4. `store_feature_risk` - если `asks_for_rule_check = true` и не chain; - также anomaly path: `asks_for_anomaly_scan = true` без ranking и без multi-entity chain. 5. `store_canonical` - default routed путь для in-scope, если нет более сильного сигнала. 6. `no_route` - если fragment out-of-scope / insufficient specificity / missing mapping / unsupported fragment type. Fallback type в summary: - `out_of_scope` — сообщение вне контура; - `clarification` — нет routable in-scope fragment’ов из-за недоспецификации; - `partial` — часть in-scope/routed, часть no-route/out-of-scope; - `none` — все ок для текущего контура. --- ## 3.6 Answer composer rules Реализовано в: - `llm_normalizer/backend/src/services/answerComposer.ts` Логика: 1. `out_of_scope` - вежливый boundary response (работа только по company-specific accounting contour). 2. `clarification` - конкретный уточняющий ответ: период/счет/документ/контрагент. 3. `partial` - сообщает, что обработана только часть запроса; - выводит routed части; - явно фиксирует sandbox retrieval mode. 4. `none` - human-readable summary с перечислением planned routes. 5. `unknown` - защитный fallback, если routed items не сформированы. Важно: - на этом этапе composer формирует **человеко-читаемый operational ответ**; - это не финальный production-grade semantic answer over full live retrieval. --- ## 3.7 Retrieval слой (текущий статус) Текущее состояние: **stubbed / sandbox retrieval plan**. Что есть: - генерация плана “что и по какому route исполнять”; - диагностический payload по fragment’ам. Чего пока нет: - боевой deep retrieval из 1С по всем route; - гарантированного factual grounding для каждого ответа assistant mode. --- ## 3.8 Логирование и трассировка В `assistantService` пишется structured log c событием: - `assistant_message_processed` Поля: - `session_id` - `message_id` - `user_message` - `normalizer_output` - `resolved_execution_state` - `routes` - `fallback_type` - `retrieval_payloads` - `assistant_reply` - `trace_id` Это дает базу для будущего field-eval hardening. --- ## 4. Frontend: функциональная архитектура ## 4.1 Режимы UI Реализовано в: - `llm_normalizer/frontend/src/App.tsx` Есть явный переключатель: - `Assistant` - `Decomposition` Поведение: - backend pipeline общий; - UI-представление разное; - decomposition stack не ломается и остается доступным. --- ## 4.2 Assistant Mode UI состав Реализовано в: - `llm_normalizer/frontend/src/components/AssistantPanel.tsx` Элементы: 1. Chat timeline: - user/assistant messages, - timestamp, - trace id для assistant сообщений. 2. Input зона: - поле сообщения, - send, - reset session. 3. Контекст: - `periodHint` - `businessContext` 4. Toggle: - `useMock`. 5. Debug drawer: - раскрывается per assistant message, - показывает raw debug JSON (`trace/fragments/routes/fallback/retrieval/normalized`). --- ## 4.3 Pipeline progress UX Во время обработки показывается этапный status ticker: 1. `Razbirayu zapros` 2. `Proveryayu kontur` 3. `Opredelyayu marshrut` 4. `Ishchu dannye` 5. `Sobirayu otvet` Цель: убрать ощущение “зависло” и визуализировать pipeline. --- ## 4.4 Frontend state flow Ключевые state переменные: - `uiMode` - `assistantSessionId` - `assistantConversation` - `assistantInput` - `assistantBusy` - `assistantStatus` - `assistantError` Flow отправки: 1. optimistic append user message в chat; 2. запуск status ticker; 3. вызов `apiClient.sendAssistantMessage(...)`; 4. обновление `session_id` и полной conversation с backend; 5. остановка ticker + финальный статус. --- ## 4.5 API client для Assistant Реализовано в: - `llm_normalizer/frontend/src/api/client.ts` Добавлены методы: - `sendAssistantMessage(...)` -> `POST /api/assistant/message` - `loadAssistantSession(sessionId)` -> `GET /api/assistant/session/:id` --- ## 5. Что сделано по требованиям ТЗ (mapping) 1. `docs/assistant_mode_spec.md` — выполнено 2. GUI с переключателем `Assistant` / `Decomposition` — выполнено 3. backend endpoint assistant loop — выполнено 4. `answer_composer` слой — выполнено 5. session-based chat history — выполнено (in-memory) 6. debug drawer/expandable technical view — выполнено 7. `docs/assistant_mode_flow.md` — выполнено 8. `docs/known_limits_before_field_eval.md` — выполнено --- ## 6. Критические ограничения текущей реализации 1. **retrieval sandbox/stubbed** - assistant выдает план/маршрут, не full factual extraction по всем route. 2. **session memory volatile** - хранится только в памяти backend процесса. 3. **нет production hardening** - auth/tenancy/persistence/SLO не включены. 4. **composer базовый** - достаточен для MVP loop, но не финальный policy-grade layer. --- ## 7. Запуск и проверка на новой машине (текущий этап) ## 7.1 Backend ```powershell cd X:\1C\NDC_1C\llm_normalizer\backend npm install npm run dev ``` ## 7.2 Frontend ```powershell cd X:\1C\NDC_1C\llm_normalizer\frontend npm install npm run dev ``` ## 7.3 Открыть GUI - `http://localhost:5174` ## 7.4 Smoke test Assistant Mode 1. Переключить mode -> `Assistant`. 2. Ввести сообщение в чат. 3. Нажать `Send`. 4. Проверить: - появился assistant reply; - появился trace id; - открывается debug drawer; - session сохраняет историю. --- ## 8. Тестовый статус к моменту фиксации Проверки выполнены 24.03.2026: - backend tests: `npm test` -> **21 passed** - backend build: `npm run build` -> **OK** - frontend build: `npm run build` -> **OK** Также добавлен endpoint test: - `llm_normalizer/backend/tests/assistantEndpoint.test.ts` Покрывает: - успешный `POST /api/assistant/message`; - session continuity; - `GET /api/assistant/session/:session_id`. --- ## 9. Архитектурный итог этапа Текущий Assistant Mode — это уже **usable dialog loop**: - user-friendly вход (чат), - deterministic decomposition/routing ядро, - единый backend pipeline, - прозрачная debug-плоскость для инженерной диагностики, - session-based continuity в рамках процесса. Для перехода в следующий уровень (field-hardened assistant) нужен следующий блок: - подключение route-specific factual retrieval, - сбор 30–40 реальных полевых запросов, - policy hardening по traces (clarification/no-route/partial quality).