# V2IntentRouter Architecture ## 1. Архитектура Текущий `V2IntentRouter` состоит из следующих компонентов: - `router.py` Главная точка входа и оркестратор. - `modules/normalizer.py` Нормализация текста запроса в `normalized_query`. - `modules/target_terms.py` Извлечение `target_terms`, `endpoint_paths`, `matched_aliases`, `alias_docs`. - `modules/anchors.py` Извлечение `anchors` и вспомогательных marker-сигналов. - `routers/docs_subintent_resolver.py` Определение `subintent`. - `routers/deterministic.py` Детерминированное определение `routing_domain`, `intent`, `subintent`, `confidence`, `routing_mode`, `llm_router_used`, `reason_short`. - `routers/llm.py` LLM-based определение `routing_domain`, `intent`, `subintent`, `confidence`, `reason_short`. - `routers/prompts.yml` Prompt для LLM-router. ## 2. Контракт ### Вход - `user_query: str` ### Выход `V2RouteResult`: - `routing_domain: str` - `intent: str` - `subintent: str` - `user_query: str` - `normalized_query: str` - `target_terms: list[str]` - `anchors: V2RouteAnchors` - `confidence: float` - `routing_mode: str` - `llm_router_used: bool` - `reason_short: str` `V2RouteAnchors`: - `entity_names: list[str]` - `terms: list[str]` - `file_names: list[str]` - `endpoint_paths: list[str]` - `target_doc_hints: list[str]` - `matched_aliases: list[str]` - `process_domain: str | None` - `process_subdomain: str | None` ## 3. Поддерживаемые домены, интенты и сабинтенты ### Домены - `DOCS` - `GENERAL` ### Интенты - `DOC_EXPLAIN` - `GENERAL_QA` ### Сабинтенты - `SUMMARY` - `FIND_FILES` ### Поддерживаемые маршруты - `GENERAL / GENERAL_QA / SUMMARY` - `DOCS / DOC_EXPLAIN / SUMMARY` - `DOCS / DOC_EXPLAIN / FIND_FILES` ## 4. Флоу обработки запроса 1. `router.py` принимает `user_query`. 2. `modules/normalizer.py` строит `normalized_query`. 3. `modules/target_terms.py` извлекает ключевые термы и alias-based сигналы. 4. `modules/anchors.py` строит `anchors` и marker-сигналы. 5. `router.py` собирает `QueryFeatures`. 6. `routers/deterministic.py` пытается определить маршрут детерминированно. 7. Если deterministic route найден, он сразу возвращается. 8. Если deterministic route не найден, `router.py` вызывает `routers/llm.py`. 9. Если LLM вернул валидный маршрут, собирается `V2RouteResult` с `routing_mode="llm_assisted"`. 10. Если LLM недоступен или не вернул валидный маршрут, используется fallback: `GENERAL / GENERAL_QA / SUMMARY` с `routing_mode="llm_fallback"`. ## 5. Компоненты по флоу ### `router.py` - Задача Собрать весь процесс роутинга в одной входной точке. - Как решает Последовательно вызывает normalizer, target terms extractor, anchors extractor, deterministic router и при необходимости LLM router. - Вход `user_query: str` - Выход `V2RouteResult` ### `modules/normalizer.py` - Задача Привести запрос к стабильной форме для дальнейшего анализа. - Как решает Схлопывает лишние пробелы через `" ".join(...split())`. - Вход `user_query: str` - Выход `normalized_query: str` ### `modules/target_terms.py` - Задача Выделить ключевые термы и retrieval-сигналы из запроса. - Как решает Использует: - regex для path/entity-like фрагментов - список stop-words - alias rules с фразами и каноническими термами - эвристику для `/health` - Вход `normalized_query: str` - Выход `TargetTermsAnalysis`: - `target_terms` - `endpoint_paths` - `matched_aliases` - `alias_docs` ### `modules/anchors.py` - Задача Построить полный набор `anchors` и doc-oriented marker-сигналов. - Как решает Использует: - regex для `entity_names` и `file_names` - словари marker-фраз: - file markers - architecture markers - logic markers - domain markers - endpoint markers - map `endpoint -> target_doc_hint` - alias docs из `TargetTermsAnalysis` - Вход - `normalized_query: str` - `TargetTermsAnalysis` - Выход `AnchorAnalysis`: - `anchors` - `file_markers` - `architecture_markers` - `logic_markers` - `domain_markers` - `endpoint_markers` ### `routers/docs_subintent_resolver.py` - Задача Определить `subintent`. - Как решает Эвристика: - если есть `file_markers` -> `FIND_FILES` - если есть doc-signals (`endpoint_paths`, `endpoint_markers`, `architecture_markers`, `logic_markers`, `domain_markers`, `target_doc_hints`) -> `SUMMARY` - иначе `None` - Вход `QueryFeatures` - Выход `subintent: str | None` ### `routers/deterministic.py` - Задача Детерминированно определить маршрут без LLM там, где это возможно. - Как решает Использует: - `DocsSubintentResolver` - проверку conflicting doc anchors - список general markers Правила: - `FIND_FILES` -> `DOCS / DOC_EXPLAIN / FIND_FILES` - `subintent != None` и нет конфликта doc-signals -> `DOCS / DOC_EXPLAIN / SUMMARY` - general marker -> `GENERAL / GENERAL_QA / SUMMARY` - Вход - `user_query: str` - `QueryFeatures` - `anchors: V2RouteAnchors` - Выход `V2RouteResult | None` ### `routers/llm.py` - Задача Определить маршрут через LLM, если deterministic routing не дал результата. - Как решает Формирует JSON payload из: - `user_query` - `normalized_query` - `target_terms` - `anchors` - списка допустимых маршрутов Затем: - вызывает LLM - парсит JSON - валидирует маршрут по whitelist - нормализует `confidence` - Вход - `user_query: str` - `normalized_query: str` - `target_terms: list[str]` - `anchors: dict` - Выход `dict | None`: - `routing_domain` - `intent` - `subintent` - `confidence` - `reason_short` ### `routers/prompts.yml` - Задача Задать LLM-router формальный контракт ответа. - Как решает Описывает допустимые маршруты и требует вернуть только JSON. - Вход Payload от `routers/llm.py` - Выход Структурированный JSON-ответ LLM