423 lines
51 KiB
Markdown
423 lines
51 KiB
Markdown
# Архитектура агента As Is — отчёт
|
||
|
||
## 1. Executive Summary
|
||
|
||
- **Текущее устройство.** Запрос пользователя принимается в модуле `chat` (POST `/api/chat/messages`), ставится в очередь задач и обрабатывается асинхронно. Обработку выполняет `GraphAgentRuntime`: вызывается **router агента** (не IntentRouterV2), по его решению выбирается сценарий и план шагов оркестратора; шаги выполняются как вызовы функций или подграфов LangGraph. Итог — ответ или changeset в задаче и в событии `task_result`.
|
||
|
||
- **Два режима входа.** При `SIMPLE_CODE_EXPLAIN_ONLY=true` (по умолчанию) запросы идут в **CodeExplainChatService**: без роутера, сразу retrieval через CodeExplainRetrieverV2, evidence gate и один промпт. При `false` используется полный агент с роутером и оркестратором.
|
||
|
||
- **Router.** В продакшене используется **RouterService** из `app/modules/agent/engine/router/`: классификатор интентов (эвристики + LLM), регистр графов по `domain_id`/`process_id`, контекст диалога в AgentRepository. **IntentRouterV2** (модуль `rag/intent_router_v2`) в основном приложении **не вызывается** — только в тестах и пайплайне `tests/pipeline_intent_rag`.
|
||
|
||
- **Retrieval.** В основном флоу агента **RAG по запросу в рантайме не вызывается**: в `GraphAgentRuntime.run` переменная `rag_ctx` задаётся как пустой список и не заполняется; граф `project_qa/context_retrieval` получает этот пустой список и строит `source_bundle` только из `files_map` (вложения пользователя). Реальный retrieval по индексу выполняется только: (1) в режиме **direct code explain** (CodeExplainRetrieverV2 → LayeredRetrievalGateway → RagRepository); (2) внутри шага **build_code_explain_pack** при сценарии EXPLAIN_PART (тот же CodeExplainRetrieverV2). Контракт `RagRetriever` (async `retrieve(rag_session_id, query)`) в коде **нигде не реализован**: RagService умеет только индексировать, не извлекать.
|
||
|
||
- **Индексация.** При создании/обновлении RAG-сессии используется RagService с двумя пайплайнами: CodeIndexingPipeline (C0–C4: chunks, symbols, edges, entrypoints, traces, semantic roles) и DocsIndexingPipeline (D1–D4: module catalog, facts, sections, policy). Слои попадают в `rag_chunks`; retrieval по слоям делается только через RagRepository (LayeredRetrievalGateway), не через RagService.
|
||
|
||
- **Графы и пайплайны.** Есть общий оркестратор (ScenarioTemplateRegistry → PlanCompiler → ExecutionEngine). Сценарии: GENERAL_QA (в т.ч. project/qa как подплан project_qa), EXPLAIN_PART, ANALYTICS_REVIEW, DOCS_FROM_ANALYTICS, TARGETED_EDIT, GHERKIN_MODEL. Для project/qa выполняется цепочка подграфов: conversation_understanding → question_classification → context_retrieval (без вызова RAG) → опционально build_code_explain_pack → context_analysis → answer_composition. Отдельные графы зарегистрированы для default/general, project/qa, project/edits, docs/generation и для подшагов project_qa.
|
||
|
||
- **Сборка контекста для LLM.** В основном флоу в модель попадают: `rag_context` (из task_spec; по факту пустой), `confluence_context` (страницы из вложений), `files_map` (переданные пользователем файлы). Контекст по коду из индекса собирается только в direct code explain и в build_code_explain_pack (ExplainPack → PromptBudgeter).
|
||
|
||
- **Диагностика.** В приложении: логи (router decision, graph step result, code explain pack, orchestrator decision), события прогресса (task_progress с stage/message/meta), в `task_result` — meta (route, used_rag, orchestrator_steps, quality). Отдельная структура диагностики (router_plan, execution, retrieval, timings_ms, constraint_violations) реализована в тестовом пайплайне под IntentRouterV2 и в ответ не отдаётся.
|
||
|
||
- **Главные пробелы.** (1) Нет вызова RAG в основном агентском флоу — context_retrieval не использует индекс. (2) IntentRouterV2 и его retrieval/diagnostics не интегрированы в продакшен. (3) RagService не реализует контракт RagRetriever. (4) Целевые слои C5 (Test Mappings), C6 (Code Facts), D5 (Reference Graph), D6 (Doc-Code Links) в индексации и retrieval не представлены. (5) Evidence gate есть только у direct code explain; в оркестраторе quality gates проверяют артефакты шагов, но не «достаточность evidence» в целевом смысле.
|
||
|
||
- **Близость к целевой архитектуре.** Частично: индексация уже многослойная (CODE C0–C4, DOCS D1–D4), есть задел intent-based роутинга (IntentRouterV2 в тестах), оркестрация по сценариям и графам есть. Не хватает: подключения retrieval к основному флоу, объединения роутера с intent/retrieval-спеками, полного набора слоёв и явного evidence gate в оркестраторе.
|
||
|
||
---
|
||
|
||
## 2. End-to-End Flow As Is
|
||
|
||
### 2.1. Request intake
|
||
|
||
**Что происходит.** Клиент шлёт POST `/api/chat/messages` (ChatMessageRequest: message, mode, attachments, files, dialog_session_id и т.д.). ChatModule при `SIMPLE_CODE_EXPLAIN_ONLY=true` отдаёт запрос в CodeExplainChatService.handle_message; иначе — в ChatOrchestrator.enqueue_message. В последнем случае создаётся задача (TaskStore), по idempotency может возвращаться существующая, затем в фоне запускается _process_task.
|
||
|
||
**Evidence.** `app/modules/chat/module.py` (send_message, условие по `_simple_code_explain_only`), `app/modules/chat/service.py` (enqueue_message, _process_task, _resolve_sessions).
|
||
|
||
**Комментарий.** Точка входа одна; разветвление по флагу окружения определяет упрощённый (direct) или полный (agent) путь.
|
||
|
||
### 2.2. Routing
|
||
|
||
**Что происходит.** В полном пути GraphAgentRuntime.run вызывает `self._router.resolve(message, dialog_session_id, mode)`. Это RouterService (agent): читает контекст из RouterContextStore (AgentRepository), при принудительном mode возвращает маршрут из маппинга (project_qa, project_edits, docs_generation и др.), иначе — IntentClassifier: короткие подтверждения → last_routing, детерминированные правила (редакт файла, запрос документации) → соответствующий route, в остальных случаях — LLM (prompt "router_intent") с разбором JSON. Результат — RouteResolution (domain_id, process_id, confidence, reason, fallback_used). При низкой уверенности или невалидной паре (domain_id, process_id) возвращается fallback default/general. Graph factory выбирается по (domain_id, process_id) из IntentRegistry.
|
||
|
||
**Evidence.** `app/modules/agent/service.py` (run, _resolve_graph), `app/modules/agent/engine/router/router_service.py` (resolve, _is_acceptable, _resolution, _fallback), `app/modules/agent/engine/router/intent_classifier.py` (classify_new_intent, from_mode, _deterministic_route, _classify_with_llm), `app/modules/agent/engine/router/__init__.py` (build_router_service, регистрация графов).
|
||
|
||
**Комментарий.** IntentRouterV2 в этом флоу не участвует. graph_id в продакшене — это пара (domain_id, process_id), а не строка из IntentRouterV2.
|
||
|
||
### 2.3. Retrieval
|
||
|
||
**Что происходит.** В GraphAgentRuntime.run перед вызовом оркестратора `rag_ctx` инициализируется как `[]` и не заполняется. TaskSpec получает rag_items=rag_ctx и rag_context=_format_rag(rag_ctx) — т.е. пустой контекст. В плане project_qa шаг context_retrieval (граф ProjectQaRetrievalGraphFactory) в _retrieve_context читает state (resolved_request, question_profile, files_map), объявляет `rag_items: list[dict] = []`, вызывает build_source_bundle(profile, rag_items, files_map) — т.е. только ранжирование переданных файлов, без вызова RAG. Реальный retrieval: (1) CodeExplainChatService — CodeExplainRetrieverV2.build_pack → LayeredRetrievalGateway (C3, C1, C2, C0, lexical fallback); (2) шаг build_code_explain_pack в оркестраторе — тот же build_pack с file_candidates из source_bundle.
|
||
|
||
**Evidence.** `app/modules/agent/service.py` (rag_ctx: list[dict] = [], task_spec), `app/modules/agent/engine/graphs/project_qa_step_graphs.py` (ProjectQaRetrievalGraphFactory._retrieve_context, rag_items=[], build_source_bundle), `app/modules/rag/explain/retriever_v2.py` (build_pack, _entrypoints, _seed_symbols, _trace_builder, _excerpt_fetcher, lexical fallback), `app/modules/rag/explain/layered_gateway.py` (retrieve_layer, retrieve_lexical_code → repository).
|
||
|
||
**Комментарий.** Намеренно не меняя код: в as is основной агентский пайплайн не выполняет retrieval по индексу; контракт RagRetriever не реализован (RagService не имеет метода retrieve).
|
||
|
||
### 2.4. Context assembly
|
||
|
||
**Что происходит.** Для основного агента контекст для шагов собирается в TaskSpecBuilder: metadata содержит rag_items, rag_context, confluence_context, files_map. rag_context формируется в agent как _format_rag(rag_ctx) — при пустом rag_ctx это пустая строка. Confluence — из вложений типа confluence_url. В шагах оркестратора (collect_state) в agent_state попадает этот metadata; графы получают state с rag_context, confluence_context, files_map. Для ответа LLM контекст собирается внутри графов: в project_qa — ProjectQaSupport (build_answer_brief, compose_answer) и при наличии explain_pack — PromptBudgeter.build_prompt_input + code_explain_answer_v2. В direct code explain контекст — только ExplainPack через PromptBudgeter.
|
||
|
||
**Evidence.** `app/modules/agent/service.py` (_format_rag, _format_confluence, task_spec), `app/modules/agent/engine/orchestrator/step_registry.py` (_collect_state, agent_state), `app/modules/agent/engine/graphs/project_qa_step_graphs.py` (ProjectQaAnswerGraphFactory._compose_answer, _compose_explain_answer), `app/modules/rag/explain` (PromptBudgeter).
|
||
|
||
**Комментарий.** Разделения «intent-driven» сборки контекста по слоям в основном флоу нет; слои используются только в CodeExplainRetrieverV2 и при формировании промпта code_explain_answer_v2.
|
||
|
||
### 2.5. LLM answer synthesis
|
||
|
||
**Что происходит.** Ответ генерируется внутри графов и шагов оркестратора. Для default/general — граф, собранный BaseGraphFactory(llm). Для project/qa — цепочка подграфов, финальный ответ в ProjectQaAnswerGraphFactory (_compose_answer: при наличии explain_pack — LLM code_explain_answer_v2, иначе ProjectQaSupport.compose_answer по brief). Для direct code explain — один вызов LLM code_explain_answer_v2 после evidence gate. AgentLlmService.generate вызывается с ключом промпта (router_intent, code_explain_answer_v2 и т.д.) и payload; промпты загружаются через PromptLoader.
|
||
|
||
**Evidence.** `app/modules/agent/engine/graphs/project_qa_step_graphs.py` (ProjectQaAnswerGraphFactory), `app/modules/agent/llm` (AgentLlmService), `app/modules/chat/direct_service.py` (CodeExplainChatService), `app/modules/agent/engine/graphs` (фабрики графов).
|
||
|
||
**Комментарий.** Итоговый ответ и/или changeset собираются ResultAssembler из артефактов шагов (final_answer, final_changeset).
|
||
|
||
### 2.6. Diagnostics
|
||
|
||
**Что происходит.** В рантайме: логи (router decision, graph step result, code explain pack, orchestrator decision); события task_progress (stage, message, meta); в конце — task_result с meta (route, used_rag, used_confluence, orchestrator_steps, quality при наличии). Quality метрики при наличии записываются MetricsPersister в agent_repository. Структурированная диагностика (router_plan, execution, retrieval, timings_ms, constraint_violations) строится в тестах pipeline_intent_rag (helpers/diagnostics) для результата IntentRouterV2 и в ответ API не входит.
|
||
|
||
**Evidence.** `app/modules/agent/service.py` (LOGGER.warning по route/orchestrator, meta в AgentResult, _persist_quality_metrics), `app/modules/chat/service.py` (_publish_progress, task_result), `tests/pipeline_intent_rag/helpers/diagnostics.py` (build_router_plan, init_diagnostics, apply_retrieval_report, validate_constraints).
|
||
|
||
**Комментарий.** used_rag в meta всегда False в текущем коде, т.к. rag_ctx не заполняется.
|
||
|
||
---
|
||
|
||
## 3. Router As Is
|
||
|
||
### 3.1. Main router entrypoints
|
||
|
||
Единственная точка входа роутера в основном приложении — `RouterService.resolve(user_message, conversation_key, mode)` в `app/modules/agent/engine/router/router_service.py`. Сборка: `build_router_service` в `app/modules/agent/engine/router/__init__.py` (IntentRegistry, IntentClassifier, RouterContextStore, IntentSwitchDetector, RouterService).
|
||
|
||
### 3.2. Input contract
|
||
|
||
- **Вход:** `user_message: str`, `conversation_key: str` (dialog_session_id), `mode: str` (например "auto", "project_qa", "project_edits", "docs_generation").
|
||
- **Контекст:** из RouterContextStore по conversation_key — RouterContext (last_routing, message_history, active_intent, dialog_started, turn_index). Контекст обновляется при persist_context после ответа агента.
|
||
|
||
**Evidence.** `app/modules/agent/engine/router/router_service.py` (resolve, context = self._ctx.get), `app/modules/agent/engine/router/schemas.py` (RouterContext).
|
||
|
||
### 3.3. Output contract
|
||
|
||
RouteResolution: domain_id, process_id, confidence, reason, fallback_used, decision_type, explicit_switch. Фабрика графа запрашивается отдельно: graph_factory(domain_id, process_id).
|
||
|
||
**Evidence.** `app/modules/agent/engine/router/schemas.py` (RouteResolution), `app/modules/agent/engine/router/router_service.py` (_resolution, _fallback, _continue_current, graph_factory).
|
||
|
||
### 3.4. Supported intents and sub-intents
|
||
|
||
**Намерения (domain_id / process_id):** default/general, project/qa, project/edits, docs/generation. Внутри оркестратора сценарий (Scenario) определяется TaskSpecBuilder по mode, route и тексту сообщения: GENERAL_QA, EXPLAIN_PART, ANALYTICS_REVIEW, DOCS_FROM_ANALYTICS, TARGETED_EDIT, GHERKIN_MODEL. Подграфы project_qa зарегистрированы как project_qa/conversation_understanding, question_classification, context_retrieval, context_analysis, answer_composition. Sub-intent в смысле IntentRouterV2 (EXPLAIN, OPEN_FILE и т.д.) в этом роутере не фигурируют.
|
||
|
||
**Evidence.** `app/modules/agent/engine/router/__init__.py` (registry.register), `app/modules/agent/engine/router/intent_classifier.py` (_route_mapping, from_mode), `app/modules/agent/engine/orchestrator/task_spec_builder.py` (_detect_scenario).
|
||
|
||
### 3.5. Graph selection logic
|
||
|
||
Граф выбирается по (domain_id, process_id). Для основного запроса оркестратор по сценарию решает, какой план выполнять; в плане шаги могут иметь graph_id="route" (тогда берётся domain_id/process_id из task.routing) или graph_id вида "project_qa/context_retrieval". Резолвер графа: _resolve_graph в GraphAgentRuntime — factory = self._router.graph_factory(domain_id, process_id), fallback на default/general.
|
||
|
||
**Evidence.** `app/modules/agent/service.py` (_resolve_graph), `app/modules/agent/engine/orchestrator/step_registry.py` (_execute_graph_step, graph_key), `app/modules/agent/engine/orchestrator/template_registry.py` (graph_id в шагах).
|
||
|
||
### 3.6. Heuristics / LLM / deterministic logic
|
||
|
||
- Детерминировано: короткие подтверждения → last_routing; целевой редакт файла (_is_targeted_file_edit_request); запрос документации (_is_broad_docs_request) → project/edits, docs/generation.
|
||
- LLM: один вызов при отсутствии детерминированного решения — prompt "router_intent", ожидается JSON с route, confidence, reason; парсинг с допуском code fence.
|
||
- Эвристики: min_confidence=0.7, проверка registry.is_valid(domain_id, process_id); при переключении интента — IntentSwitchDetector.should_switch, при отказе — _continue_current.
|
||
|
||
**Evidence.** `app/modules/agent/engine/router/intent_classifier.py`, `app/modules/agent/engine/router/router_service.py`.
|
||
|
||
### 3.7. Current limitations
|
||
|
||
- Нет keyword_hints, path_scope, layers в выходном контракте роутера; они не передаются в retrieval, т.к. retrieval в основном флоу не вызывается.
|
||
- Контекст диалога ограничен last_routing и message_history; нет структуры query plan / anchors как в IntentRouterV2.
|
||
- IntentRouterV2 с полным контрактом (intent, sub_intent, graph_id, retrieval_spec, retrieval_constraints, evidence_policy) в приложении не используется.
|
||
|
||
| Router capability | Current state | Status | Evidence | Notes |
|
||
|-------------------------|---------------|--------|---------------------------------------------------------------------------|------------------------------------------------------|
|
||
| Main entrypoint | RouterService.resolve | full | router_service.py | |
|
||
| Input: message, session, mode | Yes | full | router_service.py | |
|
||
| Output: domain_id, process_id, confidence, reason | Yes | full | RouteResolution, schemas.py | |
|
||
| intent / sub-intent | domain/process only | partial | intent_classifier _route_mapping; no sub_intent in agent router | Sub-intent только в IntentRouterV2 |
|
||
| graph_id | (domain_id, process_id) | full | registry.get_factory, _resolve_graph | |
|
||
| conversation_mode | decision_type (start/continue/switch) | partial | RouteResolution.decision_type | Не буквально CONTINUE/FOLLOWUP_LIKELY |
|
||
| keyword_hints | — | none | — | Есть в IntentRouterV2.query_plan |
|
||
| path_scope | — | none | — | Есть в IntentRouterV2.retrieval_spec.filters |
|
||
| layers | — | none | — | Есть в IntentRouterV2 |
|
||
| Heuristics + LLM | Yes | full | intent_classifier | |
|
||
| Fallback default/general| Yes | full | _fallback, _is_acceptable | |
|
||
|
||
---
|
||
|
||
## 4. Retrieval / RAG As Is
|
||
|
||
### 4.1. Code retrieval as is
|
||
|
||
- **Где выполняется:** только при direct code explain (CodeExplainChatService) и в шаге build_code_explain_pack (сценарий EXPLAIN_PART). Оба пути используют CodeExplainRetrieverV2 → LayeredRetrievalGateway → RagRepository.
|
||
- **Chunking:** при индексации — CodeTextChunker (code), при retrieval — C0_SOURCE_CHUNKS и lexical fallback по тексту запроса.
|
||
- **Symbol-based:** C1_SYMBOL_CATALOG через retrieve_layer; после entrypoints подтягиваются handler symbols через CodeGraphRepository.get_symbols_by_ids.
|
||
- **Path-aware:** path_prefixes передаются в retrieve_layer и retrieve_lexical_code (из intent/file_candidates).
|
||
- **Entrypoints:** C3_ENTRYPOINTS, фильтрация по entry_type из intent.
|
||
- **Test-specific:** exclude_tests в gateway; при малом числе excerpts делается _merge_test_fallback с include_tests.
|
||
- **Структурные связи:** C2 (edges), TraceBuilder строит пути по графу; SourceExcerptFetcher по путям достаёт фрагменты. Execution traces индексируются (entrypoints + execution_trace_document_builder).
|
||
|
||
В основном агентском флоу (project_qa/context_retrieval) вызова RAG нет: rag_items пустые, source_bundle строится только из files_map.
|
||
|
||
**Evidence.** `app/modules/rag/explain/retriever_v2.py`, `app/modules/rag/explain/layered_gateway.py`, `app/modules/rag/persistence/repository.py`, `app/modules/agent/engine/graphs/project_qa_step_graphs.py` (ProjectQaRetrievalGraphFactory).
|
||
|
||
### 4.2. Docs retrieval as is
|
||
|
||
- **Парсинг документов:** DocsIndexingPipeline при индексации: frontmatter, MarkdownDocChunker, DocsClassifier (doc_kind), build_module_catalog, build_section, build_policy, _extract_facts. Слои: D1_MODULE_CATALOG, D2_FACT_INDEX, D3_SECTION_INDEX, D4_POLICY_INDEX (enums).
|
||
- **Retrieval по документам:** в основном приложении отдельного «docs retrieval» по запросу пользователя не вызывается. LayeredRetrievalGateway и RetrievalStatementBuilder поддерживают слои D1–D4 в запросах (layer_rank_sql), но код, который бы по intent «DOCS_QA» или «GENERATE_DOCS_FROM_CODE» вызывал только docs-слои, в основном флоу не прослеживается — IntentRouterV2 с retrieval_profile "docs" используется только в тестах.
|
||
- **Doc-to-code linking:** явного слоя или индекса D6 (Doc-Code Links) нет. В индексации есть ссылки в документах (frontmatter links), но отдельного кросс-доменного индекса нет.
|
||
|
||
**Evidence.** `app/modules/rag/indexing/docs/pipeline.py`, `app/modules/rag/contracts/enums.py`, `app/modules/rag/persistence/retrieval_statement_builder.py` (D1–D4 в SQL).
|
||
|
||
### 4.3. Map current implementation to target layers
|
||
|
||
| Target element | Current implementation | Status | Evidence | Notes |
|
||
|----------------|------------------------|--------|----------|--------|
|
||
| CODE / C0 Source Chunks | CodeTextChunker + CodeTextDocumentBuilder, слой C0_SOURCE_CHUNKS; retrieval через retrieve_lexical_code и retrieve(..., layers=[C0]) | full | code_text/document_builder.py, pipeline.py, retrieval_statement_builder.py, layered_gateway | |
|
||
| CODE / C1 Symbol Catalog | SymbolExtractor + SymbolDocumentBuilder, C1_SYMBOL_CATALOG; retrieval в retriever_v2 _seed_symbols | full | indexing/code/symbols/, enums.py, retriever_v2.py | |
|
||
| CODE / C2 Symbol Relations | EdgeExtractor, EdgeDocumentBuilder, DataflowDocumentBuilder; слой C2_DEPENDENCY_GRAPH; TraceBuilder использует граф | full | indexing/code/edges/, graph_repository.py | Целевое имя «Symbol Relations»; в коде «dependency/dataflow» |
|
||
| CODE / C3 Entrypoints | EntrypointDetectorRegistry (FastAPI, Flask, Typer/Click), EntrypointDocumentBuilder, execution_trace; C3_ENTRYPOINTS | full | indexing/code/entrypoints/, retriever_v2 _entrypoints | |
|
||
| CODE / C4 Execution Paths | Execution traces индексируются в C2 (execution_trace); пути строятся в рантайме TraceBuilder по графу | partial | execution_trace_builder, trace_builder.py, retriever_v2 | Нет отдельного слоя «C4 Execution Paths»; логика есть |
|
||
| CODE / C5 Test Mappings | Нет отдельного слоя или индекса тест→код | none | — | test_filter только исключает/включает пути |
|
||
| CODE / C6 Code Facts | Нет слоя «code facts» | none | — | |
|
||
| DOCS / D0 Document Chunks | Секции документов как D3_SECTION_INDEX; общего «D0» как аналога C0 нет | partial | docs pipeline build_section | Chunks по сути есть как section docs |
|
||
| DOCS / D1 Document Catalog | D1_MODULE_CATALOG, build_module_catalog | full | enums.py, docs/document_builder.py | |
|
||
| DOCS / D2 Fact Index | D2_FACT_INDEX, _extract_facts из frontmatter links | full | docs pipeline | |
|
||
| DOCS / D3 Entity Catalog | D3_SECTION_INDEX в коде; целевое «Entity Catalog» может отличаться | partial | enums.py DOCS_SECTION_INDEX | Именование не 1:1 |
|
||
| DOCS / D4 Workflow Index | D4_POLICY_INDEX (policy-документы) | partial | docs pipeline build_policy | Ограничено type=policy |
|
||
| DOCS / D5 Reference Graph | Нет отдельного графа ссылок между документами | none | — | |
|
||
| DOCS / D6 Doc-Code Links | Нет | none | — | |
|
||
|
||
---
|
||
|
||
## 5. Graphs / Pipelines As Is
|
||
|
||
### 5.1. List of existing graphs / pipelines
|
||
|
||
- **По (domain_id, process_id):** default/general (BaseGraphFactory), project/qa (ProjectQaGraphFactory), project/edits (ProjectEditsGraphFactory), docs/generation (DocsGraphFactory).
|
||
- **Подграфы project_qa:** project_qa/conversation_understanding (ProjectQaConversationGraphFactory), project_qa/question_classification (ProjectQaClassificationGraphFactory), project_qa/context_retrieval (ProjectQaRetrievalGraphFactory), project_qa/context_analysis (ProjectQaAnalysisGraphFactory), project_qa/answer_composition (ProjectQaAnswerGraphFactory).
|
||
|
||
Планы (ExecutionPlan) задаются ScenarioTemplateRegistry по сценарию: general_qa_v1, project_qa_reasoning_v1, explain_part_v1, analytics_review_v1, docs_from_analytics_v1, targeted_edit_v1, gherkin_model_v1.
|
||
|
||
**Evidence.** `app/modules/agent/engine/router/__init__.py`, `app/modules/agent/engine/orchestrator/template_registry.py`, `app/modules/agent/engine/graphs/`.
|
||
|
||
### 5.2. Shared orchestration logic
|
||
|
||
OrchestratorService: build template → compile plan → validate → ExecutionEngine.run(ctx) → ResultAssembler.assemble. Шаги выполняются StepRegistry: либо функция (action_id), либо executor="graph" с graph_id. Состояние передаётся через ExecutionContext (task, plan, artifacts, evidences, graph_resolver, graph_invoker). Общая логика: один сценарий на запрос, линейные/параллельные зависимости шагов.
|
||
|
||
**Evidence.** `app/modules/agent/engine/orchestrator/service.py`, `app/modules/agent/engine/orchestrator/execution_engine.py`, `app/modules/agent/engine/orchestrator/step_registry.py`.
|
||
|
||
### 5.3. Specialized logic
|
||
|
||
- project_qa: последовательность подграфов + опционально build_code_explain_pack; context_retrieval не вызывает RAG; context_analysis использует explain_pack или analyzer по profile (code/docs).
|
||
- explain_part: при route project/qa тот же project_qa_reasoning_v1 с добавлением шага build_code_explain_pack; анализ и ответ с ExplainPack.
|
||
- Остальные сценарии (review, docs, edit, gherkin) — свои шаги (fetch_source_doc, normalize_document, …), без слоёвого retrieval.
|
||
|
||
**Evidence.** template_registry.py _project_qa, _explain, _review, _docs, _edit, _gherkin; project_qa_step_graphs.py.
|
||
|
||
### 5.4. Retrieval failure behavior
|
||
|
||
В основном флоу retrieval не вызывается, поэтому «failure» не возникает. В CodeExplainRetrieverV2 при пустых entrypoints/symbols/traces/excerpts заполняется pack.missing, делается lexical fallback; при недостатке excerpts — test fallback. CodeExplainEvidenceGate при числе excerpts < min_excerpts возвращает passed=False и шаблонный ответ с диагностикой (без вызова LLM).
|
||
|
||
**Evidence.** retriever_v2.py (_run_pass, _merge_test_fallback), evidence_gate.py.
|
||
|
||
### 5.5. Fallback behavior
|
||
|
||
Router: при низкой уверенности или невалидной паре — fallback default/general. При явном переключении интента, если новый интент не принят — _continue_current. В retrieval (CodeExplainRetrieverV2): lexical fallback, затем при необходимости test fallback. Отдельного «fallback graph» или единого fallback-пайплайна при слабом retrieval в оркестраторе нет.
|
||
|
||
**Evidence.** router_service.py _fallback, _continue_current; retriever_v2.py.
|
||
|
||
### 5.6. Evidence sufficiency checks
|
||
|
||
CodeExplainEvidenceGate (direct code explain): проверка количества code_excerpts >= min_excerpts; при неуспехе — ответ без вызова LLM. В оркестраторе QualityGateRunner проверяет evidence_required по ctx.evidences; шаги вроде explain/review могут добавлять evidence через add_evidence, но в project_qa flow заполнение evidences не прослеживается в коде (collect_state не вызывает retrieval). Т.е. «evidence gate» в смысле «достаточно ли retrieval для ответа» есть только в direct code explain.
|
||
|
||
**Evidence.** `app/modules/chat/evidence_gate.py`, `app/modules/agent/engine/orchestrator/quality_gates.py` (_evidence_required), `app/modules/agent/engine/orchestrator/actions/common.py` (add_evidence).
|
||
|
||
| Pipeline / graph capability | Current state | Status | Evidence | Notes |
|
||
|-----------------------------|---------------|--------|----------|--------|
|
||
| List of graphs by route | Yes | full | router __init__, template_registry | |
|
||
| Shared orchestration | Yes | full | OrchestratorService, ExecutionEngine, StepRegistry | |
|
||
| project_qa subgraphs | Yes | full | project_qa_step_graphs, template_registry | |
|
||
| context_retrieval uses RAG | No | none | project_qa_step_graphs rag_items=[] | |
|
||
| Fallback default/general | Yes (router) | full | router_service | |
|
||
| Fallback on weak retrieval | Only direct explain (evidence gate) | partial | evidence_gate, retriever_v2 | |
|
||
| Evidence sufficiency in orchestrator | Gates есть, evidences в project_qa не наполняются из RAG | partial | quality_gates, step_registry | |
|
||
|
||
---
|
||
|
||
## 6. LLM Context Assembly As Is
|
||
|
||
### 6.1. Inputs to LLM
|
||
|
||
В основном флоу: message (user_message), rag_context (пустой), confluence_context (из вложений), files_map (из запроса). В state графов дополнительно: resolved_request, question_profile, source_bundle (rag_items + file_candidates; rag_items пустые), при EXPLAIN_PART — explain_pack (entrypoints, trace_paths, code_excerpts, missing). В direct code explain — только user message и ExplainPack (после build_pack и evidence gate).
|
||
|
||
**Evidence.** agent/service.py (task_spec, _format_rag), template_registry (metadata), project_qa_step_graphs (state), direct_service.py.
|
||
|
||
### 6.2. Context selection logic
|
||
|
||
Нет отдельного «context selection» по слоям в основном агенте. В CodeExplainRetrieverV2: порядок C3 → C1 → C2 (traces) → excerpts по путям; при нехватке — lexical C0, затем при необходимости тесты. Ограничение по объёму — в PromptBudgeter при сборке промпта.
|
||
|
||
**Evidence.** retriever_v2.py, explain/prompt_budgeter (если есть).
|
||
|
||
### 6.3. Prompt construction
|
||
|
||
AgentLlmService.generate(key, payload). Ключи: router_intent, code_explain_answer_v2 и др. Промпты загружаются через PromptLoader. Для code_explain_answer_v2 вход формирует PromptBudgeter.build_prompt_input(message, pack).
|
||
|
||
**Evidence.** app/modules/agent/llm, project_qa_step_graphs _compose_explain_answer, direct_service.
|
||
|
||
### 6.4. Noise control
|
||
|
||
Явного «noise control» в основном флоу нет. В CodeExplainRetrieverV2: ограничение числа entrypoints, seeds, trace depth, excerpts; PromptBudgeter ограничивает объём в промпте.
|
||
|
||
### 6.5. Handling tests
|
||
|
||
exclude_tests в LayeredRetrievalGateway и retrieval; при малом количестве excerpts — _merge_test_fallback с include_tests. В project_qa_support при build_source_bundle для file_candidates/rag_items применяется штраф за test path, если нет explicit_test в terms.
|
||
|
||
**Evidence.** layered_gateway (exclude_tests, _filter_args), retriever_v2 _merge_test_fallback, project_qa_support build_source_bundle.
|
||
|
||
### 6.6. Current weaknesses
|
||
|
||
- Пустой rag_context в основном флоу; контекст по коду только из вложений (files_map) и при сценарии explain — из explain_pack.
|
||
- Нет intent-driven выбора слоёв и объёмов контекста в оркестраторе.
|
||
- Prompt-level контракты (имена полей, лимиты) разбросаны по промптам и бюджетеру, не оформлены как единый контракт.
|
||
|
||
---
|
||
|
||
## 7. Diagnostics As Is
|
||
|
||
### 7.1. Existing diagnostic artifacts
|
||
|
||
- В приложении: объект meta в ответе задачи (route, used_rag, used_confluence, orchestrator_steps, changeset_filtered_out и т.д.); при наличии quality — сохраняются через MetricsPersister. События: task_status, task_progress (stage, message, meta), task_result, task_error.
|
||
- В тестовом пайплайне (IntentRouterV2): router_plan (intent, sub_intent, graph_id, layers, path_scope, keyword_hints, retrieval_constraints), execution (executed_layers, retrieval_mode_by_layer, top_k_by_layer, filters_by_layer, repo_scope), retrieval (requests, applied, fallback), timings_ms (router, retrieval_total, retrieval_by_layer, prompt_build, llm_call), constraint_violations, prompt (prompt_stats, evidence_summary).
|
||
|
||
**Evidence.** agent/service.py (AgentResult.meta, _persist_quality_metrics), chat/service.py (task_result, _publish_progress), tests/pipeline_intent_rag/helpers/diagnostics.py.
|
||
|
||
### 7.2. Where diagnostics are produced
|
||
|
||
- Router: логи (router decision с route, reason, confidence, fallback_used) в agent/service.py.
|
||
- Графы: логи (graph step result) в project_qa_step_graphs и др.
|
||
- Оркестратор: логи (orchestrator decision), meta в результате (orchestrator_steps, scenario).
|
||
- Quality: quality_meta из orchestrator_result.meta, сохраняется в БД при наличии.
|
||
- IntentRouterV2-диагностика: только в тестах (init_diagnostics, apply_retrieval_report, validate_constraints).
|
||
|
||
### 7.3. Human-readable value
|
||
|
||
Поле message в task_progress; ответ при evidence gate failure (paths, entrypoints, symbols, missing); meta.route (domain_id, process_id, reason); orchestrator_steps (step_id, status). Для аналитика полезны: сценарий, маршрут, факт использования RAG (сейчас всегда false), количество шагов и их статусы.
|
||
|
||
### 7.4. Technical-only value
|
||
|
||
timings_ms, executed_layers, retrieval_mode_by_layer, constraint_violations, детали retrieval_spec — в текущем приложении в API не отдаются, только в тестовой диагностике.
|
||
|
||
### 7.5. Gaps and overload
|
||
|
||
- Пробел: в продакшене нет слоёвой диагностики retrieval (какие слои запрашивались, сколько вернулось, fallback), нет constraint_violations. Слабо видно, почему ответ мог быть слабым (нет привязки к «мало evidence»).
|
||
- Перегрузка: при желании вывести полную диагностику IntentRouterV2 в API пришлось бы дублировать структуру; сейчас она только для тестов.
|
||
|
||
| Diagnostic field / artifact | Produced where | Useful for human | Useful for debug | Notes |
|
||
|-----------------------------|----------------|------------------|------------------|--------|
|
||
| task_progress (stage, message) | chat/service, agent run | Yes | Yes | |
|
||
| meta.route | agent/service | Yes | Yes | |
|
||
| meta.orchestrator_steps | agent/service | Yes | Yes | |
|
||
| meta.used_rag | agent/service | Yes | — | Всегда false as is |
|
||
| quality (persisted) | metrics_persister | Yes | Yes | |
|
||
| router_plan, execution, retrieval, timings_ms | tests pipeline_intent_rag | — | Yes | Не в API |
|
||
| constraint_violations | diagnostics.validate_constraints | — | Yes | Только тесты |
|
||
|
||
---
|
||
|
||
## 8. Docs Support As Is
|
||
|
||
### 8.1. Current docs ingestion / parsing
|
||
|
||
DocsIndexingPipeline: поддержка файлов по DocsFileFilter; парсинг frontmatter (YAML), MarkdownDocChunker по body; DocsClassifier по path (doc_kind); build_module_catalog (D1), build_section (D3), build_policy для type=policy (D4), _extract_facts из frontmatter links (D2). Результат пишется в те же rag_chunks с layer D1–D4.
|
||
|
||
**Evidence.** `app/modules/rag/indexing/docs/pipeline.py`, file_filter, chunkers, document_builder.
|
||
|
||
### 8.2. Current docs retrieval
|
||
|
||
Retrieval по слоям D1–D4 возможен через RagRepository.retrieve(..., layers=[...]) и используется в общем retrieval_statement_builder (layer_rank_sql). В основном агенте и в direct code explain путь «только docs» не вызывается; IntentRouterV2 в тестах может задавать retrieval_profile "docs", но в приложении этот путь не задействован.
|
||
|
||
### 8.3. Existing cross-domain hooks
|
||
|
||
Нет явного слоя или индекса Doc-Code Links. В документах есть frontmatter links; код и доки индексируются в одну БД (rag_chunks), общий запрос по слоям может смешивать CODE и DOCS слои, но выделенной логики «связать док с кодом» нет.
|
||
|
||
### 8.4. Readiness for docs generation from code
|
||
|
||
Сценарий docs_from_analytics и граф docs/generation есть: шаги fetch_source_doc, normalize_document, extract_change_intents, map_to_doc_tree, load_current_docs_context, generate_doc_updates и т.д. Это рассчитано на генерацию/обновление документации из аналитики/контекста, а не напрямую «из кода» в одну команду. База для генерации доков (текущие доки, структура) частично есть; генерация «из кода» опиралась бы на код-контекст, который в основном флоу сейчас не подтягивается через RAG.
|
||
|
||
### 8.5. Main limitations
|
||
|
||
- Нет отдельного docs-only retrieval path в рантайме основного приложения.
|
||
- Нет D0 как общего «document chunks» и нет D5 (Reference Graph), D6 (Doc-Code Links).
|
||
- Различие code vs docs на уровне retrieval_profile и слоёв реализовано в IntentRouterV2 и в БД, но не в цепочке chat → agent → retrieval.
|
||
|
||
---
|
||
|
||
## 9. Gap Analysis vs Target Architecture
|
||
|
||
| Target capability | Current state | Gap | Priority | Notes |
|
||
|------------------|---------------|-----|----------|--------|
|
||
| Router: intent + sub-intent + graph_id | domain_id/process_id, сценарий по эвристикам | Нет sub_intent, keyword_hints, path_scope, layers в контракте агента | high | IntentRouterV2 есть, не подключён |
|
||
| Retrieval в основном флоу | Не вызывается; context_retrieval с пустым rag_items | Подключить вызов RAG по запросу и передавать результат в source_bundle | high | RagService не реализует retrieve |
|
||
| RagRetriever contract | Не реализован | Либо адаптер над RagRepository/LayeredRetrievalGateway, либо вызов gateway из агента | high | |
|
||
| Intent-driven context assembly | Только в direct explain и build_code_explain_pack | Сборка контекста по intent/layers в оркестраторе | medium | |
|
||
| Evidence gate в оркестраторе | Только quality gates по артефактам; evidence_required без RAG | Решение: достаточность evidence после retrieval и при отказе — fallback/деградация | medium | |
|
||
| Слои C5, C6, D5, D6 | Отсутствуют | C5 Test Mappings, C6 Code Facts; D5 Reference Graph, D6 Doc-Code Links | medium | |
|
||
| Docs retrieval в рантайме | Слои есть в БД, вызова нет | Отдельный путь или единый retrieval с profile docs | medium | |
|
||
| Диагностика retrieval и constraints | Только в тестах | Вынести router_plan, execution, retrieval, timings, violations в API или лог-артефакт | low | |
|
||
| README vs реализация | README описывает rag_session как источник retrieval | В основном флоу rag_session по запросу не используется для ответа | high | Уточнить или менять реализацию |
|
||
|
||
---
|
||
|
||
## 10. Concrete Evidence Index
|
||
|
||
### 10.1. Router
|
||
|
||
- `app/modules/agent/engine/router/router_service.py` — RouterService.resolve, persist_context, graph_factory, _fallback, _continue_current, _is_acceptable.
|
||
- `app/modules/agent/engine/router/intent_classifier.py` — classify_new_intent, from_mode, _deterministic_route, _classify_with_llm, _route_mapping.
|
||
- `app/modules/agent/engine/router/__init__.py` — build_router_service, регистрация графов в IntentRegistry.
|
||
- `app/modules/agent/engine/router/schemas.py` — RouteDecision, RouteResolution, RouterContext.
|
||
- `app/modules/agent/engine/router/intents_registry.yaml` — список допустимых пар (domain_id, process_id) для IntentRegistry.is_valid.
|
||
|
||
### 10.2. Retrieval
|
||
|
||
- `app/modules/agent/service.py` — rag_ctx = [], task_spec с rag_items/rag_context.
|
||
- `app/modules/agent/engine/graphs/project_qa_step_graphs.py` — ProjectQaRetrievalGraphFactory._retrieve_context (rag_items=[]), build_source_bundle.
|
||
- `app/modules/rag/explain/retriever_v2.py` — build_pack, _entrypoints, _seed_symbols, _run_pass, _merge_test_fallback.
|
||
- `app/modules/rag/explain/layered_gateway.py` — retrieve_layer, retrieve_lexical_code, RagRepository.
|
||
- `app/modules/rag/persistence/repository.py` — retrieve, retrieve_lexical_code, retrieve_exact_files.
|
||
- `app/modules/rag/services/rag_service.py` — только index_snapshot/index_changes, нет retrieve.
|
||
- `app/modules/contracts.py` — RagRetriever (async retrieve).
|
||
|
||
### 10.3. Graph orchestration
|
||
|
||
- `app/modules/agent/engine/orchestrator/service.py` — OrchestratorService.run, template → compile → validate → engine.run → assemble.
|
||
- `app/modules/agent/engine/orchestrator/template_registry.py` — ScenarioTemplateRegistry.build, _general, _project_qa, _explain, _review, _docs, _edit, _gherkin.
|
||
- `app/modules/agent/engine/orchestrator/step_registry.py` — StepRegistry.execute, _execute_graph_step, graph_id, _build_graph_state.
|
||
- `app/modules/agent/engine/orchestrator/execution_engine.py` — выполнение шагов, quality gates.
|
||
- `app/modules/agent/engine/graphs/project_qa_step_graphs.py` — все ProjectQa*GraphFactory.
|
||
|
||
### 10.4. Diagnostics
|
||
|
||
- `app/modules/agent/service.py` — LOGGER.warning (route, orchestrator), AgentResult.meta, _persist_quality_metrics.
|
||
- `app/modules/chat/service.py` — _publish_progress, task_result event.
|
||
- `tests/pipeline_intent_rag/helpers/diagnostics.py` — build_router_plan, init_diagnostics, apply_retrieval_report, validate_constraints.
|
||
|
||
### 10.5. Docs support
|
||
|
||
- `app/modules/rag/indexing/docs/pipeline.py` — DocsIndexingPipeline.index_file, D1–D4.
|
||
- `app/modules/rag/contracts/enums.py` — RagLayer DOCS_*.
|
||
- `app/modules/rag/intent_router_v2/router.py` — _resolve_retrieval_profile("docs" для DOCS_QA).
|
||
|
||
---
|
||
|
||
## 11. Final Conclusion
|
||
|
||
### 11.1. Насколько текущая реализация уже соответствует целевой архитектуре?
|
||
|
||
Реализация частично соответствует: есть многослойная индексация (CODE C0–C4, DOCS D1–D4), оркестрация по сценариям и подграфам, роутер по домену/процессу с LLM и эвристиками, задел в виде IntentRouterV2 с полным контрактом (intent, retrieval_spec, evidence_policy) и тестовый пайплайн с диагностикой. При этом основной агентский флоу не вызывает RAG при ответе, контракт RagRetriever не реализован, а IntentRouterV2 и его retrieval не интегрированы в приложение. Целевые слои C5, C6, D5, D6 отсутствуют; evidence gate в смысле «достаточность retrieval» есть только в direct code explain.
|
||
|
||
### 11.2. Что логичнее делать следующим шагом?
|
||
|
||
Имеет смысл **сначала уточнить документацию (README и целевую модель)** под as is, чтобы зафиксировать два режима (direct code explain vs full agent), факт отсутствия вызова RAG в основном флоу и роль IntentRouterV2 как тестового/перспективного контура. Затем **параллельно** задать приоритеты: (1) подключение retrieval к основному флоу (адаптер или вызов LayeredRetrievalGateway по решению роутера) и (2) решение о том, переносить ли в продакшен контракт IntentRouterV2 (intent, retrieval_spec, layers) или расширять текущий RouterService. Делать только доработку реализации без обновления README рискованно — расхождение описания и кода сохранится.
|
||
|
||
### 11.3. Какие 3–5 самых важных расхождений между as is и target есть сейчас?
|
||
|
||
1. **Retrieval не вызывается в основном флоу** — context_retrieval не использует индекс; rag_context всегда пустой. Приоритет: high.
|
||
2. **RagRetriever не реализован** — RagService только индексирует; агент не может получить список документов по запросу через контракт. Приоритет: high.
|
||
3. **IntentRouterV2 не в продакшене** — intent, sub_intent, retrieval_spec, layers, evidence_policy есть только в тестах; в приложении другой роутер и нет слоёвого retrieval. Приоритет: high.
|
||
4. **README говорит про retrieval из rag_session для ответа** — по факту для ответа в основном режиме rag_session по запросу не используется. Приоритет: high (документация).
|
||
5. **Нет evidence gate в оркестраторе** после retrieval — проверка «достаточно ли evidence» и деградация при слабом retrieval только в direct code explain. Приоритет: medium.
|