# 0) TL;DR (10–15 строк) - В `intent_router_v2` графы задаются как строковые `graph_id`: `CodeQAGraph` и `DocsQAGraph` (`app/modules/rag/intent_router_v2/intent/graph_id_resolver.py:4`, класс `GraphIdResolver.resolve`). - Точка входа роутера: `IntentRouterV2.route(...)` (`app/modules/rag/intent_router_v2/router.py:35`, класс `IntentRouterV2`). - Отдельные классы/функции с именами `CodeQAGraph` и `DocsQAGraph` в `app/` не найдены (поиск по коду). - В тестовом CLI-пайплайне выполнение идет через `IntentRouterRagPipelineRunner.run_case(...)` (`tests/pipeline_intent_rag/helpers/pipeline_runner.py:45`) и `PipelineRuntime.run_*` (`tests/pipeline_intent_rag/helpers/runtime.py:31`). - Контракт роутера возвращается моделью `IntentRouterResult` (`app/modules/rag/intent_router_v2/models.py:139`) и включает `intent`, `retrieval_profile`, `query_plan`, `retrieval_spec`, `retrieval_constraints`, `symbol_resolution`, `evidence_policy`. - `sub_intent`, `symbol_kind_hint`, `symbol_candidates`, `path_hints`, `doc_scope_hints` находятся внутри `query_plan` (`app/modules/rag/intent_router_v2/models.py:43`). - Топ-слои retrieval задаются фабрикой `RetrievalSpecFactory` (`app/modules/rag/intent_router_v2/retrieval/retrieval_spec_factory.py:9`). - Реально индексируемые/используемые слои: `C0..C3`, `D1..D4` (`app/modules/rag/indexing/code/pipeline.py:37`, `app/modules/rag/indexing/docs/pipeline.py:24`, `app/modules/rag/intent_router_v2/retrieval/retrieval_spec_factory.py:10`). - В enum есть `C4..C6`, но build/retrieval-код для них в `app/modules/rag` (кроме `README` и `enums.py`) не найден (`app/modules/rag/contracts/enums.py:13`). - Слой `F0` в `app/` и `tests/` не найден (поиск по коду). - Ранжирование retrieval: `lexical_rank -> test_penalty -> layer_rank -> distance` (`app/modules/rag/persistence/retrieval_statement_builder.py:59`). - В `pipeline_intent_rag` evidence gate отсутствует; в `chat` есть `CodeExplainEvidenceGate(min_excerpts=2)` (`app/modules/chat/evidence_gate.py:15`). ## 1) High-level pipeline (диаграмма текстом) ### CodeQAGraph `Router -> Plan -> Retrieval per layer -> Merge/Rank -> Evidence gate -> LLM prompt builder` - Router: `IntentRouterV2.route` (`app/modules/rag/intent_router_v2/router.py:35`, класс `IntentRouterV2`). Определяет `intent`, `graph_id`, `query_plan`, `retrieval_spec`, `retrieval_constraints`, `symbol_resolution`. - Plan: `QueryPlanBuilder.build` (`app/modules/rag/intent_router_v2/analysis/query_plan_builder.py:50`, класс `QueryPlanBuilder`). Извлекает anchors, `sub_intent`, symbol/path/doc hints. - Retrieval per layer: `RetrievalSpecFactory.build` (`app/modules/rag/intent_router_v2/retrieval/retrieval_spec_factory.py:74`) + `RagDbAdapter.retrieve` (`tests/pipeline_intent_rag/helpers/rag_db_adapter.py:41`). Для `CODE_QA` выбираются `C*` слои; выполняется запрос в БД с фильтрами. - Merge/Rank: `RetrievalStatementBuilder.build_retrieve` (`app/modules/rag/persistence/retrieval_statement_builder.py:9`). Все выбранные слои читаются одним SQL и сортируются по `lexical_rank`, `test_penalty`, `layer_rank`, `distance`. - Evidence gate: в цепочке `tests/pipeline_intent_rag` не найден. Для отдельного code-explain чата есть `CodeExplainEvidenceGate.evaluate` (`app/modules/chat/evidence_gate.py:19`). - LLM prompt builder: в режиме `full_chain` — `GigaChatAnswerer.answer`/`_format_context` (`tests/pipeline_intent_rag/helpers/llm_answerer.py:15`, `:27`). Формируется prompt из вопроса и первых RAG-строк. ### DocsQAGraph `Router -> Plan -> Retrieval per layer -> Merge/Rank -> Evidence gate -> LLM prompt builder` - Router: `IntentRouterV2.route` (`app/modules/rag/intent_router_v2/router.py:35`). Для `DOCS_QA` ставит `retrieval_profile="docs"` (`app/modules/rag/intent_router_v2/router.py:112`). - Plan: `QueryPlanBuilder.build` (`app/modules/rag/intent_router_v2/analysis/query_plan_builder.py:50`). Для `DOCS_QA` принудительно `sub_intent="EXPLAIN"` (`app/modules/rag/intent_router_v2/analysis/query_plan_builder.py:78`). - Retrieval per layer: `RetrievalSpecFactory.build` (`app/modules/rag/intent_router_v2/retrieval/retrieval_spec_factory.py:74`) + `RagDbAdapter.retrieve` (`tests/pipeline_intent_rag/helpers/rag_db_adapter.py:41`). Для docs выбираются `D*` слои; при `path_scope` используется docs-scoped набор (`app/modules/rag/intent_router_v2/retrieval/retrieval_spec_factory.py:97`). - Merge/Rank: `RetrievalStatementBuilder.build_retrieve` (`app/modules/rag/persistence/retrieval_statement_builder.py:9`). Механизм ранжирования тот же, что и для code. - Evidence gate: для docs в `pipeline_intent_rag` не найден. - LLM prompt builder: в `full_chain` тот же `GigaChatAnswerer` (`tests/pipeline_intent_rag/helpers/llm_answerer.py:15`). ## 2) Router contract (фактическое API) ### Пример JSON (code) ```json { "intent": "CODE_QA", "sub_intent": "EXPLAIN", "retrieval_profile": "code", "symbol_kind_hint": "class", "symbol_candidates": ["Context"], "path_hints": [], "path_scope": [], "doc_scope_hints": [], "layers": ["C1_SYMBOL_CATALOG", "C0_SOURCE_CHUNKS", "C2_DEPENDENCY_GRAPH"], "retrieval_constraints": { "include_globs": ["src/**"], "exclude_globs": ["tests/**", "**/test_*.py", "**/*_test.py"], "prefer_globs": [], "test_file_globs": [], "test_symbol_patterns": [], "max_candidates": 20, "fuzzy_symbol_search": {"enabled": true, "max_distance": 2, "top_k": 5} }, "symbol_resolution": { "status": "pending", "resolved_symbol": null, "alternatives": ["Context"], "confidence": 0.0 } } ``` ### Пример JSON (docs) ```json { "intent": "DOCS_QA", "sub_intent": "EXPLAIN", "retrieval_profile": "docs", "symbol_kind_hint": "unknown", "symbol_candidates": [], "path_hints": ["README_DEPLOY.md"], "path_scope": ["README_DEPLOY.md"], "doc_scope_hints": ["README_DEPLOY.md", "README*", "docs/**", "**/*.md"], "layers": ["D3_SECTION_INDEX", "D2_FACT_INDEX"], "retrieval_constraints": { "include_globs": ["README_DEPLOY.md", "docs/**", "README*", "**/*.md"], "exclude_globs": [".venv/**", "node_modules/**", "**/*.bin", "**/*.png", "**/*.jpg"], "prefer_globs": [], "test_file_globs": [], "test_symbol_patterns": [], "max_candidates": 20, "fuzzy_symbol_search": {"enabled": true, "max_distance": 2, "top_k": 5} }, "symbol_resolution": { "status": "not_requested", "resolved_symbol": null, "alternatives": [], "confidence": 0.0 } } ``` ### Поля контракта - `intent`, `retrieval_profile`: формируются в `IntentRouterV2.route` (`app/modules/rag/intent_router_v2/router.py:35`). - `sub_intent`, `symbol_kind_hint`, `symbol_candidates`, `path_hints`, `doc_scope_hints`: внутри `QueryPlan` (`app/modules/rag/intent_router_v2/models.py:43`), заполняются в `QueryPlanBuilder.build` (`app/modules/rag/intent_router_v2/analysis/query_plan_builder.py:50`). - `path_scope`: находится в `retrieval_spec.filters.path_scope`; строится `RetrievalFilterBuilder._path_scope` (`app/modules/rag/intent_router_v2/retrieval/retrieval_filter_builder.py:63`). - `layers`: отдельного top-level поля в `IntentRouterResult` нет; фактический источник — `retrieval_spec.layer_queries[].layer_id` (`app/modules/rag/intent_router_v2/models.py:121`, `:125`). - `retrieval_constraints`: модель `RetrievalConstraints` (`app/modules/rag/intent_router_v2/models.py:67`), заполняется в `RetrievalConstraintsFactory.build` (`app/modules/rag/intent_router_v2/retrieval/retrieval_constraints_factory.py:22`). - `symbol_resolution`: модель `SymbolResolution` (`app/modules/rag/intent_router_v2/models.py:79`), первичный статус задает `_initial_symbol_resolution` (`app/modules/rag/intent_router_v2/router.py:93`). ### `symbol_resolution` статусы и переходы - Допустимые статусы: `not_requested`, `pending`, `resolved`, `ambiguous`, `not_found` (`app/modules/rag/intent_router_v2/models.py:15`). - Начальное состояние: `IntentRouterV2._initial_symbol_resolution` (`app/modules/rag/intent_router_v2/router.py:93`). - Изменение статуса в тестовом router+rag пайплайне: `_resolve_symbol` (`tests/pipeline_intent_rag/helpers/pipeline_runner.py:69`), где `pending` переходит в `resolved`/`ambiguous`/`not_found`. ### Где определены типы/схемы и где валидация - Типы/схемы: `QueryPlan`, `RetrievalConstraints`, `SymbolResolution`, `RetrievalSpec`, `IntentRouterResult` в `app/modules/rag/intent_router_v2/models.py:43`, `:67`, `:79`, `:121`, `:139`. - Валидация: pydantic-модели с `ConfigDict(extra="forbid")` (например `app/modules/rag/intent_router_v2/models.py:44`, `:68`, `:80`, `:122`, `:140`), плюс валидаторы confidence (`app/modules/rag/intent_router_v2/models.py:37`, `:208`). ## 3) Layer inventory (что реально индексируется и как) ### 3.1 Code layers #### C0_SOURCE_CHUNKS - Назначение: фрагменты исходного кода для цитирования и lexical fallback. - Единица индексации: chunk. - Источник данных: AST-разбор (`ast.parse`) с fallback на оконную нарезку (`app/modules/rag/indexing/code/code_text/chunker.py:17`). - Схема записи: - Базовые поля документа: `layer`, `repo_id`, `commit_sha`, `path`, `title`, `text`, `span_start/end`, `metadata`, `embedding` (`app/modules/rag/contracts/documents.py:62`). - C0 metadata: `chunk_index`, `chunk_type`, `module_or_unit`, `is_test`, `artifact_type` (`app/modules/rag/indexing/code/code_text/document_builder.py:17`). - Колонки БД: `rag_chunks` + `layer/lang/repo_id/commit_sha/title/metadata_json/span_*...` (`app/modules/rag/persistence/schema_repository.py:47`, `:112`). - Где строится индекс: `CodeIndexingPipeline.index_file` (`app/modules/rag/indexing/code/pipeline.py:37`) + `CodeTextDocumentBuilder.build` (`app/modules/rag/indexing/code/code_text/document_builder.py:9`). - Где retrieval: `RagDbAdapter.retrieve` (`tests/pipeline_intent_rag/helpers/rag_db_adapter.py:41`) -> `RagRepository.retrieve|retrieve_lexical_code` (`app/modules/rag/persistence/repository.py:62`, `:87`). - Как ранжируется: `build_retrieve` и `build_lexical_code` (`app/modules/rag/persistence/retrieval_statement_builder.py:9`, `:64`). #### C1_SYMBOL_CATALOG - Назначение: каталог символов (class/function/method/import aliases). - Единица индексации: symbol. - Источник данных: Python AST visitor (`app/modules/rag/indexing/code/symbols/extractor.py:32`). - Схема записи: - C1 metadata: `symbol_id`, `qname`, `kind`, `signature`, `decorators_or_annotations`, `docstring_or_javadoc`, `parent_symbol_id`, `package_or_module`, `is_entry_candidate`, `is_test`, `lang_payload`, `artifact_type` (`app/modules/rag/indexing/code/symbols/document_builder.py:20`). - Где строится индекс: `SymbolExtractor.extract` (`app/modules/rag/indexing/code/symbols/extractor.py:24`) + `SymbolDocumentBuilder.build` (`app/modules/rag/indexing/code/symbols/document_builder.py:9`). - Где retrieval: тот же общий путь SQL retrieval (`app/modules/rag/persistence/retrieval_statement_builder.py:9`). - Как ранжируется: общий ranking SQL (`app/modules/rag/persistence/retrieval_statement_builder.py:31`, `:39`, `:59`). #### C2_DEPENDENCY_GRAPH - Назначение: связи между символами. - Единица индексации: edge. - Источник данных: AST visitor по классам/функциям/import/call (`app/modules/rag/indexing/code/edges/extractor.py:33`). - Схема записи: - C2 metadata: `edge_id`, `edge_type`, `src_symbol_id`, `src_qname`, `dst_symbol_id`, `dst_ref`, `resolution`, `is_test`, `lang_payload`, `artifact_type` (`app/modules/rag/indexing/code/edges/document_builder.py:18`). - Где строится индекс: `EdgeExtractor.extract` (`app/modules/rag/indexing/code/edges/extractor.py:24`) + `EdgeDocumentBuilder.build` (`app/modules/rag/indexing/code/edges/document_builder.py:9`). - Где retrieval: общий SQL retrieval (`app/modules/rag/persistence/retrieval_statement_builder.py:9`). - Как ранжируется: общий ranking SQL (`app/modules/rag/persistence/retrieval_statement_builder.py:59`). Отдельно по `C2_DEPENDENCY_GRAPH`: - Поддерживаемые `edge_type`: `inherits`, `imports`, `calls` (`app/modules/rag/indexing/code/edges/extractor.py:43`, `:58`, `:72`). - `dst_ref`: собирается из AST-узла имени/атрибута (`app/modules/rag/indexing/code/edges/extractor.py:107`). - `dst_symbol_id`: ищется в `qname_map` (`app/modules/rag/indexing/code/edges/extractor.py:89`). - `resolution`: `"resolved"` если `dst_symbol_id` найден, иначе `"partial"` (`app/modules/rag/indexing/code/edges/extractor.py:102`). #### C3_ENTRYPOINTS - Назначение: точки входа (HTTP/CLI). - Единица индексации: entrypoint. - Источник данных: эвристики по decorators символов (`FastAPI`, `Flask`, `Typer/Click`) (`app/modules/rag/indexing/code/entrypoints/registry.py:23`). - Схема записи: - C3 metadata: `entry_id`, `entry_type`, `framework`, `route_or_command`, `handler_symbol_id`, `is_test`, `lang_payload`, `artifact_type` (`app/modules/rag/indexing/code/entrypoints/document_builder.py:17`). - Где строится индекс: detectors `FastApiEntrypointDetector.detect`, `FlaskEntrypointDetector.detect`, `TyperClickEntrypointDetector.detect` (`app/modules/rag/indexing/code/entrypoints/fastapi_detector.py:11`, `flask_detector.py:9`, `typer_click_detector.py:9`). - Где retrieval: общий SQL retrieval (`app/modules/rag/persistence/retrieval_statement_builder.py:9`). - Как ранжируется: общий ranking SQL (`app/modules/rag/persistence/retrieval_statement_builder.py:59`), приоритет слоя `C3` в `layer_rank` = 0 (`app/modules/rag/persistence/retrieval_statement_builder.py:41`). ### 3.2 Docs layers #### D1_MODULE_CATALOG - Назначение: карточка модуля документации. - Единица: документ на файл (если есть `id/type/domain` во frontmatter). - Схема: `module_id`, `type`, `domain`, `status`, `version`, `tags`, `owners`, `links`, `source_path`, `summary_text`, `doc_kind` и поля связей (`calls_api`, `called_by`, ... ) (`app/modules/rag/indexing/docs/document_builder.py:10`). - Build: `DocsIndexingPipeline.index_file` (`app/modules/rag/indexing/docs/pipeline.py:24`) -> `DocsDocumentBuilder.build_module_catalog` (`app/modules/rag/indexing/docs/document_builder.py:10`). - Retrieval: общий SQL retrieval (`app/modules/rag/persistence/retrieval_statement_builder.py:9`). #### D2_FACT_INDEX - Назначение: атомарные факты. - Единица: fact. - Схема: `fact_id`, `subject_id`, `predicate`, `object`, `object_ref`, `anchor`, `tags`, `source_path` (`app/modules/rag/indexing/docs/document_builder.py:86`). - Build: `DocsIndexingPipeline._extract_facts/_facts_from_table/_facts_from_lists` (`app/modules/rag/indexing/docs/pipeline.py:55`, `:76`, `:118`) -> `build_fact` (`app/modules/rag/indexing/docs/document_builder.py:86`). - Retrieval: общий SQL retrieval (`app/modules/rag/persistence/retrieval_statement_builder.py:9`). #### D3_SECTION_INDEX - Назначение: секции документа. - Единица: section chunk. - Схема: `module_id`, `type`, `domain`, `tags`, `section_path`, `section_title`, `order`, `doc_kind`, `source_path`, `artifact_type` (`app/modules/rag/indexing/docs/document_builder.py:42`). - Build: `MarkdownDocChunker.chunk` (`app/modules/rag/indexing/docs/chunkers/markdown_chunker.py:20`) -> `DocsDocumentBuilder.build_section` (`app/modules/rag/indexing/docs/document_builder.py:42`). - Retrieval: общий SQL retrieval (`app/modules/rag/persistence/retrieval_statement_builder.py:9`). #### D4_POLICY_INDEX - Назначение: policy-документы. - Единица: policy doc. - Схема: `policy_id`, `applies_to`, `rules`, `default_behaviors`, `doc_kind`, `section_path`, `source_path` (`app/modules/rag/indexing/docs/document_builder.py:64`). - Build: только если `frontmatter.type == "policy"` (`app/modules/rag/indexing/docs/pipeline.py:36`) -> `build_policy` (`app/modules/rag/indexing/docs/document_builder.py:64`). - Retrieval: общий SQL retrieval (`app/modules/rag/persistence/retrieval_statement_builder.py:9`). ## 4) Scoping & filtering (самое важное) - `repo_id`/workspace scope при индексации: - `RagService._resolve_repo_id` берет `project_id` из `rag_session`; fallback — сам `rag_session_id` (`app/modules/rag/services/rag_service.py:161`). - `repo_id` пишется в документы/metadata (`app/modules/rag/services/rag_service.py:147`). - Retrieval scope: SQL всегда фильтрует по `rag_session_id = :sid` (`app/modules/rag/persistence/retrieval_statement_builder.py:23`). - `include_globs`, `exclude_globs`, `prefer_globs`: - Формируются роутером в `RetrievalConstraintsFactory.build` (`app/modules/rag/intent_router_v2/retrieval/retrieval_constraints_factory.py:22`). - В `RagDbAdapter.retrieve` применяются `include_globs`/`exclude_globs` через перевод в prefixes/LIKE (`tests/pipeline_intent_rag/helpers/rag_db_adapter.py:46`). - Использование `prefer_globs` в retrieval-коде не найдено; найдено только формирование/тесты. - `path_scope`: - Формируется в `RetrievalFilterBuilder._path_scope` (`app/modules/rag/intent_router_v2/retrieval/retrieval_filter_builder.py:63`). - В retrieval используется как prefixes: сначала точный scope, затем parent prefix, затем без scope (`tests/pipeline_intent_rag/helpers/rag_db_adapter.py:98`). - До/после ранжирования: - Path/layer/test exclude фильтры попадают в `WHERE` до `ORDER BY` (`app/modules/rag/persistence/retrieval_statement_builder.py:23`, `:58`, `:59`). - `tests/**` penalty: - Penalty вычисляется как `CASE WHEN lower(path) LIKE ... THEN 1 ELSE 0 END` при `prefer_non_tests=True` (`app/modules/rag/persistence/retrieval_statement_builder.py:176`). - В `RagDbAdapter` `prefer_non_tests` зависит от `test_policy` (`tests/pipeline_intent_rag/helpers/rag_db_adapter.py:72`). ## 5) Merge policy (как собираются rag_rows) - Top-K на слой задается в `retrieval_spec.layer_queries` (`app/modules/rag/intent_router_v2/models.py:125`) и заполняется `RetrievalSpecFactory` (`app/modules/rag/intent_router_v2/retrieval/retrieval_spec_factory.py:10`). - Фактический SQL limit в `pipeline_intent_rag`: `limit = max(top_k)` по всем слоям, не отдельный budget на слой (`tests/pipeline_intent_rag/helpers/rag_db_adapter.py:56`). - Смешивание слоев: один SQL по списку слоев `layer = ANY(:layers)` + общий `ORDER BY` (`app/modules/rag/persistence/retrieval_statement_builder.py:29`, `:59`). - Политика merge: interleave/concat как отдельные алгоритмы не найдены; порядок задает SQL sorting. - Дедупликация по `blob_sha`/`symbol_id` для `rag_rows` в `pipeline_intent_rag` не найдена. - Общий budget: - retrieval rows ограничены `LIMIT :lim` (`app/modules/rag/persistence/retrieval_statement_builder.py:60`); - в `full_chain` в prompt уходит максимум 6 `rag_rows`, каждый `content` режется до 1200 символов (`tests/pipeline_intent_rag/helpers/llm_answerer.py:31`, `:34`). ## 6) Prompt builder / evidence packaging - Формат передачи `rag_rows` в LLM (`pipeline_intent_rag/full_chain`): - `GigaChatAnswerer._format_context` делает блоки `- path | title\\ncontent` (`tests/pipeline_intent_rag/helpers/llm_answerer.py:35`), - затем `answer` добавляет вопрос+контекст в `user_prompt` (`tests/pipeline_intent_rag/helpers/llm_answerer.py:17`). - Evidence gate: - в `pipeline_intent_rag` gate не найден; - в direct code-explain есть `CodeExplainEvidenceGate(min_excerpts=2)` (`app/modules/chat/evidence_gate.py:16`), применяется в `CodeExplainChatService.handle_message` (`app/modules/chat/direct_service.py:46`). - Шаблоны промптов: - code explain: `app/modules/agent/prompts/code_explain_answer_v2.txt:1` (используется в `app/modules/chat/direct_service.py:50`, `app/modules/agent/engine/graphs/project_qa_step_graphs.py:169`); - project/docs QA: `app/modules/agent/prompts/project_answer.txt:1` (используется в `app/modules/agent/engine/graphs/project_qa_graph.py:36`); - general: `app/modules/agent/prompts/general_answer.txt:1` (используется в `app/modules/agent/engine/graphs/base_graph.py:62`). ## 7) Repro commands - Построить новый индекс (новая `rag_session`) для локального репозитория: ```bash python3 -m tests.pipeline_intent_rag reindex --repo-path /abs/path/to/repo # optional: python3 -m tests.pipeline_intent_rag reindex --repo-path /abs/path/to/repo --project-id my-project ``` Источник: `tests/pipeline_intent_rag/cli.py:143`, `:123`; README `tests/pipeline_intent_rag/README.md:54`. - Прогнать тесткейсы: ```bash python3 -m tests.pipeline_intent_rag run --mode router_only python3 -m tests.pipeline_intent_rag run --mode router_rag --rag-session-id python3 -m tests.pipeline_intent_rag run --mode full_chain --rag-session-id ``` Источник: `tests/pipeline_intent_rag/cli.py:135`, `:138`; README `tests/pipeline_intent_rag/README.md:49`. - Получить `rag_rows` как в логах артефактов: ```bash python3 -m tests.pipeline_intent_rag run --mode router_rag --rag-session-id --test-name rag_probe ls -t tests/artifacts/rag_probe_*.jsonl | head -n 1 tail -n 50 "$(ls -t tests/artifacts/rag_probe_*.jsonl | head -n 1)" ``` `rag_rows` сериализуются в JSONL через `PipelineResult.to_record` (`tests/pipeline_intent_rag/helpers/models.py:31`) и `ArtifactWriter` (`tests/pipeline_intent_rag/helpers/artifact_writer.py:20`), имя файла `_.jsonl` (`tests/pipeline_intent_rag/helpers/artifact_writer.py:16`). ## 8) Appendix: Code pointers - Entrypoints: - Router API: `app/modules/rag/intent_router_v2/router.py:35` (`IntentRouterV2.route`). - Graph-id map: `app/modules/rag/intent_router_v2/intent/graph_id_resolver.py:4` (`GraphIdResolver`). - CLI: `tests/pipeline_intent_rag/__main__.py:1`, `tests/pipeline_intent_rag/cli.py:178` (`main`). - Ключевые классы: - `IntentRouterV2`: `app/modules/rag/intent_router_v2/router.py:14`. - `RagService`: `app/modules/rag/services/rag_service.py:20`. - `CodeIndexingPipeline`: `app/modules/rag/indexing/code/pipeline.py:19`. - `DocsIndexingPipeline`: `app/modules/rag/indexing/docs/pipeline.py:14`. - `RagDbAdapter`: `tests/pipeline_intent_rag/helpers/rag_db_adapter.py:36`. - `RetrievalStatementBuilder`: `app/modules/rag/persistence/retrieval_statement_builder.py:8`. - Конфиги/переменные окружения: - Test env: `tests/pipeline_intent_rag/.env.test:3`. - Env loader: `tests/pipeline_intent_rag/helpers/env_bootstrap.py:13`. - Run config keys: `tests/pipeline_intent_rag/helpers/pipeline_config.py:30`. - Форматы данных (pydantic/dataclasses): - Router schema: `app/modules/rag/intent_router_v2/models.py:43`, `:139`. - RAG document dataclass: `app/modules/rag/contracts/documents.py:29`. - Pipeline result JSONL model: `tests/pipeline_intent_rag/helpers/models.py:18`. - Not found: - Классы/функции `CodeQAGraph`, `DocsQAGraph` как реальные graph-реализации в `app/` не найдены (строки встречаются как `graph_id` map). - `F0` layer не найден в `app/` и `tests/`.