51 KiB
Архитектура агента 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(asyncretrieve(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 есть сейчас?
- Retrieval не вызывается в основном флоу — context_retrieval не использует индекс; rag_context всегда пустой. Приоритет: high.
- RagRetriever не реализован — RagService только индексирует; агент не может получить список документов по запросу через контракт. Приоритет: high.
- IntentRouterV2 не в продакшене — intent, sub_intent, retrieval_spec, layers, evidence_policy есть только в тестах; в приложении другой роутер и нет слоёвого retrieval. Приоритет: high.
- README говорит про retrieval из rag_session для ответа — по факту для ответа в основном режиме rag_session по запросу не используется. Приоритет: high (документация).
- Нет evidence gate в оркестраторе после retrieval — проверка «достаточно ли evidence» и деградация при слабом retrieval только в direct code explain. Приоритет: medium.