Files
agent/architecture_as_is.md
2026-03-12 16:55:23 +03:00

51 KiB
Raw Permalink Blame History

Архитектура агента 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 (C0C4: chunks, symbols, edges, entrypoints, traces, semantic roles) и DocsIndexingPipeline (D1D4: 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 C0C4, DOCS D1D4), есть задел 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 поддерживают слои D1D4 в запросах (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 (D1D4 в 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 D1D4.

Evidence. app/modules/rag/indexing/docs/pipeline.py, file_filter, chunkers, document_builder.

8.2. Current docs retrieval

Retrieval по слоям D1D4 возможен через 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, D1D4.
  • 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 C0C4, DOCS D1D4), оркестрация по сценариям и подграфам, роутер по домену/процессу с 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. Какие 35 самых важных расхождений между 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.