ййй
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
# Снимок runtime-контура CODE_QA (answer layer)
|
||||
|
||||
Документ фиксирует текущее состояние runtime-контура `CODE_QA` после рефакторинга для планирования доработок answer layer. Без предложений по новому дизайну и без implementation brief.
|
||||
|
||||
---
|
||||
|
||||
## 1. Entry point
|
||||
|
||||
- **HTTP:** `POST /api/chat/messages` → `ChatModule.public_router()` → `send_message()`.
|
||||
Файл: `src/app/modules/chat/module.py`, строки 74–81.
|
||||
|
||||
- **Условие:** при `SIMPLE_CODE_EXPLAIN_ONLY=true` запрос идёт в `CodeExplainChatService.handle_message()` (прямой explain без полного CODE_QA pipeline). При `false` — в оркестратор.
|
||||
|
||||
- **Оркестратор:** `ChatOrchestrator.enqueue_message()` создаёт задачу и запускает `_process_task()` → в нём вызывается `self._runtime.run(...)`.
|
||||
Файл: `src/app/modules/chat/service.py`, строки 47–69, 71–132.
|
||||
|
||||
- **Runtime-адаптер:** `CodeQaRunnerAdapter` реализует `AgentRunner`; в `run()` вызывает `self._executor.execute(user_query=..., rag_session_id=..., files_map=...)` в thread pool.
|
||||
Файл: `src/app/modules/agent/runtime/code_qa_runner_adapter.py`, строки 21–41.
|
||||
|
||||
- **Фактическая точка входа CODE_QA:** `AgentRuntimeExecutor.execute()`.
|
||||
Файл: `src/app/modules/agent/runtime/executor.py`, строка 53.
|
||||
Создание executor: `application.py`, строка 48 — `_executor = AgentRuntimeExecutor(llm=..., retrieval=...)`.
|
||||
|
||||
---
|
||||
|
||||
## 2. Runtime pipeline
|
||||
|
||||
Цепочка внутри `AgentRuntimeExecutor.execute()` (файл `executor.py`):
|
||||
|
||||
| Шаг | Файл | Класс/функция | Роль |
|
||||
|-----|------|----------------|------|
|
||||
| 1. Роутинг | `executor.py` | `self._router.route(user_query, ...)` | Intent + sub-intent, query_plan, retrieval_spec, symbol_resolution (pending). |
|
||||
| 2. Сборка запроса retrieval | `retrieval_request_builder.py` | `build_retrieval_request(router_result, rag_session_id)` | Из `RouterResult` собирается `RetrievalRequest`: query, sub_intent, path_scope, requested_layers, retrieval_spec, constraints, query_plan. |
|
||||
| 3. Retrieval | `executor.py` | `self._retrieve(state)` → `RuntimeRetrievalAdapter.retrieve_with_plan()` или `retrieve_exact_files()` для OPEN_FILE | По плану или по точным путям; возвращает `raw_rows` (list[dict]). |
|
||||
| 4. Догидрация (только FIND_ENTRYPOINTS) | `executor.py` | `_hydrate_entrypoint_sources()` | Дозапрос C0 по путям из C3 entrypoints. |
|
||||
| 5. Разрешение символа | `executor.py` | `_resolve_symbol(initial, raw_rows)` | По C1_SYMBOL_CATALOG: resolved / ambiguous / not_found; обновляет `state.router_result.symbol_resolution`. |
|
||||
| 6. Retrieval result | `retrieval_result_builder.py` | `build_retrieval_result(raw_rows, report, symbol_resolution)` | Нормализованный `RetrievalResult`: code_chunks, relations, entrypoints, test_candidates, layer_outcomes и т.д. Для EXPLAIN при not_found/ambiguous — пересборка с пустыми rows (строки 90–91 executor). |
|
||||
| 7. Evidence bundle | `evidence_bundle_builder.py` | `build_evidence_bundle(retrieval_result, router_result)` | `EvidenceBundle`: resolved_sub_intent, resolved_target, code_chunks, relations, entrypoints, test_evidence, retrieval_summary. sufficient/failure_reasons не выставляются здесь. |
|
||||
| 8. Pre evidence gate | `evidence_gate.py` | `evaluate_evidence(state.evidence_pack)` | По sub_intent проверяет достаточность (target, evidence_count, слои, entrypoints, tests). Выставляет `bundle.sufficient`, возвращает `EvidenceGateDecision`; от этого — `state.answer_mode` (normal/degraded). |
|
||||
| 9. Answer policy | `policy.py` | `self._answer_policy.decide(router_result, gate_decision)` | Решение: вызывать LLM или короткий ответ (OPEN_FILE not_found, EXPLAIN not_found/ambiguous, gate не прошёл). При `should_call_llm=False` сразу идём в `assemble_final_result` с `decision.answer`. |
|
||||
| 10. Synthesis input | `answer_synthesis.py` | `build_answer_synthesis_input(user_query, state.evidence_pack)` | Строит `AnswerSynthesisInput`: fast_context, deep_context, evidence_summary, semantic_hints, curated_facts (из answer_fact_curator). |
|
||||
| 11. Выбор промпта | `prompt_selector.py` | `self._prompt_selector.select(sub_intent=..., answer_mode=...)` | Имя системного промпта по sub_intent (и degraded). |
|
||||
| 12. Payload | `prompt_payload_builder.py` | `self._payload_builder.build(user_query, synthesis_input, evidence_pack, answer_mode)` | JSON payload для LLM: user_query, resolved_scenario, fast/deep_context, evidence_summary, curated must_mention_*, layer_guide, entrypoints, scenario-specific поля. |
|
||||
| 13. Генерация черновика | `generator.py` | `self._generator.generate(prompt_name, prompt_payload)` | Вызов `AgentLlmService.generate(prompt_name, payload)` → черновик ответа. |
|
||||
| 14. Post evidence gate | `post_gate.py` | `self._post_gate.validate(answer, answer_mode, ..., sub_intent, user_query, evidence_pack)` | Проверка черновика по sub_intent (EXPLAIN/ARCHITECTURE/TRACE_FLOW/…), возврат `RuntimeValidationResult(passed, action, reasons)`. |
|
||||
| 15. Repair (если не passed) | `repair.py` | `self._repair.repair(draft_answer, validation, prompt_payload)` | Один вызов LLM с промптом `code_qa_repair_answer`; повторная валидация; при повторном fail — fallback answer. |
|
||||
| 16. Финальный результат | `result_assembler.py` | `assemble_final_result(state, draft=..., final_answer=..., ...)` | Сборка `RuntimeFinalResult` и диагностики. |
|
||||
|
||||
Sub-intent для CODE_QA задаётся в роутере: `QueryPlanBuilder` использует `SubIntentDetector.detect()` и `_resolve_sub_intent()`; итог в `query_plan.sub_intent`. Ретривал-слои по sub_intent задаются в `RetrievalSpecFactory._with_sub_intent_layers()` (`retrieval_spec_factory.py`).
|
||||
|
||||
---
|
||||
|
||||
## 3. Answer path
|
||||
|
||||
- **Выбор промпта:** `RuntimePromptSelector.select(sub_intent, answer_mode)` — `src/app/modules/agent/runtime/steps/generation/prompt_selector.py`, строки 18–21. При answer_mode in `{"degraded","not_found","insufficient"}` возвращается `code_qa_degraded_answer`, иначе — по `sub_intent` из словаря (fallback `code_qa_explain_answer`).
|
||||
|
||||
- **Сборка payload:** `RuntimePromptPayloadBuilder.build()` — `prompt_payload_builder.py`, строки 21–44. В payload попадают: `user_query`, `resolved_scenario`, `resolved_target`, `answer_mode`, `fast_context`, `deep_context`, `evidence_summary`, `semantic_hints`, `diagnostic_hints`, `retrieval_summary`, `confirmed_entrypoints`, `required_entrypoints`, `layer_guide`, плюс сценарий-специфичные поля из `_scenario_payload(synthesis_input)` (must_mention_*, fact_gaps и т.д.).
|
||||
|
||||
- **Draft answer:** создаётся в `executor.py`, строки 242–246: `RuntimeDraftAnswer(prompt_name=..., prompt_payload=..., answer=self._generator.generate(...))`.
|
||||
|
||||
- **Post-processing:** отдельного шага нет; после генерации сразу идёт post-validation.
|
||||
|
||||
- **Repair:** `RuntimeAnswerRepairService.repair()` — `repair.py`, строки 16–37. Формирует JSON с draft_answer, validation_reasons, repair_focus, prompt_payload и один раз вызывает LLM с `code_qa_repair_answer`.
|
||||
|
||||
- **Final text:** в executor: при passed — `final_answer = draft.answer` (или результат repair); при не passed после repair — `_fallback_answer(state)`. Итоговая строка попадает в `RuntimeFinalResult.final_answer` в `assemble_final_result()`.
|
||||
|
||||
---
|
||||
|
||||
## 4. Prompt selection
|
||||
|
||||
- **Где:** `src/app/modules/agent/runtime/steps/generation/prompt_selector.py`, класс `RuntimePromptSelector`, метод `select(sub_intent, answer_mode)`.
|
||||
|
||||
- **Правила:**
|
||||
- answer_mode in `{"degraded","not_found","insufficient"}` → `code_qa_degraded_answer`.
|
||||
- Иначе по `sub_intent.upper()` из `_PROMPTS`; при отсутствии ключа — `code_qa_explain_answer`.
|
||||
|
||||
- **Используемые имена промптов для целевых sub_intent:**
|
||||
|
||||
| sub_intent | prompt name |
|
||||
|-------------|--------------------------------|
|
||||
| EXPLAIN | `code_qa_explain_answer` |
|
||||
| EXPLAIN_LOCAL| `code_qa_explain_local_answer` |
|
||||
| ARCHITECTURE| `code_qa_architecture_answer` |
|
||||
| TRACE_FLOW | `code_qa_trace_flow_answer` |
|
||||
|
||||
- **Шаблоны:** загружаются по имени из YAML в `AgentLlmService.generate()` → `PromptLoader.load(name)`; конфиг — `src/app/modules/agent/llm/prompts.yml`. Ключи в YAML совпадают с именами выше (в т.ч. `code_qa_explain_answer`, `code_qa_architecture_answer`, `code_qa_trace_flow_answer`); repair — `code_qa_repair_answer`.
|
||||
|
||||
- **Выбор по sub_intent:** да, только через `RuntimePromptSelector.select(sub_intent=state.retrieval_request.sub_intent, ...)` в executor, строка 231.
|
||||
|
||||
---
|
||||
|
||||
## 5. Evidence-to-answer boundary
|
||||
|
||||
- **В answer layer evidence приходит как:**
|
||||
- `EvidenceBundle` (в state.evidence_pack) и
|
||||
- `AnswerSynthesisInput` (state.synthesis_input), собранный из bundle в `build_answer_synthesis_input()`.
|
||||
|
||||
- **Модели/DTO:**
|
||||
- `EvidenceBundle`: `contracts.py`, 90–106 — resolved_intent, resolved_sub_intent, resolved_target, target_type, code_chunks, relations, entrypoints, test_evidence, evidence_count, retrieval_summary.
|
||||
- `AnswerSynthesisInput`: `contracts.py`, 109–121 — user_question, resolved_scenario, resolved_target, fast_context, deep_context, evidence_summary, semantic_hints, **curated_facts**, evidence_sufficient, diagnostic_hints.
|
||||
- Curated facts строит `answer_fact_curator.build_curated_answer_facts(bundle)` — словарь с ключами `explain`, `architecture`, `trace_flow` и общими полями (scenario, semantic_hints, relation_count и т.д.).
|
||||
|
||||
- **Что реально уходит в payload (prompt_payload_builder):**
|
||||
- Общее: user_query, resolved_scenario, resolved_target, answer_mode, fast_context, deep_context, evidence_summary, semantic_hints, diagnostic_hints, retrieval_summary, confirmed_entrypoints, required_entrypoints, layer_guide.
|
||||
- EXPLAIN: must_mention_methods/fields/calls/dependencies/constructor_args/files, must_not_infer_missing_details, fact_gaps (из curated_facts["explain"]).
|
||||
- ARCHITECTURE: must_mention_components/relations, must_use_relation_verbs, must_avoid_semantic_labels_as_primary_claims, must_not_use_retrieval_labels, fact_gaps (из curated_facts["architecture"]).
|
||||
- TRACE_FLOW: must_mention_flow_steps/calls/sequence_edges, must_avoid_overclaiming_full_flow, fact_gaps (из curated_facts["trace_flow"]).
|
||||
|
||||
- **Curated-поля (answer_fact_curator):**
|
||||
- explain: required_methods, required_calls, required_fields, required_dependencies, required_constructor_args, required_files, fact_gaps (и др.).
|
||||
- architecture: required_components, required_relations (source/verb/target/edge_type), required_relation_verbs, required_*_edges, forbidden_labels, fact_gaps.
|
||||
- trace_flow: required_flow_steps (step, source, verb, target, path, line_span), required_calls, required_sequence_edges, fact_gaps.
|
||||
|
||||
То есть в LLM попадает не сырой retrieval, а нормализованный контекст (fast/deep_context, evidence_summary) плюс явные списки «must_mention_*» и fact_gaps по сценарию; для methods/dependencies/relations/flow steps уже есть выделенные curated-поля.
|
||||
|
||||
---
|
||||
|
||||
## 6. Post-validation / answer quality control
|
||||
|
||||
- **Post-evidence gate (runtime):** есть. `RuntimePostEvidenceGate.validate()` — `src/app/modules/agent/runtime/steps/gates/post/post_gate.py`, строки 39–65. Вызывается после генерации черновика (и после repair — повторно).
|
||||
|
||||
- **Answer validator:** это тот же post_gate: проверяет пустой ответ, соответствие answer_mode (degraded/not_found/ambiguous) требуемым формулировкам, длину при degraded, затем для normal — `_normal_answer_reasons()` по sub_intent.
|
||||
|
||||
- **Repair loop:** один раунд. При `not validation.passed` и наличии `self._repair` вызывается `repair()`; затем повторный `validate()`; если снова не passed — подставляется `_fallback_answer()` и смена answer_mode (`executor.py`, 281–298).
|
||||
|
||||
- **Правила по sub_intent (post_gate):**
|
||||
- **EXPLAIN** (93–124): target focus; vagueness (_VAGUE_PHRASES); наличие required_methods/calls/dependencies (хотя бы одна группа); «too_vague_for_explain» при нуле совпадений; semantic_leakage (роли из semantic_hints без опоры на код).
|
||||
- **ARCHITECTURE** (126–150): target focus; vagueness; required_components, required_relations, relation_verbs; forbidden_labels (retrieval artifacts); methods_as_primary_components; «too_vague_for_architecture»; semantic_leakage.
|
||||
- **TRACE_FLOW** (152–171): target focus; vagueness; required_flow_steps и required_calls; _mentions_steps (сначала/затем или нумерация); overclaims (_OPTIMISTIC_TRACE_CLAIMS); «too_vague_for_trace_flow».
|
||||
|
||||
- **Technical precision для EXPLAIN:** проверяется косвенно: упоминание методов/вызовов/зависимостей из curated; явной проверки «только факты из кода» по токенам нет.
|
||||
- **Concrete relations для ARCHITECTURE:** да — `_mentions_relations(answer, relations)` и упоминание verbs.
|
||||
- **Concrete steps и overclaim для TRACE_FLOW:** да — `_mentions_steps`, `_mentions_relations` по steps, и проверка фраз из _OPTIMISTIC_TRACE_CLAIMS.
|
||||
|
||||
---
|
||||
|
||||
## 7. Problem sources (что может давать слабые ответы)
|
||||
|
||||
- **Payload shaping:** `prompt_payload_builder.py` — если curated_facts пустые или скудные (мало methods/calls/relations/steps), must_mention_* не направляют модель; deep_context обрезается до 30 чанков по 800 символов — возможна потеря важных деталей.
|
||||
|
||||
- **Prompts:** `prompts.yml` — длинные общие инструкции; для EXPLAIN/ARCHITECTURE/TRACE_FLOW нет жёсткой привязки к структуре payload (например, «обязательно используй must_mention_flow_steps по порядку»); модель может игнорировать fact_gaps.
|
||||
|
||||
- **Evidence normalization:** `answer_fact_curator` — методы/вызовы/relations извлекаются эвристически (regex, C1/C2); при слабом C1/C2 или нестандартных именах curated-списки пустеют → валидатор не к чему привязываться, ответ считается «vague».
|
||||
|
||||
- **Weak validation:** `post_gate` — проверки по вхождению подстрок (alias) и по небольшому набору фраз; нет проверки полноты (все ли must_mention_* упомянуты), нет проверки порядка шагов для TRACE_FLOW; semantic_leakage выключается при has_concrete_support, что может пропускать смешанные ответы.
|
||||
|
||||
- **Repair policy:** один вызов repair с общим промптом `code_qa_repair_answer` и repair_focus по reasons; при множественных reasons фокус может размываться; после repair при повторном fail сразу fallback — без второго раунда repair.
|
||||
|
||||
---
|
||||
|
||||
## 8. Minimal intervention points
|
||||
|
||||
1. **`src/app/modules/agent/runtime/steps/generation/prompt_payload_builder.py`**
|
||||
Класс `RuntimePromptPayloadBuilder`, метод `build()` и `_scenario_payload()`.
|
||||
Контролирует: какие поля и списки (must_mention_*, fact_gaps, layer_guide) попадают в JSON для LLM.
|
||||
Удобно: один вход в «что видит модель»; можно усилить структуру под EXPLAIN/ARCHITECTURE/TRACE_FLOW без трогания оркестрации.
|
||||
|
||||
2. **`src/app/modules/agent/runtime/steps/context/answer_fact_curator.py`**
|
||||
Функции `_explain_facts()`, `_architecture_facts()`, `_trace_flow_facts()`.
|
||||
Контролируют: состав и качество curated_facts (required_*, fact_gaps).
|
||||
Удобно: улучшение извлечения методов/relations/steps напрямую улучшает и payload, и валидацию.
|
||||
|
||||
3. **`src/app/modules/agent/runtime/steps/gates/post/post_gate.py`**
|
||||
Класс `RuntimePostEvidenceGate`, методы `_validate_explain()`, `_validate_architecture()`, `_validate_trace_flow()` и хелперы (`_mentions_fact_group`, `_mentions_relations`, `_mentions_steps`).
|
||||
Контролирует: критерии прохождения и набор reasons для repair.
|
||||
Удобно: уже разбито по сценариям; можно ужесточить правила и добавить новые reasons без смены архитектуры.
|
||||
|
||||
4. **`src/app/modules/agent/llm/prompts.yml`**
|
||||
Блоки `code_qa_explain_answer`, `code_qa_architecture_answer`, `code_qa_trace_flow_answer`, `code_qa_repair_answer`.
|
||||
Контролируют: инструкции для черновика и починки.
|
||||
Удобно: точечные правки формулировок и явные отсылки к полям payload (must_mention_*, fact_gaps).
|
||||
|
||||
5. **`src/app/modules/agent/runtime/steps/generation/prompt_selector.py`**
|
||||
Класс `RuntimePromptSelector`, словарь `_PROMPTS` и метод `select()`.
|
||||
Контролирует: какой системный промпт выбирается по sub_intent/answer_mode.
|
||||
Удобно: введение отдельных промптов для подвидов (например, TRACE_FLOW по типу запроса) без изменения executor.
|
||||
|
||||
6. **`src/app/modules/agent/runtime/steps/context/answer_synthesis.py`**
|
||||
Функция `build_answer_synthesis_input()`, формирование `fast_context` и `deep_context` (в т.ч. фильтр по C4 для EXPLAIN/ARCHITECTURE).
|
||||
Контролирует: объём и приоритет контекста, передаваемого в synthesis_input.
|
||||
Удобно: можно менять лимиты, порядок чанков или фильтры слоёв локально.
|
||||
|
||||
7. **`src/app/modules/agent/runtime/steps/finalization/repair.py`**
|
||||
Класс `RuntimeAnswerRepairService`, метод `repair()` и `_repair_focus()`.
|
||||
Контролирует: как validation.reasons мапятся в repair_focus и что уходит в промпт починки.
|
||||
Удобно: можно сузить фокус repair под конкретные reasons или добавить приоритизацию без изменения цикла в executor.
|
||||
|
||||
---
|
||||
|
||||
*Документ описывает только текущую реализацию по коду после рефакторинга.*
|
||||
@@ -0,0 +1,271 @@
|
||||
# План доработки БД для хранения контекста Story и метаданных RAG
|
||||
|
||||
## Цель
|
||||
Зафиксировать проект миграции, который:
|
||||
- добавляет в таблицу чанков признаки артефакта (тип, источник, контекст),
|
||||
- вводит отдельный контур хранения инкремента по `story_id`,
|
||||
- не зависит от выбранного режима RAG (общий/сессионный/гибридный).
|
||||
|
||||
## Границы
|
||||
- Документ описывает план и целевую схему.
|
||||
- Реализация SQL-миграций и backfill выполняется отдельным шагом после согласования.
|
||||
|
||||
## 1) Метаданные чанков (RAG-слой)
|
||||
|
||||
### 1.1. Что добавить
|
||||
Для таблицы `rag_chunks` (или эквивалента таблицы чанков) добавить поля:
|
||||
- `artifact_type` (`REQ|ARCH|API|DB|UI|CODE|OTHER`)
|
||||
- `path` (нормализованный относительный путь файла)
|
||||
- `section` (заголовок/логический раздел документа)
|
||||
- `doc_id` (стабильный идентификатор документа)
|
||||
- `doc_version` (версия документа/ревизия)
|
||||
- `owner` (ответственная команда/человек)
|
||||
- `system_component` (система/подсистема/компонент)
|
||||
- `last_modified` (время последнего изменения источника)
|
||||
- `staleness_score` (0..1, в первую очередь для `CODE`)
|
||||
|
||||
### 1.2. Ограничения и индексы
|
||||
- `CHECK` для `artifact_type` и диапазона `staleness_score`.
|
||||
- Индексы:
|
||||
- `(artifact_type)`
|
||||
- `(doc_id, doc_version)`
|
||||
- `(system_component)`
|
||||
- `(path)`
|
||||
- GIN/BTREE по потребности для фильтрации в retrieval.
|
||||
|
||||
## 2) Контур Story (отдельно от чанков)
|
||||
|
||||
### 2.1. Таблица `story_records`
|
||||
Карточка Story:
|
||||
- `story_id` (PK, строковый уникальный идентификатор)
|
||||
- `project_id` (идентификатор проекта/репозитория)
|
||||
- `title`
|
||||
- `status` (`draft|in_progress|review|done|archived`)
|
||||
- `baseline_commit_sha` (базовый снимок)
|
||||
- `snapshot_id` (опционально для session-RAG)
|
||||
- `created_at`, `updated_at`
|
||||
- `created_by`, `updated_by`
|
||||
|
||||
Индексы:
|
||||
- `(project_id)`
|
||||
- `(status)`
|
||||
- `(updated_at)`
|
||||
|
||||
### 2.2. Таблица `story_artifacts`
|
||||
Связь Story с артефактами изменений:
|
||||
- `id` (PK)
|
||||
- `story_id` (FK -> `story_records.story_id`)
|
||||
- `artifact_role` (`requirement|analysis|doc_change|test_model|note|decision|risk`)
|
||||
- `doc_id`
|
||||
- `doc_version`
|
||||
- `path`
|
||||
- `section`
|
||||
- `chunk_id` (nullable; ссылка на chunk если стабильно поддерживается)
|
||||
- `change_type` (`added|updated|removed|linked`)
|
||||
- `summary` (краткое описание изменения)
|
||||
- `source_ref` (ссылка/внешний id)
|
||||
- `created_at`
|
||||
- `created_by`
|
||||
|
||||
Уникальность (черновик):
|
||||
- `UNIQUE(story_id, artifact_role, COALESCE(doc_id,''), COALESCE(path,''), COALESCE(section,''), COALESCE(change_type,''))`
|
||||
|
||||
Индексы:
|
||||
- `(story_id, artifact_role)`
|
||||
- `(story_id, change_type)`
|
||||
- `(doc_id, doc_version)`
|
||||
- `(path)`
|
||||
|
||||
### 2.3. Таблица `story_links`
|
||||
Связи Story с внешними сущностями и Story-to-Story:
|
||||
- `id` (PK)
|
||||
- `story_id` (FK)
|
||||
- `link_type` (`story|adr|ticket|pr|commit|doc|external`)
|
||||
- `target_ref` (идентификатор/ссылка)
|
||||
- `description`
|
||||
- `created_at`
|
||||
|
||||
Индексы:
|
||||
- `(story_id, link_type)`
|
||||
- `(target_ref)`
|
||||
|
||||
## 3) Почему `story_id` не в чанках
|
||||
- Один чанк может относиться к нескольким Story.
|
||||
- Чанки нестабильны при переиндексации.
|
||||
- Разделение слоев упрощает поддержку и не привязывает модель к типу RAG.
|
||||
|
||||
Итог: связь Story и чанков/документов хранить в `story_artifacts`, а не в `rag_chunks`.
|
||||
|
||||
## 4) Целевая модель RAG: Hybrid-Lite
|
||||
Выбранный вектор на текущем этапе: `Session-first + Shared Cache + Story Ledger`.
|
||||
|
||||
### 4.1. Принципы
|
||||
- Рабочий retrieval выполняется из сессионного индекса (видит незакоммиченные изменения).
|
||||
- Общий кэш чанков/эмбеддингов используется только для ускорения индексации.
|
||||
- Источник правды по инкременту Story находится в Story-таблицах, а не в RAG-индексе.
|
||||
|
||||
### 4.2. Что хранить дополнительно
|
||||
- `rag_blob_cache`: кэш файловых blob по `repo_id + blob_sha`.
|
||||
- `rag_chunk_cache`: кэш чанков/эмбеддингов, привязанный к `blob_sha`.
|
||||
- `rag_session_chunk_map`: привязка сессии к используемым chunk (чтобы retrieval был изолированным).
|
||||
- `session_artifacts`: временные артефакты сессии до появления `story_id` (late binding).
|
||||
|
||||
### 4.3. Алгоритм индексации (delta-only)
|
||||
1. На старте сессии сканировать рабочее дерево и считать `blob_sha` для файлов индексации.
|
||||
2. Для каждого файла:
|
||||
- `cache hit`: взять chunk/embedding из кэша и связать с текущей сессией.
|
||||
- `cache miss`: выполнить chunk+embed и записать результат в кэш.
|
||||
3. Для retrieval использовать `rag_session_chunk_map` как первичный источник.
|
||||
4. При необходимости делать fallback к cache-scoped данным по `repo_id` (опционально, под флагом).
|
||||
|
||||
### 4.4. Почему это подходит
|
||||
- Нет необходимости в сложном ACL общего RAG на уровне приложения.
|
||||
- Нет обязательной зависимости от ручного commit, индекс отражает локальные изменения.
|
||||
- Снижается время загрузки сессии за счет переиспользования эмбеддингов.
|
||||
- История Story не теряется и не зависит от режима RAG.
|
||||
|
||||
### 4.5. Late binding `story_id` (целевой процесс)
|
||||
1. Аналитик запускает работу только со ссылкой на документ (без `story_id`).
|
||||
2. Агент обрабатывает задачу в `session-RAG` и сохраняет все изменения в `session_artifacts`.
|
||||
3. Аналитик вручную делает commit и указывает `story_id`.
|
||||
4. Вебхук на commit:
|
||||
- извлекает `story_id` из commit metadata/message,
|
||||
- обновляет репозиторный RAG,
|
||||
- выполняет `bind session -> story`: переносит/привязывает `session_artifacts` к `story_artifacts`,
|
||||
- фиксирует связь `story_id <-> commit_sha <-> changed_files`.
|
||||
5. Исходный документ аналитики тоже попадает в контекст Story ретроспективно, даже если изначально был без `story_id`.
|
||||
|
||||
## 5) Черновик DDL (PostgreSQL)
|
||||
```sql
|
||||
-- 0. Enum-like checks можно заменить на справочники при необходимости
|
||||
|
||||
-- A) Session artifacts (временный слой до появления story_id)
|
||||
CREATE TABLE IF NOT EXISTS session_artifacts (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
session_id TEXT NOT NULL,
|
||||
project_id TEXT NOT NULL,
|
||||
artifact_role TEXT NOT NULL,
|
||||
source_ref TEXT,
|
||||
doc_id TEXT,
|
||||
doc_version TEXT,
|
||||
path TEXT,
|
||||
section TEXT,
|
||||
chunk_id TEXT,
|
||||
change_type TEXT,
|
||||
summary TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
created_by TEXT,
|
||||
CONSTRAINT chk_session_artifact_role CHECK (artifact_role IN (
|
||||
'analysis','doc_change','note','decision','risk','test_model'
|
||||
)),
|
||||
CONSTRAINT chk_session_change_type CHECK (change_type IS NULL OR change_type IN (
|
||||
'added','updated','removed','linked'
|
||||
))
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_session_artifacts_session ON session_artifacts(session_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_session_artifacts_project ON session_artifacts(project_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_session_artifacts_role ON session_artifacts(artifact_role);
|
||||
|
||||
-- 1) Story records
|
||||
CREATE TABLE IF NOT EXISTS story_records (
|
||||
story_id TEXT PRIMARY KEY,
|
||||
project_id TEXT NOT NULL,
|
||||
title TEXT,
|
||||
status TEXT NOT NULL DEFAULT 'draft',
|
||||
baseline_commit_sha TEXT,
|
||||
snapshot_id TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
created_by TEXT,
|
||||
updated_by TEXT,
|
||||
CONSTRAINT chk_story_status CHECK (status IN (
|
||||
'draft','in_progress','review','done','archived'
|
||||
))
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_story_records_project ON story_records(project_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_story_records_status ON story_records(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_story_records_updated_at ON story_records(updated_at DESC);
|
||||
|
||||
-- 2) Story artifacts
|
||||
CREATE TABLE IF NOT EXISTS story_artifacts (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
story_id TEXT NOT NULL REFERENCES story_records(story_id) ON DELETE CASCADE,
|
||||
artifact_role TEXT NOT NULL,
|
||||
doc_id TEXT,
|
||||
doc_version TEXT,
|
||||
path TEXT,
|
||||
section TEXT,
|
||||
chunk_id TEXT,
|
||||
change_type TEXT,
|
||||
summary TEXT,
|
||||
source_ref TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
created_by TEXT,
|
||||
CONSTRAINT chk_story_artifact_role CHECK (artifact_role IN (
|
||||
'requirement','analysis','doc_change','test_model','note','decision','risk'
|
||||
)),
|
||||
CONSTRAINT chk_story_change_type CHECK (change_type IS NULL OR change_type IN (
|
||||
'added','updated','removed','linked'
|
||||
))
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_story_artifacts_story_role ON story_artifacts(story_id, artifact_role);
|
||||
CREATE INDEX IF NOT EXISTS idx_story_artifacts_story_change ON story_artifacts(story_id, change_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_story_artifacts_doc ON story_artifacts(doc_id, doc_version);
|
||||
CREATE INDEX IF NOT EXISTS idx_story_artifacts_path ON story_artifacts(path);
|
||||
|
||||
-- Вариант уникальности можно уточнить после согласования процессов
|
||||
|
||||
-- 3) Story links
|
||||
CREATE TABLE IF NOT EXISTS story_links (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
story_id TEXT NOT NULL REFERENCES story_records(story_id) ON DELETE CASCADE,
|
||||
link_type TEXT NOT NULL,
|
||||
target_ref TEXT NOT NULL,
|
||||
description TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
CONSTRAINT chk_story_link_type CHECK (link_type IN (
|
||||
'story','adr','ticket','pr','commit','doc','external'
|
||||
))
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_story_links_story_type ON story_links(story_id, link_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_story_links_target_ref ON story_links(target_ref);
|
||||
```
|
||||
|
||||
## 6) План внедрения (после согласования)
|
||||
1. Подтвердить перечень полей и enum-значений.
|
||||
2. Подготовить SQL-миграцию `Vxxx__story_context.sql`.
|
||||
3. Обновить bootstrap/инициализацию схемы.
|
||||
4. Обновить репозитории для `story_records/story_artifacts/story_links`.
|
||||
5. Добавить таблицу и репозиторий `session_artifacts` (session-scoped артефакты без `story_id`).
|
||||
6. Добавить запись session-артефактов в оркестраторе во время работы аналитика.
|
||||
7. Добавить webhook-обработчик `bind session -> story` при появлении commit со `story_id`.
|
||||
8. Добавить API/сервисный метод `get_story_context(story_id)` для повторного входа в Story.
|
||||
9. Добавить тесты:
|
||||
- unit на репозитории,
|
||||
- интеграционные на happy-path записи/чтения,
|
||||
- регресс на отсутствие зависимости от типа RAG.
|
||||
10. Добавить миграцию для `rag_blob_cache/rag_chunk_cache/rag_session_chunk_map`.
|
||||
11. Внедрить `delta-only` индексацию для session-RAG с переиспользованием кэша.
|
||||
|
||||
## 7) Открытые вопросы
|
||||
- Нужен ли отдельный справочник для `artifact_type`, `artifact_role`, `link_type`.
|
||||
- Что считать `doc_version`: semver, дата, commit, hash файла.
|
||||
- Нужна ли soft-delete политика для Story.
|
||||
- Требуется ли аудит (кто/когда менял `summary` и связи).
|
||||
- Какой уровень обязательности `chunk_id` (опционален по умолчанию).
|
||||
- Нужна ли TTL/очистка для `rag_blob_cache/rag_chunk_cache`.
|
||||
- Делать ли fallback к репозиторному кэшу по умолчанию или только при explicit-флаге.
|
||||
- Как определять соответствие `session_id` и commit в webhook (1:1, последний активный, explicit token).
|
||||
- Как долго хранить `session_artifacts` до bind/cleanup.
|
||||
|
||||
## 8) Критерии готовности
|
||||
- По `story_id` можно восстановить инкремент без исходной сессии.
|
||||
- История изменений не теряется при переиндексации RAG.
|
||||
- Аналитик и тестировщик используют один `story_id` как общий ключ контекста.
|
||||
- Схема работает при любом выбранном режиме RAG.
|
||||
- Session-RAG поднимается быстрее за счет cache hit по неизмененным файлам.
|
||||
- Артефакты аналитика, созданные до появления `story_id`, корректно попадают в Story после commit/webhook bind.
|
||||
@@ -0,0 +1,161 @@
|
||||
# Агент для работы с проектной документацией
|
||||
|
||||
## 1. Общее описание
|
||||
Приложение представляет собой backend агентного режима для работы с документацией и кодом проекта.
|
||||
|
||||
Система решает следующие задачи:
|
||||
- индексирует локальную копию проекта в `rag_session` и использует ее как основной рабочий контекст пользователя;
|
||||
- принимает webhook коммитов репозитория в `rag_repo` и фиксирует контекст изменений по `story_id`;
|
||||
- ускоряет построение `rag_session` за счет переиспользования кэша чанков и эмбеддингов из `rag_repo`;
|
||||
- обрабатывает пользовательские запросы через `chat`, `agent`, оркестратор и специализированные графы;
|
||||
- сохраняет quality-метрики, Story-контекст и артефакты сессии в PostgreSQL.
|
||||
|
||||
Ключевая идея архитектуры:
|
||||
- `rag_session` отвечает за пользовательскую рабочую сессию и всегда остается основным источником retrieval;
|
||||
- `rag_repo` не участвует напрямую в пользовательском ответе, а служит фоновым источником кэша и контекста коммитов;
|
||||
- `story_id` связывает изменения аналитика, документацию и последующую работу тестировщика.
|
||||
|
||||
## 2. Архитектура
|
||||
```mermaid
|
||||
flowchart LR
|
||||
User["Пользователь"]
|
||||
Git["Git репозиторий\n(Gitea / Bitbucket)"]
|
||||
Chat["Модуль chat"]
|
||||
Agent["Модуль agent"]
|
||||
RagSession["Модуль rag_session"]
|
||||
RagRepo["Модуль rag_repo"]
|
||||
Shared["Модуль shared"]
|
||||
DB["PostgreSQL + pgvector"]
|
||||
Giga["GigaChat API"]
|
||||
|
||||
User --> Chat
|
||||
Chat --> Agent
|
||||
Agent --> RagSession
|
||||
Agent --> Shared
|
||||
RagSession --> Shared
|
||||
RagRepo --> Shared
|
||||
Chat --> DB
|
||||
Agent --> DB
|
||||
RagSession --> DB
|
||||
RagRepo --> DB
|
||||
RagSession --> Giga
|
||||
Agent --> Giga
|
||||
Git --> RagRepo
|
||||
RagRepo -.кэш и контекст коммитов.-> RagSession
|
||||
```
|
||||
|
||||
Кратко по ролям модулей:
|
||||
- `chat` — внешний API чата, фоновые задачи, SSE события, диалоги.
|
||||
- `agent` — роутер интентов, оркестратор, графы, tools, генерация ответа и changeset.
|
||||
- `rag_session` — создание и сопровождение пользовательского RAG индекса по локальным файлам.
|
||||
- `rag_repo` — прием webhook коммитов, определение `story_id`, фиксация контекста коммита и заполнение repo-cache.
|
||||
- `shared` — инфраструктурный слой: БД, retry, event bus, GigaChat client, настройки.
|
||||
|
||||
## 3. Типичный флоу
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
actor User as Пользователь
|
||||
participant Git as Git репозиторий
|
||||
participant RagRepo as Модуль rag_repo
|
||||
participant DB as PostgreSQL
|
||||
participant RagSession as Модуль rag_session
|
||||
participant Chat as Модуль chat
|
||||
participant Agent as Модуль agent
|
||||
|
||||
Note over User,RagSession: Первая рабочая сессия: кэша репозитория еще нет
|
||||
User->>RagSession: Создание rag_session и загрузка файлов проекта
|
||||
RagSession->>DB: Проверка cache hit/miss
|
||||
DB-->>RagSession: Кэш пуст
|
||||
RagSession->>RagSession: Чанкинг и расчет embeddings без repo-cache
|
||||
RagSession->>DB: Сохранение rag_chunks и rag_index_jobs
|
||||
User->>Chat: Отправка запроса в чат
|
||||
Chat->>Agent: Передача задачи
|
||||
Agent->>RagSession: Retrieval контекста
|
||||
RagSession->>DB: Чтение rag_chunks
|
||||
DB-->>RagSession: Релевантные чанки
|
||||
RagSession-->>Agent: Контекст
|
||||
Agent-->>Chat: Ответ / changeset
|
||||
|
||||
Note over User,Git: Пользователь вручную делает commit и push
|
||||
Git->>RagRepo: Webhook push
|
||||
RagRepo->>RagRepo: Определение provider, commit_sha, changed_files, story_id
|
||||
RagRepo->>DB: Запись story_records/story_links/story_artifacts
|
||||
RagRepo->>DB: Запись rag_blob_cache/rag_chunk_cache/rag_session_chunk_map
|
||||
|
||||
Note over User,RagSession: Вторая рабочая сессия: repo-cache уже существует
|
||||
User->>RagSession: Создание новой rag_session и загрузка файлов проекта
|
||||
RagSession->>DB: Проверка cache hit/miss
|
||||
DB-->>RagSession: Найдены cache hit по части файлов
|
||||
RagSession->>RagSession: Переиспользование чанков из rag_repo cache
|
||||
RagSession->>RagSession: Пересчет embeddings только для cache miss файлов
|
||||
RagSession->>DB: Сохранение rag_chunks, rag_session_chunk_map, rag_index_jobs
|
||||
User->>Chat: Новый запрос
|
||||
Chat->>Agent: Передача задачи
|
||||
Agent->>RagSession: Retrieval по новой сессии
|
||||
RagSession-->>Agent: Контекст из session-RAG
|
||||
Agent-->>Chat: Ответ / changeset
|
||||
```
|
||||
|
||||
Что важно в этом сценарии:
|
||||
- первый запуск индексации может быть полностью без кэша;
|
||||
- после коммита `rag_repo` фиксирует контекст изменений и наполняет cache-таблицы;
|
||||
- во второй и последующих сессиях `rag_session` использует `cache_hit_files`, чтобы уменьшить объем новых embeddings.
|
||||
|
||||
## 4. Инструкции к запуску
|
||||
|
||||
### Локальный запуск
|
||||
```bash
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
uvicorn app.main:app --reload --port 15000
|
||||
```
|
||||
|
||||
### Запуск через Docker Compose
|
||||
1. Создать `.env` на основе примера:
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
2. Заполнить как минимум `GIGACHAT_TOKEN`.
|
||||
|
||||
3. Запустить сервисы:
|
||||
```bash
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
4. Проверить доступность backend:
|
||||
```bash
|
||||
curl http://localhost:15000/health
|
||||
```
|
||||
|
||||
Ожидаемый ответ:
|
||||
```json
|
||||
{"status":"ok"}
|
||||
```
|
||||
|
||||
### Основные адреса
|
||||
- Backend API: `http://localhost:15000`
|
||||
- PostgreSQL + pgvector: `localhost:5432`
|
||||
- Webhook репозитория: `POST /internal/rag-repo/webhook`
|
||||
|
||||
### Базовый сценарий проверки
|
||||
1. Создать `rag_session` через `POST /api/rag/sessions`.
|
||||
2. Дождаться завершения index-job через `GET /api/rag/sessions/{rag_session_id}/jobs/{index_job_id}`.
|
||||
3. Создать диалог через `POST /api/chat/dialogs`.
|
||||
4. Отправить сообщение через `POST /api/chat/messages`.
|
||||
5. Настроить webhook репозитория на `POST /internal/rag-repo/webhook`.
|
||||
6. Сделать commit с `story_id` в сообщении, например `FEAT-1 ...`.
|
||||
7. Проверить заполнение таблиц:
|
||||
- `story_records`, `story_links`, `story_artifacts`
|
||||
- `rag_blob_cache`, `rag_chunk_cache`, `rag_session_chunk_map`
|
||||
8. Во второй сессии индексации проверить поля job-статуса:
|
||||
- `indexed_files`
|
||||
- `cache_hit_files`
|
||||
- `cache_miss_files`
|
||||
|
||||
### Полезные замечания
|
||||
- Текущая chat-модель: `GigaChat`.
|
||||
- Основной retrieval всегда идет из `rag_session`.
|
||||
- `rag_repo` используется как фоновый источник кэша и контекста коммитов.
|
||||
- Если в webhook не найден `story_id`, commit-контекст Story не будет привязан, но cache-таблицы все равно должны наполняться.
|
||||
@@ -0,0 +1,33 @@
|
||||
# Agent Rules v1
|
||||
|
||||
## 1. Evidence-first
|
||||
|
||||
Агент должен формировать документацию только на основе подтвержденных источников: кода, существующей документации, системной аналитики и других явно доступных артефактов. Нельзя додумывать поведение системы, зависимости или бизнес-логику, если они не подтверждаются исходными материалами.
|
||||
|
||||
## 2. One Stable Object = One Document
|
||||
|
||||
Каждый документ должен описывать только одну устойчивую техническую сущность или один устойчивый аспект системы. Если по сущности могут ссылаться другие документы или она может переиспользоваться, ее нужно выносить в отдельный документ.
|
||||
|
||||
## 3. No Semantic Duplication
|
||||
|
||||
Документы не должны пересекаться по смыслу и повторять одно и то же содержание. Если одна и та же логика, правило или описание нужны в нескольких местах, агент должен вынести их в отдельный документ и использовать ссылки вместо дублирования текста.
|
||||
|
||||
## 4. Explicit Document Type
|
||||
|
||||
Для каждого документа агент должен явно определять его тип. На базовом уровне нужно использовать типы `ui_page`, `api_method`, `logic_block` и применять для каждого типа свой шаблон содержания и набор метаданных.
|
||||
|
||||
## 5. Hierarchical File Structure
|
||||
|
||||
Агент должен строить документацию как иерархию каталогов и файлов, а не как плоский набор страниц. Документы нужно раскладывать по смысловым разделам, например `docs/ui`, `docs/api`, `docs/logic`, `docs/architecture`, чтобы структура отражала архитектуру и упрощала навигацию.
|
||||
|
||||
## 6. Required YAML Frontmatter
|
||||
|
||||
Каждый документ должен начинаться с единообразного `YAML frontmatter`. В нем обязательно должны быть базовые метаданные документа: стабильный `id`, `title`, `doc_type`, `status`, `source_of_truth`, а также ссылки на связанные документы и кодовые артефакты.
|
||||
|
||||
## 7. Correct Internal Decomposition
|
||||
|
||||
Содержимое документа должно следовать шаблону своего типа и быть правильно декомпозировано внутри самого документа. Сценарии работы нужно описывать отдельно от детальных правил, контрактов, ограничений и дополнительных требований, чтобы документ оставался читаемым, атомарным и пригодным для индексирования.
|
||||
|
||||
## 8. Explicit Links Between Code and Docs
|
||||
|
||||
Каждый документ должен быть явно связан как минимум с соответствующим кодом и с соседними документами, если такие связи существуют. Агент должен фиксировать эти связи в метаданных и в тексте документа, чтобы документация образовывала связанную систему знаний, а не набор изолированных файлов.
|
||||
@@ -0,0 +1,422 @@
|
||||
# Архитектура агента As Is — отчёт
|
||||
|
||||
## 1. Executive Summary
|
||||
|
||||
- **Текущее устройство.** Запрос пользователя принимается в модуле `chat` (POST `/api/chat/messages`), ставится в очередь задач и обрабатывается асинхронно. Обработку выполняет `GraphAgentRuntime`: вызывается **router агента** (не IntentRouterV2), по его решению выбирается сценарий и план шагов оркестратора; шаги выполняются как вызовы функций или подграфов LangGraph. Итог — ответ или changeset в задаче и в событии `task_result`.
|
||||
|
||||
- **Два режима входа.** При `SIMPLE_CODE_EXPLAIN_ONLY=true` (по умолчанию) запросы идут в **CodeExplainChatService**: без роутера, сразу retrieval через CodeExplainRetrieverV2, evidence gate и один промпт. При `false` используется полный агент с роутером и оркестратором.
|
||||
|
||||
- **Router.** В продакшене используется **RouterService** из `app/modules/agent/engine/router/`: классификатор интентов (эвристики + LLM), регистр графов по `domain_id`/`process_id`, контекст диалога в AgentRepository. **IntentRouterV2** (модуль `rag/intent_router_v2`) в основном приложении **не вызывается** — только в тестах и пайплайне `tests/pipeline_intent_rag`.
|
||||
|
||||
- **Retrieval.** В основном флоу агента **RAG по запросу в рантайме не вызывается**: в `GraphAgentRuntime.run` переменная `rag_ctx` задаётся как пустой список и не заполняется; граф `project_qa/context_retrieval` получает этот пустой список и строит `source_bundle` только из `files_map` (вложения пользователя). Реальный retrieval по индексу выполняется только: (1) в режиме **direct code explain** (CodeExplainRetrieverV2 → LayeredRetrievalGateway → RagRepository); (2) внутри шага **build_code_explain_pack** при сценарии EXPLAIN_PART (тот же CodeExplainRetrieverV2). Контракт `RagRetriever` (async `retrieve(rag_session_id, query)`) в коде **нигде не реализован**: RagService умеет только индексировать, не извлекать.
|
||||
|
||||
- **Индексация.** При создании/обновлении RAG-сессии используется RagService с двумя пайплайнами: CodeIndexingPipeline (C0–C4: chunks, symbols, edges, entrypoints, traces, semantic roles) и DocsIndexingPipeline (D1–D4: module catalog, facts, sections, policy). Слои попадают в `rag_chunks`; retrieval по слоям делается только через RagRepository (LayeredRetrievalGateway), не через RagService.
|
||||
|
||||
- **Графы и пайплайны.** Есть общий оркестратор (ScenarioTemplateRegistry → PlanCompiler → ExecutionEngine). Сценарии: GENERAL_QA (в т.ч. project/qa как подплан project_qa), EXPLAIN_PART, ANALYTICS_REVIEW, DOCS_FROM_ANALYTICS, TARGETED_EDIT, GHERKIN_MODEL. Для project/qa выполняется цепочка подграфов: conversation_understanding → question_classification → context_retrieval (без вызова RAG) → опционально build_code_explain_pack → context_analysis → answer_composition. Отдельные графы зарегистрированы для default/general, project/qa, project/edits, docs/generation и для подшагов project_qa.
|
||||
|
||||
- **Сборка контекста для LLM.** В основном флоу в модель попадают: `rag_context` (из task_spec; по факту пустой), `confluence_context` (страницы из вложений), `files_map` (переданные пользователем файлы). Контекст по коду из индекса собирается только в direct code explain и в build_code_explain_pack (ExplainPack → PromptBudgeter).
|
||||
|
||||
- **Диагностика.** В приложении: логи (router decision, graph step result, code explain pack, orchestrator decision), события прогресса (task_progress с stage/message/meta), в `task_result` — meta (route, used_rag, orchestrator_steps, quality). Отдельная структура диагностики (router_plan, execution, retrieval, timings_ms, constraint_violations) реализована в тестовом пайплайне под IntentRouterV2 и в ответ не отдаётся.
|
||||
|
||||
- **Главные пробелы.** (1) Нет вызова RAG в основном агентском флоу — context_retrieval не использует индекс. (2) IntentRouterV2 и его retrieval/diagnostics не интегрированы в продакшен. (3) RagService не реализует контракт RagRetriever. (4) Целевые слои C5 (Test Mappings), C6 (Code Facts), D5 (Reference Graph), D6 (Doc-Code Links) в индексации и retrieval не представлены. (5) Evidence gate есть только у direct code explain; в оркестраторе quality gates проверяют артефакты шагов, но не «достаточность evidence» в целевом смысле.
|
||||
|
||||
- **Близость к целевой архитектуре.** Частично: индексация уже многослойная (CODE C0–C4, DOCS D1–D4), есть задел intent-based роутинга (IntentRouterV2 в тестах), оркестрация по сценариям и графам есть. Не хватает: подключения retrieval к основному флоу, объединения роутера с intent/retrieval-спеками, полного набора слоёв и явного evidence gate в оркестраторе.
|
||||
|
||||
---
|
||||
|
||||
## 2. End-to-End Flow As Is
|
||||
|
||||
### 2.1. Request intake
|
||||
|
||||
**Что происходит.** Клиент шлёт POST `/api/chat/messages` (ChatMessageRequest: message, mode, attachments, files, dialog_session_id и т.д.). ChatModule при `SIMPLE_CODE_EXPLAIN_ONLY=true` отдаёт запрос в CodeExplainChatService.handle_message; иначе — в ChatOrchestrator.enqueue_message. В последнем случае создаётся задача (TaskStore), по idempotency может возвращаться существующая, затем в фоне запускается _process_task.
|
||||
|
||||
**Evidence.** `app/modules/chat/module.py` (send_message, условие по `_simple_code_explain_only`), `app/modules/chat/service.py` (enqueue_message, _process_task, _resolve_sessions).
|
||||
|
||||
**Комментарий.** Точка входа одна; разветвление по флагу окружения определяет упрощённый (direct) или полный (agent) путь.
|
||||
|
||||
### 2.2. Routing
|
||||
|
||||
**Что происходит.** В полном пути GraphAgentRuntime.run вызывает `self._router.resolve(message, dialog_session_id, mode)`. Это RouterService (agent): читает контекст из RouterContextStore (AgentRepository), при принудительном mode возвращает маршрут из маппинга (project_qa, project_edits, docs_generation и др.), иначе — IntentClassifier: короткие подтверждения → last_routing, детерминированные правила (редакт файла, запрос документации) → соответствующий route, в остальных случаях — LLM (prompt "router_intent") с разбором JSON. Результат — RouteResolution (domain_id, process_id, confidence, reason, fallback_used). При низкой уверенности или невалидной паре (domain_id, process_id) возвращается fallback default/general. Graph factory выбирается по (domain_id, process_id) из IntentRegistry.
|
||||
|
||||
**Evidence.** `app/modules/agent/service.py` (run, _resolve_graph), `app/modules/agent/engine/router/router_service.py` (resolve, _is_acceptable, _resolution, _fallback), `app/modules/agent/engine/router/intent_classifier.py` (classify_new_intent, from_mode, _deterministic_route, _classify_with_llm), `app/modules/agent/engine/router/__init__.py` (build_router_service, регистрация графов).
|
||||
|
||||
**Комментарий.** IntentRouterV2 в этом флоу не участвует. graph_id в продакшене — это пара (domain_id, process_id), а не строка из IntentRouterV2.
|
||||
|
||||
### 2.3. Retrieval
|
||||
|
||||
**Что происходит.** В GraphAgentRuntime.run перед вызовом оркестратора `rag_ctx` инициализируется как `[]` и не заполняется. TaskSpec получает rag_items=rag_ctx и rag_context=_format_rag(rag_ctx) — т.е. пустой контекст. В плане project_qa шаг context_retrieval (граф ProjectQaRetrievalGraphFactory) в _retrieve_context читает state (resolved_request, question_profile, files_map), объявляет `rag_items: list[dict] = []`, вызывает build_source_bundle(profile, rag_items, files_map) — т.е. только ранжирование переданных файлов, без вызова RAG. Реальный retrieval: (1) CodeExplainChatService — CodeExplainRetrieverV2.build_pack → LayeredRetrievalGateway (C3, C1, C2, C0, lexical fallback); (2) шаг build_code_explain_pack в оркестраторе — тот же build_pack с file_candidates из source_bundle.
|
||||
|
||||
**Evidence.** `app/modules/agent/service.py` (rag_ctx: list[dict] = [], task_spec), `app/modules/agent/engine/graphs/project_qa_step_graphs.py` (ProjectQaRetrievalGraphFactory._retrieve_context, rag_items=[], build_source_bundle), `app/modules/rag/explain/retriever_v2.py` (build_pack, _entrypoints, _seed_symbols, _trace_builder, _excerpt_fetcher, lexical fallback), `app/modules/rag/explain/layered_gateway.py` (retrieve_layer, retrieve_lexical_code → repository).
|
||||
|
||||
**Комментарий.** Намеренно не меняя код: в as is основной агентский пайплайн не выполняет retrieval по индексу; контракт RagRetriever не реализован (RagService не имеет метода retrieve).
|
||||
|
||||
### 2.4. Context assembly
|
||||
|
||||
**Что происходит.** Для основного агента контекст для шагов собирается в TaskSpecBuilder: metadata содержит rag_items, rag_context, confluence_context, files_map. rag_context формируется в agent как _format_rag(rag_ctx) — при пустом rag_ctx это пустая строка. Confluence — из вложений типа confluence_url. В шагах оркестратора (collect_state) в agent_state попадает этот metadata; графы получают state с rag_context, confluence_context, files_map. Для ответа LLM контекст собирается внутри графов: в project_qa — ProjectQaSupport (build_answer_brief, compose_answer) и при наличии explain_pack — PromptBudgeter.build_prompt_input + code_explain_answer_v2. В direct code explain контекст — только ExplainPack через PromptBudgeter.
|
||||
|
||||
**Evidence.** `app/modules/agent/service.py` (_format_rag, _format_confluence, task_spec), `app/modules/agent/engine/orchestrator/step_registry.py` (_collect_state, agent_state), `app/modules/agent/engine/graphs/project_qa_step_graphs.py` (ProjectQaAnswerGraphFactory._compose_answer, _compose_explain_answer), `app/modules/rag/explain` (PromptBudgeter).
|
||||
|
||||
**Комментарий.** Разделения «intent-driven» сборки контекста по слоям в основном флоу нет; слои используются только в CodeExplainRetrieverV2 и при формировании промпта code_explain_answer_v2.
|
||||
|
||||
### 2.5. LLM answer synthesis
|
||||
|
||||
**Что происходит.** Ответ генерируется внутри графов и шагов оркестратора. Для default/general — граф, собранный BaseGraphFactory(llm). Для project/qa — цепочка подграфов, финальный ответ в ProjectQaAnswerGraphFactory (_compose_answer: при наличии explain_pack — LLM code_explain_answer_v2, иначе ProjectQaSupport.compose_answer по brief). Для direct code explain — один вызов LLM code_explain_answer_v2 после evidence gate. AgentLlmService.generate вызывается с ключом промпта (router_intent, code_explain_answer_v2 и т.д.) и payload; промпты загружаются через PromptLoader.
|
||||
|
||||
**Evidence.** `app/modules/agent/engine/graphs/project_qa_step_graphs.py` (ProjectQaAnswerGraphFactory), `app/modules/agent/llm` (AgentLlmService), `app/modules/chat/direct_service.py` (CodeExplainChatService), `app/modules/agent/engine/graphs` (фабрики графов).
|
||||
|
||||
**Комментарий.** Итоговый ответ и/или changeset собираются ResultAssembler из артефактов шагов (final_answer, final_changeset).
|
||||
|
||||
### 2.6. Diagnostics
|
||||
|
||||
**Что происходит.** В рантайме: логи (router decision, graph step result, code explain pack, orchestrator decision); события task_progress (stage, message, meta); в конце — task_result с meta (route, used_rag, used_confluence, orchestrator_steps, quality при наличии). Quality метрики при наличии записываются MetricsPersister в agent_repository. Структурированная диагностика (router_plan, execution, retrieval, timings_ms, constraint_violations) строится в тестах pipeline_intent_rag (helpers/diagnostics) для результата IntentRouterV2 и в ответ API не входит.
|
||||
|
||||
**Evidence.** `app/modules/agent/service.py` (LOGGER.warning по route/orchestrator, meta в AgentResult, _persist_quality_metrics), `app/modules/chat/service.py` (_publish_progress, task_result), `tests/pipeline_intent_rag/helpers/diagnostics.py` (build_router_plan, init_diagnostics, apply_retrieval_report, validate_constraints).
|
||||
|
||||
**Комментарий.** used_rag в meta всегда False в текущем коде, т.к. rag_ctx не заполняется.
|
||||
|
||||
---
|
||||
|
||||
## 3. Router As Is
|
||||
|
||||
### 3.1. Main router entrypoints
|
||||
|
||||
Единственная точка входа роутера в основном приложении — `RouterService.resolve(user_message, conversation_key, mode)` в `app/modules/agent/engine/router/router_service.py`. Сборка: `build_router_service` в `app/modules/agent/engine/router/__init__.py` (IntentRegistry, IntentClassifier, RouterContextStore, IntentSwitchDetector, RouterService).
|
||||
|
||||
### 3.2. Input contract
|
||||
|
||||
- **Вход:** `user_message: str`, `conversation_key: str` (dialog_session_id), `mode: str` (например "auto", "project_qa", "project_edits", "docs_generation").
|
||||
- **Контекст:** из RouterContextStore по conversation_key — RouterContext (last_routing, message_history, active_intent, dialog_started, turn_index). Контекст обновляется при persist_context после ответа агента.
|
||||
|
||||
**Evidence.** `app/modules/agent/engine/router/router_service.py` (resolve, context = self._ctx.get), `app/modules/agent/engine/router/schemas.py` (RouterContext).
|
||||
|
||||
### 3.3. Output contract
|
||||
|
||||
RouteResolution: domain_id, process_id, confidence, reason, fallback_used, decision_type, explicit_switch. Фабрика графа запрашивается отдельно: graph_factory(domain_id, process_id).
|
||||
|
||||
**Evidence.** `app/modules/agent/engine/router/schemas.py` (RouteResolution), `app/modules/agent/engine/router/router_service.py` (_resolution, _fallback, _continue_current, graph_factory).
|
||||
|
||||
### 3.4. Supported intents and sub-intents
|
||||
|
||||
**Намерения (domain_id / process_id):** default/general, project/qa, project/edits, docs/generation. Внутри оркестратора сценарий (Scenario) определяется TaskSpecBuilder по mode, route и тексту сообщения: GENERAL_QA, EXPLAIN_PART, ANALYTICS_REVIEW, DOCS_FROM_ANALYTICS, TARGETED_EDIT, GHERKIN_MODEL. Подграфы project_qa зарегистрированы как project_qa/conversation_understanding, question_classification, context_retrieval, context_analysis, answer_composition. Sub-intent в смысле IntentRouterV2 (EXPLAIN, OPEN_FILE и т.д.) в этом роутере не фигурируют.
|
||||
|
||||
**Evidence.** `app/modules/agent/engine/router/__init__.py` (registry.register), `app/modules/agent/engine/router/intent_classifier.py` (_route_mapping, from_mode), `app/modules/agent/engine/orchestrator/task_spec_builder.py` (_detect_scenario).
|
||||
|
||||
### 3.5. Graph selection logic
|
||||
|
||||
Граф выбирается по (domain_id, process_id). Для основного запроса оркестратор по сценарию решает, какой план выполнять; в плане шаги могут иметь graph_id="route" (тогда берётся domain_id/process_id из task.routing) или graph_id вида "project_qa/context_retrieval". Резолвер графа: _resolve_graph в GraphAgentRuntime — factory = self._router.graph_factory(domain_id, process_id), fallback на default/general.
|
||||
|
||||
**Evidence.** `app/modules/agent/service.py` (_resolve_graph), `app/modules/agent/engine/orchestrator/step_registry.py` (_execute_graph_step, graph_key), `app/modules/agent/engine/orchestrator/template_registry.py` (graph_id в шагах).
|
||||
|
||||
### 3.6. Heuristics / LLM / deterministic logic
|
||||
|
||||
- Детерминировано: короткие подтверждения → last_routing; целевой редакт файла (_is_targeted_file_edit_request); запрос документации (_is_broad_docs_request) → project/edits, docs/generation.
|
||||
- LLM: один вызов при отсутствии детерминированного решения — prompt "router_intent", ожидается JSON с route, confidence, reason; парсинг с допуском code fence.
|
||||
- Эвристики: min_confidence=0.7, проверка registry.is_valid(domain_id, process_id); при переключении интента — IntentSwitchDetector.should_switch, при отказе — _continue_current.
|
||||
|
||||
**Evidence.** `app/modules/agent/engine/router/intent_classifier.py`, `app/modules/agent/engine/router/router_service.py`.
|
||||
|
||||
### 3.7. Current limitations
|
||||
|
||||
- Нет keyword_hints, path_scope, layers в выходном контракте роутера; они не передаются в retrieval, т.к. retrieval в основном флоу не вызывается.
|
||||
- Контекст диалога ограничен last_routing и message_history; нет структуры query plan / anchors как в IntentRouterV2.
|
||||
- IntentRouterV2 с полным контрактом (intent, sub_intent, graph_id, retrieval_spec, retrieval_constraints, evidence_policy) в приложении не используется.
|
||||
|
||||
| Router capability | Current state | Status | Evidence | Notes |
|
||||
|-------------------------|---------------|--------|---------------------------------------------------------------------------|------------------------------------------------------|
|
||||
| Main entrypoint | RouterService.resolve | full | router_service.py | |
|
||||
| Input: message, session, mode | Yes | full | router_service.py | |
|
||||
| Output: domain_id, process_id, confidence, reason | Yes | full | RouteResolution, schemas.py | |
|
||||
| intent / sub-intent | domain/process only | partial | intent_classifier _route_mapping; no sub_intent in agent router | Sub-intent только в IntentRouterV2 |
|
||||
| graph_id | (domain_id, process_id) | full | registry.get_factory, _resolve_graph | |
|
||||
| conversation_mode | decision_type (start/continue/switch) | partial | RouteResolution.decision_type | Не буквально CONTINUE/FOLLOWUP_LIKELY |
|
||||
| keyword_hints | — | none | — | Есть в IntentRouterV2.query_plan |
|
||||
| path_scope | — | none | — | Есть в IntentRouterV2.retrieval_spec.filters |
|
||||
| layers | — | none | — | Есть в IntentRouterV2 |
|
||||
| Heuristics + LLM | Yes | full | intent_classifier | |
|
||||
| Fallback default/general| Yes | full | _fallback, _is_acceptable | |
|
||||
|
||||
---
|
||||
|
||||
## 4. Retrieval / RAG As Is
|
||||
|
||||
### 4.1. Code retrieval as is
|
||||
|
||||
- **Где выполняется:** только при direct code explain (CodeExplainChatService) и в шаге build_code_explain_pack (сценарий EXPLAIN_PART). Оба пути используют CodeExplainRetrieverV2 → LayeredRetrievalGateway → RagRepository.
|
||||
- **Chunking:** при индексации — CodeTextChunker (code), при retrieval — C0_SOURCE_CHUNKS и lexical fallback по тексту запроса.
|
||||
- **Symbol-based:** C1_SYMBOL_CATALOG через retrieve_layer; после entrypoints подтягиваются handler symbols через CodeGraphRepository.get_symbols_by_ids.
|
||||
- **Path-aware:** path_prefixes передаются в retrieve_layer и retrieve_lexical_code (из intent/file_candidates).
|
||||
- **Entrypoints:** C3_ENTRYPOINTS, фильтрация по entry_type из intent.
|
||||
- **Test-specific:** exclude_tests в gateway; при малом числе excerpts делается _merge_test_fallback с include_tests.
|
||||
- **Структурные связи:** C2 (edges), TraceBuilder строит пути по графу; SourceExcerptFetcher по путям достаёт фрагменты. Execution traces индексируются (entrypoints + execution_trace_document_builder).
|
||||
|
||||
В основном агентском флоу (project_qa/context_retrieval) вызова RAG нет: rag_items пустые, source_bundle строится только из files_map.
|
||||
|
||||
**Evidence.** `app/modules/rag/explain/retriever_v2.py`, `app/modules/rag/explain/layered_gateway.py`, `app/modules/rag/persistence/repository.py`, `app/modules/agent/engine/graphs/project_qa_step_graphs.py` (ProjectQaRetrievalGraphFactory).
|
||||
|
||||
### 4.2. Docs retrieval as is
|
||||
|
||||
- **Парсинг документов:** DocsIndexingPipeline при индексации: frontmatter, MarkdownDocChunker, DocsClassifier (doc_kind), build_module_catalog, build_section, build_policy, _extract_facts. Слои: D1_MODULE_CATALOG, D2_FACT_INDEX, D3_SECTION_INDEX, D4_POLICY_INDEX (enums).
|
||||
- **Retrieval по документам:** в основном приложении отдельного «docs retrieval» по запросу пользователя не вызывается. LayeredRetrievalGateway и RetrievalStatementBuilder поддерживают слои D1–D4 в запросах (layer_rank_sql), но код, который бы по intent «DOCS_QA» или «GENERATE_DOCS_FROM_CODE» вызывал только docs-слои, в основном флоу не прослеживается — IntentRouterV2 с retrieval_profile "docs" используется только в тестах.
|
||||
- **Doc-to-code linking:** явного слоя или индекса D6 (Doc-Code Links) нет. В индексации есть ссылки в документах (frontmatter links), но отдельного кросс-доменного индекса нет.
|
||||
|
||||
**Evidence.** `app/modules/rag/indexing/docs/pipeline.py`, `app/modules/rag/contracts/enums.py`, `app/modules/rag/persistence/retrieval_statement_builder.py` (D1–D4 в SQL).
|
||||
|
||||
### 4.3. Map current implementation to target layers
|
||||
|
||||
| Target element | Current implementation | Status | Evidence | Notes |
|
||||
|----------------|------------------------|--------|----------|--------|
|
||||
| CODE / C0 Source Chunks | CodeTextChunker + CodeTextDocumentBuilder, слой C0_SOURCE_CHUNKS; retrieval через retrieve_lexical_code и retrieve(..., layers=[C0]) | full | code_text/document_builder.py, pipeline.py, retrieval_statement_builder.py, layered_gateway | |
|
||||
| CODE / C1 Symbol Catalog | SymbolExtractor + SymbolDocumentBuilder, C1_SYMBOL_CATALOG; retrieval в retriever_v2 _seed_symbols | full | indexing/code/symbols/, enums.py, retriever_v2.py | |
|
||||
| CODE / C2 Symbol Relations | EdgeExtractor, EdgeDocumentBuilder, DataflowDocumentBuilder; слой C2_DEPENDENCY_GRAPH; TraceBuilder использует граф | full | indexing/code/edges/, graph_repository.py | Целевое имя «Symbol Relations»; в коде «dependency/dataflow» |
|
||||
| CODE / C3 Entrypoints | EntrypointDetectorRegistry (FastAPI, Flask, Typer/Click), EntrypointDocumentBuilder, execution_trace; C3_ENTRYPOINTS | full | indexing/code/entrypoints/, retriever_v2 _entrypoints | |
|
||||
| CODE / C4 Execution Paths | Execution traces индексируются в C2 (execution_trace); пути строятся в рантайме TraceBuilder по графу | partial | execution_trace_builder, trace_builder.py, retriever_v2 | Нет отдельного слоя «C4 Execution Paths»; логика есть |
|
||||
| CODE / C5 Test Mappings | Нет отдельного слоя или индекса тест→код | none | — | test_filter только исключает/включает пути |
|
||||
| CODE / C6 Code Facts | Нет слоя «code facts» | none | — | |
|
||||
| DOCS / D0 Document Chunks | Секции документов как D3_SECTION_INDEX; общего «D0» как аналога C0 нет | partial | docs pipeline build_section | Chunks по сути есть как section docs |
|
||||
| DOCS / D1 Document Catalog | D1_MODULE_CATALOG, build_module_catalog | full | enums.py, docs/document_builder.py | |
|
||||
| DOCS / D2 Fact Index | D2_FACT_INDEX, _extract_facts из frontmatter links | full | docs pipeline | |
|
||||
| DOCS / D3 Entity Catalog | D3_SECTION_INDEX в коде; целевое «Entity Catalog» может отличаться | partial | enums.py DOCS_SECTION_INDEX | Именование не 1:1 |
|
||||
| DOCS / D4 Workflow Index | D4_POLICY_INDEX (policy-документы) | partial | docs pipeline build_policy | Ограничено type=policy |
|
||||
| DOCS / D5 Reference Graph | Нет отдельного графа ссылок между документами | none | — | |
|
||||
| DOCS / D6 Doc-Code Links | Нет | none | — | |
|
||||
|
||||
---
|
||||
|
||||
## 5. Graphs / Pipelines As Is
|
||||
|
||||
### 5.1. List of existing graphs / pipelines
|
||||
|
||||
- **По (domain_id, process_id):** default/general (BaseGraphFactory), project/qa (ProjectQaGraphFactory), project/edits (ProjectEditsGraphFactory), docs/generation (DocsGraphFactory).
|
||||
- **Подграфы project_qa:** project_qa/conversation_understanding (ProjectQaConversationGraphFactory), project_qa/question_classification (ProjectQaClassificationGraphFactory), project_qa/context_retrieval (ProjectQaRetrievalGraphFactory), project_qa/context_analysis (ProjectQaAnalysisGraphFactory), project_qa/answer_composition (ProjectQaAnswerGraphFactory).
|
||||
|
||||
Планы (ExecutionPlan) задаются ScenarioTemplateRegistry по сценарию: general_qa_v1, project_qa_reasoning_v1, explain_part_v1, analytics_review_v1, docs_from_analytics_v1, targeted_edit_v1, gherkin_model_v1.
|
||||
|
||||
**Evidence.** `app/modules/agent/engine/router/__init__.py`, `app/modules/agent/engine/orchestrator/template_registry.py`, `app/modules/agent/engine/graphs/`.
|
||||
|
||||
### 5.2. Shared orchestration logic
|
||||
|
||||
OrchestratorService: build template → compile plan → validate → ExecutionEngine.run(ctx) → ResultAssembler.assemble. Шаги выполняются StepRegistry: либо функция (action_id), либо executor="graph" с graph_id. Состояние передаётся через ExecutionContext (task, plan, artifacts, evidences, graph_resolver, graph_invoker). Общая логика: один сценарий на запрос, линейные/параллельные зависимости шагов.
|
||||
|
||||
**Evidence.** `app/modules/agent/engine/orchestrator/service.py`, `app/modules/agent/engine/orchestrator/execution_engine.py`, `app/modules/agent/engine/orchestrator/step_registry.py`.
|
||||
|
||||
### 5.3. Specialized logic
|
||||
|
||||
- project_qa: последовательность подграфов + опционально build_code_explain_pack; context_retrieval не вызывает RAG; context_analysis использует explain_pack или analyzer по profile (code/docs).
|
||||
- explain_part: при route project/qa тот же project_qa_reasoning_v1 с добавлением шага build_code_explain_pack; анализ и ответ с ExplainPack.
|
||||
- Остальные сценарии (review, docs, edit, gherkin) — свои шаги (fetch_source_doc, normalize_document, …), без слоёвого retrieval.
|
||||
|
||||
**Evidence.** template_registry.py _project_qa, _explain, _review, _docs, _edit, _gherkin; project_qa_step_graphs.py.
|
||||
|
||||
### 5.4. Retrieval failure behavior
|
||||
|
||||
В основном флоу retrieval не вызывается, поэтому «failure» не возникает. В CodeExplainRetrieverV2 при пустых entrypoints/symbols/traces/excerpts заполняется pack.missing, делается lexical fallback; при недостатке excerpts — test fallback. CodeExplainEvidenceGate при числе excerpts < min_excerpts возвращает passed=False и шаблонный ответ с диагностикой (без вызова LLM).
|
||||
|
||||
**Evidence.** retriever_v2.py (_run_pass, _merge_test_fallback), evidence_gate.py.
|
||||
|
||||
### 5.5. Fallback behavior
|
||||
|
||||
Router: при низкой уверенности или невалидной паре — fallback default/general. При явном переключении интента, если новый интент не принят — _continue_current. В retrieval (CodeExplainRetrieverV2): lexical fallback, затем при необходимости test fallback. Отдельного «fallback graph» или единого fallback-пайплайна при слабом retrieval в оркестраторе нет.
|
||||
|
||||
**Evidence.** router_service.py _fallback, _continue_current; retriever_v2.py.
|
||||
|
||||
### 5.6. Evidence sufficiency checks
|
||||
|
||||
CodeExplainEvidenceGate (direct code explain): проверка количества code_excerpts >= min_excerpts; при неуспехе — ответ без вызова LLM. В оркестраторе QualityGateRunner проверяет evidence_required по ctx.evidences; шаги вроде explain/review могут добавлять evidence через add_evidence, но в project_qa flow заполнение evidences не прослеживается в коде (collect_state не вызывает retrieval). Т.е. «evidence gate» в смысле «достаточно ли retrieval для ответа» есть только в direct code explain.
|
||||
|
||||
**Evidence.** `app/modules/chat/evidence_gate.py`, `app/modules/agent/engine/orchestrator/quality_gates.py` (_evidence_required), `app/modules/agent/engine/orchestrator/actions/common.py` (add_evidence).
|
||||
|
||||
| Pipeline / graph capability | Current state | Status | Evidence | Notes |
|
||||
|-----------------------------|---------------|--------|----------|--------|
|
||||
| List of graphs by route | Yes | full | router __init__, template_registry | |
|
||||
| Shared orchestration | Yes | full | OrchestratorService, ExecutionEngine, StepRegistry | |
|
||||
| project_qa subgraphs | Yes | full | project_qa_step_graphs, template_registry | |
|
||||
| context_retrieval uses RAG | No | none | project_qa_step_graphs rag_items=[] | |
|
||||
| Fallback default/general | Yes (router) | full | router_service | |
|
||||
| Fallback on weak retrieval | Only direct explain (evidence gate) | partial | evidence_gate, retriever_v2 | |
|
||||
| Evidence sufficiency in orchestrator | Gates есть, evidences в project_qa не наполняются из RAG | partial | quality_gates, step_registry | |
|
||||
|
||||
---
|
||||
|
||||
## 6. LLM Context Assembly As Is
|
||||
|
||||
### 6.1. Inputs to LLM
|
||||
|
||||
В основном флоу: message (user_message), rag_context (пустой), confluence_context (из вложений), files_map (из запроса). В state графов дополнительно: resolved_request, question_profile, source_bundle (rag_items + file_candidates; rag_items пустые), при EXPLAIN_PART — explain_pack (entrypoints, trace_paths, code_excerpts, missing). В direct code explain — только user message и ExplainPack (после build_pack и evidence gate).
|
||||
|
||||
**Evidence.** agent/service.py (task_spec, _format_rag), template_registry (metadata), project_qa_step_graphs (state), direct_service.py.
|
||||
|
||||
### 6.2. Context selection logic
|
||||
|
||||
Нет отдельного «context selection» по слоям в основном агенте. В CodeExplainRetrieverV2: порядок C3 → C1 → C2 (traces) → excerpts по путям; при нехватке — lexical C0, затем при необходимости тесты. Ограничение по объёму — в PromptBudgeter при сборке промпта.
|
||||
|
||||
**Evidence.** retriever_v2.py, explain/prompt_budgeter (если есть).
|
||||
|
||||
### 6.3. Prompt construction
|
||||
|
||||
AgentLlmService.generate(key, payload). Ключи: router_intent, code_explain_answer_v2 и др. Промпты загружаются через PromptLoader. Для code_explain_answer_v2 вход формирует PromptBudgeter.build_prompt_input(message, pack).
|
||||
|
||||
**Evidence.** app/modules/agent/llm, project_qa_step_graphs _compose_explain_answer, direct_service.
|
||||
|
||||
### 6.4. Noise control
|
||||
|
||||
Явного «noise control» в основном флоу нет. В CodeExplainRetrieverV2: ограничение числа entrypoints, seeds, trace depth, excerpts; PromptBudgeter ограничивает объём в промпте.
|
||||
|
||||
### 6.5. Handling tests
|
||||
|
||||
exclude_tests в LayeredRetrievalGateway и retrieval; при малом количестве excerpts — _merge_test_fallback с include_tests. В project_qa_support при build_source_bundle для file_candidates/rag_items применяется штраф за test path, если нет explicit_test в terms.
|
||||
|
||||
**Evidence.** layered_gateway (exclude_tests, _filter_args), retriever_v2 _merge_test_fallback, project_qa_support build_source_bundle.
|
||||
|
||||
### 6.6. Current weaknesses
|
||||
|
||||
- Пустой rag_context в основном флоу; контекст по коду только из вложений (files_map) и при сценарии explain — из explain_pack.
|
||||
- Нет intent-driven выбора слоёв и объёмов контекста в оркестраторе.
|
||||
- Prompt-level контракты (имена полей, лимиты) разбросаны по промптам и бюджетеру, не оформлены как единый контракт.
|
||||
|
||||
---
|
||||
|
||||
## 7. Diagnostics As Is
|
||||
|
||||
### 7.1. Existing diagnostic artifacts
|
||||
|
||||
- В приложении: объект meta в ответе задачи (route, used_rag, used_confluence, orchestrator_steps, changeset_filtered_out и т.д.); при наличии quality — сохраняются через MetricsPersister. События: task_status, task_progress (stage, message, meta), task_result, task_error.
|
||||
- В тестовом пайплайне (IntentRouterV2): router_plan (intent, sub_intent, graph_id, layers, path_scope, keyword_hints, retrieval_constraints), execution (executed_layers, retrieval_mode_by_layer, top_k_by_layer, filters_by_layer, repo_scope), retrieval (requests, applied, fallback), timings_ms (router, retrieval_total, retrieval_by_layer, prompt_build, llm_call), constraint_violations, prompt (prompt_stats, evidence_summary).
|
||||
|
||||
**Evidence.** agent/service.py (AgentResult.meta, _persist_quality_metrics), chat/service.py (task_result, _publish_progress), tests/pipeline_intent_rag/helpers/diagnostics.py.
|
||||
|
||||
### 7.2. Where diagnostics are produced
|
||||
|
||||
- Router: логи (router decision с route, reason, confidence, fallback_used) в agent/service.py.
|
||||
- Графы: логи (graph step result) в project_qa_step_graphs и др.
|
||||
- Оркестратор: логи (orchestrator decision), meta в результате (orchestrator_steps, scenario).
|
||||
- Quality: quality_meta из orchestrator_result.meta, сохраняется в БД при наличии.
|
||||
- IntentRouterV2-диагностика: только в тестах (init_diagnostics, apply_retrieval_report, validate_constraints).
|
||||
|
||||
### 7.3. Human-readable value
|
||||
|
||||
Поле message в task_progress; ответ при evidence gate failure (paths, entrypoints, symbols, missing); meta.route (domain_id, process_id, reason); orchestrator_steps (step_id, status). Для аналитика полезны: сценарий, маршрут, факт использования RAG (сейчас всегда false), количество шагов и их статусы.
|
||||
|
||||
### 7.4. Technical-only value
|
||||
|
||||
timings_ms, executed_layers, retrieval_mode_by_layer, constraint_violations, детали retrieval_spec — в текущем приложении в API не отдаются, только в тестовой диагностике.
|
||||
|
||||
### 7.5. Gaps and overload
|
||||
|
||||
- Пробел: в продакшене нет слоёвой диагностики retrieval (какие слои запрашивались, сколько вернулось, fallback), нет constraint_violations. Слабо видно, почему ответ мог быть слабым (нет привязки к «мало evidence»).
|
||||
- Перегрузка: при желании вывести полную диагностику IntentRouterV2 в API пришлось бы дублировать структуру; сейчас она только для тестов.
|
||||
|
||||
| Diagnostic field / artifact | Produced where | Useful for human | Useful for debug | Notes |
|
||||
|-----------------------------|----------------|------------------|------------------|--------|
|
||||
| task_progress (stage, message) | chat/service, agent run | Yes | Yes | |
|
||||
| meta.route | agent/service | Yes | Yes | |
|
||||
| meta.orchestrator_steps | agent/service | Yes | Yes | |
|
||||
| meta.used_rag | agent/service | Yes | — | Всегда false as is |
|
||||
| quality (persisted) | metrics_persister | Yes | Yes | |
|
||||
| router_plan, execution, retrieval, timings_ms | tests pipeline_intent_rag | — | Yes | Не в API |
|
||||
| constraint_violations | diagnostics.validate_constraints | — | Yes | Только тесты |
|
||||
|
||||
---
|
||||
|
||||
## 8. Docs Support As Is
|
||||
|
||||
### 8.1. Current docs ingestion / parsing
|
||||
|
||||
DocsIndexingPipeline: поддержка файлов по DocsFileFilter; парсинг frontmatter (YAML), MarkdownDocChunker по body; DocsClassifier по path (doc_kind); build_module_catalog (D1), build_section (D3), build_policy для type=policy (D4), _extract_facts из frontmatter links (D2). Результат пишется в те же rag_chunks с layer D1–D4.
|
||||
|
||||
**Evidence.** `app/modules/rag/indexing/docs/pipeline.py`, file_filter, chunkers, document_builder.
|
||||
|
||||
### 8.2. Current docs retrieval
|
||||
|
||||
Retrieval по слоям D1–D4 возможен через RagRepository.retrieve(..., layers=[...]) и используется в общем retrieval_statement_builder (layer_rank_sql). В основном агенте и в direct code explain путь «только docs» не вызывается; IntentRouterV2 в тестах может задавать retrieval_profile "docs", но в приложении этот путь не задействован.
|
||||
|
||||
### 8.3. Existing cross-domain hooks
|
||||
|
||||
Нет явного слоя или индекса Doc-Code Links. В документах есть frontmatter links; код и доки индексируются в одну БД (rag_chunks), общий запрос по слоям может смешивать CODE и DOCS слои, но выделенной логики «связать док с кодом» нет.
|
||||
|
||||
### 8.4. Readiness for docs generation from code
|
||||
|
||||
Сценарий docs_from_analytics и граф docs/generation есть: шаги fetch_source_doc, normalize_document, extract_change_intents, map_to_doc_tree, load_current_docs_context, generate_doc_updates и т.д. Это рассчитано на генерацию/обновление документации из аналитики/контекста, а не напрямую «из кода» в одну команду. База для генерации доков (текущие доки, структура) частично есть; генерация «из кода» опиралась бы на код-контекст, который в основном флоу сейчас не подтягивается через RAG.
|
||||
|
||||
### 8.5. Main limitations
|
||||
|
||||
- Нет отдельного docs-only retrieval path в рантайме основного приложения.
|
||||
- Нет D0 как общего «document chunks» и нет D5 (Reference Graph), D6 (Doc-Code Links).
|
||||
- Различие code vs docs на уровне retrieval_profile и слоёв реализовано в IntentRouterV2 и в БД, но не в цепочке chat → agent → retrieval.
|
||||
|
||||
---
|
||||
|
||||
## 9. Gap Analysis vs Target Architecture
|
||||
|
||||
| Target capability | Current state | Gap | Priority | Notes |
|
||||
|------------------|---------------|-----|----------|--------|
|
||||
| Router: intent + sub-intent + graph_id | domain_id/process_id, сценарий по эвристикам | Нет sub_intent, keyword_hints, path_scope, layers в контракте агента | high | IntentRouterV2 есть, не подключён |
|
||||
| Retrieval в основном флоу | Не вызывается; context_retrieval с пустым rag_items | Подключить вызов RAG по запросу и передавать результат в source_bundle | high | RagService не реализует retrieve |
|
||||
| RagRetriever contract | Не реализован | Либо адаптер над RagRepository/LayeredRetrievalGateway, либо вызов gateway из агента | high | |
|
||||
| Intent-driven context assembly | Только в direct explain и build_code_explain_pack | Сборка контекста по intent/layers в оркестраторе | medium | |
|
||||
| Evidence gate в оркестраторе | Только quality gates по артефактам; evidence_required без RAG | Решение: достаточность evidence после retrieval и при отказе — fallback/деградация | medium | |
|
||||
| Слои C5, C6, D5, D6 | Отсутствуют | C5 Test Mappings, C6 Code Facts; D5 Reference Graph, D6 Doc-Code Links | medium | |
|
||||
| Docs retrieval в рантайме | Слои есть в БД, вызова нет | Отдельный путь или единый retrieval с profile docs | medium | |
|
||||
| Диагностика retrieval и constraints | Только в тестах | Вынести router_plan, execution, retrieval, timings, violations в API или лог-артефакт | low | |
|
||||
| README vs реализация | README описывает rag_session как источник retrieval | В основном флоу rag_session по запросу не используется для ответа | high | Уточнить или менять реализацию |
|
||||
|
||||
---
|
||||
|
||||
## 10. Concrete Evidence Index
|
||||
|
||||
### 10.1. Router
|
||||
|
||||
- `app/modules/agent/engine/router/router_service.py` — RouterService.resolve, persist_context, graph_factory, _fallback, _continue_current, _is_acceptable.
|
||||
- `app/modules/agent/engine/router/intent_classifier.py` — classify_new_intent, from_mode, _deterministic_route, _classify_with_llm, _route_mapping.
|
||||
- `app/modules/agent/engine/router/__init__.py` — build_router_service, регистрация графов в IntentRegistry.
|
||||
- `app/modules/agent/engine/router/schemas.py` — RouteDecision, RouteResolution, RouterContext.
|
||||
- `app/modules/agent/engine/router/intents_registry.yaml` — список допустимых пар (domain_id, process_id) для IntentRegistry.is_valid.
|
||||
|
||||
### 10.2. Retrieval
|
||||
|
||||
- `app/modules/agent/service.py` — rag_ctx = [], task_spec с rag_items/rag_context.
|
||||
- `app/modules/agent/engine/graphs/project_qa_step_graphs.py` — ProjectQaRetrievalGraphFactory._retrieve_context (rag_items=[]), build_source_bundle.
|
||||
- `app/modules/rag/explain/retriever_v2.py` — build_pack, _entrypoints, _seed_symbols, _run_pass, _merge_test_fallback.
|
||||
- `app/modules/rag/explain/layered_gateway.py` — retrieve_layer, retrieve_lexical_code, RagRepository.
|
||||
- `app/modules/rag/persistence/repository.py` — retrieve, retrieve_lexical_code, retrieve_exact_files.
|
||||
- `app/modules/rag/services/rag_service.py` — только index_snapshot/index_changes, нет retrieve.
|
||||
- `app/modules/contracts.py` — RagRetriever (async retrieve).
|
||||
|
||||
### 10.3. Graph orchestration
|
||||
|
||||
- `app/modules/agent/engine/orchestrator/service.py` — OrchestratorService.run, template → compile → validate → engine.run → assemble.
|
||||
- `app/modules/agent/engine/orchestrator/template_registry.py` — ScenarioTemplateRegistry.build, _general, _project_qa, _explain, _review, _docs, _edit, _gherkin.
|
||||
- `app/modules/agent/engine/orchestrator/step_registry.py` — StepRegistry.execute, _execute_graph_step, graph_id, _build_graph_state.
|
||||
- `app/modules/agent/engine/orchestrator/execution_engine.py` — выполнение шагов, quality gates.
|
||||
- `app/modules/agent/engine/graphs/project_qa_step_graphs.py` — все ProjectQa*GraphFactory.
|
||||
|
||||
### 10.4. Diagnostics
|
||||
|
||||
- `app/modules/agent/service.py` — LOGGER.warning (route, orchestrator), AgentResult.meta, _persist_quality_metrics.
|
||||
- `app/modules/chat/service.py` — _publish_progress, task_result event.
|
||||
- `tests/pipeline_intent_rag/helpers/diagnostics.py` — build_router_plan, init_diagnostics, apply_retrieval_report, validate_constraints.
|
||||
|
||||
### 10.5. Docs support
|
||||
|
||||
- `app/modules/rag/indexing/docs/pipeline.py` — DocsIndexingPipeline.index_file, D1–D4.
|
||||
- `app/modules/rag/contracts/enums.py` — RagLayer DOCS_*.
|
||||
- `app/modules/rag/intent_router_v2/router.py` — _resolve_retrieval_profile("docs" для DOCS_QA).
|
||||
|
||||
---
|
||||
|
||||
## 11. Final Conclusion
|
||||
|
||||
### 11.1. Насколько текущая реализация уже соответствует целевой архитектуре?
|
||||
|
||||
Реализация частично соответствует: есть многослойная индексация (CODE C0–C4, DOCS D1–D4), оркестрация по сценариям и подграфам, роутер по домену/процессу с LLM и эвристиками, задел в виде IntentRouterV2 с полным контрактом (intent, retrieval_spec, evidence_policy) и тестовый пайплайн с диагностикой. При этом основной агентский флоу не вызывает RAG при ответе, контракт RagRetriever не реализован, а IntentRouterV2 и его retrieval не интегрированы в приложение. Целевые слои C5, C6, D5, D6 отсутствуют; evidence gate в смысле «достаточность retrieval» есть только в direct code explain.
|
||||
|
||||
### 11.2. Что логичнее делать следующим шагом?
|
||||
|
||||
Имеет смысл **сначала уточнить документацию (README и целевую модель)** под as is, чтобы зафиксировать два режима (direct code explain vs full agent), факт отсутствия вызова RAG в основном флоу и роль IntentRouterV2 как тестового/перспективного контура. Затем **параллельно** задать приоритеты: (1) подключение retrieval к основному флоу (адаптер или вызов LayeredRetrievalGateway по решению роутера) и (2) решение о том, переносить ли в продакшен контракт IntentRouterV2 (intent, retrieval_spec, layers) или расширять текущий RouterService. Делать только доработку реализации без обновления README рискованно — расхождение описания и кода сохранится.
|
||||
|
||||
### 11.3. Какие 3–5 самых важных расхождений между as is и target есть сейчас?
|
||||
|
||||
1. **Retrieval не вызывается в основном флоу** — context_retrieval не использует индекс; rag_context всегда пустой. Приоритет: high.
|
||||
2. **RagRetriever не реализован** — RagService только индексирует; агент не может получить список документов по запросу через контракт. Приоритет: high.
|
||||
3. **IntentRouterV2 не в продакшене** — intent, sub_intent, retrieval_spec, layers, evidence_policy есть только в тестах; в приложении другой роутер и нет слоёвого retrieval. Приоритет: high.
|
||||
4. **README говорит про retrieval из rag_session для ответа** — по факту для ответа в основном режиме rag_session по запросу не используется. Приоритет: high (документация).
|
||||
5. **Нет evidence gate в оркестраторе** после retrieval — проверка «достаточно ли evidence» и деградация при слабом retrieval только в direct code explain. Приоритет: medium.
|
||||
@@ -0,0 +1,323 @@
|
||||
# Концепция документации (Strong MVP, без связи с кодом)
|
||||
|
||||
## 1. Область применения
|
||||
Документ описывает систему работы с документацией как самостоятельный слой.
|
||||
|
||||
Включает:
|
||||
- текущее состояние (as-is)
|
||||
- целевые сценарии использования
|
||||
- целевую модель документации
|
||||
- расширенный frontmatter
|
||||
- базовую структуру документа `frontmatter + Summary + Details`
|
||||
- RAG-слои (без связи с кодом)
|
||||
|
||||
---
|
||||
|
||||
# 2. Текущее состояние (As-Is)
|
||||
|
||||
## 2.1 Источник истины
|
||||
- Документация хранится в Confluence
|
||||
- Основная модель — иерархия страниц
|
||||
- Навигация через дерево страниц
|
||||
|
||||
## 2.2 Структура и связи
|
||||
- Документы не атомарны
|
||||
- Одна страница содержит несколько тем
|
||||
- Используются перекрестные ссылки между страницами
|
||||
|
||||
## 2.3 Ограничения
|
||||
- Нет типизации документов
|
||||
- Нет структурированного metadata-слоя
|
||||
- Связи не формализованы
|
||||
|
||||
---
|
||||
|
||||
# 3. Целевые сценарии использования
|
||||
|
||||
## 3.1 Поиск документации
|
||||
|
||||
Пользователь формулирует запрос, например: "как работает создание заказа".
|
||||
|
||||
Система должна:
|
||||
- найти релевантные документы
|
||||
- отобрать наиболее точные фрагменты
|
||||
- учитывать тип документа, модуль и сущности
|
||||
|
||||
Результат:
|
||||
- короткий список релевантных документов
|
||||
- возможность перейти в детали
|
||||
|
||||
## 3.2 Объяснение (Explain)
|
||||
|
||||
Пользователь хочет понять:
|
||||
- как работает компонент
|
||||
- что делает API
|
||||
- как устроен процесс
|
||||
|
||||
Система должна:
|
||||
- взять summary документа
|
||||
- дополнить его деталями из Details
|
||||
- дать краткое и точное объяснение без лишнего текста
|
||||
|
||||
## 3.3 Поиск по сущности (Entity Lookup)
|
||||
|
||||
Пользователь ищет:
|
||||
- где используется сущность
|
||||
- какие документы с ней связаны
|
||||
|
||||
Система должна:
|
||||
- найти все документы, где упоминается сущность
|
||||
- показать связи между ними
|
||||
|
||||
## 3.4 Навигация по документации
|
||||
|
||||
Пользователь начинает с одного документа и хочет:
|
||||
- понять контекст
|
||||
- перейти к связанным частям
|
||||
|
||||
Система должна:
|
||||
- использовать parent/children
|
||||
- использовать links
|
||||
- строить осмысленный путь по документации
|
||||
|
||||
## 3.5 Генерация документации
|
||||
|
||||
Система создает новый документ:
|
||||
- по шаблону
|
||||
- с корректным frontmatter
|
||||
- с заполненными разделами `Summary` и `Details`
|
||||
|
||||
Результат:
|
||||
- документ сразу пригоден для использования
|
||||
- соответствует структуре системы
|
||||
|
||||
## 3.6 Актуализация документации
|
||||
|
||||
При изменениях документа:
|
||||
- система должна обновить только нужные части
|
||||
- сохранить структуру
|
||||
- обновить frontmatter и Details
|
||||
|
||||
Результат:
|
||||
- документ остается консистентным
|
||||
- не происходит деградации структуры
|
||||
|
||||
## 3.7 Связывание документации
|
||||
|
||||
При создании или обновлении:
|
||||
- система добавляет связи между документами
|
||||
- формирует граф знаний
|
||||
|
||||
Результат:
|
||||
- документы не изолированы
|
||||
- появляется навигация и reasoning
|
||||
|
||||
---
|
||||
|
||||
# 4. Frontmatter (расширенный контракт)
|
||||
|
||||
```yaml
|
||||
id: api.create_order
|
||||
type: api_method
|
||||
name: create_order
|
||||
title: Create order API
|
||||
|
||||
module: orders
|
||||
layer: application
|
||||
|
||||
status: draft
|
||||
updated_at: 2026-03-20
|
||||
|
||||
tags:
|
||||
- orders
|
||||
- api
|
||||
|
||||
entities:
|
||||
- Order
|
||||
- Cart
|
||||
|
||||
parent: orders_api
|
||||
children: []
|
||||
|
||||
links:
|
||||
- type: related_api
|
||||
target: api.get_order
|
||||
```
|
||||
|
||||
## Назначение ключевых полей
|
||||
|
||||
- `id` — стабильный идентификатор документа
|
||||
- `type` — тип документа
|
||||
- `title` — человекочитаемое имя
|
||||
- `module` — модуль или bounded context
|
||||
- `layer` — слой системы
|
||||
- `status` — состояние документа
|
||||
- `updated_at` — дата последнего обновления
|
||||
- `tags` — фильтрация и поиск
|
||||
- `entities` — база для entity lookup
|
||||
- `parent` / `children` — иерархия
|
||||
- `links` — граф связей
|
||||
|
||||
Все сведения о связях, сущностях и навигации должны храниться во frontmatter.
|
||||
В теле документа отдельные разделы для связей, сущностей и навигации не создаются.
|
||||
|
||||
---
|
||||
|
||||
# 5. Структура документа (целевая)
|
||||
|
||||
Каждый документ состоит из двух смысловых слоев:
|
||||
- frontmatter
|
||||
- контент
|
||||
|
||||
Контент документа всегда состоит из двух обязательных разделов:
|
||||
- `# Summary`
|
||||
- `# Details`
|
||||
|
||||
## 5.1 Общие правила структуры
|
||||
|
||||
- `Summary` и `Details` всегда имеют заголовок уровня `#`
|
||||
- других заголовков первого уровня в документе быть не должно
|
||||
- `Summary` остается кратким и пригодным для explain
|
||||
- `Details` заменяет прежние разделы `Context` и `Основное описание`
|
||||
- внутренняя структура `Details` зависит от типа документа
|
||||
|
||||
## 5.2 Summary
|
||||
|
||||
Краткое описание на 3-6 строк.
|
||||
Используется для explain, краткого ответа и быстрого понимания сути документа.
|
||||
|
||||
## 5.3 Details
|
||||
|
||||
Раздел содержит полное содержательное описание документа.
|
||||
Состав подразделов определяется типом документа.
|
||||
|
||||
---
|
||||
|
||||
# 6. Типовая структура Details для API
|
||||
|
||||
Для документов типа `api_method` раздел `# Details` должен содержать следующие подразделы:
|
||||
|
||||
- `## Описание`
|
||||
- `## Сценарий`
|
||||
- `## Функциональные требования`
|
||||
- `## Нефункциональные требования`
|
||||
- `## Контракт`
|
||||
|
||||
## 6.1 Описание
|
||||
|
||||
Короткое описание сути метода:
|
||||
- какую работу он выполняет
|
||||
- для чего предназначен
|
||||
|
||||
## 6.2 Сценарий
|
||||
|
||||
Сценарий описывается в формате технического use case и включает:
|
||||
- название
|
||||
- предусловия
|
||||
- триггер
|
||||
- основной сценарий
|
||||
- альтернативный сценарий
|
||||
- обработку ошибок
|
||||
- постусловие
|
||||
|
||||
Правила для сценария:
|
||||
- сценарий должен быть лаконичным
|
||||
- сценарий должен быть читаемым человеком
|
||||
- в сценарии фиксируется суть шага, а не полная техническая реализация
|
||||
- если условие можно выразить одним предложением, его допустимо оставить в сценарии
|
||||
- если шаг требует детального описания формирования запроса, обработки ответа или внутренней логики, детали выносятся в функциональные требования
|
||||
|
||||
## 6.3 Функциональные требования
|
||||
|
||||
Функциональные требования описываются как последовательность требований внутри одного документа.
|
||||
|
||||
Формат:
|
||||
- `FR-1`
|
||||
- `FR-2`
|
||||
- `FR-3`
|
||||
|
||||
Правила:
|
||||
- идентификаторы локальны для документа
|
||||
- на них нельзя ссылаться извне как на сквозные идентификаторы
|
||||
- каждое требование описывает отдельный обязательный аспект реализации
|
||||
|
||||
## 6.4 Нефункциональные требования
|
||||
|
||||
Нефункциональные требования описываются аналогично функциональным.
|
||||
|
||||
Формат:
|
||||
- `NFR-1`
|
||||
- `NFR-2`
|
||||
- `NFR-3`
|
||||
|
||||
Детальный формат записи может быть уточнен правилами конкретного проекта.
|
||||
|
||||
## 6.5 Контракт
|
||||
|
||||
Контракт должен быть пригоден для последующей сборки OpenAPI-спецификации.
|
||||
|
||||
Контракт описывает:
|
||||
- входные параметры метода API
|
||||
- выходные параметры
|
||||
- структуру сообщения, как правило JSON
|
||||
- обязательность полей
|
||||
- типы полей
|
||||
- ограничения на размер и формат
|
||||
- назначение полей
|
||||
- правила заполнения полей
|
||||
- примеры данных
|
||||
|
||||
---
|
||||
|
||||
# 7. Базовая структура Details для остальных типов документов
|
||||
|
||||
Для всех типов документов, кроме `api_method`, на текущем этапе обязателен минимум:
|
||||
- `# Summary`
|
||||
- `# Details`
|
||||
|
||||
Дополнительные рекомендации по внутренней структуре `Details` для `logic_block`, `architecture_overview`, `domain_entity` и других типов будут заданы отдельно.
|
||||
|
||||
---
|
||||
|
||||
# 8. RAG слои (только документация)
|
||||
|
||||
## D0 — Чанки документов
|
||||
Полный текст + разбиение.
|
||||
|
||||
## D1 — Каталог документов
|
||||
- `id`
|
||||
- `type`
|
||||
- `title`
|
||||
- `module`
|
||||
- `tags`
|
||||
|
||||
## D2 — Индекс фактов
|
||||
Факты, извлеченные из документов.
|
||||
|
||||
## D3 — Каталог сущностей
|
||||
- сущности
|
||||
- документы, где они используются
|
||||
|
||||
## D4 — Индекс сценариев (Workflow)
|
||||
- последовательности действий
|
||||
- пользовательские сценарии
|
||||
|
||||
## D5 — Граф связей
|
||||
- связи между документами
|
||||
|
||||
---
|
||||
|
||||
# 9. Итог
|
||||
|
||||
Система документации:
|
||||
- атомарные документы
|
||||
- строгий frontmatter
|
||||
- единая структура `Summary + Details`
|
||||
- типовые правила для API-документов
|
||||
- разделенные RAG-слои
|
||||
|
||||
Это позволяет:
|
||||
- точно искать
|
||||
- объяснять
|
||||
- строить навигацию
|
||||
- генерировать и обновлять документацию
|
||||
@@ -0,0 +1,267 @@
|
||||
# Iteration 2 — Calibration Harness Report
|
||||
|
||||
## 1. Executive Summary
|
||||
|
||||
This iteration adds **calibration and evaluation infrastructure** for the canonical CODE_QA pipeline. The pipeline remains test-first and is not integrated into the UI or production runtime.
|
||||
|
||||
**Added:**
|
||||
|
||||
- A small **deterministic fixture repository** (`tests/fixtures/code_qa_repo/`) for reproducible tests.
|
||||
- **Golden case format and initial cases** for OPEN_FILE, EXPLAIN, FIND_TESTS, FIND_ENTRYPOINTS, and GENERAL_QA (positive, borderline, negative).
|
||||
- An **evaluation harness** that indexes a repo (fixture or user-provided path), runs golden cases through `CodeQAPipelineRunner` with the **real retrieval adapter** (`RagDbAdapter`), and compares actual vs expected (intent, sub_intent, answer_mode, path_scope, symbol_candidates).
|
||||
- **Diagnostics artifact dumping** per run (Markdown + JSON) under `tests/artifacts/code_qa_eval/<run_id>/`.
|
||||
- A **batch evaluation summary** (Markdown table + failure list) for manual review.
|
||||
- **Two modes:** fixture repo by default; optional `CODE_QA_REPO_PATH` for a local real repository.
|
||||
|
||||
**Now possible:**
|
||||
|
||||
- Run the canonical pipeline end-to-end on the fixture repo with real indexing and retrieval.
|
||||
- Run the same harness against a user-provided repo path (no hardcoded external repo).
|
||||
- Inspect per-case diagnostics and batch summary to tune routing, retrieval, evidence gate, and answer mode.
|
||||
|
||||
**Still manual / out of scope:**
|
||||
|
||||
- Tuning prompts and retrieval heuristics (harness supports observation, not automatic tuning).
|
||||
- UI integration, docs runtime retrieval, production router replacement.
|
||||
- Exact LLM answer matching (we assert routing, retrieval alignment, evidence sufficiency, answer mode only).
|
||||
|
||||
---
|
||||
|
||||
## 2. Fixture Repository
|
||||
|
||||
**Location:** `tests/fixtures/code_qa_repo/`
|
||||
|
||||
**Structure:**
|
||||
|
||||
```
|
||||
tests/fixtures/code_qa_repo/
|
||||
├── app/
|
||||
│ └── main.py # Entrypoint: create_app(), app.run()
|
||||
├── api/
|
||||
│ └── orders.py # Handlers: create_order, get_order; OrderService, OrderRepository
|
||||
├── services/
|
||||
│ └── order_service.py # OrderService: create_order, get_order
|
||||
├── repositories/
|
||||
│ └── order_repository.py # OrderRepository: save, find_by_id
|
||||
├── domain/
|
||||
│ └── order.py # Order: id, product_id, quantity, status
|
||||
├── tests/
|
||||
│ └── test_order_service.py # test_create_order, test_get_order_returns_saved_order
|
||||
└── utils/
|
||||
└── helpers.py # format_order_id
|
||||
```
|
||||
|
||||
**Purpose of each file:**
|
||||
|
||||
| File | Purpose |
|
||||
|------|--------|
|
||||
| `app/main.py` | Single clear entrypoint for FIND_ENTRYPOINTS and “open main” style queries. |
|
||||
| `api/orders.py` | API/handler layer; distinct symbols `create_order`, `get_order`, `create_app`. |
|
||||
| `services/order_service.py` | Service calling repository; symbol `OrderService`. |
|
||||
| `repositories/order_repository.py` | Persistence; symbol `OrderRepository`. |
|
||||
| `domain/order.py` | Domain model; symbol `Order`. |
|
||||
| `tests/test_order_service.py` | Tests tied to production code for FIND_TESTS. |
|
||||
| `utils/helpers.py` | Extra module for bounded GENERAL_QA and path/symbol variety. |
|
||||
|
||||
**Scenarios covered:**
|
||||
|
||||
- **File by path:** `app/main.py`, `api/orders.py` (OPEN_FILE).
|
||||
- **Symbol explanation:** `Order`, `OrderService`, `create_order` (EXPLAIN).
|
||||
- **Import/call relations:** service → repository → domain (EXPLAIN / GENERAL_QA).
|
||||
- **Entrypoint:** `app/main.py` (FIND_ENTRYPOINTS).
|
||||
- **Related tests:** `tests/test_order_service.py` for OrderService/Order (FIND_TESTS).
|
||||
- **Fallback:** “Что делает этот проект?” (GENERAL_QA with bounded context).
|
||||
|
||||
The fixture is small and structured so routing and retrieval expectations are unambiguous for calibration.
|
||||
|
||||
---
|
||||
|
||||
## 3. Real Adapter Integration
|
||||
|
||||
The canonical pipeline runs with the **existing** retrieval/index stack:
|
||||
|
||||
- **Indexing:** `RagSessionIndexer` (in `tests/pipeline_intent_rag/helpers/repo_indexer.py`) uses `RagService` and `LocalRepoFileCollector` to index a directory. The fixture (or `CODE_QA_REPO_PATH`) is indexed once per eval run.
|
||||
- **Retrieval:** `RagDbAdapter` (in `tests/pipeline_intent_rag/helpers/rag_db_adapter.py`) implements the pipeline’s `RetrievalAdapter` protocol: `retrieve_with_plan`, `retrieve_exact_files`, `hydrate_resolved_symbol_sources`, `force_symbol_context_c0`, `consume_retrieval_report`. It uses `RagRepository` and the same layer logic as the rest of the project.
|
||||
- **Pipeline:** `CodeQAPipelineRunner` (in `app/modules/rag/code_qa_pipeline/pipeline.py`) takes `IntentRouterV2` and this adapter, builds `RetrievalRequest` from the router, runs retrieval, builds `EvidenceBundle`, runs the evidence gate, and produces diagnostics.
|
||||
|
||||
**Fixture repo:** The harness indexes `tests/fixtures/code_qa_repo` by default and runs all golden cases against that index. No external repo is required.
|
||||
|
||||
**User-provided repo:** Set `CODE_QA_REPO_PATH` to a local directory. The harness indexes that path and runs the same golden cases (or the user can add repo-specific cases). Optional `CODE_QA_PROJECT_ID` sets the project id for the session. The codebase does **not** depend on any private or external repo being present.
|
||||
|
||||
---
|
||||
|
||||
## 4. Golden Case Format
|
||||
|
||||
**Location:** `tests/golden/code_qa/`
|
||||
**File:** `cases.yaml`
|
||||
|
||||
**Fields per case:**
|
||||
|
||||
| Field | Meaning |
|
||||
|-------|--------|
|
||||
| `id` | Unique case id. |
|
||||
| `query` | User query text. |
|
||||
| `expected_intent` | Expected top-level intent (e.g. CODE_QA). |
|
||||
| `expected_sub_intent` | OPEN_FILE \| EXPLAIN \| FIND_TESTS \| FIND_ENTRYPOINTS \| GENERAL_QA. |
|
||||
| `expected_answer_mode` | normal \| degraded \| insufficient. |
|
||||
| `expected_target_hint` | Optional: path, symbol, or test-like. |
|
||||
| `expected_path_scope_contains` | Optional list of substrings that must appear in path_scope. |
|
||||
| `expected_symbol_candidates_contain` | Optional list of symbols that must appear in symbol_candidates. |
|
||||
| `expected_layers` | Optional list of layer ids expected in the retrieval plan. |
|
||||
| `notes` | Optional: borderline, negative, or calibration hint. |
|
||||
|
||||
**Expected results:** We assert routing (intent, sub_intent), retrieval alignment (path_scope, symbol_candidates, layers when specified), evidence sufficiency (via answer_mode), and diagnostics shape. We do **not** assert exact LLM wording.
|
||||
|
||||
**Not asserted (yet):** Exact chunk content, relation counts, or full evidence bundle structure beyond what drives answer_mode and target hints.
|
||||
|
||||
---
|
||||
|
||||
## 5. Golden Runner / Evaluation Harness
|
||||
|
||||
**Entrypoints:**
|
||||
|
||||
- **Programmatic:** `tests.code_qa_eval.runner.run_eval(config)` — runs all golden cases and returns `list[EvalCaseResult]`.
|
||||
- **CLI:** `python -m tests.code_qa_eval.run` (from project root) — loads config, runs eval, writes artifacts and summary, exits 0 only if all pass.
|
||||
|
||||
**Fixture mode (default):**
|
||||
|
||||
1. Do not set `CODE_QA_REPO_PATH`.
|
||||
2. Run: `python -m tests.code_qa_eval.run` (or call `run_eval(EvalConfig.from_env())`).
|
||||
3. Repo used: `tests/fixtures/code_qa_repo`. It is indexed once; then each golden case is run through the pipeline and compared to expected.
|
||||
|
||||
**User-provided repo:**
|
||||
|
||||
1. Set `CODE_QA_REPO_PATH` to the repository root (e.g. `export CODE_QA_REPO_PATH=/path/to/your/repo`).
|
||||
2. Optionally set `CODE_QA_PROJECT_ID`.
|
||||
3. Run the same command. The harness indexes that path and runs the same golden cases (or you can point to a different `cases.yaml` by changing `EvalConfig.golden_cases_path` in code).
|
||||
|
||||
**Outputs:**
|
||||
|
||||
- **Per case:** under `tests/artifacts/code_qa_eval/<run_id>/`: `<case_id>.md` and `<case_id>.json` (query, expected/actual, router, retrieval, evidence gate, timings, mismatches).
|
||||
- **Batch:** `tests/artifacts/code_qa_eval/summary_<run_id>.md` — table (case id, query, expected/actual scenario, target, evidence, answer mode, pass/fail) and a failure list.
|
||||
- **Exit code:** 0 if all cases pass, 1 otherwise; failures are printed to stderr.
|
||||
|
||||
---
|
||||
|
||||
## 6. Diagnostics Artifacts
|
||||
|
||||
**Generated artifacts:**
|
||||
|
||||
- **Per run (per case):** `<run_id>/<case_id>.md` and `<case_id>.json`.
|
||||
- **Batch:** `summary_<run_id>.md` in `tests/artifacts/code_qa_eval/`.
|
||||
|
||||
**Location:** `tests/artifacts/code_qa_eval/` (created if missing).
|
||||
|
||||
**Markdown (per case) contains:**
|
||||
|
||||
- Query, expected (intent, sub_intent, answer_mode), actual (intent, sub_intent, answer_mode, evidence_gate_passed, evidence_count).
|
||||
- Pass/fail and list of mismatches.
|
||||
- Router: path_scope, layers.
|
||||
- Retrieval: requested_layers, chunk_count, layer_outcomes.
|
||||
- Evidence gate: failure_reasons.
|
||||
- Timings (ms).
|
||||
|
||||
**JSON (per case)** adds machine-readable detail: full expected/actual, passed, mismatches, router_result, retrieval_request, per_layer_outcome, failure_reasons, timings_ms.
|
||||
|
||||
**Useful for calibration:**
|
||||
|
||||
- **Router:** path_scope and layers — confirm OPEN_FILE vs EXPLAIN vs FIND_* routing and plan.
|
||||
- **Retrieval:** layer_outcomes and chunk_count — see which layers returned hits.
|
||||
- **Evidence gate:** failure_reasons and evidence_count — see why answer_mode is degraded/insufficient.
|
||||
- **Mismatches:** quick list of what to fix (routing vs retrieval vs gate).
|
||||
|
||||
**Example snippet (Markdown):**
|
||||
|
||||
```markdown
|
||||
# open_file_main_positive
|
||||
|
||||
## Query
|
||||
Открой файл app/main.py
|
||||
|
||||
## Expected
|
||||
- intent: CODE_QA, sub_intent: OPEN_FILE
|
||||
- answer_mode: normal
|
||||
|
||||
## Actual
|
||||
- intent: CODE_QA, sub_intent: OPEN_FILE
|
||||
- answer_mode: normal
|
||||
- evidence_gate_passed: True
|
||||
- evidence_count: 2
|
||||
|
||||
## Result
|
||||
PASS
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Tests Added
|
||||
|
||||
| File | What it validates |
|
||||
|------|-------------------|
|
||||
| `tests/code_qa_eval/test_eval_harness.py` | Golden loader, compare logic, config, fixture-mode run structure. |
|
||||
|
||||
**Test groups:**
|
||||
|
||||
- **Golden loader:** `test_load_golden_cases_returns_list` — loads `cases.yaml`, checks count and field presence (id, query, expected_intent, expected_sub_intent, expected_answer_mode).
|
||||
- **Compare logic:** `test_compare_passed_when_all_match`, `test_compare_fails_on_intent_mismatch`, `test_compare_fails_on_answer_mode_mismatch`, `test_compare_path_scope_contains` — assert pass/fail and mismatch messages for intent, sub_intent, answer_mode, path_scope.
|
||||
- **Config:** `test_eval_config_fixture_mode_by_default` — default config uses fixture path, golden path, and artifacts dir under `tests/`.
|
||||
- **Fixture-mode run:** `test_run_eval_fixture_mode_structure` — runs `run_eval(config)` with fixture config; asserts result list and that each item is `EvalCaseResult` with case, pipeline_result, passed, mismatches. **Skips** if DB or dependencies (e.g. sqlalchemy) are unavailable.
|
||||
|
||||
**Modes:** Loader and compare tests are unit (no DB). Config test uses paths only. Fixture-mode test is integration-style with real adapter and DB; it is skipped when the environment cannot connect or import.
|
||||
|
||||
---
|
||||
|
||||
## 8. Known Limitations
|
||||
|
||||
- **LLM answer:** The harness does not call the LLM; `answer_mode` is derived from the evidence gate only. No assertion on final answer text.
|
||||
- **Routing stability:** Golden expectations (especially borderline/negative) may need manual adjustment as the router or retrieval changes.
|
||||
- **Real DB required:** Full eval (index + retrieve) needs a configured DB; otherwise the integration test and CLI run skip or fail. No in-memory SQLite path is implemented in this iteration.
|
||||
- **Single session per run:** Each run indexes the repo once and reuses one RAG session for all cases. Cross-session or re-index behaviour is not exercised.
|
||||
- **Docs / cross-domain:** Golden cases and harness are CODE_QA only; docs retrieval and cross-domain flows are out of scope.
|
||||
- **Performance:** No timings or regression assertions; artifacts are for manual inspection and tuning.
|
||||
|
||||
---
|
||||
|
||||
## 9. How to Use for Manual Calibration
|
||||
|
||||
1. **Run fixture evaluation**
|
||||
From project root: `python -m tests.code_qa_eval.run`. Check exit code and console output (pass/fail counts and failure lines).
|
||||
|
||||
2. **Inspect diagnostics**
|
||||
Open `tests/artifacts/code_qa_eval/<run_id>/*.md` for failing (or borderline) cases. Use router (path_scope, layers), retrieval (layer_outcomes, chunk_count), and evidence gate (failure_reasons) to see why a case failed.
|
||||
|
||||
3. **Run against a real local repo**
|
||||
Set `CODE_QA_REPO_PATH=/path/to/repo`, then run the same command. Compare behaviour to the fixture run.
|
||||
|
||||
4. **Compare mismatches**
|
||||
Use the batch summary and per-case mismatches to decide what to tune: intent/sub_intent (router/prompts), path_scope/symbol_candidates (router or retrieval), or evidence thresholds (evidence gate).
|
||||
|
||||
5. **Adjust and re-run**
|
||||
Update router, retrieval, or evidence policy; add/edit golden cases if needed; re-run the harness and confirm improvements in the summary and artifacts.
|
||||
|
||||
---
|
||||
|
||||
## 10. Changed Files Index
|
||||
|
||||
| File | Purpose |
|
||||
|------|--------|
|
||||
| `tests/fixtures/code_qa_repo/app/main.py` | Fixture entrypoint. |
|
||||
| `tests/fixtures/code_qa_repo/api/orders.py` | Fixture API handlers. |
|
||||
| `tests/fixtures/code_qa_repo/services/order_service.py` | Fixture service layer. |
|
||||
| `tests/fixtures/code_qa_repo/repositories/order_repository.py` | Fixture repository. |
|
||||
| `tests/fixtures/code_qa_repo/domain/order.py` | Fixture domain model. |
|
||||
| `tests/fixtures/code_qa_repo/tests/test_order_service.py` | Fixture tests. |
|
||||
| `tests/fixtures/code_qa_repo/utils/helpers.py` | Fixture utility. |
|
||||
| `tests/golden/code_qa/README.md` | Golden case format description. |
|
||||
| `tests/golden/code_qa/cases.yaml` | Golden cases for all MVP scenarios. |
|
||||
| `tests/code_qa_eval/__init__.py` | Package init. |
|
||||
| `tests/code_qa_eval/config.py` | EvalConfig: repo path (fixture vs CODE_QA_REPO_PATH), artifacts dir, golden path. |
|
||||
| `tests/code_qa_eval/golden_loader.py` | Load and parse golden cases from YAML. |
|
||||
| `tests/code_qa_eval/runner.py` | run_eval: index repo, run pipeline, compare to golden; _compare logic. |
|
||||
| `tests/code_qa_eval/artifacts.py` | dump_run_artifact (md+json), write_batch_summary. |
|
||||
| `tests/code_qa_eval/run.py` | CLI entrypoint: load config, run eval, write artifacts and summary. |
|
||||
| `tests/code_qa_eval/test_eval_harness.py` | Tests for loader, compare, config, fixture-mode run. |
|
||||
| `pytest.ini` | Added marker `code_qa_eval`. |
|
||||
| `iteration2_calibration_harness_report.md` | This report. |
|
||||
|
||||
No changes were made to production router, UI, or docs retrieval. The canonical pipeline and existing retrieval/index stack are reused; the harness is test-side only.
|
||||
@@ -0,0 +1,546 @@
|
||||
# Текущая архитектура тестового пайплайна `pipeline_setup_v3`
|
||||
|
||||
Документ предназначен как краткое, но точное описание текущего устройства `pipeline_setup_v3` для внешней модели вроде ChatGPT.
|
||||
|
||||
Важно: текущий `pipeline_setup_v3` уже использует реальные runtime-компоненты агента, но по сути остается в первую очередь `code-first` пайплайном. Это особенно заметно в `evidence gate` и в наборе prompt'ов для LLM.
|
||||
|
||||
## 1. Общая схема пайплайна
|
||||
|
||||
`pipeline_setup_v3` запускает один из трех режимов:
|
||||
|
||||
- `router_only`
|
||||
- `router_rag`
|
||||
- `full_chain`
|
||||
|
||||
Во всех режимах используется `AgentRuntimeAdapter`, который является тестовым адаптером поверх реальных компонентов рантайма.
|
||||
|
||||
Общий поток для `full_chain`:
|
||||
|
||||
1. Пользовательский запрос
|
||||
2. `IntentRouterV2`
|
||||
3. Построение `RetrievalRequest`
|
||||
4. `RuntimeRetrievalAdapter`
|
||||
5. Построение нормализованного `RetrievalResult`
|
||||
6. Сборка `EvidenceBundle`
|
||||
7. `pre-evidence gate`
|
||||
8. `RuntimeAnswerPolicy`
|
||||
9. Вызов LLM через `AgentLlmService`
|
||||
10. `post-evidence gate`
|
||||
11. При необходимости `repair`
|
||||
12. Сборка итогового результата, диагностики и артефактов теста
|
||||
|
||||
Ключевая идея: `pipeline_setup_v3` не эмулирует локальный тестовый сценарий вручную, а прогоняет реальные компоненты: роутер, retrieval, runtime executor и LLM.
|
||||
|
||||
## 2. Из каких компонентов состоит `pipeline_setup_v3`
|
||||
|
||||
### 2.1. Harness уровня тестов
|
||||
|
||||
Основные части:
|
||||
|
||||
- `tests/pipeline_setup_v3/run.py` — CLI-вход для запуска набора кейсов
|
||||
- `tests/pipeline_setup_v3/core/runner.py` — оркестратор прогона кейсов
|
||||
- `tests/pipeline_setup_v3/core/case_loader.py` — загрузка YAML-кейсов
|
||||
- `tests/pipeline_setup_v3/core/validators.py` — проверка ожиданий
|
||||
- `tests/pipeline_setup_v3/core/artifacts.py` — запись JSON/Markdown-результатов
|
||||
- `tests/pipeline_setup_v3/runtime/agent_runtime_adapter.py` — мост к runtime-компонентам приложения
|
||||
|
||||
### 2.2. Runtime-компоненты, которые реально вызываются
|
||||
|
||||
- `IntentRouterV2`
|
||||
- `RuntimeRepoContextFactory`
|
||||
- `RuntimeRetrievalAdapter`
|
||||
- `AgentRuntimeExecutor`
|
||||
- `AgentLlmService`
|
||||
- `PromptLoader`
|
||||
|
||||
### 2.3. Два варианта исполнения
|
||||
|
||||
#### `router_only`
|
||||
|
||||
Проверяет только результат роутера:
|
||||
|
||||
- `intent`
|
||||
- `sub_intent`
|
||||
- `graph_id`
|
||||
- `conversation_mode`
|
||||
|
||||
RAG и LLM не вызываются.
|
||||
|
||||
#### `router_rag`
|
||||
|
||||
Проверяет:
|
||||
|
||||
- роутер
|
||||
- retrieval plan
|
||||
- реальный retrieval
|
||||
- нормализованный `RetrievalResult`
|
||||
|
||||
LLM не вызывается.
|
||||
|
||||
#### `full_chain`
|
||||
|
||||
Проверяет полный runtime-контур:
|
||||
|
||||
- роутер
|
||||
- retrieval
|
||||
- evidence bundle
|
||||
- pre-gate
|
||||
- answer policy
|
||||
- LLM
|
||||
- post-gate
|
||||
- repair
|
||||
- итоговый answer/diagnostics
|
||||
|
||||
## 3. Компонент: Intent Router
|
||||
|
||||
### 3.1. Что это такое
|
||||
|
||||
`IntentRouterV2` классифицирует запрос и возвращает структурированный план для retrieval и дальнейшего рантайма.
|
||||
|
||||
Он не просто выбирает `intent`, а сразу строит:
|
||||
|
||||
- `conversation_mode`
|
||||
- `query_plan`
|
||||
- `retrieval_spec`
|
||||
- `retrieval_constraints`
|
||||
- `symbol_resolution`
|
||||
- `evidence_policy`
|
||||
- `graph_id`
|
||||
|
||||
### 3.2. Какие интенты есть сейчас
|
||||
|
||||
Сейчас в коде поддерживаются:
|
||||
|
||||
- `CODE_QA`
|
||||
- `DOCUMENTATION_EXPLAIN`
|
||||
- `GENERATE_DOCS_FROM_CODE`
|
||||
- `FALLBACK`
|
||||
|
||||
### 3.3. Какие саб-интенты есть сейчас
|
||||
|
||||
#### Для `CODE_QA`
|
||||
|
||||
- `OPEN_FILE`
|
||||
- `EXPLAIN`
|
||||
- `EXPLAIN_LOCAL`
|
||||
- `FIND_TESTS`
|
||||
- `FIND_ENTRYPOINTS`
|
||||
- `TRACE_FLOW`
|
||||
- `ARCHITECTURE`
|
||||
- `NEXT_STEPS` может появляться как follow-up режим на уровне query planning
|
||||
|
||||
#### Для `DOCUMENTATION_EXPLAIN`
|
||||
|
||||
- `SYSTEM_FLOW_EXPLAIN`
|
||||
- `COMPONENT_EXPLAIN`
|
||||
- `API_METHOD_EXPLAIN`
|
||||
- `ENTITY_EXPLAIN`
|
||||
|
||||
#### Для `FALLBACK`
|
||||
|
||||
- `GENERIC_FALLBACK`
|
||||
|
||||
### 3.4. Что роутер возвращает на выходе
|
||||
|
||||
Результат роутера — это `IntentRouterResult`.
|
||||
|
||||
Ключевые поля:
|
||||
|
||||
- `intent`
|
||||
- `retrieval_profile`
|
||||
- `graph_id`
|
||||
- `conversation_mode`
|
||||
- `query_plan`
|
||||
- `retrieval_spec`
|
||||
- `retrieval_constraints`
|
||||
- `symbol_resolution`
|
||||
- `evidence_policy`
|
||||
|
||||
### 3.5. Что входит в `query_plan`
|
||||
|
||||
`query_plan` содержит:
|
||||
|
||||
- `raw`
|
||||
- `normalized`
|
||||
- `sub_intent`
|
||||
- `negations`
|
||||
- `expansions`
|
||||
- `keyword_hints`
|
||||
- `path_hints`
|
||||
- `doc_scope_hints`
|
||||
- `symbol_candidates`
|
||||
- `symbol_kind_hint`
|
||||
- `anchors`
|
||||
|
||||
Это основной bridge между классификацией запроса и retrieval.
|
||||
|
||||
### 3.6. Что входит в `retrieval_spec`
|
||||
|
||||
`retrieval_spec` содержит:
|
||||
|
||||
- `domains`
|
||||
- `layer_queries`
|
||||
- `filters`
|
||||
- `rerank_profile`
|
||||
|
||||
Именно этот объект задает, какие слои RAG должны быть запрошены.
|
||||
|
||||
### 3.7. Что важно про текущее состояние
|
||||
|
||||
Текущий роутер уже умеет выделять docs-интенты и docs-сабинтенты, но downstream runtime ниже по пайплайну все еще во многом оптимизирован под `CODE_QA`.
|
||||
|
||||
Это означает:
|
||||
|
||||
- docs routing уже есть
|
||||
- docs layer selection уже есть
|
||||
- но `pre/post evidence gate` и prompt selection пока ориентированы в первую очередь на code sub-intents
|
||||
|
||||
## 4. Структура RAG
|
||||
|
||||
### 4.1. Общая идея
|
||||
|
||||
RAG устроен как многослойный индекс. Retrieval работает не по одному единственному типу чанков, а по наборам специализированных слоев.
|
||||
|
||||
### 4.2. Code-слои
|
||||
|
||||
- `C0_SOURCE_CHUNKS` — сырой код / чанки исходников
|
||||
- `C1_SYMBOL_CATALOG` — каталог символов
|
||||
- `C2_DEPENDENCY_GRAPH` — зависимости и связи
|
||||
- `C3_ENTRYPOINTS` — точки входа, маршруты, handler'ы
|
||||
- `C4_SEMANTIC_ROLES` — семантические роли и behavioral hints
|
||||
|
||||
### 4.3. Docs-слои
|
||||
|
||||
- `D0_DOC_CHUNKS` — чанки документов
|
||||
- `D1_DOCUMENT_CATALOG` — каталог документов
|
||||
- `D2_FACT_INDEX` — атомарные факты
|
||||
- `D3_ENTITY_CATALOG` — сущности
|
||||
- `D4_WORKFLOW_INDEX` — сценарии и workflow
|
||||
- `D5_RELATION_GRAPH` — связи между документами
|
||||
|
||||
### 4.4. Как retrieval связывается с роутером
|
||||
|
||||
Роутер возвращает:
|
||||
|
||||
- `domains`
|
||||
- `layer_queries`
|
||||
- `filters`
|
||||
- `retrieval_constraints`
|
||||
|
||||
Дальше `build_retrieval_request(...)` превращает это в `RetrievalRequest`, который содержит:
|
||||
|
||||
- `rag_session_id`
|
||||
- `query`
|
||||
- `sub_intent`
|
||||
- `path_scope`
|
||||
- `keyword_hints`
|
||||
- `symbol_candidates`
|
||||
- `requested_layers`
|
||||
- `retrieval_spec`
|
||||
- `retrieval_constraints`
|
||||
- `query_plan`
|
||||
|
||||
### 4.5. Что возвращает retrieval
|
||||
|
||||
Сырые строки RAG затем нормализуются в `RetrievalResult`, который содержит:
|
||||
|
||||
- `target_symbol_candidates`
|
||||
- `resolved_symbol`
|
||||
- `symbol_resolution_status`
|
||||
- `file_candidates`
|
||||
- `code_chunks`
|
||||
- `relations`
|
||||
- `semantic_hints`
|
||||
- `entrypoints`
|
||||
- `test_candidates`
|
||||
- `layer_outcomes`
|
||||
- `missing_layers`
|
||||
- `raw_rows`
|
||||
- `retrieval_report`
|
||||
|
||||
### 4.6. Как из retrieval строится evidence
|
||||
|
||||
`build_evidence_bundle(...)` собирает `EvidenceBundle`.
|
||||
|
||||
Ключевые поля:
|
||||
|
||||
- `resolved_intent`
|
||||
- `resolved_sub_intent`
|
||||
- `resolved_target`
|
||||
- `target_type`
|
||||
- `target_symbol_candidates`
|
||||
- `file_candidates`
|
||||
- `code_chunks`
|
||||
- `relations`
|
||||
- `entrypoints`
|
||||
- `test_evidence`
|
||||
- `evidence_count`
|
||||
- `sufficient`
|
||||
- `failure_reasons`
|
||||
- `retrieval_summary`
|
||||
|
||||
Важно: `evidence_count` сейчас считается по количеству `code_chunks`. Это еще одно подтверждение, что runtime сегодня code-first.
|
||||
|
||||
## 5. Evidence Gate
|
||||
|
||||
В пайплайне есть два gate'а.
|
||||
|
||||
## 5.1. Pre-evidence gate
|
||||
|
||||
Расположение:
|
||||
|
||||
- `src/app/modules/agent/runtime/steps/gates/pre/evidence_gate.py`
|
||||
|
||||
Когда срабатывает:
|
||||
|
||||
- после retrieval
|
||||
- после сборки `EvidenceBundle`
|
||||
- до вызова LLM
|
||||
|
||||
Задача:
|
||||
|
||||
- понять, достаточно ли evidence для уверенного ответа
|
||||
- выдать `passed/failure_reasons/degraded_message`
|
||||
|
||||
Как работает сейчас:
|
||||
|
||||
- для `OPEN_FILE` требует найденный path/file и хотя бы один `C0` chunk
|
||||
- для `EXPLAIN` требует target symbol и минимум 2 evidence chunk'а
|
||||
- для `FIND_TESTS` требует target и хотя бы один test candidate
|
||||
- для `FIND_ENTRYPOINTS` требует хотя бы один entrypoint
|
||||
- для остальных сценариев требует минимум 1 evidence
|
||||
|
||||
Что возвращает:
|
||||
|
||||
- `passed`
|
||||
- `failure_reasons`
|
||||
- `degraded_message`
|
||||
|
||||
Ограничение:
|
||||
|
||||
- логика pre-gate пока написана в терминах code sub-intents
|
||||
- docs-сценарии там явно не моделированы
|
||||
|
||||
## 5.2. Post-evidence gate
|
||||
|
||||
Расположение:
|
||||
|
||||
- `src/app/modules/agent/runtime/steps/gates/post/post_gate.py`
|
||||
|
||||
Когда срабатывает:
|
||||
|
||||
- после генерации draft answer
|
||||
- до возврата финального ответа
|
||||
|
||||
Задача:
|
||||
|
||||
- проверить groundedness черновика
|
||||
- убедиться, что ответ действительно опирается на evidence
|
||||
- решить, нужен ли `repair`
|
||||
|
||||
Что проверяет:
|
||||
|
||||
- что ответ не пустой
|
||||
- что degraded/not_found/ambiguous-ответы содержат обязательные guardrail-фразы
|
||||
- что normal answer не слишком общий
|
||||
- что упоминаются обязательные факты из curated evidence
|
||||
- что нет явной semantic leakage или contradictions
|
||||
|
||||
Отдельные проверки есть для:
|
||||
|
||||
- `FIND_ENTRYPOINTS`
|
||||
- `EXPLAIN`
|
||||
- `ARCHITECTURE`
|
||||
- `TRACE_FLOW`
|
||||
|
||||
Если gate не проходит, он возвращает:
|
||||
|
||||
- `passed=False`
|
||||
- `action="repair"`
|
||||
- список `reasons`
|
||||
|
||||
После этого runtime может сделать дополнительный шаг `repair` через LLM.
|
||||
|
||||
Ограничение:
|
||||
|
||||
- post-gate тоже пока ориентирован на code-oriented sub-intents
|
||||
- docs-сабинтенты для него еще не описаны отдельными правилами
|
||||
|
||||
## 6. Обращение к LLM
|
||||
|
||||
### 6.1. Где вызывается LLM
|
||||
|
||||
В `pipeline_setup_v3` есть два места использования LLM:
|
||||
|
||||
1. В классификации интента внутри `IntentClassifierV2`
|
||||
2. В финальной генерации ответа внутри `AgentRuntimeExecutor`
|
||||
|
||||
### 6.2. Prompt для классификации интента
|
||||
|
||||
Используется prompt:
|
||||
|
||||
- `rag_intent_router_v2`
|
||||
|
||||
Назначение:
|
||||
|
||||
- если deterministic rules не дали результата, LLM выбирает интент
|
||||
|
||||
Текущий prompt исторически описывает старые имена интентов, поэтому его еще нужно синхронизировать с новым docs/fallback контрактом.
|
||||
|
||||
### 6.3. Prompt'ы для генерации ответа
|
||||
|
||||
Prompt selector сейчас выбирает:
|
||||
|
||||
- `code_qa_architecture_answer`
|
||||
- `code_qa_explain_answer`
|
||||
- `code_qa_explain_local_answer`
|
||||
- `code_qa_find_entrypoints_answer`
|
||||
- `code_qa_find_tests_answer`
|
||||
- `code_qa_general_answer`
|
||||
- `code_qa_open_file_answer`
|
||||
- `code_qa_trace_flow_answer`
|
||||
- `code_qa_degraded_answer`
|
||||
|
||||
Дополнительно для repair используется:
|
||||
|
||||
- `code_qa_repair_answer`
|
||||
|
||||
### 6.4. Как строится payload для LLM
|
||||
|
||||
Перед вызовом LLM runtime собирает:
|
||||
|
||||
- `AnswerSynthesisInput`
|
||||
- `EvidenceBundle`
|
||||
- `prompt_payload`
|
||||
|
||||
В payload передаются:
|
||||
|
||||
- `user_question`
|
||||
- `resolved_target`
|
||||
- `answer_mode`
|
||||
- `evidence_summary`
|
||||
- `retrieval_summary`
|
||||
- curated facts
|
||||
- обязательные для упоминания сущности, методы, связи, шаги и т.д.
|
||||
|
||||
То есть LLM не получает просто "вопрос и куски текста", а получает уже структурированный grounded payload.
|
||||
|
||||
### 6.5. Что важно про текущее состояние prompt'ов
|
||||
|
||||
Сейчас runtime prompt selection и prompt contracts явно заточены под code QA.
|
||||
|
||||
Это значит:
|
||||
|
||||
- для `CODE_QA` full chain оформлен хорошо
|
||||
- для `DOCUMENTATION_EXPLAIN` routing и retrieval есть, но отдельного docs answer-prompt слоя пока нет
|
||||
- для docs full-chain пока не хватает собственных prompt names, prompt payload contract и post-gate правил
|
||||
|
||||
## 7. Что именно сейчас проверяет `pipeline_setup_v3`
|
||||
|
||||
YAML-кейс может проверять четыре группы ожиданий:
|
||||
|
||||
- `router`
|
||||
- `retrieval`
|
||||
- `llm`
|
||||
- `pipeline`
|
||||
|
||||
Примеры ожиданий:
|
||||
|
||||
- ожидаемый `intent`
|
||||
- ожидаемый `sub_intent`
|
||||
- нужные слои в `layers_include`
|
||||
- что retrieval не пустой
|
||||
- что в answer есть нужные фразы
|
||||
- какой `answer_mode` получился
|
||||
|
||||
## 8. Ключевые выводы о текущей архитектуре
|
||||
|
||||
### 8.1. Что уже сделано хорошо
|
||||
|
||||
- `pipeline_setup_v3` работает поверх реальных runtime-компонентов
|
||||
- есть явный контракт между router → retrieval → evidence → answer
|
||||
- есть два evidence gate
|
||||
- есть structured diagnostics
|
||||
- есть нормализованные типы `RetrievalRequest`, `RetrievalResult`, `EvidenceBundle`
|
||||
|
||||
### 8.2. Что остается code-first
|
||||
|
||||
- pre-evidence gate
|
||||
- post-evidence gate
|
||||
- prompt selector
|
||||
- набор answer prompts
|
||||
- часть логики нормализации evidence
|
||||
|
||||
### 8.3. Что это значит для docs use case
|
||||
|
||||
Сейчас docs use case уже частично внедрен:
|
||||
|
||||
- есть docs intent
|
||||
- есть docs sub-intents
|
||||
- есть docs layer mapping
|
||||
- есть docs retrieval profile
|
||||
|
||||
Но для полноценного `full_chain` по документации еще не хватает:
|
||||
|
||||
- docs-oriented pre-gate правил
|
||||
- docs-oriented post-gate правил
|
||||
- docs-specific answer prompts
|
||||
- docs-specific synthesis contract
|
||||
- отдельных full-chain test cases для `DOCUMENTATION_EXPLAIN` и `FALLBACK`
|
||||
|
||||
## 9. Краткое резюме по компонентам
|
||||
|
||||
### Intent Router
|
||||
|
||||
Назначение:
|
||||
|
||||
- классифицировать запрос
|
||||
- построить retrieval plan
|
||||
- задать evidence policy
|
||||
|
||||
Выход:
|
||||
|
||||
- `IntentRouterResult`
|
||||
|
||||
### RAG
|
||||
|
||||
Назначение:
|
||||
|
||||
- вернуть evidence из многослойного индекса
|
||||
|
||||
Выход:
|
||||
|
||||
- `RetrievalResult`
|
||||
- затем `EvidenceBundle`
|
||||
|
||||
### Pre-evidence gate
|
||||
|
||||
Назначение:
|
||||
|
||||
- решить, можно ли вообще уверенно отвечать
|
||||
|
||||
Выход:
|
||||
|
||||
- `passed/failure_reasons/degraded_message`
|
||||
|
||||
### Post-evidence gate
|
||||
|
||||
Назначение:
|
||||
|
||||
- проверить, grounded ли уже сгенерированный ответ
|
||||
|
||||
Выход:
|
||||
|
||||
- `return` или `repair`
|
||||
|
||||
### LLM
|
||||
|
||||
Назначение:
|
||||
|
||||
- классификация сложных интентов
|
||||
- генерация финального ответа
|
||||
- repair ответа при провале post-gate
|
||||
|
||||
Текущий фокус:
|
||||
|
||||
- в первую очередь `CODE_QA`
|
||||
@@ -0,0 +1,323 @@
|
||||
# 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 <uuid>
|
||||
python3 -m tests.pipeline_intent_rag run --mode full_chain --rag-session-id <uuid>
|
||||
```
|
||||
|
||||
Источник: `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 <uuid> --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`), имя файла `<test_name>_<YYYYMMDD_HHMMSS>.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/`.
|
||||
Reference in New Issue
Block a user