Роутер работает нормально в process v2

This commit is contained in:
2026-04-07 14:09:51 +03:00
parent 0a25e42ea1
commit 8b7b72967e
1746 changed files with 216414 additions and 14037 deletions
+220
View File
@@ -0,0 +1,220 @@
# MVP: процесс v2
## 1. Общее описание
Процесс v2 в текущем MVP ориентирован в первую очередь на **документацию проекта**, но роутер также поддерживает `GENERAL / GENERAL_QA / SUMMARY` для общих обзорных вопросов. Для документных веток нужна активная RAG-сессия с проиндексированными документами.
Это **узкий MVP**, а не полная target architecture. Поддерживаются три маршрута:
- `GENERAL`
- `GENERAL_QA`
- `SUMMARY`
- `DOCS`
- `DOC_EXPLAIN`
- `SUMMARY`
- `FIND_FILES`
Запрос проходит следующие смысловые этапы:
1. проверка готовности сессии;
2. intent routing;
3. формирование retrieval-параметров;
4. retrieval из `DOCS RAG`;
5. минимальная сборка evidence;
6. запуск task-focused workflow нужной ветки;
7. формирование ответа.
```mermaid
flowchart TB
subgraph api [API]
RS[RequestService]
end
subgraph runtime [Agent runtime]
AR[AgentRuntime]
PR[ProcessRunner]
end
subgraph v2 [Процесс v2]
P2[V2Process]
IR[V2IntentRouter]
POL[V2RetrievalPolicyResolver]
AD[V2RagRetrievalAdapter]
RSR[RagSessionRetriever]
ASM[DocsEvidenceAssembler]
end
subgraph rag [Пакет rag]
RR[RagRepository]
end
subgraph wf [Workflow]
SUM[DocsExplainSummaryGraph]
FF[DocsExplainFindFilesGraph]
end
LLM[AgentLlmService]
RS --> AR --> PR --> P2
P2 --> IR --> POL --> AD --> RSR --> RR
AD --> ASM
ASM --> SUM
ASM --> FF
SUM --> LLM
```
Клиент указывает `process_version: v2`. Без `active_rag_session_id` в сессии процесс возвращает сообщение об ошибке. Иначе выполняется цепочка:
маршрутизация → `RetrievalPlan` → retrieval строк из `DOCS RAG` → минимальная сборка evidence → ветвление по `subintent` → запуск workflow.
### Реализованные домены, интенты и сабинтенты
В коде заданы константы `V2Domain`, `V2Intent`, `V2Subintent`. Сейчас процесс intentionally ограничен одной рабочей областью.
| Уровень | Значение (строка) | Реализация |
|--------|-------------------|------------|
| **Домен (routing_domain)** | `DOCS` | Единственный поддерживаемый домен: документация проекта. |
| **Интент** | `DOC_EXPLAIN` | Единственный интент: объяснение по документации. |
| **Сабинтент** | `SUMMARY` | Объяснение темы по SUMMARY-блокам документации. |
| **Сабинтент** | `FIND_FILES` | Поиск путей к документам, где описана нужная сущность или тема. |
Итого в текущем MVP реализована **одна** рабочая тройка домен×интент: `DOCS` + `DOC_EXPLAIN`, с **двумя** ветками по сабинтенту.
---
## 2. Этапы вне workflow (внутри `V2Process.run`)
### 2.1. `V2IntentRouter.route`
| | |
|--|--|
| **Название** | Маршрутизация запроса (v2) |
| **Задача** | Определить домен, интент, subintent и извлечь якоря из текста. |
| **Вход** | `user_query: str` (текст сообщения пользователя). |
| **Выход** | `V2RouteResult`: `routing_domain`, `intent`, `subintent`, `user_query`, `normalized_query`, `target_terms`, `anchors` (`V2RouteAnchors`), `confidence`. |
| **Как работает** | Router реализован по схеме **LLM-first**: `normalization``target_terms`/`anchors extraction``LLM router``deterministic validator``fallback`. LLM является **основным селектором маршрута**. Deterministic-слой больше не выбирает маршрут по умолчанию: он отвечает только за extraction, валидацию enum/комбинаций и fallback при сломанном или невалидном ответе LLM. В trace пишется событие `intent_routed`. |
Код: `src/app/core/agent/processes/v2/intent_router/router.py`, `modules/normalizer.py`, `modules/target_terms.py`, `modules/anchors.py`, `routers/llm.py`, `routers/validator.py`, `routers/fallback.py`.
---
### 2.2. `V2RetrievalPolicyResolver.resolve`
| | |
|--|--|
| **Название** | Политика retrieval для v2 |
| **Задача** | По результату роутинга выбрать профиль, список слоёв RAG и лимит строк выдачи. |
| **Вход** | `V2RouteResult`. |
| **Выход** | `RetrievalPlan`: `profile`, `layers`, `limit`, опционально `filters`. |
| **Как работает** | Это отдельный смысловой шаг между routing и retrieval. Он не ходит в БД и не извлекает данные, а только подготавливает параметры поиска. Для `FIND_FILES` выбирается один профиль слоёв и лимит, для `SUMMARY` — другой. Лог: `retrieval_plan_resolved`. |
Код: `src/app/core/agent/processes/v2/retrieval/policy_resolver.py`.
---
### 2.3. `V2RagRetrievalAdapter` → `RagSessionRetriever.retrieve`
| | |
|--|--|
| **Название** | Загрузка сырых строк из RAG по плану |
| **Задача** | Делегировать поиск в единственную реализацию retrieval в пакете `rag`. |
| **Вход** | `rag_session_id`, `query_text` (нормализованный запрос), `RetrievalPlan`. |
| **Выход** | `list[dict]` — строки чанков в формате `RagRepository.retrieve` (поля `path`, `layer`, `metadata`, и т.д.). |
| **Как работает** | Выполняется retrieval по уже сформированному плану: профиль, список слоёв и лимит. На этом шаге происходит только извлечение сырых строк из `DOCS RAG`. Лог: `rag_rows_fetched`. |
Код адаптера: `src/app/core/agent/processes/v2/retrieval/v2_rag_adapter.py`.
Код API: `src/app/core/rag/retrieval/session_retriever.py`.
---
### 2.4. `DocsEvidenceAssembler`
| | |
|--|--|
| **Название** | Сборка evidence для задачи |
| **Задача** | Превратить сырые строки retrieval в списки summary или кандидатов файлов с дедупом и скорингом. |
| **Вход** | Список строк `rows`, `V2RouteResult` (для `target_terms`). |
| **Выход** | `list[RetrievedSummary]` или `list[RetrievedFile]`. |
| **Как работает** | Это **минимальная evidence-проверка**, достаточная для MVP. Для `SUMMARY` отбрасываются записи без summary-текста и summary-like секции, затем применяется дедуп и простой скоринг по терминам. Для `FIND_FILES` остаются только релевантные пути документов, также с дедупом и простым скорингом. Здесь нет сложной многоступенчатой валидации: задача шага — отфильтровать очевидный шум и передать в workflow компактное evidence. Лог: `evidence_assembled`. |
Код: `src/app/core/agent/processes/v2/evidence/assembler.py`.
---
## 3. Шаги workflow
Текущие workflow являются **task-focused**: каждая ветка решает одну узкую прикладную задачу и не содержит общей универсальной логики для всех типов вопросов.
### 3.1. Ветка `SUMMARY`: `GenerateSummaryAnswerStep`
| | |
|--|--|
| **Название** | Сборка ответа по summary |
| **Задача** | Сформировать ответ пользователю по найденным SUMMARY-блокам или сообщить об отсутствии. |
| **Вход** | `DocsExplainSummaryContext`: `runtime`, `route`, `rag_session_id`, `prompt_name`, `documents` (список `RetrievedSummary`). |
| **Выход** | Контекст с `answer: str`, `prompt_input` при успешном вызове LLM. |
| **Как работает** | Workflow получает уже отобранные summary-документы. Если документов нет — возвращает честный fallback-ответ. Иначе собирает prompt input из запроса пользователя и найденных summary-блоков и вызывает LLM. Workflow не занимается retrieval и не строит retrieval-план: он решает только задачу генерации ответа по уже подготовленному evidence. |
Код: `src/app/core/agent/processes/v2/workflows/docs_explain_summary/steps/generate_summary_answer_step.py`.
Граф: `DocsExplainSummaryGraph` (`V2WorkflowGraph`).
---
### 3.2. Ветка `FIND_FILES`: `FinalizeFindFilesAnswerStep`
| | |
|--|--|
| **Название** | Сборка списка файлов |
| **Задача** | Вывести пользователю markdown-список путей к файлам документации. |
| **Вход** | `DocsExplainFindFilesContext`: `runtime`, `route`, `rag_session_id`, `files` (`RetrievedFile`). |
| **Выход** | Контекст с `answer: str`. |
| **Как работает** | Workflow получает уже собранный список файлов и формирует финальный ответ. Если файлов нет — возвращает fallback. Если файлы есть — отдает детерминированный список путей. Эта ветка intentionally не использует LLM, потому что задача сводится к выдаче путей, а не к генерации объяснения. |
Код: `src/app/core/agent/processes/v2/workflows/docs_explain_find_files/steps/finalize_find_files_answer_step.py`.
Граф: `DocsExplainFindFilesGraph` (`V2WorkflowGraph`).
---
### 3.3. Транспорт: `V2WorkflowGraph`
| | |
|--|--|
| **Название** | Workflow v2 с буфером trace |
| **Задача** | Выполнить шаги без пошаговых `step_started`/`step_completed` в trace; один раз сбросить сводку. |
| **Вход** | Контекст workflow (`DocsExplainSummaryContext` или `DocsExplainFindFilesContext`). |
| **Выход** | Обновлённый контекст. |
| **Как работает** | Для каждого шага: `trace_input` до `run`, затем `run`, затем `trace_output`; записи копятся в список. В trace уходят `workflow_started`, затем `workflow_trace_flushed` с массивом шагов, затем `workflow_completed`. Статусы пользователю публикуются через `publisher` как и раньше. |
Код: `src/app/core/agent/processes/v2/workflows/v2_workflow_graph.py`.
---
## 4. Сборка в приложении
В `ModularApplication` создаются `RagSessionRetriever`, `V2RagRetrievalAdapter`, `V2RetrievalPolicyResolver`, `DocsEvidenceAssembler` и передаются в `V2Process` (см. `src/app/core/application.py`).
---
## 5. Итоговая концептуальная схема текущего MVP
В концептуальном виде текущий `v2` работает так:
1. **Session check**
Проверка, что есть активная RAG-сессия проекта.
2. **LLM-first intent routing**
Нормализация, extraction (`target_terms`, `anchors`), затем основной выбор маршрута через LLM.
3. **Deterministic validation + fallback**
Проверка enum/комбинации маршрута и fallback только если LLM не ответил или вернул невалидный маршрут.
4. **Retrieval parameter planning**
Формирование профиля поиска, слоёв и лимитов.
5. **RAG retrieval**
Загрузка сырых строк из `DOCS RAG`.
6. **Minimal evidence assembly**
Дедуп, базовый скоринг, отбор полезных summary или файлов.
7. **Task-focused workflow**
Узкая ветка `SUMMARY` или `FIND_FILES`.
8. **Final response**
Либо explanation через LLM, либо детерминированный список файлов.
Это и есть актуальная архитектура **узкого MVP**, синхронизированная с текущей реализацией.