Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 88987abaa6 | |||
| 02eaab6bce | |||
| eab98ca388 | |||
| 6ccfe54e92 | |||
| 8fb76bb331 | |||
| bc29d51a29 | |||
| 6b74d410cd | |||
| 5d77ab1a88 | |||
| 0bff171936 |
@@ -0,0 +1,14 @@
|
||||
# Analysis Assets
|
||||
|
||||
Этот каталог содержит служебные артефакты для аналитической и генеративной работы агента.
|
||||
|
||||
## Структура
|
||||
|
||||
- `rules/` — правила построения документации, frontmatter и шаблоны документов.
|
||||
|
||||
## Назначение
|
||||
|
||||
Каталог `.analysis/` отделен от `docs/`, чтобы:
|
||||
- хранить служебные policy- и template-материалы вне пользовательской документации;
|
||||
- передавать правила в LLM как отдельный policy-context;
|
||||
- не смешивать документацию проекта и внутренние артефакты анализа.
|
||||
@@ -0,0 +1,32 @@
|
||||
# Documentation Rules
|
||||
|
||||
## Назначение
|
||||
|
||||
Этот файл фиксирует общие правила формирования, обновления и поддержки технической документации проекта.
|
||||
|
||||
Документация проекта должна создаваться как система атомарных, связанных между собой документов, пригодных:
|
||||
- для чтения человеком;
|
||||
- для сопровождения командой;
|
||||
- для индексирования в RAG;
|
||||
- для автоматического обновления агентом на основе кода и существующих артефактов.
|
||||
|
||||
Этот файл задает:
|
||||
- общие принципы документационной архитектуры;
|
||||
- правила декомпозиции документации;
|
||||
- правила размещения файлов;
|
||||
- требования к связям между документами;
|
||||
- требования к качеству markdown-документов;
|
||||
- правила генерации и обновления документации агентом.
|
||||
|
||||
Детальные шаблоны документов и правила frontmatter описываются отдельно:
|
||||
- `.analysis/rules/frontmatter-rules.md`
|
||||
- `.analysis/rules/templates/*.md`
|
||||
|
||||
---
|
||||
|
||||
## Область действия
|
||||
|
||||
Правила из этого файла применяются ко всей проектной документации, размещаемой в:
|
||||
|
||||
```text
|
||||
docs/documentation/
|
||||
@@ -0,0 +1,60 @@
|
||||
# Frontmatter Rules
|
||||
|
||||
## Назначение
|
||||
|
||||
Этот файл фиксирует правила YAML frontmatter для документов в `docs/documentation/`.
|
||||
|
||||
Frontmatter обязателен для каждого markdown-документа и нужен для:
|
||||
- идентификации документа;
|
||||
- определения типа документа;
|
||||
- фиксации связей с кодом и другими документами;
|
||||
- выделения сущностей, тегов и домена;
|
||||
- поддержки индексирования в RAG.
|
||||
|
||||
Общие правила построения документации описаны в:
|
||||
- `.analysis/rules/documentation-rules.md`
|
||||
|
||||
Шаблоны markdown body описаны в:
|
||||
- `.analysis/rules/templates/*.md`
|
||||
|
||||
---
|
||||
|
||||
## Общие правила
|
||||
|
||||
1. Frontmatter размещается в начале файла.
|
||||
2. Формат — YAML между двумя строками `---`.
|
||||
3. Все документы в `docs/documentation/` должны содержать frontmatter.
|
||||
4. Поля должны быть стабильными и заполняться единообразно.
|
||||
5. Не использовать произвольные поля без необходимости.
|
||||
6. Если значение неизвестно и его нельзя уверенно вывести из evidence, поле лучше не заполнять, кроме обязательных полей.
|
||||
7. Списковые поля должны оформляться как YAML-массивы.
|
||||
8. Идентификаторы и ссылки должны быть стабильными и пригодными для машинной обработки.
|
||||
|
||||
---
|
||||
|
||||
## Базовый frontmatter
|
||||
|
||||
Каждый документ должен начинаться с frontmatter вида:
|
||||
|
||||
```yaml
|
||||
---
|
||||
id: api-orders-create
|
||||
title: Метод создания заказа
|
||||
doc_type: api_method
|
||||
domain: orders
|
||||
status: draft
|
||||
owner: system-analyst
|
||||
source_of_truth: code
|
||||
related_docs:
|
||||
- ui-order-create-page
|
||||
- logic-order-validation
|
||||
related_code:
|
||||
- src/orders/api/create_order.py
|
||||
entities:
|
||||
- Order
|
||||
- CreateOrder
|
||||
tags:
|
||||
- api
|
||||
- orders
|
||||
- create
|
||||
---
|
||||
@@ -0,0 +1,29 @@
|
||||
# Rule: Use Document Templates From Fixed Paths
|
||||
|
||||
Агент должен создавать и обновлять техническую документацию только с опорой на шаблоны документов, расположенные в `.analysis/rules`.
|
||||
|
||||
Если агент формирует новый документ, он обязан:
|
||||
|
||||
- определить тип документа;
|
||||
- выбрать соответствующий шаблон по фиксированному пути;
|
||||
- сохранить структуру секций и базовых метаданных из шаблона;
|
||||
- заполнять только те секции, которые подтверждены кодом и артефактами;
|
||||
- не придумывать новые произвольные форматы, если для типа уже существует шаблон.
|
||||
|
||||
Пути к базовым шаблонам:
|
||||
|
||||
- `.analysis/rules/legacy/template_ui_page.md`
|
||||
- `.analysis/rules/legacy/template_api_method.md`
|
||||
- `.analysis/rules/legacy/template_logic_block.md`
|
||||
|
||||
Правило выбора шаблона:
|
||||
|
||||
- для документа типа `ui_page` использовать `.analysis/rules/legacy/template_ui_page.md`
|
||||
- для документа типа `api_method` использовать `.analysis/rules/legacy/template_api_method.md`
|
||||
- для документа типа `logic_block` использовать `.analysis/rules/legacy/template_logic_block.md`
|
||||
|
||||
Если для нужного типа шаблон отсутствует, агент должен:
|
||||
|
||||
1. использовать ближайший подходящий существующий шаблон как временную основу;
|
||||
2. явно сохранить тип документа в `YAML frontmatter`;
|
||||
3. не смешивать в одном документе несколько независимых сущностей.
|
||||
@@ -0,0 +1,89 @@
|
||||
# Template: api_method
|
||||
|
||||
```md
|
||||
---
|
||||
id: api-<stable-id>
|
||||
title: <Human-readable title>
|
||||
doc_type: api_method
|
||||
status: draft
|
||||
source_of_truth: code
|
||||
domain: <domain-name>
|
||||
owner: system-analyst
|
||||
endpoint: <METHOD /path>
|
||||
auth: <auth-mode-or-unknown>
|
||||
idempotent: <true-or-false>
|
||||
related_docs:
|
||||
- <doc-id>
|
||||
related_code:
|
||||
- <path/to/file>
|
||||
entities:
|
||||
- <EntityName>
|
||||
tags:
|
||||
- api
|
||||
---
|
||||
|
||||
# <API Method Title>
|
||||
|
||||
## Purpose
|
||||
|
||||
Кратко опиши, какую системную задачу решает метод.
|
||||
|
||||
## Endpoint Summary
|
||||
|
||||
- Endpoint: `<METHOD /path>`
|
||||
- Auth: `<auth-mode>`
|
||||
- Idempotent: `<true/false>`
|
||||
- Triggered by: `<ui/system/integration if known>`
|
||||
|
||||
## Technical Use Case
|
||||
|
||||
Опиши пошагово обработку запроса:
|
||||
|
||||
- вход в endpoint;
|
||||
- ключевые проверки;
|
||||
- вызовы логики;
|
||||
- обращения к БД и внешним системам;
|
||||
- формирование ответа.
|
||||
|
||||
## Functional Requirements
|
||||
|
||||
Вынеси сюда подтвержденные правила, которые дополняют основной сценарий:
|
||||
|
||||
- валидации;
|
||||
- branching logic;
|
||||
- побочные эффекты;
|
||||
- ограничения по данным;
|
||||
- условия ошибок.
|
||||
|
||||
## Request and Response Contract
|
||||
|
||||
Опиши контракт в кратком виде или дай ссылку на OpenAPI / контрактный файл.
|
||||
|
||||
## Related Logic Blocks
|
||||
|
||||
- [<Logic block title>](<path-or-doc-link>)
|
||||
|
||||
## Data Access and Integrations
|
||||
|
||||
- Reads DB: `<if known>`
|
||||
- Writes DB: `<if known>`
|
||||
- Integrates with: `<if known>`
|
||||
|
||||
## Non-Functional Requirements
|
||||
|
||||
Укажи только подтвержденные НФТ:
|
||||
|
||||
- timeout;
|
||||
- audit;
|
||||
- monitoring;
|
||||
- security;
|
||||
- idempotency rules.
|
||||
|
||||
## Related Code
|
||||
|
||||
- `<path/to/file>`
|
||||
|
||||
## Related Documents
|
||||
|
||||
- [<Related document>](<path-or-doc-link>)
|
||||
```
|
||||
@@ -0,0 +1,71 @@
|
||||
# Template: logic_block
|
||||
|
||||
```md
|
||||
---
|
||||
id: logic-<stable-id>
|
||||
title: <Human-readable title>
|
||||
doc_type: logic_block
|
||||
status: draft
|
||||
source_of_truth: code
|
||||
domain: <domain-name>
|
||||
owner: system-analyst
|
||||
related_docs:
|
||||
- <doc-id>
|
||||
related_code:
|
||||
- <path/to/file>
|
||||
entities:
|
||||
- <EntityName>
|
||||
tags:
|
||||
- logic
|
||||
---
|
||||
|
||||
# <Logic Block Title>
|
||||
|
||||
## Purpose
|
||||
|
||||
Кратко опиши, какую переиспользуемую или устойчивую логику реализует блок.
|
||||
|
||||
## Where Used
|
||||
|
||||
- Called from: `<ui/api/jobs/services if known>`
|
||||
- Used by: `<list of known callers>`
|
||||
|
||||
## Technical Use Case
|
||||
|
||||
Опиши пошагово, как работает логический блок:
|
||||
|
||||
- входные данные;
|
||||
- ключевые проверки;
|
||||
- преобразования;
|
||||
- обращения к данным;
|
||||
- результат работы.
|
||||
|
||||
## Functional Requirements
|
||||
|
||||
Вынеси сюда устойчивые правила и ограничения:
|
||||
|
||||
- бизнес-правила;
|
||||
- проверки;
|
||||
- ветвления;
|
||||
- ограничения на вход и выход;
|
||||
- условия отказа.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Uses logic: `<other logic blocks if known>`
|
||||
- Reads DB: `<if known>`
|
||||
- Writes DB: `<if known>`
|
||||
- Integrates with: `<if known>`
|
||||
|
||||
## Error Cases
|
||||
|
||||
Опиши значимые ошибки и условия их возникновения, если они подтверждены кодом.
|
||||
|
||||
## Related Code
|
||||
|
||||
- `<path/to/file>`
|
||||
|
||||
## Related Documents
|
||||
|
||||
- [<Related document>](<path-or-doc-link>)
|
||||
```
|
||||
@@ -0,0 +1,82 @@
|
||||
# Template: ui_page
|
||||
|
||||
```md
|
||||
---
|
||||
id: ui-<stable-id>
|
||||
title: <Human-readable title>
|
||||
doc_type: ui_page
|
||||
status: draft
|
||||
source_of_truth: code
|
||||
domain: <domain-name>
|
||||
owner: system-analyst
|
||||
related_docs:
|
||||
- <doc-id>
|
||||
related_code:
|
||||
- <path/to/file>
|
||||
entities:
|
||||
- <EntityName>
|
||||
tags:
|
||||
- ui
|
||||
---
|
||||
|
||||
# <Page Title>
|
||||
|
||||
## Purpose
|
||||
|
||||
Кратко опиши, какую пользовательскую задачу решает страница.
|
||||
|
||||
## Route and Entry Points
|
||||
|
||||
- Route: `<route-if-known>`
|
||||
- Entry points: `<where user comes from>`
|
||||
|
||||
## Technical Use Case
|
||||
|
||||
Опиши пошаговый сценарий работы страницы как поток действий и системных реакций.
|
||||
|
||||
## UI Structure
|
||||
|
||||
Перечисли основные UI-элементы и для каждого укажи:
|
||||
|
||||
- назначение;
|
||||
- источник данных;
|
||||
- значение по умолчанию или placeholder;
|
||||
- условия доступности или активации;
|
||||
- поведение при взаимодействии;
|
||||
- правила валидации.
|
||||
|
||||
## Functional Requirements
|
||||
|
||||
Вынеси сюда детальные правила, которые не стоит перегружать в use case:
|
||||
|
||||
- вызовы API;
|
||||
- обработку ответов;
|
||||
- локальные правила отображения;
|
||||
- условия переходов;
|
||||
- feature toggles.
|
||||
|
||||
## Related APIs
|
||||
|
||||
- [<API document title>](<path-or-doc-link>)
|
||||
|
||||
## Related Logic Blocks
|
||||
|
||||
- [<Logic block title>](<path-or-doc-link>)
|
||||
|
||||
## Non-Functional Requirements
|
||||
|
||||
Укажи НФТ, если они подтверждены:
|
||||
|
||||
- analytics events;
|
||||
- observability;
|
||||
- feature toggles;
|
||||
- security constraints.
|
||||
|
||||
## Related Code
|
||||
|
||||
- `<path/to/file>`
|
||||
|
||||
## Related Documents
|
||||
|
||||
- [<Related document>](<path-or-doc-link>)
|
||||
```
|
||||
@@ -0,0 +1,115 @@
|
||||
# {{title}}
|
||||
|
||||
## Summary
|
||||
- Purpose:
|
||||
- Actor:
|
||||
- Trigger:
|
||||
- Endpoint:
|
||||
- Main entities:
|
||||
- Main logic:
|
||||
- Main errors:
|
||||
- Source of truth:
|
||||
|
||||
## Назначение
|
||||
|
||||
## Контекст
|
||||
|
||||
## Технический use case
|
||||
|
||||
### Основной сценарий
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
### Альтернативные ветки
|
||||
|
||||
-
|
||||
-
|
||||
|
||||
## Функциональные требования
|
||||
|
||||
### Request validation
|
||||
-
|
||||
|
||||
### Processing rules
|
||||
-
|
||||
|
||||
### State changes
|
||||
-
|
||||
|
||||
### Side effects
|
||||
-
|
||||
|
||||
## Contract
|
||||
|
||||
### Endpoint
|
||||
- Method:
|
||||
- Path:
|
||||
- Auth:
|
||||
- Idempotent:
|
||||
- Timeout:
|
||||
- Retry:
|
||||
|
||||
### Request
|
||||
| Field | Type | Required | Constraints | Description |
|
||||
|------|------|----------|-------------|-------------|
|
||||
| | | | | |
|
||||
|
||||
### Response
|
||||
| Field | Type | Description |
|
||||
|------|------|-------------|
|
||||
| | | |
|
||||
|
||||
### External contract refs
|
||||
- OpenAPI:
|
||||
- Schema:
|
||||
- DTO / serializer:
|
||||
- Additional refs:
|
||||
|
||||
## Errors
|
||||
|
||||
| error_id | http_code | when | client_behavior | retry |
|
||||
|----------|-----------|------|-----------------|-------|
|
||||
| | | | | |
|
||||
|
||||
## Нефункциональные требования
|
||||
|
||||
### Security
|
||||
-
|
||||
|
||||
### Observability
|
||||
- Logs:
|
||||
- Metrics:
|
||||
- Traces:
|
||||
- Audit:
|
||||
|
||||
### Reliability
|
||||
-
|
||||
-
|
||||
|
||||
### Performance
|
||||
-
|
||||
|
||||
## Связанные блоки логики
|
||||
-
|
||||
|
||||
## Связанные сущности
|
||||
-
|
||||
|
||||
## Связанный код
|
||||
|
||||
### Files
|
||||
-
|
||||
|
||||
### Symbols
|
||||
-
|
||||
|
||||
## Связанные документы
|
||||
-
|
||||
|
||||
## История изменений
|
||||
|
||||
| Date | Source | Changes |
|
||||
|------|--------|---------|
|
||||
| | | |
|
||||
@@ -0,0 +1,105 @@
|
||||
# {{title}}
|
||||
|
||||
## Summary
|
||||
- Scope:
|
||||
- Purpose:
|
||||
- Main modules:
|
||||
- Main domains:
|
||||
- Main integrations:
|
||||
- Key entrypoints:
|
||||
- Key data flows:
|
||||
- Source of truth:
|
||||
|
||||
## Назначение
|
||||
|
||||
## Контекст
|
||||
|
||||
## Границы системы
|
||||
|
||||
### In scope
|
||||
-
|
||||
|
||||
### Out of scope
|
||||
-
|
||||
|
||||
## Архитектурная схема
|
||||
|
||||
## Основные модули
|
||||
|
||||
| module | responsibility | depends_on | key_code_refs |
|
||||
|--------|----------------|------------|---------------|
|
||||
| | | | |
|
||||
|
||||
## Основные доменные области
|
||||
|
||||
-
|
||||
-
|
||||
|
||||
## Основные интеграции
|
||||
|
||||
| integration | direction | purpose | protocol / transport | related_docs |
|
||||
|-------------|-----------|---------|----------------------|--------------|
|
||||
| | | | | |
|
||||
|
||||
## Основные потоки
|
||||
|
||||
### Flow 1
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
### Flow 2
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
## Архитектурные решения и ограничения
|
||||
|
||||
### Key decisions
|
||||
-
|
||||
|
||||
### Constraints
|
||||
-
|
||||
|
||||
### Risks
|
||||
-
|
||||
|
||||
## Нефункциональные аспекты
|
||||
|
||||
### Security
|
||||
-
|
||||
|
||||
### Reliability
|
||||
-
|
||||
|
||||
### Observability
|
||||
- Logs:
|
||||
- Metrics:
|
||||
- Traces:
|
||||
- Audit:
|
||||
|
||||
### Performance
|
||||
-
|
||||
|
||||
### Scalability
|
||||
-
|
||||
|
||||
## Связанные сущности
|
||||
-
|
||||
|
||||
## Связанный код
|
||||
|
||||
### Files
|
||||
-
|
||||
|
||||
### Symbols
|
||||
-
|
||||
|
||||
## Связанные документы
|
||||
-
|
||||
|
||||
## История изменений
|
||||
|
||||
| Date | Source | Changes |
|
||||
|------|--------|---------|
|
||||
| | | |
|
||||
@@ -0,0 +1,92 @@
|
||||
# {{title}}
|
||||
|
||||
## Summary
|
||||
- Domain:
|
||||
- Purpose:
|
||||
- Entity role:
|
||||
- Main attributes:
|
||||
- Lifecycle:
|
||||
- Invariants:
|
||||
- Related APIs:
|
||||
- Related logic:
|
||||
- Source of truth:
|
||||
|
||||
## Назначение
|
||||
|
||||
## Контекст
|
||||
|
||||
## Роль в доменной модели
|
||||
|
||||
## Атрибуты
|
||||
|
||||
| attribute | type | required | description | constraints |
|
||||
|-----------|------|----------|-------------|-------------|
|
||||
| | | | | |
|
||||
|
||||
## Состояния и жизненный цикл
|
||||
|
||||
### Основные состояния
|
||||
-
|
||||
|
||||
### Переходы состояний
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
## Инварианты и ограничения
|
||||
|
||||
-
|
||||
-
|
||||
|
||||
## Связи с другими сущностями
|
||||
|
||||
| entity | relation | description |
|
||||
|--------|----------|-------------|
|
||||
| | | |
|
||||
|
||||
## Использование в системе
|
||||
|
||||
### Related API
|
||||
-
|
||||
|
||||
### Related UI
|
||||
-
|
||||
|
||||
### Related logic
|
||||
-
|
||||
|
||||
### Related integrations
|
||||
-
|
||||
|
||||
## Функциональные требования
|
||||
|
||||
-
|
||||
-
|
||||
|
||||
## Нефункциональные требования
|
||||
|
||||
### Audit / history
|
||||
-
|
||||
|
||||
### Security
|
||||
-
|
||||
|
||||
### Observability
|
||||
-
|
||||
|
||||
## Связанный код
|
||||
|
||||
### Files
|
||||
-
|
||||
|
||||
### Symbols
|
||||
-
|
||||
|
||||
## Связанные документы
|
||||
-
|
||||
|
||||
## История изменений
|
||||
|
||||
| Date | Source | Changes |
|
||||
|------|--------|---------|
|
||||
| | | |
|
||||
@@ -0,0 +1,93 @@
|
||||
```md
|
||||
# {{title}}
|
||||
|
||||
## Summary
|
||||
- Purpose:
|
||||
- Trigger:
|
||||
- Inputs:
|
||||
- Outputs:
|
||||
- Main entities:
|
||||
- Main dependencies:
|
||||
- Side effects:
|
||||
- Source of truth:
|
||||
|
||||
## Назначение
|
||||
|
||||
## Контекст
|
||||
|
||||
## Технический use case
|
||||
|
||||
### Основной сценарий
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
### Альтернативные ветки
|
||||
|
||||
-
|
||||
-
|
||||
|
||||
## Функциональные требования
|
||||
|
||||
### Preconditions
|
||||
-
|
||||
|
||||
### Processing rules
|
||||
-
|
||||
|
||||
### Validation rules
|
||||
-
|
||||
|
||||
### Output / result rules
|
||||
-
|
||||
|
||||
### Side effects
|
||||
-
|
||||
|
||||
## Ограничения и условия вызова
|
||||
|
||||
-
|
||||
-
|
||||
|
||||
## Нефункциональные требования
|
||||
|
||||
### Security
|
||||
-
|
||||
|
||||
### Observability
|
||||
- Logs:
|
||||
- Metrics:
|
||||
- Traces:
|
||||
- Audit:
|
||||
|
||||
### Reliability
|
||||
-
|
||||
-
|
||||
|
||||
### Performance
|
||||
-
|
||||
|
||||
## Связанные API / UI / integration points
|
||||
-
|
||||
|
||||
## Связанные сущности
|
||||
-
|
||||
|
||||
## Связанный код
|
||||
|
||||
### Files
|
||||
-
|
||||
|
||||
### Symbols
|
||||
-
|
||||
|
||||
## Связанные документы
|
||||
-
|
||||
|
||||
## История изменений
|
||||
|
||||
| Date | Source | Changes |
|
||||
|------|--------|---------|
|
||||
| | | |
|
||||
```
|
||||
@@ -0,0 +1,97 @@
|
||||
# {{title}}
|
||||
|
||||
## Summary
|
||||
- Purpose:
|
||||
- Actor:
|
||||
- Trigger:
|
||||
- Route:
|
||||
- Main API:
|
||||
- Main entities:
|
||||
- Main logic:
|
||||
- Main states:
|
||||
- Source of truth:
|
||||
|
||||
## Назначение
|
||||
|
||||
## Контекст
|
||||
|
||||
## Технический use case
|
||||
|
||||
### Основной сценарий
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
### Альтернативные ветки
|
||||
|
||||
-
|
||||
-
|
||||
|
||||
## Описание UI
|
||||
|
||||
## UI Elements
|
||||
|
||||
| id | type | label | data_source | default / placeholder | validation | behavior |
|
||||
|----|------|-------|-------------|------------------------|------------|----------|
|
||||
| | | | | | | |
|
||||
|
||||
## Функциональные требования
|
||||
|
||||
### Input rules
|
||||
-
|
||||
|
||||
### State rules
|
||||
-
|
||||
|
||||
### Navigation rules
|
||||
-
|
||||
|
||||
### Client-side validation
|
||||
-
|
||||
|
||||
## Нефункциональные требования
|
||||
|
||||
### Security
|
||||
-
|
||||
|
||||
### Observability
|
||||
- Logs:
|
||||
- Metrics:
|
||||
- Traces:
|
||||
- Analytics:
|
||||
|
||||
### Accessibility
|
||||
-
|
||||
|
||||
### Performance
|
||||
-
|
||||
|
||||
### Feature toggles
|
||||
-
|
||||
|
||||
## Связанные API
|
||||
-
|
||||
|
||||
## Связанные блоки логики
|
||||
-
|
||||
|
||||
## Связанные сущности
|
||||
-
|
||||
|
||||
## Связанный код
|
||||
|
||||
### Files
|
||||
-
|
||||
|
||||
### Symbols
|
||||
-
|
||||
|
||||
## Связанные документы
|
||||
-
|
||||
|
||||
## История изменений
|
||||
|
||||
| Date | Source | Changes |
|
||||
|------|--------|---------|
|
||||
| | | |
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
При задачах на создание или обновление документации всегда:
|
||||
1. Читай .analysis/rules/documentation-rules.md, .analysis/rules/frontmatter-rules.md и нужный шаблон из .analysis/rules/templates/.
|
||||
2. Создавай и обновляй документы только в docs/documentation/.
|
||||
3. Не создавай дублей: сначала ищи существующий документ, потом обновляй его.
|
||||
4. Соблюдай принцип: один документ = одна сущность / один устойчивый аспект.
|
||||
5. Каждый документ должен иметь YAML frontmatter, обязательные разделы Summary и Details и структуру по шаблону.
|
||||
6. Все связи фиксируй явно: related_docs, related_code, entities, tags и typed-поля.
|
||||
7. Используй только подтвержденный evidence из кода, контрактов, конфигов и существующей документации.
|
||||
8. Не дублируй содержание между документами — используй ссылки.
|
||||
9. Явно указывай связанный код и связанные документы.
|
||||
10. Не выдумывай факты, если evidence недостаточно.
|
||||
+7
-1
@@ -1,3 +1,9 @@
|
||||
.env
|
||||
.venv
|
||||
__pycache__
|
||||
__pycache__
|
||||
|
||||
# Pipeline harness: per-run artifacts (md/json from tests.pipeline_setup_v3/v4)
|
||||
tests/**/test_runs/**/*.md
|
||||
tests/**/test_runs/**/*.json
|
||||
tests/**/test_results/**/*.md
|
||||
tests/**/test_results/**/*.json
|
||||
Vendored
+25
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Agent Backend: Uvicorn (Debug)",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"module": "uvicorn",
|
||||
"args": [
|
||||
"app.main:app",
|
||||
"--host",
|
||||
"0.0.0.0",
|
||||
"--port",
|
||||
"15000"
|
||||
],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"envFile": "${workspaceFolder}/.env",
|
||||
"env": {
|
||||
"PYTHONPATH": "${workspaceFolder}/src"
|
||||
},
|
||||
"console": "integratedTerminal",
|
||||
"justMyCode": false
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"files.exclude": {
|
||||
"**/__pycache__": true
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -3,12 +3,13 @@ FROM python:3.12-slim
|
||||
WORKDIR /app
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1
|
||||
PYTHONUNBUFFERED=1 \
|
||||
PYTHONPATH=/app/src
|
||||
|
||||
COPY requirements.txt ./
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
COPY app ./app
|
||||
COPY src ./src
|
||||
|
||||
EXPOSE 15000
|
||||
|
||||
|
||||
@@ -915,15 +915,15 @@ flowchart TD
|
||||
|
||||
### 4.1.3. Канонический MVP runtime (CODE-first)
|
||||
|
||||
Единая точка входа исполнения — пакет `app.modules.agent.runtime`:
|
||||
Единая точка входа исполнения — пакет `app.core.agent.runtime`:
|
||||
|
||||
- **Роутер:** `app.modules.agent.intent_router_v2`; он отвечает и за routing, и за retrieval planning.
|
||||
- **LLM-слой:** `app.modules.agent.llm`; здесь живут `AgentLlmService`, `PromptLoader` и системные prompt assets.
|
||||
- **Runtime:** `app.modules.agent.runtime`; внутри него stages разложены по подпакетам `retrieval`, `context`, `gates`, `answer_policy`, `generation`, `finalization`.
|
||||
- **Роутер:** `app.core.agent.intent_router`; он отвечает и за routing, и за retrieval planning.
|
||||
- **LLM-слой:** `app.core.agent.llm`; здесь живут `AgentLlmService`, `PromptLoader` и системные prompt assets.
|
||||
- **Runtime:** `app.core.agent.runtime`; внутри него stages разложены по подпакетам `retrieval`, `context`, `gates`, `answer_policy`, `generation`, `finalization`.
|
||||
- **Цепочка:** запрос → `IntentRouterV2` → retrieval planning → runtime retrieval adapter → нормализованный context/evidence → evidence gate 1 → answer policy → LLM generation → evidence gate 2 → finalization → diagnostics.
|
||||
- **Evidence gates:** pre/post проверки достаточности evidence и качества ответа по сценарию.
|
||||
- **Диагностика:** runtime возвращает machine-readable diagnostics и trace по стадиям.
|
||||
- **RAG:** `app.modules.rag` больше не содержит agent use-case слоев; он остается инфраструктурой indexing/retrieval/storage.
|
||||
- **RAG:** `app.core.rag` больше не содержит agent use-case слоев; он остается инфраструктурой indexing/retrieval/storage.
|
||||
|
||||
Тесты: `pipeline_setup_v3` и связанные suite-ы проверяют канонический runtime и его stage-based execution.
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# Запросы
|
||||
1. Какие методы апи есть в проекте
|
||||
2. Какие методы апи есть для healthcheck
|
||||
3. Где документация на healthcheck
|
||||
Binary file not shown.
@@ -0,0 +1,126 @@
|
||||
# Процессы работы с документацией (AS IS / TO BE)
|
||||
|
||||
|
||||
## Основные артефакты системной аналитики
|
||||
Системные аналитики работают с 3 артефактами:
|
||||
|
||||
- бизнес-требованиями
|
||||
- системной аналитикой
|
||||
- технической документацией
|
||||
|
||||
|
||||
### Бизнес требования
|
||||
Описывает бизнес и пользовательские требования, пользователькие use case, макеты экранов.
|
||||
Сейчас не всегда оформляется как отдельный документ, часто этот шаг пропускается и требования фиксируются сразу в документе системной аналитики.
|
||||
|
||||
|
||||
### Системная аналитика
|
||||
Документ описыватет изменения в автоматизированной системе. Пишется системными аналитиками для разработчиков и тестировщиков. Так же этот документ проходит согласование с экспертами по архитектуре, безопасности, сопровождению.
|
||||
|
||||
Может описывать как целиком процесс (в случае реализации с нуля), так и инкремент, который вносит небольшие изменения в существующие процессы.
|
||||
|
||||
В данном документе содкржится вся информация по сути вносимых изменений, но отсутствует контекст о текущей реализации системы.
|
||||
|
||||
Состоит из разделов:
|
||||
- Цели - короткое описание какую проблему и для кого решаем.
|
||||
- Процесс AS IS и TO BE - фокус на изменения с точки зрения бизнес функций, без технической детализации.
|
||||
- Ограничения - ограничения и допущения в реализации.
|
||||
- Архитектура - описывает схему уровня контейнеров, основной фокус на интеграции между контейнерами и интеграционные сценарии.
|
||||
- Функциональные требования - описывают изменения в системе.
|
||||
- Нефункциональные требования - требования к аудиту, мониторингу, фичетоглам, пользовтелькой аналитике.
|
||||
|
||||
|
||||
### Техническая документация
|
||||
Техническая документация описывает реализацию системы. Эта информация используется командой разработки при проектировании и реализации новых фичей, понимании как работает система. Артефакт живет чуть впереди кода
|
||||
Представялет из себя иерархическую модель документов, сейчас реализованную в конфлюенсе.
|
||||
|
||||
Есть несколько типов страниц, каждая из которы описывает определенный тип функциональности
|
||||
|
||||
- UI страницы
|
||||
- API методы
|
||||
- БД
|
||||
- Логические блоки
|
||||
|
||||
#### UI страницы
|
||||
Описывают экран на UI.
|
||||
**Декомпозиция**
|
||||
Как правило на страницу с описанием выносится целый макет/страница фронтального приложения, с одной основной интеграцией и опционально вспомогательными интеграциями.
|
||||
Например - форма создания сущности. Есть вспомогательгные методы для полученяи правочников, использующихся при заполнении полей на форме, и вызов оснвного метода создания сущности.
|
||||
|
||||
Таким образом приложение декомпозируется на отдельные экраны, коотры свызываются между собой последовательно, но сами по себе являются независимыми
|
||||
|
||||
**Состав описания**
|
||||
Все разделы обязательны.
|
||||
Страница с описанием содержит:
|
||||
- Краткое описание
|
||||
- Технический use case
|
||||
- Описание макета с декомпозицией на компоненты + их поведение
|
||||
- Функциональные требования - описание интеграций и логики, специфичной для этой формы UI
|
||||
- Нефункциональные требования - фичетоглы и события пользовательской аналитики
|
||||
|
||||
|
||||
#### API методы
|
||||
**Декомпозиция**
|
||||
На каждый метод API заводится отдельная страница.
|
||||
**Состав описания**
|
||||
Все разделы обязательны.
|
||||
Страница с описанием содержит:
|
||||
- Краткое описание
|
||||
- Технический use case
|
||||
- Функциональные требования - описание интеграций и логики, специфичной для этой формы UI
|
||||
- Нефункциональные требования - фичетоглы и события пользовательской аналитики
|
||||
- Контракт метода - описание запроса и ответа. Для ответа так же приводится описание как заполнять поля.
|
||||
|
||||
#### БД
|
||||
**Декомпозиция**
|
||||
Сейсас это только странциа с описанием таблица. На каждую таблицу заводится отдельная страница.
|
||||
**Состав описания**
|
||||
Все разделы обязательны.
|
||||
Страница с описанием содержит:
|
||||
- Краткое описание
|
||||
- Таблица с офисанием физической модели данных
|
||||
|
||||
#### Логические блоки
|
||||
**Декомпозиция**
|
||||
На отдельную страницу может быть вынесен общий переиспользуемый блок логики. Это позволяет не дублировать его на страницах документации. Как правило соответствует реализации общего компонента в коде.
|
||||
**Состав описания**
|
||||
Часть разделов в описании может отсутствовать.
|
||||
- Краткое описание
|
||||
- Технический use case
|
||||
- Функциональные требования - описание интеграций и логики, специфичной для этой формы UI
|
||||
- Нефункциональные требования - фичетоглы и события пользовательской аналитики
|
||||
|
||||
#### Прочие особенности процесса
|
||||
##### Описание технических use cases
|
||||
Сценарий описывает основные шаги процесса в разрезе участников, все технические детали, если их нельзя описать одним предложением, выносятся в разделы функциональных требований, нефункциональных требований, или даются ссылки на другие страницы (как правило это страницы с логическими блоками).
|
||||
|
||||
В технических use cases приводятся ссылки на страницы с описнаием вызываемых методов API. Особенно это актуально для страниц фронта, т.к. он использует наши методы API, которые есть в документации. Для интеграций с другими АС как правило приводистя ссылка на описание конфлюенса.
|
||||
|
||||
|
||||
|
||||
## AS IS
|
||||
Сейчас все артефакты ведутся в конфлюенс. Одна страница содержит описанием одного аретфакта (бизнес требования, системная аналитика, страница документации), страницы организованы иерархически, используюстя ссылки для обозначения связей.
|
||||
|
||||
Проблемы:
|
||||
- документация со временем теряет актуальность
|
||||
- отсутствие автоматизации
|
||||
- ручное ведение
|
||||
---
|
||||
|
||||
## TO BE
|
||||
|
||||
Целевое состояние:
|
||||
- аналитик продолжает писать артефакты бизнес-требований и системной аналитики
|
||||
- агент генерирует и обновляет документацию по странице системной аналитики
|
||||
- документация становится инженерным артефактом, который ведется в GIT
|
||||
|
||||
### Форматы
|
||||
- Markdown
|
||||
- OpenAPI
|
||||
- Mermaid / PlantUML
|
||||
|
||||
### Роль агента
|
||||
- использование документации как базы знаний - как для ответов на вопросы, так и для проектирования изменений в системе.
|
||||
- внесение изменений в документацию по артефактам системной аналитики
|
||||
- генерация из документации спецификаций OPENAPI и JSON-schema
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
Ниже обновленная версия с учетом гибридной модели интент роутера.
|
||||
|
||||
---
|
||||
|
||||
## 1. Концепция агента
|
||||
|
||||
Агент проектируется как intent-driven система для работы с кодом и документацией, где пользовательский запрос сначала нормализуется и интерпретируется, затем по нему извлекается релевантный контекст из многослойного RAG, после чего специализированный task workflow выполняет целевую задачу. Агент не является единым “умным чатом”: логика разделена на маршрутизацию, retrieval и специализированные execution workflows. Проверка evidence, вызовы LLM и правила сборки ответа находятся внутри task workflows и зависят от типа задачи.
|
||||
|
||||
---
|
||||
|
||||
## 2. Компонентная модель
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
IDE[IDE Plugin / Client] --> API[API Layer]
|
||||
API --> IR[IntentRouter V3]
|
||||
IR --> RAG[Retrieval RAG]
|
||||
|
||||
RAG --> TW1[Task Workflow: Documentation Explain]
|
||||
RAG --> TW2[Task Workflow: OpenAPI Generation]
|
||||
RAG --> TW3[Task Workflow: Documentation Generation]
|
||||
RAG --> TWN[Other Specialized Task Workflows]
|
||||
|
||||
TW1 --> OUT[Response / Artifact]
|
||||
TW2 --> OUT
|
||||
TW3 --> OUT
|
||||
TWN --> OUT
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Основной flow процесса
|
||||
|
||||
### Основной процесс
|
||||
|
||||
1. Пользователь отправляет запрос через IDE plugin или другой клиент.
|
||||
2. `API Layer` принимает запрос и передает его в агент.
|
||||
3. `IntentRouter V3`:
|
||||
|
||||
* нормализует запрос;
|
||||
* детерминированно извлекает ключевые артефакты;
|
||||
* с помощью LLM определяет тип задачи и параметры обработки;
|
||||
* формирует параметры retrieval.
|
||||
4. Выполняется извлечение данных из `Retrieval RAG`.
|
||||
5. Извлеченный контекст передается в соответствующий `Task Workflow`.
|
||||
6. Внутри workflow выполняется:
|
||||
|
||||
* подготовка контекста;
|
||||
* evidence-проверки;
|
||||
* вызовы LLM;
|
||||
* формирование результата.
|
||||
7. Результат возвращается пользователю.
|
||||
|
||||
### Sequence diagram
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as User / IDE Plugin
|
||||
participant API as API Layer
|
||||
participant Router as IntentRouter V3
|
||||
participant RAG as Retrieval RAG
|
||||
participant WF as Task Workflow
|
||||
|
||||
User->>API: request
|
||||
API->>Router: agent call
|
||||
Router->>Router: normalize + extract artifacts
|
||||
Router->>Router: LLM routing (task / intent)
|
||||
Router->>RAG: retrieval request
|
||||
RAG-->>Router: retrieved context
|
||||
Router->>WF: route result + context
|
||||
WF->>WF: evidence logic + LLM calls
|
||||
WF-->>API: final result
|
||||
API-->>User: response
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Описание компонентов
|
||||
|
||||
### 4.1. IDE Plugin / Client
|
||||
|
||||
**Задача**
|
||||
Точка входа пользователя в агент.
|
||||
|
||||
**Как устроен**
|
||||
Любой внешний клиент (IDE plugin, web UI и др.), который отправляет запрос и получает результат.
|
||||
|
||||
**Почему так**
|
||||
Агент изначально проектируется как backend-система, независимая от интерфейса.
|
||||
|
||||
---
|
||||
|
||||
### 4.2. API Layer
|
||||
|
||||
**Задача**
|
||||
Обеспечивает внешний интерфейс взаимодействия с агентом.
|
||||
|
||||
**Как устроен**
|
||||
Принимает запрос, валидирует его и передает во внутренний pipeline, затем возвращает результат.
|
||||
|
||||
**Почему так**
|
||||
Позволяет изолировать транспортный слой от логики агента.
|
||||
|
||||
---
|
||||
|
||||
### 4.3. IntentRouter V3
|
||||
|
||||
**Задача**
|
||||
Определяет, как должен обрабатываться пользовательский запрос и какой сценарий выполнения применить.
|
||||
|
||||
**Как устроен**
|
||||
|
||||
Гибридная модель из двух частей:
|
||||
|
||||
#### 1. Детерминированный слой
|
||||
|
||||
Выполняет:
|
||||
|
||||
* нормализацию запроса;
|
||||
* извлечение ключевых артефактов:
|
||||
|
||||
* домены;
|
||||
* типы сущностей (API, entity, component и т.д.);
|
||||
* явные ссылки (endpoint, путь, имя);
|
||||
* выделение базовых сигналов (например: explain / list / generate).
|
||||
|
||||
Этот слой задает **жесткие рамки интерпретации запроса**.
|
||||
|
||||
#### 2. LLM-роутинг
|
||||
|
||||
Использует:
|
||||
|
||||
* нормализованный запрос;
|
||||
* извлеченные артефакты;
|
||||
* описание доступных типов задач;
|
||||
|
||||
и определяет:
|
||||
|
||||
* тип задачи;
|
||||
* общий сценарий обработки;
|
||||
* параметры retrieval;
|
||||
* ожидаемую форму ответа.
|
||||
|
||||
#### Итог
|
||||
|
||||
Router формирует:
|
||||
|
||||
* параметры retrieval;
|
||||
* тип task workflow;
|
||||
* контекст для дальнейшего выполнения.
|
||||
|
||||
**Почему решение такое**
|
||||
|
||||
Ранее использовался более детерминированный подход с фиксированными сценариями, который хорошо работал в узком наборе задач, но плохо масштабируется. Полностью LLM-based роутинг, наоборот, дает гибкость, но теряет предсказуемость и управляемость.
|
||||
|
||||
Поэтому выбран гибридный подход:
|
||||
|
||||
* детерминированный слой фиксирует ключевые артефакты и ограничения;
|
||||
* LLM выполняет гибкую интерпретацию задачи.
|
||||
|
||||
Это позволяет:
|
||||
|
||||
* сохранить управляемость и стабильность;
|
||||
* избежать взрывного роста количества сценариев;
|
||||
* поддерживать сложные и нетиповые запросы.
|
||||
|
||||
---
|
||||
|
||||
### 4.4. Retrieval RAG
|
||||
|
||||
**Задача**
|
||||
Извлечь релевантный контекст для выполнения задачи.
|
||||
|
||||
**Как устроен**
|
||||
Многослойная система хранения знаний (код, документация, факты, связи), из которой извлекается структурированный контекст в зависимости от параметров, заданных роутером.
|
||||
|
||||
**Почему так**
|
||||
Разные задачи требуют разных типов данных, поэтому используется слойная модель вместо плоского поиска.
|
||||
|
||||
---
|
||||
|
||||
### 4.5. Task Workflows
|
||||
|
||||
**Задача**
|
||||
Реализуют прикладную логику выполнения конкретного типа задачи.
|
||||
|
||||
**Как устроены**
|
||||
Набор специализированных workflows, например:
|
||||
|
||||
* объяснение по документации;
|
||||
* генерация OpenAPI;
|
||||
* генерация документации;
|
||||
* другие сценарии.
|
||||
|
||||
Внутри workflow находятся:
|
||||
|
||||
* обработка контекста;
|
||||
* evidence-проверки;
|
||||
* вызовы LLM;
|
||||
* сборка результата.
|
||||
|
||||
**Почему так**
|
||||
Логика проверки данных и генерации сильно зависит от задачи, поэтому она инкапсулируется в отдельных workflows, а не в одном универсальном слое.
|
||||
|
||||
---
|
||||
|
||||
### 4.6. Output / Artifact
|
||||
|
||||
**Задача**
|
||||
Вернуть результат пользователю.
|
||||
|
||||
**Как устроен**
|
||||
Может быть:
|
||||
|
||||
* текстовый ответ;
|
||||
* структурированный список;
|
||||
* OpenAPI спецификация;
|
||||
* документация;
|
||||
* иной артефакт.
|
||||
|
||||
**Почему так**
|
||||
Агент должен поддерживать не только ответы, но и генерацию инженерных артефактов.
|
||||
|
||||
---
|
||||
|
||||
## Итог
|
||||
|
||||
Обновленная архитектура строится на следующем принципе:
|
||||
|
||||
* **детерминированное извлечение ключевых артефактов** задает рамки;
|
||||
* **LLM выполняет гибкий роутинг внутри этих рамок**;
|
||||
* **retrieval обеспечивает данные**;
|
||||
* **task workflows реализуют прикладную логику и контроль качества**.
|
||||
|
||||
Это позволяет одновременно сохранить управляемость системы и обеспечить масштабируемость под новые типы задач.
|
||||
@@ -0,0 +1,59 @@
|
||||
# Intents
|
||||
|
||||
## Domains
|
||||
|
||||
- `DOCS`
|
||||
- `GENERAL`
|
||||
- `CODE` - временно отключен
|
||||
|
||||
## GENERAL
|
||||
|
||||
### Intent `GENERAL_QA`
|
||||
|
||||
Общий интент для вопросов без точного маршрута.
|
||||
В дальнейшем может использоваться как fallback.
|
||||
|
||||
Subintents:
|
||||
- `SUMMARY` - ответы на общие вопросы по SUMMARY
|
||||
|
||||
|
||||
|
||||
## DOCS
|
||||
|
||||
### Intent `ARCHITECTURE`
|
||||
|
||||
Обработка вопросов по архитектуре.
|
||||
Subintents пока отсутствуют.
|
||||
Интент запланирован, без реализации.
|
||||
|
||||
### Intent `DOC_EXPLAIN`
|
||||
|
||||
Объяснение по документации.
|
||||
|
||||
Subintents:
|
||||
- `SUMMARY` - краткое объяснение темы по SUMMARY-блокам документации
|
||||
- `FIND_FILES` - поиск файлов с релевантной информацией
|
||||
- `EXPLAIN_API` - объяснение работы метода
|
||||
- `COMPONENT_INTEGRATIONS` - перечень интеграций компонента, API, UI, сущности, внешних систем
|
||||
- `ENTITY_INTEGRATIONS` - перечень интеграций сущности
|
||||
|
||||
В текущем узком MVP реально реализованы только:
|
||||
|
||||
- `SUMMARY`
|
||||
- `FIND_FILES`
|
||||
|
||||
Для запросов по интеграциям целевым retrieval-слоем является `D6_INTEGRATION_INDEX`.
|
||||
|
||||
### Intent `OPENAPI_GENERATION`
|
||||
|
||||
Генерация OpenAPI-спеки.
|
||||
|
||||
Subintents:
|
||||
- `FULL_SPEC` - создание полной спецификации
|
||||
|
||||
### Intent `DOC_GENERATION`
|
||||
|
||||
Редактирование документации.
|
||||
|
||||
Subintents:
|
||||
- `FROM_FEATURE` - создание документации из системной аналитики на фичу
|
||||
@@ -0,0 +1,345 @@
|
||||
# RAG
|
||||
|
||||
## Состояние as is
|
||||
|
||||
RAG сейчас используется как общее ядро индексации и retrieval по коду и документации.
|
||||
Основной storage - `rag_session` и многослойный индекс в БД.
|
||||
|
||||
## Основные части
|
||||
|
||||
- `RagService` - фасад индексации и retrieval
|
||||
- `DocsIndexingPipeline` - индексация документации
|
||||
- `CodeIndexingPipeline` - индексация кода
|
||||
- `RagRepository` - persistence и retrieval
|
||||
- `IntentRouterV2` - планирование retrieval: слои, фильтры, ограничения
|
||||
- `RuntimeRetrievalAdapter` - выполнение retrieval в runtime
|
||||
|
||||
## Индексация
|
||||
|
||||
Индексация идет по двум направлениям:
|
||||
|
||||
- `DOCS`
|
||||
- `CODE`
|
||||
|
||||
На вход подается snapshot или changes.
|
||||
Для каждого файла выбирается подходящий pipeline.
|
||||
На выходе формируются документы по слоям и сохраняются в RAG-хранилище.
|
||||
|
||||
## Структура БД
|
||||
|
||||
Все слои сохраняются в общую таблицу `rag_chunks`.
|
||||
|
||||
### Общие поля по слоям
|
||||
|
||||
| Поле БД | Назначение |
|
||||
|---|---|
|
||||
| `rag_session_id` | идентификатор сессии индексации |
|
||||
| `path` | путь исходного файла |
|
||||
| `content` | основной текст записи для retrieval |
|
||||
| `layer` | идентификатор слоя |
|
||||
| `title` | короткий заголовок записи |
|
||||
| `lang` | язык исходного содержимого, в основном для code-слоев |
|
||||
| `repo_id` | идентификатор репозитория или проекта |
|
||||
| `commit_sha` | версия кода или документов на момент индексации |
|
||||
| `span_start`, `span_end` | диапазон строк в исходном файле, если он есть |
|
||||
| `embedding` | векторное представление записи |
|
||||
| `metadata_json` | структурированные атрибуты конкретного слоя |
|
||||
|
||||
### Поля со смыслом слоя
|
||||
|
||||
Смысл конкретного слоя хранится в `metadata_json`.
|
||||
Именно эти атрибуты определяют, какой объект был извлечен и как его интерпретировать в retrieval.
|
||||
Домены и поддомены должны храниться в `metadata_json` явно.
|
||||
|
||||
## Слои DOCS
|
||||
|
||||
### `D0_DOC_CHUNKS`
|
||||
|
||||
Задача:
|
||||
Хранит текстовые фрагменты документации для retrieval по содержимому разделов.
|
||||
|
||||
Формирование:
|
||||
Документ сначала разбирается на frontmatter и body, затем body режется на секции через markdown chunker.
|
||||
Для каждой секции создается отдельная запись слоя.
|
||||
Нарезка идет по разделам документа.
|
||||
Только в fallback-сценарии, когда markdown-структура не найдена, используется нарезка по фиксированным текстовым чанкам.
|
||||
|
||||
Фиксация в БД:
|
||||
| Атрибут в `metadata_json` | Описание | Источник |
|
||||
|---|---|---|
|
||||
| `document_id` | идентификатор документа-источника | `frontmatter.id`, иначе путь файла |
|
||||
| `type` | тип документа из frontmatter | `frontmatter.type` |
|
||||
| `module` | модуль документа | `frontmatter.module` |
|
||||
| `domain` | домен документа | `frontmatter.domain` |
|
||||
| `subdomain` | поддомен документа | `frontmatter.subdomain` |
|
||||
| `tags` | теги документа | `frontmatter.tags` |
|
||||
| `section_path` | полный путь секции в иерархии заголовков | результат `MarkdownDocChunker` |
|
||||
| `section_title` | заголовок текущей секции | результат `MarkdownDocChunker` |
|
||||
| `order` | порядок секции внутри документа | результат `MarkdownDocChunker` |
|
||||
| `doc_kind` | классификация документа, например `readme`, `spec`, `runbook` | `DocsClassifier.classify(path)` |
|
||||
| `source_path` | исходный путь документа | путь файла |
|
||||
| `artifact_type` | тип артефакта, здесь `DOCS` | константа builder |
|
||||
|
||||
Связанные классы:
|
||||
`DocsIndexingPipeline`, `DocsContentParser`, `MarkdownDocChunker`, `DocsDocumentBuilder`
|
||||
|
||||
### `D1_DOCUMENT_CATALOG`
|
||||
|
||||
Задача:
|
||||
Хранит карточку документа как точку входа в документ и его краткое описание.
|
||||
|
||||
Формирование:
|
||||
Источник данных - frontmatter `as is`, summary и doc kind, вычисленный классификатором документации.
|
||||
В `metadata_json` копируются все `key-value` из frontmatter без нормализации и без fallback для frontmatter-атрибутов.
|
||||
Дополнительно в `metadata_json` добавляются служебные поля `source_path`, `summary_text`, `doc_kind`.
|
||||
Атрибут `document_id` добавляется только при наличии `frontmatter.id` (fallback до пути файла не применяется).
|
||||
В `content` попадает summary документа, а не склейка всех частей документа в сплошной текст.
|
||||
|
||||
Фиксация в БД:
|
||||
| Атрибут в `metadata_json` | Описание | Источник |
|
||||
|---|---|---|
|
||||
| `*` frontmatter fields | все поля frontmatter в исходном виде | frontmatter документа |
|
||||
| `document_id` | идентификатор документа, добавляется только если в frontmatter есть `id` | `frontmatter.id` |
|
||||
| `source_path` | исходный путь документа | путь файла |
|
||||
| `summary_text` | краткое содержание документа | секция `# Summary` |
|
||||
| `doc_kind` | классификация документа, например `readme`, `spec`, `runbook` | `DocsClassifier.classify(path)` |
|
||||
|
||||
Связанные классы:
|
||||
`DocsIndexingPipeline`, `DocsFrontmatterParser`, `DocsClassifier`, `DocsContentParser`, `DocsDocumentBuilder`
|
||||
|
||||
### `D2_FACT_INDEX`
|
||||
|
||||
Задача:
|
||||
Хранит атомарные факты в форме `subject-predicate-object` для точного retrieval по утверждениям.
|
||||
|
||||
Формирование:
|
||||
Факты извлекаются из frontmatter и секций документа, после чего каждая найденная тройка превращается в отдельную запись.
|
||||
|
||||
Фиксация в БД:
|
||||
| Атрибут в `metadata_json` | Описание | Источник |
|
||||
|---|---|---|
|
||||
| `fact_id` | идентификатор факта | вычисляется builder из содержимого факта и пути |
|
||||
| `subject_id` | субъект факта | `DocsFactExtractor` |
|
||||
| `predicate` | предикат или тип связи | `DocsFactExtractor` |
|
||||
| `object` | значение или объект факта | `DocsFactExtractor` |
|
||||
| `object_ref` | ссылка на объект, если она выделена отдельно | `DocsFactExtractor` |
|
||||
| `anchor` | место в документе, откуда взят факт | `DocsFactExtractor` |
|
||||
| `tags` | теги факта | `DocsFactExtractor` |
|
||||
| `source_path` | исходный путь документа | путь файла |
|
||||
|
||||
Связанные классы:
|
||||
`DocsIndexingPipeline`, `DocsFactExtractor`, `DocsDocumentBuilder`
|
||||
|
||||
### `D3_ENTITY_CATALOG`
|
||||
|
||||
Задача:
|
||||
Хранит сущности, найденные в документации, чтобы искать документы и связи вокруг конкретной сущности.
|
||||
|
||||
Формирование:
|
||||
Сущности извлекаются из frontmatter документа, после чего каждая сущность сохраняется отдельной записью.
|
||||
|
||||
Фиксация в БД:
|
||||
| Атрибут в `metadata_json` | Описание | Источник |
|
||||
|---|---|---|
|
||||
| `entity_name` | имя сущности | `DocsEntityExtractor` |
|
||||
| `document_id` | идентификатор документа, где найдена сущность | `frontmatter.id`, иначе путь файла |
|
||||
| `document_type` | тип документа-источника | `frontmatter.type` |
|
||||
| `module` | модуль документа | `frontmatter.module` |
|
||||
| `domain` | домен документа | `frontmatter.domain` |
|
||||
| `subdomain` | поддомен документа | `frontmatter.subdomain` |
|
||||
| `tags` | теги документа или сущности | `frontmatter.tags` |
|
||||
| `source_path` | исходный путь документа | путь файла |
|
||||
|
||||
Связанные классы:
|
||||
`DocsIndexingPipeline`, `DocsEntityExtractor`, `DocsDocumentBuilder`
|
||||
|
||||
### `D4_WORKFLOW_INDEX`
|
||||
|
||||
Задача:
|
||||
Хранит workflow и сценарии из документации для ответов про flow, шаги и жизненный цикл процесса.
|
||||
|
||||
Формирование:
|
||||
Workflow извлекаются из detail sections документа и сохраняются как отдельные сценарии.
|
||||
Извлечение идет из структуры `Details -> ## Сценарий`.
|
||||
|
||||
Фиксация в БД:
|
||||
| Атрибут в `metadata_json` | Описание | Источник |
|
||||
|---|---|---|
|
||||
| `workflow_id` | идентификатор сценария | вычисляется builder из названия, anchor и документа |
|
||||
| `document_id` | идентификатор документа-источника | `frontmatter.id`, иначе путь файла |
|
||||
| `workflow_name` | название сценария | блок `Details -> ## Сценарий -> **Название**` |
|
||||
| `preconditions` | предусловия сценария | блок `Details -> ## Сценарий -> **Предусловия**` |
|
||||
| `trigger` | триггер или событие запуска | блок `Details -> ## Сценарий -> **Триггер**` |
|
||||
| `main_flow` | основной сценарий | блок `Details -> ## Сценарий -> **Основной сценарий**` |
|
||||
| `alternative_flow` | альтернативные ветки | блок `Details -> ## Сценарий -> **Альтернативный сценарий**` |
|
||||
| `error_handling` | обработка ошибок | блок `Details -> ## Сценарий -> **Обработка ошибок**` |
|
||||
| `postconditions` | постусловия | блок `Details -> ## Сценарий -> **Постусловие**` |
|
||||
| `source_path` | исходный путь документа | путь файла |
|
||||
|
||||
Связанные классы:
|
||||
`DocsIndexingPipeline`, `DocsWorkflowExtractor`, `DocsDocumentBuilder`
|
||||
|
||||
### `D5_RELATION_GRAPH`
|
||||
|
||||
Задача:
|
||||
Хранит связи между документами и сущностями документации для navigation и related docs retrieval.
|
||||
|
||||
Формирование:
|
||||
Связи извлекаются из frontmatter и сохраняются как отдельные relation edges.
|
||||
|
||||
Фиксация в БД:
|
||||
| Атрибут в `metadata_json` | Описание | Источник |
|
||||
|---|---|---|
|
||||
| `relation_id` | идентификатор связи | вычисляется builder из source, target, relation type и anchor |
|
||||
| `source_id` | источник связи | `frontmatter.id` или source документа в extractor |
|
||||
| `relation_type` | тип связи | `DocsRelationExtractor` |
|
||||
| `target_id` | целевой объект связи | `DocsRelationExtractor` |
|
||||
| `anchor` | место в документе, где обнаружена связь | `DocsRelationExtractor` |
|
||||
| `source_path` | исходный путь документа | путь файла |
|
||||
|
||||
Связанные классы:
|
||||
`DocsIndexingPipeline`, `DocsRelationExtractor`, `DocsDocumentBuilder`
|
||||
|
||||
### `D6_INTEGRATION_INDEX`
|
||||
|
||||
Задача:
|
||||
Хранит прикладные интеграции компонента, API, UI, сущности или внешней системы.
|
||||
Используется для ответов на вопросы вида "какие интеграции есть у компонента".
|
||||
|
||||
Формирование:
|
||||
Интеграции извлекаются из блока `## Integrations` документа.
|
||||
Одна интеграция должна превращаться в отдельную запись слоя.
|
||||
Описание интеграции может быть развернутым, а структурированные атрибуты должны выделяться в словарь.
|
||||
|
||||
Фиксация в БД:
|
||||
| Атрибут в `metadata_json` | Описание | Источник |
|
||||
|---|---|---|
|
||||
| `integration_id` | идентификатор интеграции | вычисляется builder из source, target и anchor |
|
||||
| `source_id` | идентификатор объекта, для которого описана интеграция | `frontmatter.id` документа-источника |
|
||||
| `source_type` | тип исходного объекта | `frontmatter.doc_type` |
|
||||
| `target` | целевой объект интеграции | блок `## Integrations` |
|
||||
| `target_type` | тип целевого объекта, например `api`, `ui`, `entity`, `service`, `external_system` | блок `## Integrations` |
|
||||
| `direction` | направление интеграции | блок `## Integrations` |
|
||||
| `interaction` | тип взаимодействия | блок `## Integrations` |
|
||||
| `via` | технический канал интеграции | блок `## Integrations` |
|
||||
| `purpose` | назначение интеграции | блок `## Integrations` |
|
||||
| `details` | дополнительные атрибуты интеграции в виде словаря | блок `## Integrations` |
|
||||
| `domain` | домен документа | `frontmatter.domain` |
|
||||
| `subdomain` | поддомен документа | `frontmatter.subdomain` |
|
||||
| `source_path` | исходный путь документа | путь файла |
|
||||
| `anchor` | место в документе, где описана интеграция | блок `## Integrations` |
|
||||
|
||||
Связанные классы:
|
||||
`DocsIndexingPipeline`, `DocsIntegrationExtractor`, `DocsDocumentBuilder`
|
||||
|
||||
## Слои CODE
|
||||
|
||||
### `C0_SOURCE_CHUNKS`
|
||||
|
||||
Задача:
|
||||
Хранит фрагменты исходного кода как базовый слой для цитирования, explain и точечной догрузки кода.
|
||||
|
||||
Формирование:
|
||||
Исходный файл режется на кодовые чанки, и для каждого чанка создается отдельная запись.
|
||||
|
||||
Фиксация в БД:
|
||||
| Атрибут в `metadata_json` | Описание | Источник |
|
||||
|---|---|---|
|
||||
| `chunk_index` | порядковый номер чанка в файле | индекс чанка при нарезке |
|
||||
| `chunk_type` | тип чанка, например функция, класс или текстовый блок | `CodeTextChunker` |
|
||||
| `module_or_unit` | модуль, к которому относится chunk | вычисляется из пути файла |
|
||||
| `is_test` | признак тестового файла | `is_test_path(path)` |
|
||||
|
||||
Связанные классы:
|
||||
`CodeIndexingPipeline`, `CodeTextChunker`, `CodeTextDocumentBuilder`
|
||||
|
||||
### `C1_SYMBOL_CATALOG`
|
||||
|
||||
Задача:
|
||||
Хранит символы кода: классы, функции и методы. Используется для поиска по именам и структуре кода.
|
||||
|
||||
Формирование:
|
||||
Символы извлекаются `SymbolExtractor`, и каждый символ сохраняется как отдельная запись.
|
||||
|
||||
Фиксация в БД:
|
||||
| Атрибут в `metadata_json` | Описание | Источник |
|
||||
|---|---|---|
|
||||
| `symbol_id` | идентификатор символа | `SymbolExtractor` |
|
||||
| `qname` | полное квалифицированное имя | `SymbolExtractor` |
|
||||
| `kind` | тип символа: класс, функция, метод | `SymbolExtractor` |
|
||||
| `signature` | сигнатура символа | `SymbolExtractor` |
|
||||
| `parent_symbol_id` | родительский символ | `SymbolExtractor` |
|
||||
| `package_or_module` | модуль или пакет символа | вычисляется из пути файла |
|
||||
| `is_test` | признак тестового файла | `is_test_path(path)` |
|
||||
|
||||
Связанные классы:
|
||||
`CodeIndexingPipeline`, `PythonAstParser`, `SymbolExtractor`, `SymbolDocumentBuilder`
|
||||
|
||||
### `C2_DEPENDENCY_GRAPH`
|
||||
|
||||
Задача:
|
||||
Хранит связи между символами кода: вызовы, импорты, наследование. Используется для анализа зависимостей и flow.
|
||||
|
||||
Формирование:
|
||||
Связи строятся `EdgeExtractor` по AST и списку символов, после чего каждая связь сохраняется отдельной записью.
|
||||
|
||||
Фиксация в БД:
|
||||
| Атрибут в `metadata_json` | Описание | Источник |
|
||||
|---|---|---|
|
||||
| `edge_id` | идентификатор связи | `EdgeExtractor` |
|
||||
| `edge_type` | тип связи: вызов, импорт, наследование | `EdgeExtractor` |
|
||||
| `src_symbol_id` | исходный символ | `EdgeExtractor` |
|
||||
| `src_qname` | полное имя исходного символа | `EdgeExtractor` |
|
||||
| `dst_symbol_id` | целевой символ, если он разрешен | `EdgeExtractor` |
|
||||
| `dst_ref` | текстовая ссылка на целевой символ | `EdgeExtractor` |
|
||||
| `resolution` | статус разрешения связи | `EdgeExtractor` |
|
||||
| `is_test` | признак тестового файла | `is_test_path(path)` |
|
||||
|
||||
Связанные классы:
|
||||
`CodeIndexingPipeline`, `EdgeExtractor`, `EdgeDocumentBuilder`
|
||||
|
||||
### `C3_ENTRYPOINTS`
|
||||
|
||||
Задача:
|
||||
Хранит точки входа приложения: HTTP routes, CLI commands и другие entrypoints.
|
||||
|
||||
Формирование:
|
||||
Детекторы ищут HTTP и CLI точки входа по символам файла, после чего каждый найденный entrypoint сохраняется отдельной записью.
|
||||
|
||||
Фиксация в БД:
|
||||
| Атрибут в `metadata_json` | Описание | Источник |
|
||||
|---|---|---|
|
||||
| `entry_id` | идентификатор точки входа | detector entrypoint model |
|
||||
| `entry_type` | тип точки входа | detector entrypoint model |
|
||||
| `framework` | framework, в котором найдена точка входа | detector entrypoint model |
|
||||
| `route_or_command` | route или команда | detector entrypoint model |
|
||||
| `handler_symbol_id` | идентификатор обработчика | detector entrypoint model |
|
||||
| `handler_symbol` | имя обработчика | detector entrypoint model |
|
||||
| `declaring_symbol` | символ, в котором объявлен entrypoint | detector entrypoint model |
|
||||
| `entrypoint_kind` | вид точки входа | detector entrypoint model |
|
||||
| `http_method` | HTTP-метод | detector entrypoint model |
|
||||
| `route_path` | путь маршрута | detector entrypoint model |
|
||||
| `decorator_text` | текст декоратора или объявления | detector entrypoint model |
|
||||
| `summary_text` | краткое описание точки входа | detector entrypoint model |
|
||||
| `is_test` | признак тестового файла | `is_test_path(path)` |
|
||||
| `lang_payload` | дополнительные данные детектора | detector metadata |
|
||||
| `artifact_type` | тип артефакта, здесь `CODE` | константа builder |
|
||||
|
||||
Связанные классы:
|
||||
`CodeIndexingPipeline`, `EntrypointDetectorRegistry`, `FastApiEntrypointDetector`, `FlaskEntrypointDetector`, `TyperClickEntrypointDetector`, `EntrypointDocumentBuilder`
|
||||
|
||||
### `C4_SEMANTIC_ROLES`
|
||||
|
||||
Задача:
|
||||
Слой объявлен в enum и retrieval-планах как слой семантических ролей кода.
|
||||
|
||||
Формирование:
|
||||
Слой формируется на основе символов, связей, dataflow slices и execution traces.
|
||||
В текущем runtime этот слой не используется как активный маршрут, так как домен `CODE` отключен.
|
||||
|
||||
Фиксация в БД:
|
||||
Смысловые атрибуты слоя сохраняются в `rag_chunks.metadata_json`.
|
||||
Точное краткое описание состава этих атрибутов в текущем документе пока не зафиксировано.
|
||||
|
||||
Связанные классы:
|
||||
`CodeIndexingPipeline`, `SemanticRoleBuilder`, `SemanticRoleDocumentBuilder`
|
||||
@@ -0,0 +1,289 @@
|
||||
## 1. Формат ведения технической документации агентом
|
||||
|
||||
## 1.1. Общие принципы
|
||||
|
||||
Техническая документация, формируемая агентом, должна строиться как система атомарных, не пересекающихся по смыслу документов, связанных между собой явными ссылками.
|
||||
|
||||
Ключевые принципы:
|
||||
- один документ описывает одну сущность или один устойчивый технический аспект;
|
||||
- документ не должен дублировать соседние документы;
|
||||
- общая система знаний должна собираться через ссылки, а не через копипасту;
|
||||
- структура документации должна быть пригодна как для чтения человеком, так и для индексирования в RAG.
|
||||
|
||||
## 1.2. Требования к заголовкам
|
||||
|
||||
- Заголовок должен отражать только суть раздела.
|
||||
- Заголовок не должен содержать метаданные (`id`, `doc_type`, `application`, `platform`, `domain`, `sub_domain`).
|
||||
- Метаданные указываются отдельными строками в теле раздела или в YAML frontmatter.
|
||||
|
||||
Пример:
|
||||
- правильно: `## 6.2 Метод UFS получения списка заказов`
|
||||
- неправильно: `## 6.2 Блок api_method (id=..., platform=ufs)`
|
||||
|
||||
## 1.3. Базовые типы документных единиц
|
||||
|
||||
Базовые типы:
|
||||
- `ui_page`
|
||||
- `api_method`
|
||||
- `logic_block`
|
||||
|
||||
Дополнительно могут использоваться:
|
||||
- `architecture_overview`
|
||||
- `integration_doc`
|
||||
- `domain_entity`
|
||||
- `glossary_item`
|
||||
- `index_page`
|
||||
|
||||
## 1.4. Принцип декомпозиции страниц / файлов
|
||||
|
||||
### Один устойчивый объект - один документ
|
||||
Если объект можно переиспользовать или на него могут ссылаться другие документы, его нужно выносить в отдельный файл.
|
||||
|
||||
### Документы не должны пересекаться по смыслу
|
||||
Если описание повторяется в нескольких местах, нужно выделять общий документ и ссылаться на него.
|
||||
|
||||
### Use case и детали живут раздельно
|
||||
Сценарий описывает поток работы, а детали выносятся в функциональные требования, отдельные блоки логики или контрактные описания.
|
||||
|
||||
## 1.5. Иерархическая организация документации
|
||||
|
||||
Документация должна быть организована как иерархическое дерево каталогов и файлов.
|
||||
|
||||
Пример:
|
||||
|
||||
```text
|
||||
docs/
|
||||
ui/
|
||||
api/
|
||||
logic/
|
||||
domains/
|
||||
integrations/
|
||||
architecture/
|
||||
glossary/
|
||||
errors/
|
||||
```
|
||||
|
||||
## 1.6. Учет связей между документами
|
||||
|
||||
Связи должны быть явными.
|
||||
|
||||
Примеры:
|
||||
- UI-страница ссылается на вызываемые API;
|
||||
- API-документ ссылается на используемые блоки логики;
|
||||
- логический блок ссылается на интеграции;
|
||||
- документ по коду ссылается на системную аналитику, инициировавшую изменения.
|
||||
|
||||
## 1.7. Формат markdown-документов
|
||||
|
||||
Каждый документ состоит из:
|
||||
1. YAML frontmatter;
|
||||
2. Markdown body.
|
||||
|
||||
## 1.8. YAML frontmatter
|
||||
|
||||
### Обязательные поля
|
||||
- `id`
|
||||
- `title`
|
||||
- `doc_type`
|
||||
- `status`
|
||||
- `domain`
|
||||
- `sub_domain`
|
||||
- `related_docs`
|
||||
|
||||
### Рекомендуемые поля
|
||||
- `owner`
|
||||
- `entities`
|
||||
- `tags`
|
||||
- `feature`
|
||||
- `system_analytics_refs`
|
||||
- `source_of_truth`
|
||||
- `related_code`
|
||||
|
||||
### Допустимые значения `doc_type`
|
||||
- `ui_page`
|
||||
- `api_method`
|
||||
- `logic_block`
|
||||
- `architecture_overview`
|
||||
- `integration_doc`
|
||||
- `domain_entity`
|
||||
- `glossary_item`
|
||||
- `index_page`
|
||||
|
||||
### Допустимые значения `status`
|
||||
- `draft`
|
||||
- `in_review`
|
||||
- `approved`
|
||||
- `outdated`
|
||||
- `generated`
|
||||
- `active`
|
||||
|
||||
## 1.9. Синхронизация с системной аналитикой
|
||||
|
||||
Техническая документация строится на основе системной аналитики (features).
|
||||
|
||||
Обязательно учитывать:
|
||||
- концептуальный уровень аналитики;
|
||||
- детализацию технической документации;
|
||||
- согласованность терминов, ролей и интеграционных цепочек.
|
||||
|
||||
Если атрибуты или детали отсутствуют в аналитике:
|
||||
- определить их из текста аналитики;
|
||||
- дополнить данными из репозитория (код, контракты, существующие документы);
|
||||
- зафиксировать итог в документации как явные метаданные и требования.
|
||||
|
||||
## 1.10. Формат body-разделов для блока изменений
|
||||
|
||||
Для секции изменений (по аналогии с разделом `6` в аналитике) использовать единый формат.
|
||||
|
||||
Под корнем секции изменений указывать общие атрибуты:
|
||||
- `domain`
|
||||
- `sub_domain`
|
||||
|
||||
Для каждого подраздела `X.Y` указывать метаданные строками сразу после заголовка:
|
||||
- `id`
|
||||
- `doc_type`
|
||||
- `application`
|
||||
- `platform`
|
||||
|
||||
## 1.11. Различие аналитики и документации
|
||||
|
||||
- Аналитика - концептуальный уровень, упрощенный use case.
|
||||
- Документация - детальный инженерный уровень.
|
||||
|
||||
Для документации:
|
||||
- технический use case должен быть детализированным;
|
||||
- функциональные требования расширяют use case и описывают детали интеграций, логики и поведения;
|
||||
- функциональные требования не должны копировать шаги сценария без добавления новой информации.
|
||||
|
||||
Источник правил:
|
||||
- `src/app/core/agent/processes/v2/doc_rules_v2/common-elements/tech-use-case.md`
|
||||
- `src/app/core/agent/processes/v2/doc_rules_v2/common-elements/fr.md`
|
||||
|
||||
## 1.12. Требования к `ui_page`
|
||||
|
||||
Обязательная структура:
|
||||
- `### Технический use case`
|
||||
- `### Требования к UI`
|
||||
- `### Функциональные требования`
|
||||
- `### Нефункциональные требования`
|
||||
|
||||
### Требования к UI
|
||||
Внутри обязательно отдельно описывать каждую форму UI:
|
||||
- табличное представление;
|
||||
- пустой список (empty state);
|
||||
- ошибка (error state).
|
||||
|
||||
Обязательные правила:
|
||||
- если есть интеграция, обязательно описать показ ошибки;
|
||||
- если показывается список, обязательно описать показ отсутствия данных.
|
||||
|
||||
### UI-элементы
|
||||
UI-поля и элементы в документации описываются строго в таблицах.
|
||||
|
||||
Обязательные колонки (заполнять там, где применимо):
|
||||
- `Код элемента`
|
||||
- `Название и описание`
|
||||
- `Данные`
|
||||
- `Поведение`
|
||||
- `Валидация`
|
||||
|
||||
## 1.13. Пользовательская аналитика для `ui_page`
|
||||
|
||||
События пользовательской аналитики оформляются таблицей:
|
||||
- `Название события`
|
||||
- `Описание`
|
||||
- `Точка вызова`
|
||||
- `Payload`
|
||||
|
||||
## 1.14. Требования к `api_method`
|
||||
|
||||
Обязательная структура:
|
||||
- `### Технический use case`
|
||||
- `### Функциональные требования`
|
||||
- `### Нефункциональные требования`
|
||||
- `### Контракт`
|
||||
|
||||
### Технический use case
|
||||
Оформляется детально по правилам `tech-use-case.md`.
|
||||
|
||||
Обязательные части:
|
||||
- название
|
||||
- предусловия
|
||||
- триггер
|
||||
- основной сценарий
|
||||
- альтернативный сценарий
|
||||
- обработка ошибок
|
||||
- постусловие
|
||||
|
||||
### Функциональные требования
|
||||
Оформляются по правилам `fr.md`:
|
||||
- формат `FR.<номер>. <Название>`;
|
||||
- FR расширяют use case;
|
||||
- FR не дублируют шаги сценария без дополнительной ценности;
|
||||
- для интеграционных шагов FR обязательны.
|
||||
|
||||
## 1.15. Нефункциональные требования для `api_method`
|
||||
|
||||
Разделять на подразделы:
|
||||
- `#### Аудит` (если применимо)
|
||||
- `#### Мониторинг`
|
||||
|
||||
### Мониторинг
|
||||
Оформлять таблицей:
|
||||
- `Метрика`
|
||||
- `Описание`
|
||||
- `Условие срабатывания`
|
||||
|
||||
Правила:
|
||||
- в условиях указывать, при каких состояниях фиксируется событие;
|
||||
- не использовать формулировку вида «точка измерения = метод»;
|
||||
- базово закладывать метрики:
|
||||
- `<METRIC_NAME>_SUCCESS`
|
||||
- `<METRIC_NAME>_FAIL`
|
||||
- `<METRIC_NAME>_BUSINESS_ERROR`
|
||||
|
||||
## 1.16. Распределение ответственности по слоям
|
||||
|
||||
- Проверка ролевой модели пользователя обычно выполняется в `ufs`.
|
||||
- Для `pprb` аудит может не фиксироваться, если это согласовано правилами домена.
|
||||
- Если проверка ролей вынесена в `ufs`, не дублировать этот шаг в use case `pprb`.
|
||||
|
||||
## 1.17. Контракты API
|
||||
|
||||
Контракт может быть:
|
||||
- в markdown-таблицах;
|
||||
- в OpenAPI;
|
||||
- в отдельном контрактном файле.
|
||||
|
||||
Для markdown-контракта минимум:
|
||||
- endpoint/method;
|
||||
- request fields;
|
||||
- required/optional;
|
||||
- constraints;
|
||||
- response;
|
||||
- errors;
|
||||
- auth;
|
||||
- retry;
|
||||
- timeout;
|
||||
- idempotency.
|
||||
|
||||
## 1.18. Integrations-блок
|
||||
|
||||
Если у документа есть интеграции, выделять отдельный `## Integrations`.
|
||||
|
||||
Рекомендуемые атрибуты интеграции:
|
||||
- `target`
|
||||
- `target_type`
|
||||
- `direction`
|
||||
- `interaction`
|
||||
- `via`
|
||||
- `purpose`
|
||||
- `details`
|
||||
|
||||
## 1.19. Общие требования к markdown body
|
||||
|
||||
- В документе должен быть один `H1`, совпадающий с `title`.
|
||||
- Основные разделы - `H2`, подразделы - `H3`.
|
||||
- Не допускать хаотичной вложенности заголовков.
|
||||
- Вместо дублирования использовать ссылки на связанные документы.
|
||||
- Сценарии, правила, ограничения и кодовые привязки держать раздельно.
|
||||
@@ -0,0 +1,185 @@
|
||||
# Системная аналитика
|
||||
|
||||
## Общее описание
|
||||
|
||||
Документ описывает изменения в автоматизированной системе. Пишется системными аналитиками для разработчиков и тестировщиков и проходит согласование с экспертами по архитектуре, безопасности и сопровождению.
|
||||
|
||||
Документ может описывать как новый процесс, так и инкремент доработки существующей функциональности.
|
||||
|
||||
## Требования к заголовкам
|
||||
|
||||
- Заголовок должен отражать суть раздела.
|
||||
- Заголовок не должен содержать лишнюю информацию, которая относится к метаданным (id, doc_type, platform, application и т.д.).
|
||||
- Метаданные указываются отдельными строками в теле раздела.
|
||||
|
||||
## Состав документа
|
||||
|
||||
Каждый раздел верхнего уровня оформляется заголовком уровня `#`.
|
||||
|
||||
### 1. Цели
|
||||
|
||||
- Коротко описать, какую проблему и для кого решаем.
|
||||
- 1-2 предложения.
|
||||
- Не дублировать критерии приемки.
|
||||
|
||||
### 2. Процесс AS IS и TO BE
|
||||
|
||||
- Фокус на пользовательских и бизнес-изменениях.
|
||||
- Не указывать технические детали (платформы, API, внутренние интеграции).
|
||||
|
||||
### 3. Ограничения
|
||||
|
||||
- Ограничения и допущения в техническом и бизнесовом плане.
|
||||
|
||||
### 4. Критерии приемки
|
||||
|
||||
- Описывать с точки зрения пользователя.
|
||||
- Не добавлять технические детали (платформы, API, внутренние компоненты).
|
||||
|
||||
### 5. Архитектура
|
||||
|
||||
Нужно указать:
|
||||
|
||||
- схему контейнеров,
|
||||
- таблицу интеграций,
|
||||
- сквозные интеграционные сценарии.
|
||||
|
||||
Слои:
|
||||
|
||||
- `ui` - web-приложение, клиент.
|
||||
- `ufs` - BFF: аутентификация/авторизация, агрегация и маппинг данных.
|
||||
- `pprb` - backend: API, БД, логика жизненного цикла сущностей.
|
||||
|
||||
#### Диаграмма
|
||||
|
||||
Mermaid-диаграмма должна содержать:
|
||||
|
||||
- основные контейнеры,
|
||||
- названия приложений и платформ,
|
||||
- интеграции между приложениями,
|
||||
- названия вызываемых endpoint или топиков.
|
||||
|
||||
#### Таблица интеграций
|
||||
|
||||
Обязательные колонки:
|
||||
|
||||
- Код
|
||||
- Название endpoint/топика
|
||||
- Источник данных
|
||||
- Потребитель данных
|
||||
- Инициатор вызова
|
||||
- Передаваемые данные
|
||||
|
||||
#### Сквозной интеграционный сценарий
|
||||
|
||||
- Нумерованный список вызовов вида: «Компонент 1 вызывает endpoint в Компонент 2».
|
||||
- Только интеграционная цепочка, без детального разбора логики.
|
||||
|
||||
### 6. Описание изменений
|
||||
|
||||
Раздел состоит из подразделов уровня `##` (например, `6.1`, `6.2`, `6.3`).
|
||||
|
||||
Под корнем раздела `# 6` указываются общие метаданные:
|
||||
|
||||
- `domain`
|
||||
- `sub_domain`
|
||||
|
||||
Для каждого раздела `6.x` обязательно указывать метаданные строками сразу после заголовка:
|
||||
|
||||
- `id`
|
||||
- `doc_type`
|
||||
- `application`
|
||||
- `platform`
|
||||
|
||||
#### 6.x для `ui_page`
|
||||
|
||||
Обязательная структура:
|
||||
|
||||
- `### Технический use case (тезисно)`
|
||||
- `### Требования к UI`
|
||||
- `### Функциональные требования`
|
||||
- `### Нефункциональные требования`
|
||||
|
||||
Требования к разделу `### Требования к UI`:
|
||||
|
||||
- Внутри нужно отдельно описывать каждую UI-форму.
|
||||
- Если есть интеграция, обязательно описать, как показывается ошибка.
|
||||
- Если показываем список, обязательно описать, как показывается отсутствие данных.
|
||||
|
||||
Рекомендуемая детализация UI-форм:
|
||||
|
||||
- табличное представление,
|
||||
- пустой список (empty state),
|
||||
- ошибка (error state).
|
||||
|
||||
Правила описания UI-полей:
|
||||
|
||||
- Поля описывать списком (не таблицей).
|
||||
- Общие правила (например, read-only, поведение при пустом значении) выносить в общий блок, не дублировать для каждого поля.
|
||||
|
||||
Нефункциональные требования для `ui_page`:
|
||||
|
||||
- пользовательская аналитика оформляется таблицей с колонками:
|
||||
- `Название события`
|
||||
- `Описание`
|
||||
- `Точка вызова`
|
||||
- `Payload`
|
||||
|
||||
#### 6.x для `api_method`
|
||||
|
||||
Обязательная структура:
|
||||
|
||||
- `### Технический use case (тезисно)`
|
||||
- `### Функциональные требования`
|
||||
- `### Нефункциональные требования`
|
||||
- `### Контракт метода`
|
||||
|
||||
Правило для функциональных требований:
|
||||
|
||||
- Если дополнительных требований нет (дублируют сценарий), писать: `Не выявлены`.
|
||||
|
||||
Нефункциональные требования:
|
||||
|
||||
- Разделять на подразделы:
|
||||
- `#### Аудит` (если применимо)
|
||||
- `#### Мониторинг`
|
||||
|
||||
Для `Мониторинг` использовать таблицу с колонками:
|
||||
|
||||
- `Метрика`
|
||||
- `Описание`
|
||||
- `Условие срабатывания`
|
||||
|
||||
Важно:
|
||||
|
||||
- В мониторинге описывать условия срабатывания, а не «точку измерения = метод».
|
||||
- Базово закладывать 3 метрики:
|
||||
- `<METRIC_NAME>_SUCCESS`
|
||||
- `<METRIC_NAME>_FAIL`
|
||||
- `<METRIC_NAME>_BUSINESS_ERROR`
|
||||
|
||||
Контракт метода:
|
||||
|
||||
- Для запроса: таблица параметров (`header/query/path`) с колонками: название, тип параметра, тип данных, обязательность, описание, пример.
|
||||
- Для тела JSON (если есть): структура отдельной таблицей.
|
||||
- Для ответа JSON: таблица с колонками: название, тип данных, обязательность, описание, заполнение, пример.
|
||||
|
||||
#### 6.x для `logic_block`
|
||||
|
||||
Обязательная структура:
|
||||
|
||||
- `### Технический use case (тезисно)`
|
||||
- `### Функциональные требования`
|
||||
- `### Нефункциональные требования`
|
||||
|
||||
## Дополнительные правила по слоям
|
||||
|
||||
- Проверка ролевой модели пользователя обычно выполняется на уровне `ufs`.
|
||||
- Для `pprb` аудит может не фиксироваться, если это правило принято для конкретной фичи/домена.
|
||||
- Если проверка ролей вынесена в `ufs`, не дублировать этот шаг в сценарии `pprb`.
|
||||
|
||||
## Термины
|
||||
|
||||
- Аудит: события, которые фиксируют действия пользователя и позволяют ответить на вопрос «кто, что, когда сделал».
|
||||
- Мониторинг: технические события/метрики для контроля стабильности и поиска сбоев.
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
# MVP: процесс v1
|
||||
|
||||
## 1. Общее описание
|
||||
|
||||
Запрос пользователя обрабатывается цепочкой API → рантайм агента → зарегистрированный процесс версии `v1` → один workflow из трёх последовательных шагов. Процесс **не** обращается к RAG и **не** маршрутизирует интенты: текст сообщения передаётся в LLM по фиксированному промпту. Ответ агента — результат генерации с лёгкой постобработкой (trim).
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph api [API]
|
||||
RS[RequestService]
|
||||
end
|
||||
subgraph runtime [Agent runtime]
|
||||
AR[AgentRuntime]
|
||||
PR[ProcessRunner]
|
||||
end
|
||||
subgraph v1 [Процесс v1]
|
||||
P1[V1Process]
|
||||
WG[V1FlowMainGraph]
|
||||
end
|
||||
subgraph wf [Workflow v1.flow_main]
|
||||
S1[PrepareUserMessageStep]
|
||||
S2[GenerateAnswerStep]
|
||||
S3[FinalizeAnswerStep]
|
||||
end
|
||||
LLM[AgentLlmService]
|
||||
RS --> AR
|
||||
AR --> PR
|
||||
PR --> P1
|
||||
P1 --> WG
|
||||
WG --> S1 --> S2 --> S3
|
||||
S2 --> LLM
|
||||
```
|
||||
|
||||
Клиент создаёт запрос с `process_version: v1`. `AgentRuntime` поднимает `RuntimeExecutionContext` (запрос, сессия, publisher, trace), выбирает `V1Process` из реестра и вызывает `run`. `V1Process` собирает `V1FlowContext` и прогоняет линейный граф: подготовка текста, один вызов LLM, финализация строки ответа. Итог попадает в `ProcessResult.answer` и дальше в ответ пользователю.
|
||||
|
||||
---
|
||||
|
||||
## 2. Шаги и контракты
|
||||
|
||||
### 2.1. Вход в процесс: `V1Process.run`
|
||||
|
||||
| | |
|
||||
|--|--|
|
||||
| **Название** | Запуск процесса v1 |
|
||||
| **Задача** | Собрать контекст workflow и выполнить граф до готового ответа. |
|
||||
| **Вход** | `RuntimeExecutionContext`: `request` (в т.ч. `message`), `session`, `publisher`, `trace`. |
|
||||
| **Выход** | `ProcessResult` с полем `answer: str`. |
|
||||
| **Как работает** | Создаётся `V1FlowContext` с `prompt_name` по умолчанию `v1_flow_main.answer`. Вызывается `V1FlowMainGraph.run`. Возвращается ответ из контекста workflow. |
|
||||
|
||||
Код: `src/app/core/agent/processes/v1/process.py`.
|
||||
|
||||
---
|
||||
|
||||
### 2.2. Шаг workflow: `PrepareUserMessageStep`
|
||||
|
||||
| | |
|
||||
|--|--|
|
||||
| **Название** | Подготовка сообщения пользователя |
|
||||
| **Задача** | Сформировать строку, которая уйдёт в LLM как пользовательский ввод. |
|
||||
| **Вход** | `V1FlowContext` с заполненным `runtime` и `prompt_name`. |
|
||||
| **Выход** | Тот же контекст с `prepared_message: str`. |
|
||||
| **Как работает** | Берётся `context.runtime.request.message` и обрезаются пробелы по краям (`strip`). Результат пишется в `prepared_message`. Других преобразований нет. |
|
||||
|
||||
Код: `src/app/core/agent/processes/v1/workflow/flow_main/steps/prepare_user_message_step.py`.
|
||||
|
||||
---
|
||||
|
||||
### 2.3. Шаг workflow: `GenerateAnswerStep`
|
||||
|
||||
| | |
|
||||
|--|--|
|
||||
| **Название** | Вызов LLM |
|
||||
| **Задача** | Сгенерировать ответ по выбранному промпту и подготовленному сообщению. |
|
||||
| **Вход** | `V1FlowContext` с `prepared_message`, `prompt_name`, `runtime.trace` для модуля LLM. |
|
||||
| **Выход** | Контекст с `answer: str` (сырой ответ модели). |
|
||||
| **Как работает** | Асинхронно в пуле потоков вызывается `AgentLlmService.generate(prompt_name, prepared_message, ...)`. В trace подключается модуль `workflow.v1.llm`. Идентификатор запроса передаётся в `log_context` для логов. |
|
||||
|
||||
Код: `src/app/core/agent/processes/v1/workflow/flow_main/steps/generate_answer_step.py`.
|
||||
|
||||
---
|
||||
|
||||
### 2.4. Шаг workflow: `FinalizeAnswerStep`
|
||||
|
||||
| | |
|
||||
|--|--|
|
||||
| **Название** | Финализация ответа |
|
||||
| **Задача** | Нормализовать строку ответа перед выдачей пользователю. |
|
||||
| **Вход** | `V1FlowContext` с заполненным `answer` после LLM. |
|
||||
| **Выход** | Контекст с обновлённым `answer`. |
|
||||
| **Как работает** | К ответу применяется `strip()` по краям. Другой логики нет. |
|
||||
|
||||
Код: `src/app/core/agent/processes/v1/workflow/flow_main/steps/finalize_answer_step.py`.
|
||||
|
||||
---
|
||||
|
||||
### 2.5. Транспорт: `WorkflowGraph` (v1)
|
||||
|
||||
Граф для v1 использует стандартный `WorkflowGraph`: на каждом шаге пишутся события `workflow_started`, `step_started`, `step_completed`, `workflow_completed` в `runtime_traces` через `context.runtime.trace`.
|
||||
|
||||
Код: `src/app/core/agent/utils/workflow/graph.py`, обёртка `V1FlowMainGraph` в `src/app/core/agent/processes/v1/workflow/flow_main/graph.py`.
|
||||
@@ -0,0 +1,33 @@
|
||||
Нужно реализовать 2 вещи
|
||||
|
||||
Создать процесс внесения изменений в файл документации
|
||||
Создать контекст этого процесса
|
||||
|
||||
Контекст наполнять атрибутами
|
||||
что-то явно задано, фоллбэк через ллм
|
||||
|
||||
|
||||
|
||||
Написать тестовую аналитику - круд над сущностью
|
||||
фронт, ефс, ппрб
|
||||
Все в своей БД
|
||||
Атрибуты сущности задать в требованиях
|
||||
|
||||
|
||||
|
||||
|
||||
Аналитика имеет структуру
|
||||
Внутри модули - один модуль на правку одного файла.
|
||||
|
||||
|
||||
Модуль извлекается из аналитики парсером и из него формируется задача на редактирование файла
|
||||
если парсер не сработал - фоллбэк ан ллм
|
||||
|
||||
|
||||
|
||||
Процесс редактирования работает стандартно
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
# MVP: процесс v2
|
||||
|
||||
## 1. Общее описание
|
||||
|
||||
Процесс v2 в текущем MVP ориентирован в первую очередь на **документацию проекта**, но роутер также поддерживает `GENERAL / GENERAL_QA / SUMMARY` для общих обзорных вопросов. Для документных веток нужна активная RAG-сессия с проиндексированными документами.
|
||||
|
||||
Это **узкий MVP**, а не полная target architecture. Поддерживаются три маршрута:
|
||||
|
||||
- `GENERAL`
|
||||
- `GENERAL_QA`
|
||||
- `SUMMARY`
|
||||
- `DOCS`
|
||||
- `DOC_EXPLAIN`
|
||||
- `SUMMARY`
|
||||
- `FIND_FILES`
|
||||
|
||||
Запрос проходит следующие смысловые этапы:
|
||||
|
||||
1. проверка готовности сессии;
|
||||
2. intent routing;
|
||||
3. формирование retrieval-параметров;
|
||||
4. retrieval из `DOCS RAG`;
|
||||
5. минимальная сборка evidence;
|
||||
6. запуск task-focused workflow нужной ветки;
|
||||
7. формирование ответа.
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph api [API]
|
||||
RS[RequestService]
|
||||
end
|
||||
subgraph runtime [Agent runtime]
|
||||
AR[AgentRuntime]
|
||||
PR[ProcessRunner]
|
||||
end
|
||||
subgraph v2 [Процесс v2]
|
||||
P2[V2Process]
|
||||
IR[V2IntentRouter]
|
||||
POL[V2RetrievalPolicyResolver]
|
||||
AD[V2RagRetrievalAdapter]
|
||||
RSR[RagSessionRetriever]
|
||||
ASM[DocsEvidenceAssembler]
|
||||
end
|
||||
subgraph rag [Пакет rag]
|
||||
RR[RagRepository]
|
||||
end
|
||||
subgraph wf [Workflow]
|
||||
SUM[DocsExplainSummaryGraph]
|
||||
FF[DocsExplainFindFilesGraph]
|
||||
end
|
||||
LLM[AgentLlmService]
|
||||
RS --> AR --> PR --> P2
|
||||
P2 --> IR --> POL --> AD --> RSR --> RR
|
||||
AD --> ASM
|
||||
ASM --> SUM
|
||||
ASM --> FF
|
||||
SUM --> LLM
|
||||
```
|
||||
|
||||
Клиент указывает `process_version: v2`. Без `active_rag_session_id` в сессии процесс возвращает сообщение об ошибке. Иначе выполняется цепочка:
|
||||
|
||||
маршрутизация → `RetrievalPlan` → retrieval строк из `DOCS RAG` → минимальная сборка evidence → ветвление по `subintent` → запуск workflow.
|
||||
|
||||
### Реализованные домены, интенты и сабинтенты
|
||||
|
||||
В коде заданы константы `V2Domain`, `V2Intent`, `V2Subintent`. Сейчас процесс intentionally ограничен одной рабочей областью.
|
||||
|
||||
| Уровень | Значение (строка) | Реализация |
|
||||
|--------|-------------------|------------|
|
||||
| **Домен (routing_domain)** | `DOCS` | Единственный поддерживаемый домен: документация проекта. |
|
||||
| **Интент** | `DOC_EXPLAIN` | Единственный интент: объяснение по документации. |
|
||||
| **Сабинтент** | `SUMMARY` | Объяснение темы по SUMMARY-блокам документации. |
|
||||
| **Сабинтент** | `FIND_FILES` | Поиск путей к документам, где описана нужная сущность или тема. |
|
||||
|
||||
Итого в текущем MVP реализована **одна** рабочая тройка домен×интент: `DOCS` + `DOC_EXPLAIN`, с **двумя** ветками по сабинтенту.
|
||||
|
||||
---
|
||||
|
||||
## 2. Этапы вне workflow (внутри `V2Process.run`)
|
||||
|
||||
### 2.1. `V2IntentRouter.route`
|
||||
|
||||
| | |
|
||||
|--|--|
|
||||
| **Название** | Маршрутизация запроса (v2) |
|
||||
| **Задача** | Определить домен, интент, subintent и извлечь якоря из текста. |
|
||||
| **Вход** | `user_query: str` (текст сообщения пользователя). |
|
||||
| **Выход** | `V2RouteResult`: `routing_domain`, `intent`, `subintent`, `user_query`, `normalized_query`, `target_terms`, `anchors` (`V2RouteAnchors`), `confidence`. |
|
||||
| **Как работает** | Router реализован по схеме **LLM-first**: `normalization` → `target_terms`/`anchors extraction` → `LLM router` → `deterministic validator` → `fallback`. LLM является **основным селектором маршрута**. Deterministic-слой больше не выбирает маршрут по умолчанию: он отвечает только за extraction, валидацию enum/комбинаций и fallback при сломанном или невалидном ответе LLM. В trace пишется событие `intent_routed`. |
|
||||
|
||||
Код: `src/app/core/agent/processes/v2/intent_router/router.py`, `modules/normalizer.py`, `modules/target_terms.py`, `modules/anchors.py`, `routers/llm.py`, `routers/validator.py`, `routers/fallback.py`.
|
||||
|
||||
---
|
||||
|
||||
### 2.2. `V2RetrievalPolicyResolver.resolve`
|
||||
|
||||
| | |
|
||||
|--|--|
|
||||
| **Название** | Политика retrieval для v2 |
|
||||
| **Задача** | По результату роутинга выбрать профиль, список слоёв RAG и лимит строк выдачи. |
|
||||
| **Вход** | `V2RouteResult`. |
|
||||
| **Выход** | `RetrievalPlan`: `profile`, `layers`, `limit`, опционально `filters`. |
|
||||
| **Как работает** | Это отдельный смысловой шаг между routing и retrieval. Он не ходит в БД и не извлекает данные, а только подготавливает параметры поиска. Для `FIND_FILES` выбирается один профиль слоёв и лимит, для `SUMMARY` — другой. Лог: `retrieval_plan_resolved`. |
|
||||
|
||||
Код: `src/app/core/agent/processes/v2/retrieval/policy_resolver.py`.
|
||||
|
||||
---
|
||||
|
||||
### 2.3. `V2RagRetrievalAdapter` → `RagSessionRetriever.retrieve`
|
||||
|
||||
| | |
|
||||
|--|--|
|
||||
| **Название** | Загрузка сырых строк из RAG по плану |
|
||||
| **Задача** | Делегировать поиск в единственную реализацию retrieval в пакете `rag`. |
|
||||
| **Вход** | `rag_session_id`, `query_text` (нормализованный запрос), `RetrievalPlan`. |
|
||||
| **Выход** | `list[dict]` — строки чанков в формате `RagRepository.retrieve` (поля `path`, `layer`, `metadata`, и т.д.). |
|
||||
| **Как работает** | Выполняется retrieval по уже сформированному плану: профиль, список слоёв и лимит. На этом шаге происходит только извлечение сырых строк из `DOCS RAG`. Лог: `rag_rows_fetched`. |
|
||||
|
||||
Код адаптера: `src/app/core/agent/processes/v2/retrieval/v2_rag_adapter.py`.
|
||||
Код API: `src/app/core/rag/retrieval/session_retriever.py`.
|
||||
|
||||
---
|
||||
|
||||
### 2.4. `DocsEvidenceAssembler`
|
||||
|
||||
| | |
|
||||
|--|--|
|
||||
| **Название** | Сборка evidence для задачи |
|
||||
| **Задача** | Превратить сырые строки retrieval в списки summary или кандидатов файлов с дедупом и скорингом. |
|
||||
| **Вход** | Список строк `rows`, `V2RouteResult` (для `target_terms`). |
|
||||
| **Выход** | `list[RetrievedSummary]` или `list[RetrievedFile]`. |
|
||||
| **Как работает** | Это **минимальная evidence-проверка**, достаточная для MVP. Для `SUMMARY` отбрасываются записи без summary-текста и summary-like секции, затем применяется дедуп и простой скоринг по терминам. Для `FIND_FILES` остаются только релевантные пути документов, также с дедупом и простым скорингом. Здесь нет сложной многоступенчатой валидации: задача шага — отфильтровать очевидный шум и передать в workflow компактное evidence. Лог: `evidence_assembled`. |
|
||||
|
||||
Код: `src/app/core/agent/processes/v2/evidence/assembler.py`.
|
||||
|
||||
---
|
||||
|
||||
## 3. Шаги workflow
|
||||
|
||||
Текущие workflow являются **task-focused**: каждая ветка решает одну узкую прикладную задачу и не содержит общей универсальной логики для всех типов вопросов.
|
||||
|
||||
### 3.1. Ветка `SUMMARY`: `GenerateSummaryAnswerStep`
|
||||
|
||||
| | |
|
||||
|--|--|
|
||||
| **Название** | Сборка ответа по summary |
|
||||
| **Задача** | Сформировать ответ пользователю по найденным SUMMARY-блокам или сообщить об отсутствии. |
|
||||
| **Вход** | `DocsExplainSummaryContext`: `runtime`, `route`, `rag_session_id`, `prompt_name`, `documents` (список `RetrievedSummary`). |
|
||||
| **Выход** | Контекст с `answer: str`, `prompt_input` при успешном вызове LLM. |
|
||||
| **Как работает** | Workflow получает уже отобранные summary-документы. Если документов нет — возвращает честный fallback-ответ. Иначе собирает prompt input из запроса пользователя и найденных summary-блоков и вызывает LLM. Workflow не занимается retrieval и не строит retrieval-план: он решает только задачу генерации ответа по уже подготовленному evidence. |
|
||||
|
||||
Код: `src/app/core/agent/processes/v2/workflows/docs_explain_summary/steps/generate_summary_answer_step.py`.
|
||||
Граф: `DocsExplainSummaryGraph` (`V2WorkflowGraph`).
|
||||
|
||||
---
|
||||
|
||||
### 3.2. Ветка `FIND_FILES`: `FinalizeFindFilesAnswerStep`
|
||||
|
||||
| | |
|
||||
|--|--|
|
||||
| **Название** | Сборка списка файлов |
|
||||
| **Задача** | Вывести пользователю markdown-список путей к файлам документации. |
|
||||
| **Вход** | `DocsExplainFindFilesContext`: `runtime`, `route`, `rag_session_id`, `files` (`RetrievedFile`). |
|
||||
| **Выход** | Контекст с `answer: str`. |
|
||||
| **Как работает** | Workflow получает уже собранный список файлов и формирует финальный ответ. Если файлов нет — возвращает fallback. Если файлы есть — отдает детерминированный список путей. Эта ветка intentionally не использует LLM, потому что задача сводится к выдаче путей, а не к генерации объяснения. |
|
||||
|
||||
Код: `src/app/core/agent/processes/v2/workflows/docs_explain_find_files/steps/finalize_find_files_answer_step.py`.
|
||||
Граф: `DocsExplainFindFilesGraph` (`V2WorkflowGraph`).
|
||||
|
||||
---
|
||||
|
||||
### 3.3. Транспорт: `V2WorkflowGraph`
|
||||
|
||||
| | |
|
||||
|--|--|
|
||||
| **Название** | Workflow v2 с буфером trace |
|
||||
| **Задача** | Выполнить шаги без пошаговых `step_started`/`step_completed` в trace; один раз сбросить сводку. |
|
||||
| **Вход** | Контекст workflow (`DocsExplainSummaryContext` или `DocsExplainFindFilesContext`). |
|
||||
| **Выход** | Обновлённый контекст. |
|
||||
| **Как работает** | Для каждого шага: `trace_input` до `run`, затем `run`, затем `trace_output`; записи копятся в список. В trace уходят `workflow_started`, затем `workflow_trace_flushed` с массивом шагов, затем `workflow_completed`. Статусы пользователю публикуются через `publisher` как и раньше. |
|
||||
|
||||
Код: `src/app/core/agent/processes/v2/workflows/v2_workflow_graph.py`.
|
||||
|
||||
---
|
||||
|
||||
## 4. Сборка в приложении
|
||||
|
||||
В `ModularApplication` создаются `RagSessionRetriever`, `V2RagRetrievalAdapter`, `V2RetrievalPolicyResolver`, `DocsEvidenceAssembler` и передаются в `V2Process` (см. `src/app/core/application.py`).
|
||||
|
||||
---
|
||||
|
||||
## 5. Итоговая концептуальная схема текущего MVP
|
||||
|
||||
В концептуальном виде текущий `v2` работает так:
|
||||
|
||||
1. **Session check**
|
||||
Проверка, что есть активная RAG-сессия проекта.
|
||||
|
||||
2. **LLM-first intent routing**
|
||||
Нормализация, extraction (`target_terms`, `anchors`), затем основной выбор маршрута через LLM.
|
||||
|
||||
3. **Deterministic validation + fallback**
|
||||
Проверка enum/комбинации маршрута и fallback только если LLM не ответил или вернул невалидный маршрут.
|
||||
|
||||
4. **Retrieval parameter planning**
|
||||
Формирование профиля поиска, слоёв и лимитов.
|
||||
|
||||
5. **RAG retrieval**
|
||||
Загрузка сырых строк из `DOCS RAG`.
|
||||
|
||||
6. **Minimal evidence assembly**
|
||||
Дедуп, базовый скоринг, отбор полезных summary или файлов.
|
||||
|
||||
7. **Task-focused workflow**
|
||||
Узкая ветка `SUMMARY` или `FIND_FILES`.
|
||||
|
||||
8. **Final response**
|
||||
Либо explanation через LLM, либо детерминированный список файлов.
|
||||
|
||||
Это и есть актуальная архитектура **узкого MVP**, синхронизированная с текущей реализацией.
|
||||
@@ -0,0 +1,346 @@
|
||||
# V2IntentRouter Architecture
|
||||
|
||||
## 1. Архитектура
|
||||
|
||||
Текущий `V2IntentRouter` реализован как **LLM-first router**.
|
||||
Deterministic-слой не выбирает маршрут по умолчанию и используется только для:
|
||||
|
||||
- preprocessing
|
||||
- validation ответа LLM
|
||||
- fallback, если LLM не ответил или вернул невалидный маршрут
|
||||
|
||||
Актуальные компоненты:
|
||||
|
||||
- `router.py`
|
||||
Главная точка входа и оркестратор пайплайна.
|
||||
|
||||
- `modules/normalizer.py`
|
||||
Нормализация текста запроса в `normalized_query`.
|
||||
|
||||
- `modules/target_terms.py`
|
||||
Извлечение retrieval-oriented `target_terms`, `endpoint_paths`, `matched_aliases`, `alias_docs`.
|
||||
|
||||
- `modules/anchors.py`
|
||||
Извлечение `anchors` и marker-сигналов для fallback и downstream retrieval.
|
||||
|
||||
- `routers/route_catalog.py`
|
||||
Каталог допустимых маршрутов (`allowed_routes`).
|
||||
|
||||
- `routers/llm.py`
|
||||
Основной LLM-router. Получает нормализованный запрос, `target_terms`, `anchors` и список допустимых маршрутов.
|
||||
|
||||
- `routers/validator.py`
|
||||
Deterministic validator для enum-значений, комбинации маршрута и базовой нормализации `confidence`.
|
||||
|
||||
- `routers/confidence.py`
|
||||
Пост-обработка confidence после ответа LLM.
|
||||
|
||||
- `routers/fallback.py`
|
||||
Fallback-маршрутизация, если LLM не ответил или ответ не прошёл validator.
|
||||
|
||||
- `routers/prompts.yml`
|
||||
Prompt-контракт для LLM-router.
|
||||
|
||||
## 2. Контракт
|
||||
|
||||
### Вход
|
||||
|
||||
- `user_query: str`
|
||||
|
||||
### Выход
|
||||
|
||||
`V2RouteResult`:
|
||||
|
||||
- `routing_domain: str`
|
||||
- `intent: str`
|
||||
- `subintent: str`
|
||||
- `user_query: str`
|
||||
- `normalized_query: str`
|
||||
- `target_terms: list[str]`
|
||||
- `anchors: V2RouteAnchors`
|
||||
- `confidence: float`
|
||||
- `routing_mode: str`
|
||||
- `llm_router_used: bool`
|
||||
- `reason_short: str`
|
||||
|
||||
`V2RouteAnchors`:
|
||||
|
||||
- `entity_names: list[str]`
|
||||
- `file_names: list[str]`
|
||||
- `endpoint_paths: list[str]`
|
||||
- `target_doc_hints: list[str]`
|
||||
- `matched_aliases: list[str]`
|
||||
- `process_domain: str | None`
|
||||
- `process_subdomain: str | None`
|
||||
|
||||
## 3. Поддерживаемые домены, интенты и сабинтенты
|
||||
|
||||
### Домены
|
||||
|
||||
- `DOCS`
|
||||
- `GENERAL`
|
||||
|
||||
### Интенты
|
||||
|
||||
- `DOC_EXPLAIN`
|
||||
- `GENERAL_QA`
|
||||
|
||||
### Сабинтенты
|
||||
|
||||
- `SUMMARY`
|
||||
- `FIND_FILES`
|
||||
|
||||
### Допустимые маршруты
|
||||
|
||||
- `GENERAL / GENERAL_QA / SUMMARY`
|
||||
- `DOCS / DOC_EXPLAIN / SUMMARY`
|
||||
- `DOCS / DOC_EXPLAIN / FIND_FILES`
|
||||
|
||||
Эти маршруты централизованно заданы в `routers/route_catalog.py`.
|
||||
|
||||
## 4. Актуальный флоу
|
||||
|
||||
Пайплайн обработки запроса:
|
||||
|
||||
1. `router.py` принимает `user_query`.
|
||||
2. `modules/normalizer.py` строит `normalized_query`.
|
||||
3. `modules/target_terms.py` извлекает:
|
||||
- `target_terms`
|
||||
- `endpoint_paths`
|
||||
- `matched_aliases`
|
||||
- `alias_docs`
|
||||
4. `modules/anchors.py` строит:
|
||||
- `anchors`
|
||||
- `file_markers`
|
||||
- `architecture_markers`
|
||||
- `logic_markers`
|
||||
- `domain_markers`
|
||||
- `endpoint_markers`
|
||||
5. `router.py` собирает `QueryFeatures`.
|
||||
6. `routers/llm.py` вызывается как **основной селектор маршрута**.
|
||||
7. `routers/validator.py` проверяет:
|
||||
- что значения входят в допустимые enum
|
||||
- что комбинация маршрута разрешена
|
||||
- что `confidence` можно привести к `float`
|
||||
8. `routers/confidence.py` корректирует confidence на основе силы сигналов.
|
||||
9. Если ответ LLM валиден, возвращается `V2RouteResult` с `routing_mode="llm_default"`.
|
||||
10. Если LLM не ответил, вернул сломанный JSON или невалидный маршрут, `routers/fallback.py` строит fallback route:
|
||||
- `FIND_FILES`, если есть `file_markers`
|
||||
- `DOCS / DOC_EXPLAIN / SUMMARY`, если есть docs-oriented anchors
|
||||
- иначе `GENERAL / GENERAL_QA / SUMMARY`
|
||||
|
||||
## 5. Компоненты по флоу
|
||||
|
||||
### `router.py`
|
||||
|
||||
- Задача
|
||||
Оркестрировать полный routing pipeline.
|
||||
|
||||
- Как решает
|
||||
Последовательно вызывает:
|
||||
- normalizer
|
||||
- target terms extractor
|
||||
- anchor extractor
|
||||
- LLM router
|
||||
- validator
|
||||
- confidence adjuster
|
||||
- fallback router
|
||||
|
||||
- Вход
|
||||
`user_query: str`
|
||||
|
||||
- Выход
|
||||
`V2RouteResult`
|
||||
|
||||
### `modules/normalizer.py`
|
||||
|
||||
- Задача
|
||||
Привести запрос к стабильной форме для анализа.
|
||||
|
||||
- Как решает
|
||||
Схлопывает лишние пробелы через `" ".join(...split())`.
|
||||
|
||||
- Вход
|
||||
`user_query: str`
|
||||
|
||||
- Выход
|
||||
`normalized_query: str`
|
||||
|
||||
### `modules/target_terms.py`
|
||||
|
||||
- Задача
|
||||
Построить **чистое retrieval-поле** `target_terms`.
|
||||
|
||||
- Как решает
|
||||
Использует позитивную модель отбора и включает в `target_terms` только:
|
||||
- endpoint paths
|
||||
- identifier-like tokens
|
||||
- alias canonical terms
|
||||
- domain terms
|
||||
|
||||
Исключаются:
|
||||
- question words
|
||||
- intent words
|
||||
- filler/noisy words
|
||||
- marker words
|
||||
- короткие токены `< 3`, если это не endpoint или alias
|
||||
- битые path-like токены
|
||||
|
||||
Дополнительно:
|
||||
- lowercase
|
||||
- trim punctuation по краям
|
||||
- dedupe
|
||||
- ограничение до `7` элементов
|
||||
- приоритет: endpoints → identifiers → aliases → domain terms
|
||||
|
||||
- Вход
|
||||
`normalized_query: str`
|
||||
|
||||
- Выход
|
||||
`TargetTermsAnalysis`:
|
||||
- `target_terms`
|
||||
- `endpoint_paths`
|
||||
- `matched_aliases`
|
||||
- `alias_docs`
|
||||
|
||||
### `modules/anchors.py`
|
||||
|
||||
- Задача
|
||||
Построить `anchors` и marker-сигналы, не смешивая их с `target_terms`.
|
||||
|
||||
- Как решает
|
||||
Извлекает:
|
||||
- `entity_names` из PascalCase-like токенов
|
||||
- `file_names` только по жёстким правилам:
|
||||
- `*.md`, `*.yaml`, `*.yml`, `*.json`
|
||||
- `docs/...`, `doc/...`, `documentation/...`
|
||||
- `endpoint_paths` из `TargetTermsAnalysis`
|
||||
- `target_doc_hints` из alias docs, endpoint map и marker-сигналов
|
||||
|
||||
Marker-сигналы живут отдельно:
|
||||
- `file_markers`
|
||||
- `architecture_markers`
|
||||
- `logic_markers`
|
||||
- `domain_markers`
|
||||
- `endpoint_markers`
|
||||
|
||||
- Вход
|
||||
- `normalized_query: str`
|
||||
- `TargetTermsAnalysis`
|
||||
|
||||
- Выход
|
||||
`AnchorAnalysis`
|
||||
|
||||
### `routers/route_catalog.py`
|
||||
|
||||
- Задача
|
||||
Держать один источник истины для допустимых маршрутов.
|
||||
|
||||
- Как решает
|
||||
Возвращает:
|
||||
- список `allowed_routes` для payload LLM
|
||||
- проверку допустимости комбинации `routing_domain + intent + subintent`
|
||||
|
||||
### `routers/llm.py`
|
||||
|
||||
- Задача
|
||||
Выбрать маршрут через LLM как основной селектор.
|
||||
|
||||
- Как решает
|
||||
Формирует JSON payload из:
|
||||
- `normalized_query`
|
||||
- `target_terms`
|
||||
- `anchors`
|
||||
- `allowed_routes`
|
||||
|
||||
Затем:
|
||||
- вызывает LLM
|
||||
- парсит JSON
|
||||
- возвращает сырой candidate route без deterministic business-routing
|
||||
|
||||
- Вход
|
||||
- `normalized_query: str`
|
||||
- `target_terms: list[str]`
|
||||
- `anchors: dict`
|
||||
|
||||
- Выход
|
||||
`dict | None`
|
||||
|
||||
### `routers/validator.py`
|
||||
|
||||
- Задача
|
||||
Deterministic validation ответа LLM.
|
||||
|
||||
- Как решает
|
||||
Проверяет:
|
||||
- что `routing_domain`, `intent`, `subintent` заполнены
|
||||
- что комбинация маршрута входит в `route_catalog`
|
||||
- что `confidence` можно привести к числу
|
||||
|
||||
- Вход
|
||||
`dict | None`
|
||||
|
||||
- Выход
|
||||
Валидированный `dict | None`
|
||||
|
||||
### `routers/confidence.py`
|
||||
|
||||
- Задача
|
||||
Сделать confidence осмысленным после ответа LLM.
|
||||
|
||||
- Как решает
|
||||
Корректирует confidence:
|
||||
- `-0.1`, если нет strong anchors
|
||||
- `-0.1`, если запрос короткий или vague
|
||||
- `+0.05`, если есть явный signal (`file_markers`, `endpoint_paths`, `endpoint_markers`)
|
||||
- затем clamp в диапазон `0.0..1.0`
|
||||
|
||||
- Вход
|
||||
- `confidence: float`
|
||||
- `QueryFeatures`
|
||||
|
||||
- Выход
|
||||
`confidence: float`
|
||||
|
||||
### `routers/fallback.py`
|
||||
|
||||
- Задача
|
||||
Построить deterministic fallback, если LLM невалиден.
|
||||
|
||||
- Как решает
|
||||
Правила:
|
||||
- есть `file_markers` → `DOCS / DOC_EXPLAIN / FIND_FILES`
|
||||
- есть docs-signals (`endpoint_paths`, `target_doc_hints`, `matched_aliases`, marker groups) → `DOCS / DOC_EXPLAIN / SUMMARY`
|
||||
- иначе → `GENERAL / GENERAL_QA / SUMMARY`
|
||||
|
||||
- Вход
|
||||
- `user_query: str`
|
||||
- `QueryFeatures`
|
||||
- `anchors: V2RouteAnchors`
|
||||
- `llm_attempted: bool`
|
||||
|
||||
- Выход
|
||||
`V2RouteResult`
|
||||
|
||||
### `routers/prompts.yml`
|
||||
|
||||
- Задача
|
||||
Задать LLM-router контракт ответа и guidance по confidence.
|
||||
|
||||
- Как решает
|
||||
Ограничивает модель только `allowed_routes` и требует JSON с полями:
|
||||
- `routing_domain`
|
||||
- `intent`
|
||||
- `subintent`
|
||||
- `confidence`
|
||||
- `reason_short`
|
||||
|
||||
## 6. Ключевые инварианты
|
||||
|
||||
- LLM является default router.
|
||||
- Deterministic-слой не принимает основной routing decision.
|
||||
- `target_terms` содержат только retrieval-useful terms.
|
||||
- `anchors` не содержат `terms`.
|
||||
- `/health` и другие endpoint paths не должны попадать в `file_names`, если это не файл с расширением.
|
||||
- `file_names` содержат только реальные file/doc paths.
|
||||
- Fallback используется только если LLM недоступен или вернул невалидный маршрут.
|
||||
@@ -0,0 +1,316 @@
|
||||
# V2RetrievalPolicyResolver Architecture
|
||||
|
||||
## 1. Роль компонента
|
||||
|
||||
`V2RetrievalPolicyResolver` это deterministic bridge между `V2IntentRouter` и docs-RAG retrieval.
|
||||
|
||||
Компонент работает поверх уже готового `V2RouteResult` и не делает повторную интерпретацию пользовательского текста:
|
||||
|
||||
- не вызывает LLM;
|
||||
- не меняет `intent` и `subintent`;
|
||||
- не ранжирует документы;
|
||||
- не собирает evidence.
|
||||
|
||||
Его задача: собрать один `RetrievalPlan` с полями:
|
||||
|
||||
- `profile`
|
||||
- `layers`
|
||||
- `limit`
|
||||
- `filters`
|
||||
|
||||
## 2. Зависимости
|
||||
|
||||
Актуальная реализация опирается на:
|
||||
|
||||
- `src/app/core/agent/processes/v2/retrieval/policy_resolver.py`
|
||||
- `src/app/core/agent/processes/v2/anchor_signals.py`
|
||||
- `src/app/core/agent/processes/v2/models.py`
|
||||
- `src/app/core/rag/contracts/enums.py`
|
||||
- `src/app/core/agent/processes/v2/retrieval/v2_rag_adapter.py`
|
||||
- `src/app/core/rag/retrieval/session_retriever.py`
|
||||
- `src/app/core/rag/persistence/repository.py`
|
||||
- `src/app/core/rag/persistence/query_repository.py`
|
||||
- `src/app/core/rag/persistence/retrieval_statement_builder.py`
|
||||
|
||||
## 3. Входной контракт
|
||||
|
||||
Resolver использует:
|
||||
|
||||
- `route.intent`
|
||||
- `route.subintent`
|
||||
- `route.anchors.entity_names`
|
||||
- `route.anchors.file_names`
|
||||
- `route.anchors.endpoint_paths`
|
||||
- `route.anchors.target_doc_hints`
|
||||
- `route.anchors.matched_aliases`
|
||||
- `route.anchors.process_domain`
|
||||
- `route.anchors.process_subdomain`
|
||||
|
||||
`route.target_terms` в текущей реализации profile/filter branching не влияет.
|
||||
|
||||
## 4. Верхнеуровневый branching
|
||||
|
||||
`resolve(route)` имеет три ветки:
|
||||
|
||||
1. `GENERAL_QA` -> `general_qa_grounded_summary`
|
||||
2. `FIND_FILES` -> `file_lookup`
|
||||
3. иначе -> docs summary branch
|
||||
|
||||
Инварианты:
|
||||
|
||||
- `GENERAL_QA` всегда остаётся general profile;
|
||||
- `FIND_FILES` всегда остаётся `file_lookup`;
|
||||
- resolver всегда возвращает один валидный `RetrievalPlan`.
|
||||
|
||||
## 5. Внутренняя декомпозиция
|
||||
|
||||
Текущая реализация разбита на два helper-класса.
|
||||
|
||||
### `_AnchorTermCollector`
|
||||
|
||||
Собирает термы для `prefer_like_patterns`.
|
||||
|
||||
Источники:
|
||||
|
||||
- basename из `target_doc_hints`
|
||||
- `endpoint_paths`
|
||||
- `file_names`
|
||||
- `entity_names`
|
||||
- `matched_aliases`
|
||||
- `process_domain`
|
||||
- `process_subdomain`
|
||||
|
||||
Все значения нормализуются в lower-case и превращаются в SQL-like patterns вида `"%term%"`.
|
||||
|
||||
Для `FIND_FILES` действует отдельное правило:
|
||||
|
||||
- если есть `target_doc_hints`, `prefer_like_patterns` строится только по basename hints;
|
||||
- иначе используется общий набор collected terms.
|
||||
|
||||
### `_RouteFilterBuilder`
|
||||
|
||||
Собирает `filters` для трёх веток:
|
||||
|
||||
- `general_filters(route)`
|
||||
- `summary_filters(route)`
|
||||
- `find_files_filters(route)`
|
||||
|
||||
Дополнительно содержит path selection:
|
||||
|
||||
- `_summary_prefixes(route)`
|
||||
- `_find_files_prefixes(route)`
|
||||
- `_find_files_prefer_prefixes(route)`
|
||||
|
||||
## 6. Signal detection
|
||||
|
||||
Summary profile и часть path preferences зависят от `anchor_signal_types(route)`.
|
||||
|
||||
Сигналы вычисляются так:
|
||||
|
||||
- `FIND_FILES`
|
||||
- если `route.subintent == FIND_FILES`
|
||||
- `API_ENDPOINT`
|
||||
- если есть `endpoint_paths`
|
||||
- или в `target_doc_hints` / `file_names` / `matched_aliases` встречаются маркеры `"/api/"`, `"api"`, `"endpoint"`
|
||||
- `ARCHITECTURE`
|
||||
- если в `target_doc_hints` / `file_names` / `matched_aliases` встречаются `"/architecture/"`, `"architecture"`, `"arch"`
|
||||
- `LOGIC_FLOW`
|
||||
- если в `target_doc_hints` / `file_names` / `matched_aliases` встречаются `"/logic/"`, `"logic"`, `"workflow"`, `"flow"`, `"process"`
|
||||
- `DOMAIN_ENTITY`
|
||||
- если есть `entity_names`
|
||||
- или в `target_doc_hints` / `file_names` / `matched_aliases` встречаются `"/domains/"`, `"domain"`, `"entity"`, `"component"`
|
||||
|
||||
Важно:
|
||||
|
||||
- `process_domain` и `process_subdomain` сейчас **не участвуют** в signal detection;
|
||||
- они влияют только на filters и `prefer_like_patterns`.
|
||||
|
||||
## 7. Summary profile selection
|
||||
|
||||
Метод `_summary_profile(route)` использует:
|
||||
|
||||
- `meaningful = anchor_signal_types(route) - {FIND_FILES}`
|
||||
|
||||
Правило:
|
||||
|
||||
- если meaningful signal не ровно один -> `docs_summary_generic`
|
||||
- если ровно один:
|
||||
- `API_ENDPOINT` -> `docs_summary_api_endpoint`
|
||||
- `ARCHITECTURE` -> `docs_summary_architecture`
|
||||
- `LOGIC_FLOW` -> `docs_summary_logic_flow`
|
||||
- `DOMAIN_ENTITY` -> `docs_summary_domain_entity`
|
||||
|
||||
Следствие:
|
||||
|
||||
- конфликт API + architecture -> generic;
|
||||
- API + entity -> generic;
|
||||
- weak/no signals -> generic.
|
||||
|
||||
## 8. Profiles, layers, limits
|
||||
|
||||
### `general_qa_grounded_summary`
|
||||
|
||||
- condition: `route.intent == GENERAL_QA`
|
||||
- layers: `[D1_DOCUMENT_CATALOG, D0_DOC_CHUNKS]`
|
||||
- limit: `8`
|
||||
|
||||
### `file_lookup`
|
||||
|
||||
- condition: `route.subintent == FIND_FILES`
|
||||
- layers: `[D1_DOCUMENT_CATALOG, D3_ENTITY_CATALOG]`
|
||||
- limit: `12`
|
||||
|
||||
### `docs_summary_api_endpoint`
|
||||
|
||||
- layers: `[D1_DOCUMENT_CATALOG, D2_FACT_INDEX, D0_DOC_CHUNKS]`
|
||||
- limit: `8`
|
||||
|
||||
### `docs_summary_logic_flow`
|
||||
|
||||
- layers: `[D4_WORKFLOW_INDEX, D1_DOCUMENT_CATALOG, D0_DOC_CHUNKS]`
|
||||
- limit: `8`
|
||||
|
||||
### `docs_summary_domain_entity`
|
||||
|
||||
- layers: `[D3_ENTITY_CATALOG, D1_DOCUMENT_CATALOG, D0_DOC_CHUNKS]`
|
||||
- limit: `8`
|
||||
|
||||
### `docs_summary_architecture`
|
||||
|
||||
- layers: `[D1_DOCUMENT_CATALOG, D5_RELATION_GRAPH, D0_DOC_CHUNKS]`
|
||||
- limit: `8`
|
||||
|
||||
### `docs_summary_generic`
|
||||
|
||||
- layers: `[D1_DOCUMENT_CATALOG, D0_DOC_CHUNKS]`
|
||||
- limit: `8`
|
||||
|
||||
## 9. Filters by branch
|
||||
|
||||
### General branch
|
||||
|
||||
`general_filters(route)` возвращает:
|
||||
|
||||
- `prefer_path_prefixes = ["docs/architecture/", "docs/"]`
|
||||
- `prefer_like_patterns = ["%readme.md%", "%overview%"]`
|
||||
- `target_doc_hints = list(route.anchors.target_doc_hints)`
|
||||
|
||||
Это обзорный, но не узкий plan: hard `path_prefixes` здесь нет.
|
||||
|
||||
### Summary branch
|
||||
|
||||
`summary_filters(route)` всегда включает:
|
||||
|
||||
- `target_doc_hints`
|
||||
- `metadata.domain`, если есть `process_domain`
|
||||
- `metadata.subdomain`, если есть `process_subdomain`
|
||||
- `prefer_path_prefixes`
|
||||
- `prefer_like_patterns`
|
||||
|
||||
Дополнительно:
|
||||
|
||||
- если есть `API_ENDPOINT` signal, добавляется hard `path_prefixes = ["docs/api/", "docs/"]`
|
||||
|
||||
`prefer_path_prefixes` для summary:
|
||||
|
||||
- API -> `["docs/api/", "docs/"]`
|
||||
- ARCHITECTURE -> `["docs/architecture/", "docs/"]`
|
||||
- LOGIC_FLOW -> `["docs/logic/", "docs/architecture/", "docs/"]`
|
||||
- DOMAIN_ENTITY -> `["docs/domains/", "docs/", "docs/api/"]`
|
||||
- empty signals -> `["docs/"]`
|
||||
|
||||
Если сигналов несколько, prefixes объединяются и dedupe-ятся с сохранением порядка.
|
||||
|
||||
### FIND_FILES branch
|
||||
|
||||
`find_files_filters(route)` всегда включает:
|
||||
|
||||
- `target_doc_hints`
|
||||
- `metadata.domain`, если есть `process_domain`
|
||||
- `metadata.subdomain`, если есть `process_subdomain`
|
||||
- `path_prefixes`
|
||||
- `prefer_path_prefixes`
|
||||
- `prefer_like_patterns`
|
||||
|
||||
`path_prefixes` для `FIND_FILES` выбираются по приоритету:
|
||||
|
||||
1. директории из `target_doc_hints`
|
||||
2. директории из `file_names`, если путь начинается с `docs/`
|
||||
3. signal-based fallback:
|
||||
- API -> `["docs/api/", "docs/"]`
|
||||
- ARCHITECTURE -> `["docs/architecture/", "docs/"]`
|
||||
- LOGIC_FLOW -> `["docs/logic/", "docs/"]`
|
||||
- DOMAIN_ENTITY -> `["docs/domains/", "docs/"]`
|
||||
4. default -> `["docs/"]`
|
||||
|
||||
`prefer_path_prefixes` для `FIND_FILES`:
|
||||
|
||||
- начинается с `path_prefixes`
|
||||
- если есть `process_domain` или `process_subdomain`, дополнительно добавляет:
|
||||
- `"docs/domains/"`
|
||||
- `"docs/logic/"`
|
||||
|
||||
## 10. Hard и soft сигналы в текущей реализации
|
||||
|
||||
В терминах текущего кода:
|
||||
|
||||
Hard-ish / narrowing filters:
|
||||
|
||||
- `path_prefixes`
|
||||
- `metadata.domain`
|
||||
- `metadata.subdomain`
|
||||
|
||||
Soft preferences:
|
||||
|
||||
- `prefer_path_prefixes`
|
||||
- `prefer_like_patterns`
|
||||
|
||||
Отдельно:
|
||||
|
||||
- `target_doc_hints` всегда сохраняются в `RetrievalPlan.filters`, но **не маппятся напрямую** в `RagRepository.retrieve(...)` как SQL hard filter.
|
||||
|
||||
То есть сейчас `target_doc_hints` это не прямой DB filter, а downstream anchor для других шагов пайплайна и для deterministic exact-doc seeding logic.
|
||||
|
||||
## 11. Интеграция с retrieval stack
|
||||
|
||||
Следующий слой после resolver теперь исполняет plan не напрямую в `V2Process`, а через `V2RagRetrievalAdapter`.
|
||||
|
||||
`V2RagRetrievalAdapter.fetch_rows(...)` использует `RetrievalPlan` так:
|
||||
|
||||
- читает `filters["target_doc_hints"]` из самого плана;
|
||||
- делает exact-path seed через `retrieve_exact_files(...)`;
|
||||
- для missing hints делает substring fallback через `retrieve_chunks_by_path_substrings(...)`;
|
||||
- затем делает обычный semantic retrieve через `RagSessionRetriever.retrieve(...)`;
|
||||
- объединяет exact / substring / semantic rows через dedupe merge.
|
||||
|
||||
Это важный сдвиг: execution strategy теперь зависит от **контракта `RetrievalPlan`**, а не от скрытой route-specific логики внутри `V2Process`.
|
||||
|
||||
`RagSessionRetriever._map_filters()` прокидывает в `RagRepository.retrieve(...)`:
|
||||
|
||||
- `path_prefixes`
|
||||
- `exclude_path_prefixes`
|
||||
- `exclude_like_patterns`
|
||||
- `prefer_path_prefixes`
|
||||
- `prefer_like_patterns`
|
||||
- `prefer_non_tests`
|
||||
- `metadata_domain` из `filters["metadata.domain"]`
|
||||
- `metadata_subdomain` из `filters["metadata.subdomain"]`
|
||||
|
||||
`RetrievalStatementBuilder.build_retrieve(...)` добавляет SQL predicates:
|
||||
|
||||
- `lower(metadata_json->>'domain') = :metadata_domain`
|
||||
- `lower(metadata_json->>'subdomain') = :metadata_subdomain`
|
||||
|
||||
Таким образом:
|
||||
|
||||
- `process_domain/process_subdomain` реально участвуют в retrieval query;
|
||||
- `target_doc_hints` реально участвуют в retrieval execution strategy на уровне adapter;
|
||||
- `V2RetrievalPolicyResolver` определяет plan contract, а следующий шаг исполняет этот contract более буквально.
|
||||
|
||||
## 12. Актуальные ограничения
|
||||
|
||||
- Логика полностью deterministic.
|
||||
- `target_terms` сейчас не участвуют в branching resolver.
|
||||
- `process_domain/process_subdomain` не влияют на summary profile selection.
|
||||
- API signal добавляет `path_prefixes` даже в generic summary, если среди конфликтующих сигналов присутствует API.
|
||||
- `target_doc_hints` не являются прямым SQL filter внутри обычного `retrieve`, но используются adapter-уровнем для exact-path / substring seeding до semantic retrieval.
|
||||
@@ -0,0 +1,37 @@
|
||||
# Documentation Rules V3
|
||||
|
||||
Этот каталог содержит правила генерации технической документации из системной аналитики.
|
||||
|
||||
## Цель
|
||||
- синхронизировать требования к документации с требованиями к аналитике (`04. Analitycs artefacts - features.md`);
|
||||
- сохранить детальность техдокументации по сравнению с аналитикой;
|
||||
- убрать дублирование структуры и manifest-слоя между разными файлами;
|
||||
- собирать итоговый промпт из модулей: глобальные правила + template с manifest + блоки.
|
||||
|
||||
## Структура
|
||||
- `documentation-rules.md` — верхнеуровневый регламент и порядок сборки.
|
||||
- `global/` — общие правила (заголовки, frontmatter, слой ответственности, мост аналитика->документация).
|
||||
- `common-elements/` — правила для общих блоков (`summary`, `details`, `use case`, `FR`, `NFR`, `UI`, `Contract`).
|
||||
- `templates/` — единственный источник истины для структуры итоговой страницы и manifest-метаданных типа документа.
|
||||
|
||||
## Принцип сборки
|
||||
Для конкретного документа агент собирает единый набор правил из:
|
||||
1. `documentation-rules.md`
|
||||
2. `global/*.md`
|
||||
3. `templates/<doc_type>.template.md`
|
||||
4. `common-elements/*.md`, указанных в frontmatter template
|
||||
|
||||
## Правило без дублирования
|
||||
- `templates/` отвечают за структуру документа, порядок разделов и manifest-метаданные типа.
|
||||
- `common-elements/` отвечают только за правила написания конкретного раздела.
|
||||
- отдельный слой `types/` не нужен, если для типа документа используется один основной template.
|
||||
|
||||
## Формат template-manifest
|
||||
Manifest оформляется в YAML frontmatter самого template.
|
||||
|
||||
Обязательные поля manifest:
|
||||
- `doc_type`
|
||||
- `required_common_elements`
|
||||
|
||||
Рекомендуемые поля:
|
||||
- `special_rules`
|
||||
@@ -0,0 +1,21 @@
|
||||
# API Contract Rules
|
||||
|
||||
## Обязательные части
|
||||
- request parameters (`header/query/path`)
|
||||
- request body (если применимо)
|
||||
- response body
|
||||
- errors
|
||||
- auth
|
||||
- timeout
|
||||
- retry/idempotency (если применимо)
|
||||
|
||||
## Табличный формат
|
||||
Для request/response таблицы должны содержать:
|
||||
- название
|
||||
- тип данных
|
||||
- обязательность
|
||||
- описание
|
||||
- пример
|
||||
|
||||
Для response дополнительно:
|
||||
- заполнение (mapping/логика источника данных)
|
||||
@@ -0,0 +1,17 @@
|
||||
# DB Columns Rules
|
||||
|
||||
## Формат
|
||||
Структура таблицы оформляется таблицей.
|
||||
|
||||
## Обязательные колонки
|
||||
- `Поле`
|
||||
- `Тип`
|
||||
- `Nullable`
|
||||
- `Описание`
|
||||
- `Источник заполнения`
|
||||
- `Использование`
|
||||
|
||||
## Правила
|
||||
- перечислять все ключевые поля таблицы;
|
||||
- для служебных полей (`id`, `created_at`, `updated_at`, `deleted_at`) явно описывать назначение;
|
||||
- если тип или nullable не заданы в аналитике, допускается инженерное предположение с рабочим вариантом.
|
||||
@@ -0,0 +1,16 @@
|
||||
# DB Constraints Rules
|
||||
|
||||
## Что включать
|
||||
- primary key;
|
||||
- unique constraints;
|
||||
- foreign keys;
|
||||
- важные индексы;
|
||||
- бизнес-ограничения на уровне БД.
|
||||
|
||||
## Формат
|
||||
- списком или таблицей;
|
||||
- для каждого индекса и ограничения писать, зачем оно нужно.
|
||||
|
||||
## Правила
|
||||
- если индекс нужен для сценария чтения/пагинации, это должно быть явно сказано;
|
||||
- если точные названия индексов неизвестны, можно использовать осмысленные проектные названия.
|
||||
@@ -0,0 +1,12 @@
|
||||
# DB Table Purpose Rules
|
||||
|
||||
## Что описывать
|
||||
- назначение таблицы;
|
||||
- в каком сценарии она используется;
|
||||
- кто является владельцем данных;
|
||||
- является ли таблица источником истины или производным хранилищем.
|
||||
|
||||
## Формат
|
||||
- 1-3 абзаца без воды;
|
||||
- явно указывать доменную сущность, которую хранит таблица;
|
||||
- если сделаны допущения по БД, фиксировать их отдельной фразой.
|
||||
@@ -0,0 +1,11 @@
|
||||
# DB Usage Rules
|
||||
|
||||
## Что описывать
|
||||
- какие API / logic block / batch job используют таблицу;
|
||||
- какие операции выполняются: read / insert / update / delete;
|
||||
- как таблица участвует в пользовательском сценарии.
|
||||
|
||||
## Правила
|
||||
- ссылки на связанные документы давать по `doc_id` или path;
|
||||
- не дублировать полный use case, а показывать роль таблицы в сценарии;
|
||||
- если таблица используется для пагинации, фильтрации или сортировки, это нужно отметить явно.
|
||||
@@ -0,0 +1,10 @@
|
||||
# Details Rules
|
||||
|
||||
## Назначение
|
||||
Этот файл задает общие правила для секции `## Details`.
|
||||
|
||||
## Правила
|
||||
- `Details` оформляется как `## Details`.
|
||||
- Внутри `Details` используются заголовки уровня `###` и ниже.
|
||||
- Структура `Details` определяется template типа документа.
|
||||
- В `Details` не нужно дублировать навигацию и связи, если они уже есть во frontmatter.
|
||||
@@ -0,0 +1,31 @@
|
||||
# Functional Requirements Rules
|
||||
|
||||
## Формат
|
||||
- `FR.<номер>. <Название>`
|
||||
- Нумерация инкрементальная внутри документа.
|
||||
|
||||
## Правила
|
||||
- FR расширяют шаги сценария.
|
||||
- FR не копируют шаги сценария без добавления новой информации.
|
||||
- Для интеграционных шагов FR обязательны.
|
||||
- Если в сценарии есть вызов внешнего API / сервиса / БД, нужен отдельный FR на интеграцию.
|
||||
|
||||
## FR для интеграционных шагов
|
||||
Для интеграционного FR обязательно раскрывать:
|
||||
- как формируется запрос;
|
||||
- откуда берется каждый значимый атрибут запроса;
|
||||
- какой downstream вызывается;
|
||||
- какой ответ считается успешным;
|
||||
- какие ответы и ситуации считаются бизнес-ошибкой;
|
||||
- какие ситуации считаются технической ошибкой;
|
||||
- как downstream-ответ маппится в контракт текущего слоя.
|
||||
|
||||
## FR для шагов доступа к БД
|
||||
Если шаг читает или пишет БД, FR должен по возможности включать:
|
||||
- таблицу или набор таблиц;
|
||||
- логику фильтрации;
|
||||
- логику сортировки;
|
||||
- логику пагинации;
|
||||
- пример SQL или близкий к рабочему псевдо-SQL.
|
||||
|
||||
Если СУБД и диалект не заданы, допускается сделать рабочее предположение и явно зафиксировать его.
|
||||
@@ -0,0 +1,20 @@
|
||||
# Non-Functional Requirements Rules
|
||||
|
||||
## Для api_method
|
||||
- Подразделы:
|
||||
- `#### Аудит` (если применимо)
|
||||
- `#### Мониторинг`
|
||||
|
||||
## Мониторинг
|
||||
Оформлять таблицей:
|
||||
- `Метрика`
|
||||
- `Описание`
|
||||
- `Условие срабатывания`
|
||||
|
||||
Запрещено:
|
||||
- использовать «точка измерения = метод» вместо условий срабатывания.
|
||||
|
||||
Базовые суффиксы метрик:
|
||||
- `_SUCCESS`
|
||||
- `_FAIL`
|
||||
- `_BUSINESS_ERROR`
|
||||
@@ -0,0 +1,15 @@
|
||||
# SQL Example Rules
|
||||
|
||||
## Назначение
|
||||
Секция показывает пример рабочего SQL для основного сценария использования таблицы.
|
||||
|
||||
## Правила
|
||||
- SQL должен быть близок к рабочему, а не абстрактным псевдокодом;
|
||||
- если диалект БД не указан, допускается выбрать наиболее вероятный вариант и явно зафиксировать допущение;
|
||||
- пример должен отражать реальный сценарий документа: чтение, вставка, обновление или агрегация;
|
||||
- для read-сценариев по возможности показывать фильтрацию, сортировку и пагинацию;
|
||||
- если есть join, нужно кратко пояснить, зачем он нужен.
|
||||
|
||||
## Формат
|
||||
- fenced code block с указанием `sql`;
|
||||
- под кодом 1-3 поясняющих bullets о ключевых условиях, индексах и параметрах.
|
||||
@@ -0,0 +1,10 @@
|
||||
# Summary Rules
|
||||
|
||||
## Назначение
|
||||
Этот файл задает правила для секции `## Summary`.
|
||||
|
||||
## Правила
|
||||
- `Summary` должен быть коротким слоем быстрого контекста.
|
||||
- `Summary` должен объяснять суть документа без длинных деталей.
|
||||
- Предпочтительный формат: краткий список ключевых фактов.
|
||||
- `Summary` не должен дублировать `Details`.
|
||||
@@ -0,0 +1,16 @@
|
||||
# Tech Use Case Rules
|
||||
|
||||
## Обязательные части
|
||||
- название
|
||||
- предусловия
|
||||
- триггер
|
||||
- основной сценарий
|
||||
- альтернативный сценарий
|
||||
- обработка ошибок
|
||||
- постусловие
|
||||
|
||||
## Правила шага
|
||||
- Один шаг = одно предложение до 15-20 слов.
|
||||
- Формат шага: смысловое действие + техническая реализация (endpoint/топик/операция).
|
||||
- Длинные технические детали выносить в FR и ссылаться на FR из шага.
|
||||
- Для интеграционных шагов описание обработки ошибок обязательно.
|
||||
@@ -0,0 +1,22 @@
|
||||
# UI Requirements Rules
|
||||
|
||||
## Структура блока
|
||||
- `### Требования к UI`
|
||||
- Внутри обязательно отдельные формы:
|
||||
- табличное представление
|
||||
- пустой список (empty state)
|
||||
- ошибка (error state)
|
||||
|
||||
## Обязательные правила
|
||||
- Если есть интеграция, обязательно описывать показ ошибки.
|
||||
- Если есть список, обязательно описывать показ отсутствия данных.
|
||||
|
||||
## Описание UI-элементов
|
||||
UI-элементы описываются строго в таблице.
|
||||
|
||||
Обязательные колонки (где применимо):
|
||||
- `Код элемента`
|
||||
- `Название и описание`
|
||||
- `Данные`
|
||||
- `Поведение`
|
||||
- `Валидация`
|
||||
@@ -0,0 +1,7 @@
|
||||
# User Analytics Rules
|
||||
|
||||
События пользовательской аналитики оформлять таблицей:
|
||||
- `Название события`
|
||||
- `Описание`
|
||||
- `Точка вызова`
|
||||
- `Payload`
|
||||
@@ -0,0 +1,45 @@
|
||||
# Documentation Rules V3
|
||||
|
||||
## 1. Общий контракт
|
||||
- Документация строится на основе системной аналитики, но на более детальном уровне.
|
||||
- Заголовки отражают только суть раздела; метаданные в заголовках запрещены.
|
||||
- Метаданные указываются во frontmatter и/или отдельными строками в body.
|
||||
- Структура документа определяется только template соответствующего типа.
|
||||
- Правила написания конкретного раздела определяются только соответствующим `common-elements` файлом.
|
||||
- Manifest типа документа хранится во frontmatter соответствующего template.
|
||||
|
||||
## 2. Источники требований
|
||||
При генерации документа учитывать:
|
||||
- `/Users/alex/Dev_projects_v2/ai driven app process/v2/agent/_process/04. Analitycs artefacts - documentation.md`
|
||||
- `/Users/alex/Dev_projects_v2/ai driven app process/v2/agent/_process/04. Analitycs artefacts - features.md`
|
||||
- правила v2 из `src/app/core/agent/processes/v2/doc_rules_v2`
|
||||
|
||||
## 3. Разрыв аналитика vs документация
|
||||
- Аналитика: концептуальная, укрупненная.
|
||||
- Документация: технически детальная.
|
||||
- Технический use case в документации не копирует аналитический 1-в-1, а детализирует его.
|
||||
- Функциональные требования расширяют сценарий и не дублируют шаги без новой информации.
|
||||
|
||||
## 4. Заполнение пробелов
|
||||
Если атрибуты/детали отсутствуют в аналитике:
|
||||
1. восстановить из формулировок аналитики;
|
||||
2. уточнить по репозиторию (код, контракты, существующие документы);
|
||||
3. зафиксировать в документации явно.
|
||||
|
||||
## 5. Сборка итогового промпта
|
||||
1. Загрузить global-правила.
|
||||
2. Загрузить template типа документа.
|
||||
3. Прочитать YAML frontmatter template как manifest.
|
||||
4. Загрузить общие блоки, указанные в manifest.
|
||||
5. Применить body template как единственный источник структуры.
|
||||
5. Проверить чек-лист совместимости с аналитикой (domain/sub_domain, роли слоев, интеграции, ошибки).
|
||||
|
||||
## 6. Формат manifest типа документа
|
||||
Manifest типа документа хранится во frontmatter `templates/<doc_type>.template.md`.
|
||||
|
||||
Минимальная схема:
|
||||
- `doc_type`
|
||||
- `required_common_elements`
|
||||
|
||||
Дополнительно можно указывать:
|
||||
- `special_rules`
|
||||
@@ -0,0 +1,10 @@
|
||||
# Analytics to Documentation Mapping
|
||||
|
||||
## Принцип
|
||||
- Системная аналитика задает «что».
|
||||
- Документация детализирует «как».
|
||||
|
||||
## Маппинг
|
||||
- Из раздела архитектуры аналитики переносить контейнеры, интеграции и цепочки вызовов.
|
||||
- Из раздела изменений аналитики строить отдельные технические страницы (`ui_page`, `api_method`, `logic_block`).
|
||||
- Если в аналитике упрощенный use case, в документации раскрывать полный технический сценарий по правилам `tech-use-case.md`.
|
||||
@@ -0,0 +1,67 @@
|
||||
# Правила определения путей файлов
|
||||
|
||||
Текущая happy-path реализация строит путь документа по фиксированному шаблону:
|
||||
|
||||
`docs/<domain>/<platform>/<doc_type>/<doc_id>.md`
|
||||
|
||||
Пример:
|
||||
|
||||
`docs/orders/pprb/ui_page/orders.ui.list.md`
|
||||
|
||||
## Источники атрибутов
|
||||
|
||||
Для построения пути используются четыре основных атрибута:
|
||||
|
||||
- `domain`
|
||||
- `application`
|
||||
- `platform`
|
||||
- `doc_type`
|
||||
- `id` как `doc_id`
|
||||
|
||||
Если атрибуты явно указаны в подразделе `6.x`, нужно использовать их.
|
||||
Если атрибут не указан, он может быть взят из общих метаданных аналитики или определен fallback-логикой.
|
||||
|
||||
## Нормализация сегментов
|
||||
|
||||
Каждый сегмент пути нормализуется одинаково:
|
||||
|
||||
- значение переводится в lowercase;
|
||||
- все символы, кроме `a-z`, `0-9`, `.`, `_`, `-`, заменяются на `-`;
|
||||
- ведущие и хвостовые `.` и `-` удаляются.
|
||||
|
||||
Примеры нормализации:
|
||||
|
||||
- `Payment Status` -> `payment-status`
|
||||
- `UFS Orders` -> `ufs-orders`
|
||||
- `crm.mobile` -> `crm.mobile`
|
||||
|
||||
## Значения по умолчанию
|
||||
|
||||
Если после нормализации сегмент пустой, используются fallback-значения:
|
||||
|
||||
- корневая папка: `domain`, иначе `application`, иначе `common`
|
||||
- `platform` -> `web`
|
||||
- `doc_type` -> `misc`
|
||||
- `doc_id` -> `untitled`
|
||||
|
||||
## Что важно в текущей версии
|
||||
|
||||
- для корневой папки сначала используется `domain`;
|
||||
- если `domain` не задан, используется `application`;
|
||||
- `sub_domain` сейчас не участвует в построении пути;
|
||||
- операции `create`, `update`, `delete` работают с одним и тем же правилом вычисления пути;
|
||||
- специальных исключений для разных типов документов пока нет;
|
||||
- отдельные каталоги для `pprb`, `ufs`, `web` задаются только через значение `platform`.
|
||||
|
||||
## Практическое правило для агента
|
||||
|
||||
Если нужно предложить или определить путь новой страницы, агент должен:
|
||||
|
||||
1. определить `application`;
|
||||
2. определить `domain`;
|
||||
3. определить `platform`;
|
||||
4. определить `doc_type`;
|
||||
5. определить стабильный `doc_id`;
|
||||
6. взять корневую папку как `domain`, а если он пустой, то `application`;
|
||||
7. нормализовать все сегменты;
|
||||
8. собрать путь по шаблону `docs/<root>/<platform>/<doc_type>/<doc_id>.md`.
|
||||
@@ -0,0 +1,32 @@
|
||||
# Frontmatter Rules
|
||||
|
||||
## Обязательные поля
|
||||
```yaml
|
||||
id: string
|
||||
title: string
|
||||
doc_type: string
|
||||
domain: string
|
||||
sub_domain: string
|
||||
related_docs: []
|
||||
status: string
|
||||
```
|
||||
|
||||
## Рекомендуемые поля
|
||||
```yaml
|
||||
tags: []
|
||||
entities: []
|
||||
source_of_truth: string
|
||||
related_code: []
|
||||
system_analytics_refs: []
|
||||
```
|
||||
|
||||
## Body-метаданные для секции изменений
|
||||
Под корнем секции изменений указывать:
|
||||
- `domain`
|
||||
- `sub_domain`
|
||||
|
||||
Для каждого подраздела `X.Y` указывать строками:
|
||||
- `id`
|
||||
- `doc_type`
|
||||
- `application`
|
||||
- `platform`
|
||||
@@ -0,0 +1,10 @@
|
||||
# Header Rules
|
||||
|
||||
## Правила
|
||||
- Заголовок описывает только смысл раздела.
|
||||
- Не включать в заголовок: `id`, `doc_type`, `application`, `platform`, `domain`, `sub_domain`.
|
||||
- Метаданные указываются отдельными строками ниже заголовка или во frontmatter.
|
||||
|
||||
## Пример
|
||||
- Правильно: `## 6.2 Метод UFS получения списка заказов`
|
||||
- Неправильно: `## 6.2 Блок api_method (id=..., platform=ufs)`
|
||||
@@ -0,0 +1,10 @@
|
||||
# Layer Responsibility
|
||||
|
||||
- `ui`: отображение, UX, запуск пользовательских сценариев.
|
||||
- `ufs`: авторизация/аутентификация, агрегация, маппинг, оркестрация вызовов.
|
||||
- `pprb`: API, БД, доменная логика backend.
|
||||
|
||||
## Правила согласованности
|
||||
- Проверка ролевой модели пользователя обычно фиксируется на уровне `ufs`.
|
||||
- Если проверка роли вынесена в `ufs`, в `pprb`-сценарии не дублировать этот шаг.
|
||||
- Аудит для `pprb` может отсутствовать, если это явно принято для домена/фичи.
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
doc_type: api_method
|
||||
required_common_elements:
|
||||
- common-elements/summary.md
|
||||
- common-elements/details.md
|
||||
- common-elements/tech-use-case.md
|
||||
- common-elements/fr.md
|
||||
- common-elements/nfr.md
|
||||
- common-elements/api-contract.md
|
||||
special_rules:
|
||||
- Технический use case детализируется по `common-elements/tech-use-case.md`.
|
||||
- FR расширяют use case и не дублируют шаги сценария без новой информации.
|
||||
- Для интеграционных шагов FR обязательны.
|
||||
---
|
||||
|
||||
# <title>
|
||||
|
||||
## Summary
|
||||
Правила оформления: `../common-elements/summary.md`
|
||||
|
||||
## Details
|
||||
Правила оформления: `../common-elements/details.md`
|
||||
|
||||
### Технический use case
|
||||
Правила оформления: `../common-elements/tech-use-case.md`
|
||||
|
||||
### Функциональные требования
|
||||
Правила оформления: `../common-elements/fr.md`
|
||||
|
||||
### Нефункциональные требования
|
||||
Правила оформления: `../common-elements/nfr.md`
|
||||
|
||||
### Контракт
|
||||
Правила оформления: `../common-elements/api-contract.md`
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
doc_type: db_table
|
||||
required_common_elements:
|
||||
- common-elements/summary.md
|
||||
- common-elements/details.md
|
||||
- common-elements/db-purpose.md
|
||||
- common-elements/db-columns.md
|
||||
- common-elements/db-constraints.md
|
||||
- common-elements/db-usage.md
|
||||
- common-elements/sql-example.md
|
||||
special_rules:
|
||||
- Документ описывает одну физическую таблицу БД или materialized view.
|
||||
- Нужно фиксировать назначение таблицы, поля, ограничения, индексы, связи и сценарии использования.
|
||||
- Если точные детали БД не заданы, допустимо сделать рабочие инженерные допущения и явно записать их в документ.
|
||||
---
|
||||
|
||||
# <title>
|
||||
|
||||
## Summary
|
||||
Правила оформления: `../common-elements/summary.md`
|
||||
|
||||
## Details
|
||||
Правила оформления: `../common-elements/details.md`
|
||||
|
||||
### Назначение таблицы
|
||||
Правила оформления: `../common-elements/db-purpose.md`
|
||||
|
||||
### Структура таблицы
|
||||
Правила оформления: `../common-elements/db-columns.md`
|
||||
|
||||
### Ограничения и индексы
|
||||
Правила оформления: `../common-elements/db-constraints.md`
|
||||
|
||||
### Использование в сценариях
|
||||
Правила оформления: `../common-elements/db-usage.md`
|
||||
|
||||
### Пример SQL
|
||||
Правила оформления: `../common-elements/sql-example.md`
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
doc_type: logic_block
|
||||
required_common_elements:
|
||||
- common-elements/summary.md
|
||||
- common-elements/details.md
|
||||
- common-elements/tech-use-case.md
|
||||
- common-elements/fr.md
|
||||
- common-elements/nfr.md
|
||||
special_rules:
|
||||
- Logic block описывает переиспользуемую логику без дублирования UI/API деталей.
|
||||
---
|
||||
|
||||
# <title>
|
||||
|
||||
## Summary
|
||||
Правила оформления: `../common-elements/summary.md`
|
||||
|
||||
## Details
|
||||
Правила оформления: `../common-elements/details.md`
|
||||
|
||||
### Технический use case
|
||||
Правила оформления: `../common-elements/tech-use-case.md`
|
||||
|
||||
### Функциональные требования
|
||||
Правила оформления: `../common-elements/fr.md`
|
||||
|
||||
### Нефункциональные требования
|
||||
Правила оформления: `../common-elements/nfr.md`
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
doc_type: ui_page
|
||||
required_common_elements:
|
||||
- common-elements/summary.md
|
||||
- common-elements/details.md
|
||||
- common-elements/tech-use-case.md
|
||||
- common-elements/ui-requirements.md
|
||||
- common-elements/fr.md
|
||||
- common-elements/user-analytics.md
|
||||
special_rules:
|
||||
- Для списочных страниц обязательно описывать табличное представление, empty state и error state.
|
||||
- UI-элементы описываются в таблицах по правилам `common-elements/ui-requirements.md`.
|
||||
---
|
||||
|
||||
# <title>
|
||||
|
||||
## Summary
|
||||
Правила оформления: `../common-elements/summary.md`
|
||||
|
||||
## Details
|
||||
Правила оформления: `../common-elements/details.md`
|
||||
|
||||
### Технический use case
|
||||
Правила оформления: `../common-elements/tech-use-case.md`
|
||||
|
||||
### Требования к UI
|
||||
Правила оформления: `../common-elements/ui-requirements.md`
|
||||
|
||||
### Функциональные требования
|
||||
Правила оформления: `../common-elements/fr.md`
|
||||
|
||||
### Нефункциональные требования
|
||||
Правила оформления: `../common-elements/user-analytics.md`
|
||||
+1
-1
@@ -27,7 +27,7 @@ services:
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
DATABASE_URL: ${DATABASE_URL}
|
||||
DATABASE_URL: postgresql+psycopg://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}
|
||||
GIGACHAT_AUTH_URL: ${GIGACHAT_AUTH_URL}
|
||||
GIGACHAT_API_URL: ${GIGACHAT_API_URL}
|
||||
GIGACHAT_SCOPE: ${GIGACHAT_SCOPE}
|
||||
|
||||
@@ -1,380 +0,0 @@
|
||||
{
|
||||
"layers": {
|
||||
"C0_SOURCE_CHUNKS": {
|
||||
"retriever": {
|
||||
"class": "RagService",
|
||||
"file": "app/modules/rag/services/rag_service.py",
|
||||
"method": "retrieve"
|
||||
},
|
||||
"indexer": {
|
||||
"class": "CodeTextDocumentBuilder",
|
||||
"file": "app/modules/rag/indexing/code/code_text/document_builder.py",
|
||||
"method": "build"
|
||||
},
|
||||
"input": {
|
||||
"type": "observed shape",
|
||||
"fields": {
|
||||
"rag_session_id": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"query": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"layers": {
|
||||
"type": "implicit list[string]",
|
||||
"required": false,
|
||||
"source": "RagQueryRouter.layers_for_mode('code')"
|
||||
}
|
||||
}
|
||||
},
|
||||
"output": {
|
||||
"type": "list[dict]",
|
||||
"fields": {
|
||||
"source": "string",
|
||||
"content": "string",
|
||||
"layer": "\"C0_SOURCE_CHUNKS\"",
|
||||
"title": "string",
|
||||
"metadata": {
|
||||
"chunk_index": "int",
|
||||
"chunk_type": "\"symbol_block\" | \"window\"",
|
||||
"module_or_unit": "string",
|
||||
"artifact_type": "\"CODE\""
|
||||
},
|
||||
"score": "float | null"
|
||||
}
|
||||
},
|
||||
"examples": {
|
||||
"input": {
|
||||
"rag_session_id": "rag-123",
|
||||
"query": "where is implemented get_user"
|
||||
},
|
||||
"output": {
|
||||
"source": "app/api/users.py",
|
||||
"content": "async def get_user(user_id: str):\n service = UserService()\n return service.get_user(user_id)",
|
||||
"layer": "C0_SOURCE_CHUNKS",
|
||||
"title": "app/api/users.py:get_user",
|
||||
"metadata": {
|
||||
"chunk_index": 0,
|
||||
"chunk_type": "symbol_block",
|
||||
"module_or_unit": "app.api.users",
|
||||
"artifact_type": "CODE"
|
||||
},
|
||||
"score": 0.07
|
||||
}
|
||||
},
|
||||
"defaults": {
|
||||
"retrieve_limit": 8,
|
||||
"embed_batch_size_env": "RAG_EMBED_BATCH_SIZE",
|
||||
"embed_batch_size_default": 16,
|
||||
"window_chunk_size_lines": 80,
|
||||
"window_overlap_lines": 15
|
||||
},
|
||||
"limitations": [
|
||||
"Line spans are stored but not returned in the public retrieval item shape.",
|
||||
"No direct path or namespace filter is exposed through the retrieval endpoint."
|
||||
]
|
||||
},
|
||||
"C1_SYMBOL_CATALOG": {
|
||||
"retriever": {
|
||||
"class": "RagService",
|
||||
"file": "app/modules/rag/services/rag_service.py",
|
||||
"method": "retrieve"
|
||||
},
|
||||
"indexer": {
|
||||
"class": "SymbolDocumentBuilder",
|
||||
"file": "app/modules/rag/indexing/code/symbols/document_builder.py",
|
||||
"method": "build"
|
||||
},
|
||||
"input": {
|
||||
"type": "observed shape",
|
||||
"fields": {
|
||||
"rag_session_id": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"query": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"query_term_expansion": {
|
||||
"type": "list[string]",
|
||||
"required": false,
|
||||
"source": "extract_query_terms(query_text)",
|
||||
"max_items": 6
|
||||
}
|
||||
}
|
||||
},
|
||||
"output": {
|
||||
"type": "list[dict]",
|
||||
"fields": {
|
||||
"source": "string",
|
||||
"content": "string",
|
||||
"layer": "\"C1_SYMBOL_CATALOG\"",
|
||||
"title": "string",
|
||||
"metadata": {
|
||||
"symbol_id": "string",
|
||||
"qname": "string",
|
||||
"kind": "\"class\" | \"function\" | \"method\" | \"const\"",
|
||||
"signature": "string",
|
||||
"decorators_or_annotations": "list[string]",
|
||||
"docstring_or_javadoc": "string | null",
|
||||
"parent_symbol_id": "string | null",
|
||||
"package_or_module": "string",
|
||||
"is_entry_candidate": "bool",
|
||||
"lang_payload": "object",
|
||||
"artifact_type": "\"CODE\""
|
||||
},
|
||||
"score": "float | null"
|
||||
}
|
||||
},
|
||||
"examples": {
|
||||
"input": {
|
||||
"rag_session_id": "rag-123",
|
||||
"query": "where is implemented get_user"
|
||||
},
|
||||
"output": {
|
||||
"source": "app/api/users.py",
|
||||
"content": "function get_user\nget_user(user_id)",
|
||||
"layer": "C1_SYMBOL_CATALOG",
|
||||
"title": "get_user",
|
||||
"metadata": {
|
||||
"symbol_id": "sha256(...)",
|
||||
"qname": "get_user",
|
||||
"kind": "function",
|
||||
"signature": "get_user(user_id)",
|
||||
"decorators_or_annotations": [
|
||||
"router.get"
|
||||
],
|
||||
"docstring_or_javadoc": null,
|
||||
"parent_symbol_id": null,
|
||||
"package_or_module": "app.api.users",
|
||||
"is_entry_candidate": true,
|
||||
"lang_payload": {
|
||||
"async": true
|
||||
},
|
||||
"artifact_type": "CODE"
|
||||
},
|
||||
"score": 0.07
|
||||
}
|
||||
},
|
||||
"defaults": {
|
||||
"retrieve_limit": 8,
|
||||
"layer_rank": 1
|
||||
},
|
||||
"limitations": [
|
||||
"Only Python AST symbols are indexed.",
|
||||
"Cross-file resolution is not implemented.",
|
||||
"parent_symbol_id is an observed qname-like value, not guaranteed to be a symbol hash."
|
||||
]
|
||||
},
|
||||
"C2_DEPENDENCY_GRAPH": {
|
||||
"retriever": {
|
||||
"class": "RagService",
|
||||
"file": "app/modules/rag/services/rag_service.py",
|
||||
"method": "retrieve"
|
||||
},
|
||||
"indexer": {
|
||||
"class": "EdgeDocumentBuilder",
|
||||
"file": "app/modules/rag/indexing/code/edges/document_builder.py",
|
||||
"method": "build"
|
||||
},
|
||||
"input": {
|
||||
"type": "observed shape",
|
||||
"fields": {
|
||||
"rag_session_id": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"query": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"output": {
|
||||
"type": "list[dict]",
|
||||
"fields": {
|
||||
"source": "string",
|
||||
"content": "string",
|
||||
"layer": "\"C2_DEPENDENCY_GRAPH\"",
|
||||
"title": "string",
|
||||
"metadata": {
|
||||
"edge_id": "string",
|
||||
"edge_type": "\"calls\" | \"imports\" | \"inherits\"",
|
||||
"src_symbol_id": "string",
|
||||
"src_qname": "string",
|
||||
"dst_symbol_id": "string | null",
|
||||
"dst_ref": "string | null",
|
||||
"resolution": "\"resolved\" | \"partial\"",
|
||||
"lang_payload": "object",
|
||||
"artifact_type": "\"CODE\""
|
||||
},
|
||||
"score": "float | null"
|
||||
}
|
||||
},
|
||||
"examples": {
|
||||
"input": {
|
||||
"rag_session_id": "rag-123",
|
||||
"query": "how get_user calls service"
|
||||
},
|
||||
"output": {
|
||||
"source": "app/api/users.py",
|
||||
"content": "get_user calls UserService",
|
||||
"layer": "C2_DEPENDENCY_GRAPH",
|
||||
"title": "get_user:calls",
|
||||
"metadata": {
|
||||
"edge_id": "sha256(...)",
|
||||
"edge_type": "calls",
|
||||
"src_symbol_id": "sha256(...)",
|
||||
"src_qname": "get_user",
|
||||
"dst_symbol_id": null,
|
||||
"dst_ref": "UserService",
|
||||
"resolution": "partial",
|
||||
"lang_payload": {
|
||||
"callsite_kind": "function_call"
|
||||
},
|
||||
"artifact_type": "CODE"
|
||||
},
|
||||
"score": 0.11
|
||||
}
|
||||
},
|
||||
"defaults": {
|
||||
"retrieve_limit": 8,
|
||||
"layer_rank": 2,
|
||||
"graph_build_mode": "static_python_ast"
|
||||
},
|
||||
"limitations": [
|
||||
"No traversal API exists.",
|
||||
"Edges are stored as retrievable rows, not as a graph-native store.",
|
||||
"Destination resolution is local to one indexed file."
|
||||
]
|
||||
},
|
||||
"C3_ENTRYPOINTS": {
|
||||
"retriever": {
|
||||
"class": "RagService",
|
||||
"file": "app/modules/rag/services/rag_service.py",
|
||||
"method": "retrieve"
|
||||
},
|
||||
"indexer": {
|
||||
"class": "EntrypointDocumentBuilder",
|
||||
"file": "app/modules/rag/indexing/code/entrypoints/document_builder.py",
|
||||
"method": "build"
|
||||
},
|
||||
"input": {
|
||||
"type": "observed shape",
|
||||
"fields": {
|
||||
"rag_session_id": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"query": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"output": {
|
||||
"type": "list[dict]",
|
||||
"fields": {
|
||||
"source": "string",
|
||||
"content": "string",
|
||||
"layer": "\"C3_ENTRYPOINTS\"",
|
||||
"title": "string",
|
||||
"metadata": {
|
||||
"entry_id": "string",
|
||||
"entry_type": "\"http\" | \"cli\"",
|
||||
"framework": "\"fastapi\" | \"flask\" | \"typer\" | \"click\"",
|
||||
"route_or_command": "string",
|
||||
"handler_symbol_id": "string",
|
||||
"lang_payload": "object",
|
||||
"artifact_type": "\"CODE\""
|
||||
},
|
||||
"score": "float | null"
|
||||
}
|
||||
},
|
||||
"examples": {
|
||||
"input": {
|
||||
"rag_session_id": "rag-123",
|
||||
"query": "which endpoint handles get user"
|
||||
},
|
||||
"output": {
|
||||
"source": "app/api/users.py",
|
||||
"content": "fastapi http \"/users/{user_id}\"",
|
||||
"layer": "C3_ENTRYPOINTS",
|
||||
"title": "\"/users/{user_id}\"",
|
||||
"metadata": {
|
||||
"entry_id": "sha256(...)",
|
||||
"entry_type": "http",
|
||||
"framework": "fastapi",
|
||||
"route_or_command": "\"/users/{user_id}\"",
|
||||
"handler_symbol_id": "sha256(...)",
|
||||
"lang_payload": {
|
||||
"methods": [
|
||||
"GET"
|
||||
]
|
||||
},
|
||||
"artifact_type": "CODE"
|
||||
},
|
||||
"score": 0.05
|
||||
}
|
||||
},
|
||||
"defaults": {
|
||||
"retrieve_limit": 8,
|
||||
"layer_rank": 0
|
||||
},
|
||||
"limitations": [
|
||||
"Detection is decorator-string based.",
|
||||
"No Django, Celery, RQ, or cron entrypoints were found.",
|
||||
"Returned payload does not expose line spans."
|
||||
]
|
||||
}
|
||||
},
|
||||
"retrieval_endpoint": {
|
||||
"entrypoint": {
|
||||
"file": "app/modules/rag_session/module.py",
|
||||
"method": "internal_router.retrieve"
|
||||
},
|
||||
"request": {
|
||||
"type": "dict",
|
||||
"fields": {
|
||||
"rag_session_id": "string | optional if project_id provided",
|
||||
"project_id": "string | optional fallback for rag_session_id",
|
||||
"query": "string"
|
||||
}
|
||||
},
|
||||
"response": {
|
||||
"type": "dict",
|
||||
"fields": {
|
||||
"items": "list[retrieval item]"
|
||||
}
|
||||
},
|
||||
"defaults": {
|
||||
"mode": "docs unless RagQueryRouter detects code hints",
|
||||
"limit": 8,
|
||||
"embedding_provider": "GigaChat embeddings",
|
||||
"fallback_after_embedding_error": true,
|
||||
"fallback_to_docs_when_code_empty": true
|
||||
}
|
||||
},
|
||||
"ranking": {
|
||||
"storage": "PostgreSQL rag_chunks + pgvector",
|
||||
"query_repository": {
|
||||
"class": "RagQueryRepository",
|
||||
"file": "app/modules/rag/persistence/query_repository.py",
|
||||
"method": "retrieve"
|
||||
},
|
||||
"order_by": [
|
||||
"lexical_rank ASC",
|
||||
"test_penalty ASC",
|
||||
"layer_rank ASC",
|
||||
"embedding <=> query_embedding ASC"
|
||||
],
|
||||
"notes": [
|
||||
"lexical_rank is derived from qname/symbol_id/title/path/content matching extracted query terms",
|
||||
"test_penalty is applied only when prefer_non_tests=true",
|
||||
"layer priority is C3 > C1 > C2 > C0 for code retrieval"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,270 +0,0 @@
|
||||
# LLM Inventory
|
||||
|
||||
## Provider and SDK
|
||||
|
||||
- Provider in code: GigaChat / Sber
|
||||
- Local SDK style: custom thin HTTP client over `requests`
|
||||
- Core files:
|
||||
- `app/modules/shared/gigachat/client.py`
|
||||
- `app/modules/shared/gigachat/settings.py`
|
||||
- `app/modules/shared/gigachat/token_provider.py`
|
||||
- `app/modules/agent/llm/service.py`
|
||||
|
||||
There is no OpenAI SDK, Azure SDK, or local model runtime in the current implementation.
|
||||
|
||||
## Configuration
|
||||
|
||||
Model and endpoint configuration are read from environment in `GigaChatSettings.from_env()`:
|
||||
|
||||
- `GIGACHAT_AUTH_URL`
|
||||
- default: `https://ngw.devices.sberbank.ru:9443/api/v2/oauth`
|
||||
- `GIGACHAT_API_URL`
|
||||
- default: `https://gigachat.devices.sberbank.ru/api/v1`
|
||||
- `GIGACHAT_SCOPE`
|
||||
- default: `GIGACHAT_API_PERS`
|
||||
- `GIGACHAT_TOKEN`
|
||||
- required for auth
|
||||
- `GIGACHAT_SSL_VERIFY`
|
||||
- default: `true`
|
||||
- `GIGACHAT_MODEL`
|
||||
- default: `GigaChat`
|
||||
- `GIGACHAT_EMBEDDING_MODEL`
|
||||
- default: `Embeddings`
|
||||
- `AGENT_PROMPTS_DIR`
|
||||
- optional prompt directory override
|
||||
|
||||
PostgreSQL config for retrieval storage is separate:
|
||||
|
||||
- `DATABASE_URL`
|
||||
- default: `postgresql+psycopg://agent:agent@db:5432/agent`
|
||||
|
||||
## Default models
|
||||
|
||||
- Chat/completions model default: `GigaChat`
|
||||
- Embedding model default: `Embeddings`
|
||||
|
||||
## Completion payload
|
||||
|
||||
Observed payload sent by `GigaChatClient.complete(...)`:
|
||||
|
||||
```json
|
||||
{
|
||||
"model": "GigaChat",
|
||||
"messages": [
|
||||
{"role": "system", "content": "<prompt template text>"},
|
||||
{"role": "user", "content": "<runtime user input>"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Endpoint:
|
||||
|
||||
- `POST {GIGACHAT_API_URL}/chat/completions`
|
||||
|
||||
Observed response handling:
|
||||
|
||||
- reads `choices[0].message.content`
|
||||
- if no choices: returns empty string
|
||||
|
||||
## Embeddings payload
|
||||
|
||||
Observed payload sent by `GigaChatClient.embed(...)`:
|
||||
|
||||
```json
|
||||
{
|
||||
"model": "Embeddings",
|
||||
"input": [
|
||||
"<text1>",
|
||||
"<text2>"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Endpoint:
|
||||
|
||||
- `POST {GIGACHAT_API_URL}/embeddings`
|
||||
|
||||
Observed response handling:
|
||||
|
||||
- expects `data` list
|
||||
- maps each `item.embedding` to `list[float]`
|
||||
|
||||
## Parameters
|
||||
|
||||
### Explicitly implemented
|
||||
|
||||
- `model`
|
||||
- `messages`
|
||||
- `input`
|
||||
- HTTP timeout:
|
||||
- completions: `90s`
|
||||
- embeddings: `90s`
|
||||
- auth: `30s`
|
||||
- TLS verification flag:
|
||||
- `verify=settings.ssl_verify`
|
||||
|
||||
### Not implemented in payload
|
||||
|
||||
- `temperature`
|
||||
- `top_p`
|
||||
- `max_tokens`
|
||||
- `response_format`
|
||||
- tools/function calling
|
||||
- streaming
|
||||
- seed
|
||||
- stop sequences
|
||||
|
||||
`ASSUMPTION:` the service uses provider defaults for sampling and output length because these fields are not sent in the request payload.
|
||||
|
||||
## Context and budget limits
|
||||
|
||||
There is no centralized token budget manager in the current code.
|
||||
|
||||
Observed practical limits instead:
|
||||
|
||||
- prompt file text is loaded as-is from disk
|
||||
- user input is passed as-is
|
||||
- RAG context shaping happens outside the LLM client
|
||||
- docs indexing summary truncation:
|
||||
- docs module catalog summary: `4000` chars
|
||||
- docs policy text: `4000` chars
|
||||
- project QA source bundle caps:
|
||||
- top `12` rag items
|
||||
- top `10` file candidates
|
||||
- logging truncation only:
|
||||
- LLM input/output logs capped at `1500` chars for logs
|
||||
|
||||
`ASSUMPTION:` there is no explicit max-context enforcement before chat completion requests. The current system relies on upstream graph logic to keep inputs small enough.
|
||||
|
||||
## Retry, backoff, timeout
|
||||
|
||||
### Timeouts
|
||||
|
||||
- auth: `30s`
|
||||
- chat completion: `90s`
|
||||
- embeddings: `90s`
|
||||
|
||||
### Retry
|
||||
|
||||
- Generic async retry wrapper exists in `app/modules/shared/retry_executor.py`
|
||||
- It retries only:
|
||||
- `TimeoutError`
|
||||
- `ConnectionError`
|
||||
- `OSError`
|
||||
- Retry constants:
|
||||
- `MAX_RETRIES = 5`
|
||||
- backoff: `0.1 * attempt` seconds
|
||||
|
||||
### Important current limitation
|
||||
|
||||
- `GigaChatClient` raises `GigaChatError` on HTTP and request failures.
|
||||
- `RetryExecutor` does not catch `GigaChatError`.
|
||||
- Result: LLM and embeddings calls are effectively not retried by this generic retry helper unless errors are converted upstream.
|
||||
|
||||
## Prompt formation
|
||||
|
||||
Prompt loading is handled by `PromptLoader`:
|
||||
|
||||
- base dir: `app/modules/agent/prompts`
|
||||
- override: `AGENT_PROMPTS_DIR`
|
||||
- file naming convention: `<prompt_name>.txt`
|
||||
|
||||
Prompt composition model today:
|
||||
|
||||
- system prompt:
|
||||
- full contents of selected prompt file
|
||||
- user prompt:
|
||||
- raw runtime input string passed by the caller
|
||||
- no separate developer prompt layer in the application payload
|
||||
|
||||
If a prompt file is missing:
|
||||
|
||||
- fallback system prompt: `You are a helpful assistant.`
|
||||
|
||||
## Prompt templates present
|
||||
|
||||
- `router_intent`
|
||||
- `general_answer`
|
||||
- `project_answer`
|
||||
- `docs_detect`
|
||||
- `docs_strategy`
|
||||
- `docs_plan_sections`
|
||||
- `docs_generation`
|
||||
- `docs_self_check`
|
||||
- `docs_execution_summary`
|
||||
- `project_edits_plan`
|
||||
- `project_edits_hunks`
|
||||
- `project_edits_self_check`
|
||||
|
||||
## Key LLM call entrypoints
|
||||
|
||||
### Composition roots
|
||||
|
||||
- `app/modules/agent/module.py`
|
||||
- builds `GigaChatSettings`
|
||||
- builds `GigaChatTokenProvider`
|
||||
- builds `GigaChatClient`
|
||||
- builds `PromptLoader`
|
||||
- builds `AgentLlmService`
|
||||
- `app/modules/rag_session/module.py`
|
||||
- builds the same provider stack for embeddings used by RAG
|
||||
|
||||
### Main abstraction
|
||||
|
||||
- `AgentLlmService.generate(prompt_name, user_input, log_context=None)`
|
||||
|
||||
### Current generate callsites
|
||||
|
||||
- `app/modules/agent/engine/router/intent_classifier.py`
|
||||
- `router_intent`
|
||||
- `app/modules/agent/engine/graphs/base_graph.py`
|
||||
- `general_answer`
|
||||
- `app/modules/agent/engine/graphs/project_qa_graph.py`
|
||||
- `project_answer`
|
||||
- `app/modules/agent/engine/graphs/docs_graph_logic.py`
|
||||
- `docs_detect`
|
||||
- `docs_strategy`
|
||||
- `docs_plan_sections`
|
||||
- `docs_generation`
|
||||
- `docs_self_check`
|
||||
- `docs_execution_summary`-like usage via summary step
|
||||
- `app/modules/agent/engine/graphs/project_edits_logic.py`
|
||||
- `project_edits_plan`
|
||||
- `project_edits_self_check`
|
||||
- `project_edits_hunks`
|
||||
|
||||
## Logging and observability
|
||||
|
||||
`AgentLlmService` logs:
|
||||
|
||||
- input:
|
||||
- `graph llm input: context=... prompt=... user_input=...`
|
||||
- output:
|
||||
- `graph llm output: context=... prompt=... output=...`
|
||||
|
||||
Log truncation:
|
||||
|
||||
- 1500 chars
|
||||
|
||||
RAG retrieval logs separately in `RagService`, but without embedding vectors.
|
||||
|
||||
## Integration with retrieval
|
||||
|
||||
There are two distinct GigaChat usages:
|
||||
|
||||
1. Chat/completion path for agent reasoning and generation
|
||||
2. Embedding path for RAG indexing and retrieval
|
||||
|
||||
The embedding adapter is `GigaChatEmbedder`, used by:
|
||||
|
||||
- `app/modules/rag/services/rag_service.py`
|
||||
|
||||
## Notable limitations
|
||||
|
||||
- Single provider coupling: chat and embeddings both depend on GigaChat-specific endpoints.
|
||||
- No model routing by scenario.
|
||||
- No tool/function calling.
|
||||
- No centralized prompt token budgeting.
|
||||
- No explicit retry for `GigaChatError`.
|
||||
- No streaming completions.
|
||||
- No structured response mode beyond prompt conventions and downstream parsing.
|
||||
@@ -1,13 +0,0 @@
|
||||
| column | used_by | safe_to_drop | notes |
|
||||
| --- | --- | --- | --- |
|
||||
| `layer` | `USED_BY_CODE_V2`, `USED_BY_DOCS_INDEXING` | no | Core selector for C0-C3 and D1-D4 queries. |
|
||||
| `title` | `USED_BY_CODE_V2`, `USED_BY_DOCS_INDEXING` | no | Used in lexical ranking and prompt evidence labels. |
|
||||
| `metadata_json` | `USED_BY_CODE_V2`, `USED_BY_DOCS_INDEXING` | no | C2/C0 graph lookups and docs metadata depend on it. |
|
||||
| `span_start`, `span_end` | `USED_BY_CODE_V2` | no | Needed for symbol-to-chunk resolution and locations. |
|
||||
| `symbol_id`, `qname`, `kind`, `lang` | `USED_BY_CODE_V2` | no | Used by code indexing, ranking, trace building, and diagnostics. |
|
||||
| `repo_id`, `commit_sha` | `USED_BY_CODE_V2`, `USED_BY_DOCS_INDEXING` | no | Used by indexing/cache and retained for provenance. |
|
||||
| `entrypoint_type`, `framework` | `USED_BY_CODE_V2` | no | Used by C3 filtering and entrypoint diagnostics. |
|
||||
| `doc_kind`, `module_id`, `section_path` | `USED_BY_DOCS_INDEXING` | no | Still written by docs indexing and covered by docs tests. |
|
||||
| `artifact_type`, `section`, `doc_version`, `owner`, `system_component`, `last_modified`, `staleness_score` | `USED_BY_DOCS_INDEXING` | no | File metadata still flows through indexing/cache; left intact for now. |
|
||||
| `rag_doc_id` | `UNUSED` | yes | Written into `rag_chunks` only; no reads in runtime/indexing code. |
|
||||
| `links_json` | `UNUSED` | yes | Stored in `rag_chunks` only; reads exist for `rag_chunk_cache`, not `rag_chunks`. |
|
||||
@@ -1,31 +0,0 @@
|
||||
flowchart TD
|
||||
A["HTTP: POST /internal/rag/retrieve"] --> B["RagModule.internal_router.retrieve(payload)"]
|
||||
B --> C["RagService.retrieve(rag_session_id, query)"]
|
||||
C --> D["RagQueryRouter.resolve_mode(query)"]
|
||||
D --> E["RagQueryRouter.layers_for_mode(mode)"]
|
||||
C --> F["GigaChatEmbedder.embed([query])"]
|
||||
F --> G["GigaChatClient.embed(payload)"]
|
||||
G --> H["POST /embeddings"]
|
||||
C --> I["RagRepository.retrieve(...)"]
|
||||
I --> J["RagQueryRepository.retrieve(...)"]
|
||||
J --> K["PostgreSQL rag_chunks + pgvector"]
|
||||
K --> L["ORDER BY lexical_rank, test_penalty, layer_rank, vector distance"]
|
||||
L --> M["rows: path/content/layer/title/metadata/span/distance"]
|
||||
M --> N["normalize to {source, content, layer, title, metadata, score}"]
|
||||
N --> O["response: {items: [...]}"]
|
||||
|
||||
C --> P["embedding error?"]
|
||||
P -->|yes| Q["RagRepository.fallback_chunks(...)"]
|
||||
Q --> R["latest rows by id DESC"]
|
||||
R --> N
|
||||
|
||||
C --> S["no rows and mode != docs?"]
|
||||
S -->|yes| T["fallback to docs layers"]
|
||||
T --> I
|
||||
|
||||
U["GraphAgentRuntime for project/qa"] --> V["ProjectQaRetrievalGraphFactory._retrieve_context"]
|
||||
V --> C
|
||||
V --> W["ProjectQaSupport.build_source_bundle(...)"]
|
||||
W --> X["source_bundle"]
|
||||
X --> Y["context_analysis"]
|
||||
Y --> Z["answer_composition"]
|
||||
@@ -1,457 +0,0 @@
|
||||
# Retrieval Inventory
|
||||
|
||||
## Scope and method
|
||||
|
||||
This document describes the retrieval and indexing pipeline as implemented in code today. The inventory is based primarily on:
|
||||
|
||||
- `app/modules/rag/services/rag_service.py`
|
||||
- `app/modules/rag/persistence/*.py`
|
||||
- `app/modules/rag/indexing/code/**/*.py`
|
||||
- `app/modules/rag/indexing/docs/**/*.py`
|
||||
- `app/modules/rag_session/module.py`
|
||||
- `app/modules/agent/engine/graphs/project_qa_step_graphs.py`
|
||||
- `app/modules/agent/engine/orchestrator/*.py`
|
||||
|
||||
`ASSUMPTION:` the intended layer semantics are the ones implied by code and tests, not by future architecture plans. This matters because only `C0` through `C3` are materially implemented today; `C4+` exist only as enum constants.
|
||||
|
||||
## Current retrieval pipeline
|
||||
|
||||
1. Retrieval entrypoint is `POST /internal/rag/retrieve` in `app/modules/rag_session/module.py`.
|
||||
2. The endpoint calls `RagService.retrieve(rag_session_id, query)`.
|
||||
3. `RagQueryRouter` chooses `docs` or `code` mode from the raw query text.
|
||||
4. `RagService` computes a single embedding for the full query via `GigaChatEmbedder`.
|
||||
5. `RagQueryRepository.retrieve(...)` runs one SQL query against `rag_chunks` in PostgreSQL with `pgvector`.
|
||||
6. Ranking order is:
|
||||
- lexical rank
|
||||
- test-file penalty
|
||||
- layer rank
|
||||
- vector distance `embedding <=> query_embedding`
|
||||
7. Response items are normalized to `{source, content, layer, title, metadata, score}`.
|
||||
8. If embeddings fail, retrieval falls back to latest chunks from the same layers.
|
||||
9. If code retrieval returns nothing, service falls back to docs layers.
|
||||
|
||||
## Storage and indices
|
||||
|
||||
- Primary store: PostgreSQL from `DATABASE_URL`, configured in `app/modules/shared/db.py`.
|
||||
- Vector extension: `CREATE EXTENSION IF NOT EXISTS vector` in `app/modules/rag/persistence/schema_repository.py`.
|
||||
- Primary table: `rag_chunks`.
|
||||
- Cache tables:
|
||||
- `rag_blob_cache`
|
||||
- `rag_chunk_cache`
|
||||
- `rag_session_chunk_map`
|
||||
- SQL indexes currently created:
|
||||
- `(rag_session_id)`
|
||||
- `(rag_session_id, layer)`
|
||||
- `(rag_session_id, layer, path)`
|
||||
- `(qname)`
|
||||
- `(symbol_id)`
|
||||
- `(module_id)`
|
||||
- `(doc_kind)`
|
||||
- `(entrypoint_type, framework)`
|
||||
|
||||
`ASSUMPTION:` there is no explicit ANN index for the vector column in schema code. The code creates general SQL indexes, but no `ivfflat`/`hnsw` index is defined here.
|
||||
|
||||
## Layer: C0_SOURCE_CHUNKS
|
||||
|
||||
### Implementation
|
||||
|
||||
- Produced by `CodeIndexingPipeline.index_file(...)` in `app/modules/rag/indexing/code/pipeline.py`.
|
||||
- Chunking logic: `CodeTextChunker.chunk(...)` in `app/modules/rag/indexing/code/code_text/chunker.py`.
|
||||
- Document builder: `CodeTextDocumentBuilder.build(...)` in `app/modules/rag/indexing/code/code_text/document_builder.py`.
|
||||
- Persisted via `RagDocumentRepository.insert_documents(...)` into `rag_chunks`.
|
||||
|
||||
### Input contract
|
||||
|
||||
This is an indexing layer, not a direct public retriever. The observed upstream indexing input is a file dict with at least:
|
||||
|
||||
- required:
|
||||
- `path: str`
|
||||
- `content: str`
|
||||
- optional:
|
||||
- `commit_sha: str | None`
|
||||
- `content_hash: str`
|
||||
- metadata fields copied through by `RagService._document_metadata(...)`
|
||||
|
||||
For retrieval, the layer is queried only indirectly through:
|
||||
|
||||
- `rag_session_id: str`
|
||||
- `query: str`
|
||||
- inferred mode/layers from `RagQueryRouter`
|
||||
- fixed `limit=8`
|
||||
|
||||
### Output contract
|
||||
|
||||
Stored document shape:
|
||||
|
||||
- top-level:
|
||||
- `layer = "C0_SOURCE_CHUNKS"`
|
||||
- `lang = "python"`
|
||||
- `source.repo_id`
|
||||
- `source.commit_sha`
|
||||
- `source.path`
|
||||
- `title`
|
||||
- `text`
|
||||
- `span.start_line`
|
||||
- `span.end_line`
|
||||
- `embedding`
|
||||
- metadata:
|
||||
- `chunk_index`
|
||||
- `chunk_type`: `symbol_block` or `window`
|
||||
- `module_or_unit`
|
||||
- `artifact_type = "CODE"`
|
||||
- plus file-level metadata injected by `RagService`
|
||||
|
||||
Returned retrieval item shape:
|
||||
|
||||
- `source`
|
||||
- `content`
|
||||
- `layer`
|
||||
- `title`
|
||||
- `metadata`
|
||||
- `score`
|
||||
|
||||
No `line_start` / `line_end` are returned to the caller directly; they remain in DB columns `span_start` / `span_end` and are only used in logs.
|
||||
|
||||
### Defaults & limits
|
||||
|
||||
- AST chunking prefers one chunk per top-level class/function/async function.
|
||||
- Fallback window chunking:
|
||||
- `size = 80` lines
|
||||
- `overlap = 15` lines
|
||||
- Global retrieval limit from `RagService.retrieve(...)`: `8`
|
||||
- Embedding batch size from env:
|
||||
- `RAG_EMBED_BATCH_SIZE`
|
||||
- default `16`
|
||||
|
||||
### Known issues
|
||||
|
||||
- Nested methods/functions are not emitted as C0 chunks unless represented inside a selected top-level block.
|
||||
- Returned API payload omits line spans even though storage has them.
|
||||
- No direct filter by path, namespace, symbol, or `top_k` is exposed through the current endpoint.
|
||||
|
||||
## Layer: C1_SYMBOL_CATALOG
|
||||
|
||||
### Implementation
|
||||
|
||||
- Symbol extraction: `SymbolExtractor.extract(...)` in `app/modules/rag/indexing/code/symbols/extractor.py`.
|
||||
- AST parsing: `PythonAstParser.parse_module(...)`.
|
||||
- Document builder: `SymbolDocumentBuilder.build(...)`.
|
||||
- Retrieval reads rows from `rag_chunks`; there is no dedicated symbol table.
|
||||
|
||||
### Input contract
|
||||
|
||||
Indexing input is the same per-file payload as C0.
|
||||
|
||||
Observed symbol extraction source:
|
||||
|
||||
- Python AST only
|
||||
- supported symbol kinds:
|
||||
- `class`
|
||||
- `function`
|
||||
- `method`
|
||||
- `const` for top-level imports/import aliases
|
||||
|
||||
Retrieval input is still the generic text query endpoint. Query terms are enriched by `extract_query_terms(...)`:
|
||||
|
||||
- extracts identifier-like tokens from query text
|
||||
- normalizes camelCase/PascalCase to snake_case
|
||||
- adds special intent terms for management/control-related queries
|
||||
- max observed query terms: `6`
|
||||
|
||||
### Output contract
|
||||
|
||||
Stored document shape:
|
||||
|
||||
- top-level:
|
||||
- `layer = "C1_SYMBOL_CATALOG"`
|
||||
- `title = qname`
|
||||
- `text = "<kind> <qname>\n<signature>\n<docstring?>"`
|
||||
- `span.start_line`
|
||||
- `span.end_line`
|
||||
- metadata:
|
||||
- `symbol_id`
|
||||
- `qname`
|
||||
- `kind`
|
||||
- `signature`
|
||||
- `decorators_or_annotations`
|
||||
- `docstring_or_javadoc`
|
||||
- `parent_symbol_id`
|
||||
- `package_or_module`
|
||||
- `is_entry_candidate`
|
||||
- `lang_payload`
|
||||
- `artifact_type = "CODE"`
|
||||
|
||||
Observed `lang_payload` variants:
|
||||
|
||||
- class:
|
||||
- `bases`
|
||||
- function/method:
|
||||
- `async`
|
||||
- import alias:
|
||||
- `imported_from`
|
||||
- `import_alias`
|
||||
|
||||
### Defaults & limits
|
||||
|
||||
- Only Python source files are indexed into C-layers.
|
||||
- Import and import-from declarations are materialized as `const` symbols only at module top level.
|
||||
- Retrieval ranking gives C1 priority rank `1`, after C3 and before C2/C0.
|
||||
|
||||
### Known issues
|
||||
|
||||
- No explicit visibility/public-private model.
|
||||
- `parent_symbol_id` currently stores the parent qname string from the stack, not the parent symbol hash. This is an observed implementation detail.
|
||||
- Cross-file symbol resolution is not implemented; `dst_symbol_id` in edges resolves only against symbols extracted from the same file.
|
||||
|
||||
## Layer: C2_DEPENDENCY_GRAPH
|
||||
|
||||
### Implementation
|
||||
|
||||
- Edge extraction: `EdgeExtractor.extract(...)` in `app/modules/rag/indexing/code/edges/extractor.py`.
|
||||
- Document builder: `EdgeDocumentBuilder.build(...)`.
|
||||
- Built during `CodeIndexingPipeline.index_file(...)`.
|
||||
|
||||
### Input contract
|
||||
|
||||
Indexing input is the same per-file source payload as C0/C1.
|
||||
|
||||
Graph construction method:
|
||||
|
||||
- static analysis only
|
||||
- Python AST walk only
|
||||
- no runtime tracing
|
||||
- no tree-sitter
|
||||
|
||||
Observed edge types:
|
||||
|
||||
- `calls`
|
||||
- `imports`
|
||||
- `inherits`
|
||||
|
||||
### Output contract
|
||||
|
||||
Stored document shape:
|
||||
|
||||
- top-level:
|
||||
- `layer = "C2_DEPENDENCY_GRAPH"`
|
||||
- `title = "<src_qname>:<edge_type>"`
|
||||
- `text = "<src_qname> <edge_type> <dst>"`
|
||||
- `span.start_line`
|
||||
- `span.end_line`
|
||||
- `links` contains one evidence link of type `EDGE`
|
||||
- metadata:
|
||||
- `edge_id`
|
||||
- `edge_type`
|
||||
- `src_symbol_id`
|
||||
- `src_qname`
|
||||
- `dst_symbol_id`
|
||||
- `dst_ref`
|
||||
- `resolution`: `resolved` or `partial`
|
||||
- `lang_payload`
|
||||
- `artifact_type = "CODE"`
|
||||
|
||||
Observed `lang_payload` usage:
|
||||
|
||||
- for calls: may include `callsite_kind = "function_call"`
|
||||
|
||||
### Defaults & limits
|
||||
|
||||
- Edge extraction is per-file only.
|
||||
- `imports` edges are emitted only while visiting a class/function scope; top-level imports do not become C2 edges.
|
||||
- Layer rank in retrieval SQL: `2`
|
||||
|
||||
### Known issues
|
||||
|
||||
- There is no traversal API, graph repository, or query language over C2. Retrieval only treats edges as text/vector rows in `rag_chunks`.
|
||||
- Destination resolution is local to the file-level qname map.
|
||||
- Top-level module import relationships are incompletely represented because `visit_Import` / `visit_ImportFrom` skip when there is no current scope.
|
||||
|
||||
## Layer: C3_ENTRYPOINTS
|
||||
|
||||
### Implementation
|
||||
|
||||
- Detection registry: `EntrypointDetectorRegistry.detect_all(...)`.
|
||||
- Detectors:
|
||||
- `FastApiEntrypointDetector`
|
||||
- `FlaskEntrypointDetector`
|
||||
- `TyperClickEntrypointDetector`
|
||||
- Document builder: `EntrypointDocumentBuilder.build(...)`.
|
||||
|
||||
### Input contract
|
||||
|
||||
Indexing input is the same per-file source payload as other C-layers.
|
||||
|
||||
Detected entrypoint families today:
|
||||
|
||||
- HTTP:
|
||||
- FastAPI decorators such as `.get`, `.post`, `.put`, `.patch`, `.delete`, `.route`
|
||||
- Flask `.route`
|
||||
- CLI:
|
||||
- Typer/Click `.command`
|
||||
- Typer/Click `.callback`
|
||||
|
||||
Not detected:
|
||||
|
||||
- Django routes
|
||||
- Celery tasks
|
||||
- RQ jobs
|
||||
- cron jobs / scheduler entries
|
||||
|
||||
### Output contract
|
||||
|
||||
Stored document shape:
|
||||
|
||||
- top-level:
|
||||
- `layer = "C3_ENTRYPOINTS"`
|
||||
- `title = route_or_command`
|
||||
- `text = "<framework> <entry_type> <route_or_command>"`
|
||||
- `span.start_line`
|
||||
- `span.end_line`
|
||||
- `links` contains one evidence link of type `CODE_SPAN`
|
||||
- metadata:
|
||||
- `entry_id`
|
||||
- `entry_type`: observed `http` or `cli`
|
||||
- `framework`: observed `fastapi`, `flask`, `typer`, `click`
|
||||
- `route_or_command`
|
||||
- `handler_symbol_id`
|
||||
- `lang_payload`
|
||||
- `artifact_type = "CODE"`
|
||||
|
||||
FastAPI-specific observed payload:
|
||||
|
||||
- `lang_payload.methods = [HTTP_METHOD]` for `.get/.post/...`
|
||||
|
||||
### Defaults & limits
|
||||
|
||||
- Retrieval layer rank: `0` highest among code layers.
|
||||
- Entrypoint mapping is handler-symbol centric:
|
||||
- decorator match -> symbol -> `handler_symbol_id`
|
||||
- physical location comes from symbol span
|
||||
|
||||
### Known issues
|
||||
|
||||
- Route parsing is string-based from decorator text, not semantic AST argument parsing.
|
||||
- No dedicated entrypoint tags beyond `entry_type`, `framework`, and raw decorator-derived payload.
|
||||
- Background jobs and non-decorator entrypoints are not indexed.
|
||||
|
||||
## Dependency graph / trace current state
|
||||
|
||||
### Exists or stub?
|
||||
|
||||
- C2 exists and is populated.
|
||||
- It is not a stub.
|
||||
- It is also not a full-project dependency graph service; it is a set of per-edge documents stored in `rag_chunks`.
|
||||
|
||||
### How the graph is built
|
||||
|
||||
- static Python AST analysis
|
||||
- no runtime instrumentation
|
||||
- no import graph resolver across modules
|
||||
- no tree-sitter
|
||||
|
||||
### Edge types in data
|
||||
|
||||
- `calls`
|
||||
- `imports`
|
||||
- `inherits`
|
||||
|
||||
### Traversal API
|
||||
|
||||
- No traversal API was found in `app/modules/rag/*` or `app/modules/agent/*`.
|
||||
- No method accepts graph traversal parameters such as depth, start node, edge filters, or BFS/DFS strategy.
|
||||
- Current access path is only retrieval over indexed edge documents.
|
||||
|
||||
## Entrypoints current state
|
||||
|
||||
### Implemented extraction
|
||||
|
||||
- HTTP routes:
|
||||
- FastAPI
|
||||
- Flask
|
||||
- CLI:
|
||||
- Typer
|
||||
- Click
|
||||
|
||||
### Mapping model
|
||||
|
||||
- `entrypoint -> handler_symbol_id -> symbol span/path`
|
||||
- The entrypoint record itself stores:
|
||||
- framework
|
||||
- entry type
|
||||
- raw route/command string
|
||||
- handler symbol id
|
||||
|
||||
### Tags/types
|
||||
|
||||
- `entry_type` is the main normalized tag.
|
||||
- Observed values: `http`, `cli`.
|
||||
- `framework` is the second discriminator.
|
||||
- There are no richer endpoint taxonomies such as `job`, `worker`, `webhook`, `scheduler`.
|
||||
|
||||
## Defaults and operational limits
|
||||
|
||||
- Query mode default: `docs`
|
||||
- Code mode is enabled by keyword heuristics in `RagQueryRouter`
|
||||
- Retrieval hard limit: `8`
|
||||
- Fallback limit: `8`
|
||||
- Query term extraction limit: `6`
|
||||
- Ranked source bundle for project QA:
|
||||
- top `12` RAG items
|
||||
- top `10` file candidates
|
||||
- No exposed `namespace`, `path_prefixes`, `top_k`, `max_chars`, `max_chunks`, `max_depth` in the public/internal retrieval endpoint
|
||||
|
||||
`ASSUMPTION:` the absence of these controls in endpoint and service signatures means they are not part of the current supported contract, even though `RagQueryRepository.retrieve(...)` has an internal `path_prefixes` parameter.
|
||||
|
||||
## Known cross-cutting issues
|
||||
|
||||
- Retrieval contract is effectively text-only at API level; structured retrieval exists only as internal SQL parameters.
|
||||
- Response payload drops explicit line spans even though spans are stored.
|
||||
- Vector retrieval is coupled to a single provider-specific embedder.
|
||||
- Docs mode is the default, so code retrieval depends on heuristic query phrasing unless the project/qa graph prepends `по коду`.
|
||||
- There is no separate retrieval contract per layer exposed over API; all layer selection is implicit.
|
||||
|
||||
## Where to plug ExplainPack pipeline
|
||||
|
||||
### Option 1: replace or extend `project_qa/context_analysis`
|
||||
|
||||
- Code location:
|
||||
- `app/modules/agent/engine/graphs/project_qa_step_graphs.py`
|
||||
- Why:
|
||||
- retrieval is already complete at this step
|
||||
- input bundle already contains ranked `rag_items` and `file_candidates`
|
||||
- output is already a structured `analysis_brief`
|
||||
- Risk:
|
||||
- low
|
||||
- minimal invasion if ExplainPack consumes `source_bundle` and emits the same `analysis_brief` shape
|
||||
|
||||
### Option 2: insert a new orchestrator step between `context_retrieval` and `context_analysis`
|
||||
|
||||
- Code location:
|
||||
- `app/modules/agent/engine/orchestrator/template_registry.py`
|
||||
- `app/modules/agent/engine/orchestrator/step_registry.py`
|
||||
- Why:
|
||||
- preserves current retrieval behavior
|
||||
- makes ExplainPack an explicit pipeline stage with its own artifact
|
||||
- cleanest for observability and future A/B migration
|
||||
- Risk:
|
||||
- low to medium
|
||||
- requires one new artifact contract and one extra orchestration step, but no change to retrieval storage
|
||||
|
||||
### Option 3: introduce ExplainPack inside `ExplainActions.extract_logic`
|
||||
|
||||
- Code location:
|
||||
- `app/modules/agent/engine/orchestrator/actions/explain_actions.py`
|
||||
- Why:
|
||||
- useful if ExplainPack is meant only for explain-style scenarios
|
||||
- keeps general project QA untouched
|
||||
- Risk:
|
||||
- medium
|
||||
- narrower integration point; may create duplicate reasoning logic separate from project QA analysis path
|
||||
|
||||
## Bottom line
|
||||
|
||||
- C0-C3 are implemented and persisted in one physical store: `rag_chunks`.
|
||||
- Retrieval is a hybrid SQL ranking over lexical heuristics plus pgvector distance.
|
||||
- C2 exists, but only as retrievable edge documents, not as a traversable graph subsystem.
|
||||
- C3 covers FastAPI/Flask/Typer/Click only.
|
||||
- The least invasive ExplainPack integration point is after retrieval and before answer composition, preferably as a new explicit orchestrator artifact or as a replacement for `context_analysis`.
|
||||
@@ -0,0 +1,168 @@
|
||||
---
|
||||
id: api-rag-session-changes
|
||||
title: Применение изменений к RAG-сессии
|
||||
doc_type: api_method
|
||||
domain: rag
|
||||
status: draft
|
||||
owner: system-analyst
|
||||
source_of_truth: code
|
||||
related_docs:
|
||||
- arch-rag-package
|
||||
- logic-rag-indexing
|
||||
- entity-rag-session
|
||||
- entity-rag-index-job
|
||||
related_code:
|
||||
- src/app/modules/rag/module.py
|
||||
- src/app/schemas/rag_sessions.py
|
||||
- src/app/schemas/indexing.py
|
||||
entities:
|
||||
- RagSession
|
||||
- IndexJob
|
||||
tags:
|
||||
- rag
|
||||
- api
|
||||
- changes
|
||||
- incremental-indexing
|
||||
---
|
||||
# Применение изменений к RAG-сессии
|
||||
|
||||
## Summary
|
||||
- Purpose: поставить incremental indexing для уже существующей `RagSession`.
|
||||
- Actor: внешний клиент модуля RAG.
|
||||
- Trigger: частичное обновление индекса после изменения файлов.
|
||||
- Endpoint: `POST /api/rag/sessions/{rag_session_id}/changes`
|
||||
- Main entities: `RagSession`, `IndexJob`.
|
||||
- Main logic: проверка существования сессии, создание change job, асинхронная обработка `upsert`/`delete`.
|
||||
- Main errors: `not_found` для отсутствующей сессии, `422` для некорректного payload.
|
||||
- Source of truth: `src/app/modules/rag/module.py`, `src/app/schemas/rag_sessions.py`.
|
||||
|
||||
## Назначение
|
||||
|
||||
Метод позволяет обновить индекс без полной переиндексации проекта. Он принимает только изменённые файлы и операции удаления.
|
||||
|
||||
## Контекст
|
||||
|
||||
Endpoint относится к новому API с явной работой через `rag_session_id`. В отличие от legacy `/api/index/changes`, он не создаёт сессию молча и требует, чтобы она уже существовала.
|
||||
|
||||
## Технический use case
|
||||
|
||||
### Основной сценарий
|
||||
|
||||
1. Клиент передаёт `rag_session_id` в path и список `changed_files` в body.
|
||||
2. Endpoint проверяет наличие сессии через `RagSessionStore.get`.
|
||||
3. При успехе `IndexingOrchestrator.enqueue_changes` создаёт новую job и запускает фоновое применение изменений.
|
||||
4. API возвращает `index_job_id` и стартовый статус.
|
||||
|
||||
### Альтернативные ветки
|
||||
|
||||
- Если `rag_session_id` не найдена, endpoint бросает `AppError("not_found", ...)`.
|
||||
- Для `op=delete` в последующей логике происходит удаление документов по пути без повторной генерации embeddings.
|
||||
|
||||
## Функциональные требования
|
||||
|
||||
### Request validation
|
||||
- Path parameter `rag_session_id` обязателен.
|
||||
- `changed_files` обязателен и состоит из элементов `ChangedFile`.
|
||||
- Для каждого элемента обязательны `op` и `path`.
|
||||
- `op` допускает только `upsert` или `delete`.
|
||||
|
||||
### Processing rules
|
||||
- Сессия должна существовать до постановки change job.
|
||||
- Каждый вызов создаёт новый `IndexJob`.
|
||||
- Фактическое применение изменений выполняется асинхронно.
|
||||
|
||||
### State changes
|
||||
- В `rag_index_jobs` появляется новая задача.
|
||||
- Сам индекс меняется позже, внутри `RagService.index_changes`.
|
||||
|
||||
### Side effects
|
||||
- Публикация job events.
|
||||
- Удаление документов по `delete_paths` и upsert новых документов в фоне.
|
||||
|
||||
## Contract
|
||||
|
||||
### Endpoint
|
||||
- Method: `POST`
|
||||
- Path: `/api/rag/sessions/{rag_session_id}/changes`
|
||||
- Auth: определяется внешним слоем приложения.
|
||||
- Idempotent: нет, повторный вызов создаёт новую job.
|
||||
- Timeout: короткий, endpoint не дожидается завершения индексации.
|
||||
- Retry: только если клиент готов к созданию дополнительной job.
|
||||
|
||||
### Request
|
||||
| Field | Type | Required | Constraints | Description |
|
||||
|------|------|----------|-------------|-------------|
|
||||
| `rag_session_id` | `string` | yes | path param, non-empty | идентификатор существующей RAG-сессии |
|
||||
| `changed_files` | `array<ChangedFile>` | yes | схема каждого элемента обязательна | изменения файлов |
|
||||
| `changed_files[].op` | `enum` | yes | `upsert` or `delete` | тип операции |
|
||||
| `changed_files[].path` | `string` | yes | `min_length=1` | путь файла |
|
||||
| `changed_files[].content` | `string \| null` | no | нужен для `upsert` | содержимое файла |
|
||||
| `changed_files[].content_hash` | `string \| null` | no | повышает cache reuse | hash содержимого |
|
||||
|
||||
### Response
|
||||
| Field | Type | Description |
|
||||
|------|------|-------------|
|
||||
| `index_job_id` | `string` | идентификатор фоновой задачи |
|
||||
| `status` | `string` | стартовый статус задачи |
|
||||
|
||||
### External contract refs
|
||||
- OpenAPI: формируется FastAPI по `response_model=IndexJobQueuedResponse`.
|
||||
- Schema: `RagSessionChangesRequest`, `ChangedFile`, `IndexJobQueuedResponse`.
|
||||
- DTO / serializer: `src/app/schemas/rag_sessions.py`, `src/app/schemas/indexing.py`.
|
||||
- Additional refs: `logic-rag-indexing`.
|
||||
|
||||
## Errors
|
||||
|
||||
| error_id | http_code | when | client_behavior | retry |
|
||||
|----------|-----------|------|-----------------|-------|
|
||||
| `not_found` | `404` | `rag_session_id` отсутствует | создать новую сессию или исправить id | no |
|
||||
| `validation_error` | `422` | нарушена схема request | исправить payload | no |
|
||||
|
||||
## Нефункциональные требования
|
||||
|
||||
### Security
|
||||
- Метод доверяет внешнему слою авторизации.
|
||||
|
||||
### Observability
|
||||
- Logs: прямое логирование endpoint отсутствует.
|
||||
- Metrics: нет отдельной метрики на уровне метода.
|
||||
- Traces: отсутствуют.
|
||||
- Audit: каждая операция материализуется в `IndexJob`.
|
||||
|
||||
### Reliability
|
||||
- Проверка существования сессии защищает от случайной записи в неинициализированный scope.
|
||||
- Ошибки индексации доступны через job status и SSE events.
|
||||
|
||||
### Performance
|
||||
- Быстрый ответ за счёт фонового выполнения.
|
||||
|
||||
## Связанные блоки логики
|
||||
- `logic-rag-indexing`
|
||||
|
||||
## Связанные сущности
|
||||
- `RagSession`
|
||||
- `IndexJob`
|
||||
|
||||
## Связанный код
|
||||
|
||||
### Files
|
||||
- `src/app/modules/rag/module.py`
|
||||
- `src/app/schemas/rag_sessions.py`
|
||||
- `src/app/schemas/indexing.py`
|
||||
|
||||
### Symbols
|
||||
- `RagModule.public_router.rag_session_changes`
|
||||
- `RagSessionStore.get`
|
||||
- `IndexingOrchestrator.enqueue_changes`
|
||||
|
||||
## Связанные документы
|
||||
- `arch-rag-package`
|
||||
- `logic-rag-indexing`
|
||||
- `entity-rag-session`
|
||||
- `entity-rag-index-job`
|
||||
|
||||
## История изменений
|
||||
|
||||
| Date | Source | Changes |
|
||||
|------|--------|---------|
|
||||
| 2026-03-13 | code | Задокументирован публичный endpoint incremental indexing для существующей сессии. |
|
||||
@@ -0,0 +1,166 @@
|
||||
---
|
||||
id: api-rag-session-create
|
||||
title: Создание RAG-сессии и запуск snapshot-индексации
|
||||
doc_type: api_method
|
||||
domain: rag
|
||||
status: draft
|
||||
owner: system-analyst
|
||||
source_of_truth: code
|
||||
related_docs:
|
||||
- arch-rag-package
|
||||
- logic-rag-indexing
|
||||
- entity-rag-session
|
||||
- entity-rag-index-job
|
||||
related_code:
|
||||
- src/app/modules/rag/module.py
|
||||
- src/app/schemas/rag_sessions.py
|
||||
- src/app/schemas/indexing.py
|
||||
entities:
|
||||
- RagSession
|
||||
- IndexJob
|
||||
tags:
|
||||
- rag
|
||||
- api
|
||||
- session
|
||||
- snapshot
|
||||
---
|
||||
# Создание RAG-сессии и запуск snapshot-индексации
|
||||
|
||||
## Summary
|
||||
- Purpose: создать новую `RagSession` и асинхронно поставить полную индексацию snapshot-файлов.
|
||||
- Actor: внешний клиент модуля RAG.
|
||||
- Trigger: первичная загрузка файлов проекта в индекс.
|
||||
- Endpoint: `POST /api/rag/sessions`
|
||||
- Main entities: `RagSession`, `IndexJob`.
|
||||
- Main logic: создание UUID-сессии, постановка snapshot job, возврат идентификаторов сессии и job.
|
||||
- Main errors: в коде endpoint нет собственной бизнес-валидации сверх pydantic; ошибки индексации проявляются позже в job status.
|
||||
- Source of truth: `src/app/modules/rag/module.py`, `src/app/schemas/rag_sessions.py`.
|
||||
|
||||
## Назначение
|
||||
|
||||
Метод открывает новую RAG-сессию и запускает первичную индексацию файлов. Он используется как основной публичный вход для нового API пакета `rag`.
|
||||
|
||||
## Контекст
|
||||
|
||||
В отличие от legacy `/api/index/snapshot`, этот endpoint всегда создаёт новый `rag_session_id`, что позволяет независимо хранить несколько снимков одного проекта.
|
||||
|
||||
## Технический use case
|
||||
|
||||
### Основной сценарий
|
||||
|
||||
1. Клиент передаёт `project_id` и массив `files`.
|
||||
2. `RagSessionStore.create` создаёт новую запись в `rag_sessions`.
|
||||
3. `IndexingOrchestrator.enqueue_snapshot` создаёт `IndexJob` и запускает фоновую обработку.
|
||||
4. API сразу возвращает `rag_session_id`, `index_job_id` и стартовый статус.
|
||||
|
||||
### Альтернативные ветки
|
||||
|
||||
- Если часть файлов не подлежит индексации, они будут отфильтрованы уже внутри indexing pipeline, а не на этапе ответа API.
|
||||
- Ошибки индексации не меняют синхронный ответ create endpoint, а отражаются в последующем статусе job.
|
||||
|
||||
## Функциональные требования
|
||||
|
||||
### Request validation
|
||||
- `project_id` обязателен и не может быть пустым.
|
||||
- `files` передаются списком объектов `FileSnapshot`.
|
||||
- Для каждого файла обязательны `path`, `content`, `content_hash`.
|
||||
|
||||
### Processing rules
|
||||
- На каждый вызов создаётся новая `RagSession`.
|
||||
- Snapshot job создаётся сразу после сохранения сессии.
|
||||
- Ответ не ждёт завершения индексации.
|
||||
|
||||
### State changes
|
||||
- В `rag_sessions` появляется новая запись.
|
||||
- В `rag_index_jobs` появляется новая запись в статусе `queued`.
|
||||
|
||||
### Side effects
|
||||
- Запуск фоновой `asyncio` task.
|
||||
- Последующая публикация progress events в EventBus.
|
||||
|
||||
## Contract
|
||||
|
||||
### Endpoint
|
||||
- Method: `POST`
|
||||
- Path: `/api/rag/sessions`
|
||||
- Auth: определяется внешним слоем приложения, внутри endpoint не задана.
|
||||
- Idempotent: нет.
|
||||
- Timeout: короткий, так как endpoint не ждёт индексацию.
|
||||
- Retry: допустим только на стороне клиента с пониманием, что будет создана новая сессия.
|
||||
|
||||
### Request
|
||||
| Field | Type | Required | Constraints | Description |
|
||||
|------|------|----------|-------------|-------------|
|
||||
| `project_id` | `string` | yes | `min_length=1` | идентификатор проекта |
|
||||
| `files` | `array<FileSnapshot>` | yes | может быть пустым, но схема обязана соблюдаться | snapshot файлов для первичной индексации |
|
||||
| `files[].path` | `string` | yes | `min_length=1` | путь файла |
|
||||
| `files[].content` | `string` | yes | без дополнительных ограничений | содержимое файла |
|
||||
| `files[].content_hash` | `string` | yes | `min_length=1` | hash содержимого для cache reuse |
|
||||
|
||||
### Response
|
||||
| Field | Type | Description |
|
||||
|------|------|-------------|
|
||||
| `rag_session_id` | `string` | идентификатор созданной сессии |
|
||||
| `index_job_id` | `string` | идентификатор фоновой задачи индексации |
|
||||
| `status` | `IndexJobStatus` | стартовый статус задачи, обычно `queued` |
|
||||
|
||||
### External contract refs
|
||||
- OpenAPI: формируется FastAPI по `response_model=RagSessionCreateResponse`.
|
||||
- Schema: `RagSessionCreateRequest`, `RagSessionCreateResponse`.
|
||||
- DTO / serializer: `src/app/schemas/rag_sessions.py`, `src/app/schemas/indexing.py`.
|
||||
- Additional refs: `logic-rag-indexing`.
|
||||
|
||||
## Errors
|
||||
|
||||
| error_id | http_code | when | client_behavior | retry |
|
||||
|----------|-----------|------|-----------------|-------|
|
||||
| `validation_error` | `422` | нарушена pydantic-схема request | исправить payload | no |
|
||||
|
||||
## Нефункциональные требования
|
||||
|
||||
### Security
|
||||
- Авторизация и аутентификация находятся вне этого метода.
|
||||
|
||||
### Observability
|
||||
- Logs: прямое логирование в endpoint отсутствует.
|
||||
- Metrics: отдельные API-метрики не выделены.
|
||||
- Traces: отсутствуют.
|
||||
- Audit: факт вызова материализуется через `RagSession` и `IndexJob`.
|
||||
|
||||
### Reliability
|
||||
- Даже при дальнейшей ошибке индексации клиент может получить статус через job endpoint.
|
||||
- Фоновая задача создаётся немедленно после ответа.
|
||||
|
||||
### Performance
|
||||
- Время ответа не зависит от размера snapshot, кроме времени сериализации request.
|
||||
|
||||
## Связанные блоки логики
|
||||
- `logic-rag-indexing`
|
||||
|
||||
## Связанные сущности
|
||||
- `RagSession`
|
||||
- `IndexJob`
|
||||
|
||||
## Связанный код
|
||||
|
||||
### Files
|
||||
- `src/app/modules/rag/module.py`
|
||||
- `src/app/schemas/rag_sessions.py`
|
||||
- `src/app/schemas/indexing.py`
|
||||
|
||||
### Symbols
|
||||
- `RagModule.public_router.create_rag_session`
|
||||
- `RagSessionStore.create`
|
||||
- `IndexingOrchestrator.enqueue_snapshot`
|
||||
|
||||
## Связанные документы
|
||||
- `arch-rag-package`
|
||||
- `logic-rag-indexing`
|
||||
- `entity-rag-session`
|
||||
- `entity-rag-index-job`
|
||||
|
||||
## История изменений
|
||||
|
||||
| Date | Source | Changes |
|
||||
|------|--------|---------|
|
||||
| 2026-03-13 | code | Задокументирован публичный endpoint создания RAG-сессии. |
|
||||
@@ -0,0 +1,166 @@
|
||||
---
|
||||
id: api-rag-session-job
|
||||
title: Получение статуса и событий задачи индексации
|
||||
doc_type: api_method
|
||||
domain: rag
|
||||
status: draft
|
||||
owner: system-analyst
|
||||
source_of_truth: code
|
||||
related_docs:
|
||||
- arch-rag-package
|
||||
- entity-rag-session
|
||||
- entity-rag-index-job
|
||||
related_code:
|
||||
- src/app/modules/rag/module.py
|
||||
- src/app/modules/rag/job_store.py
|
||||
- src/app/schemas/rag_sessions.py
|
||||
entities:
|
||||
- RagSession
|
||||
- IndexJob
|
||||
tags:
|
||||
- rag
|
||||
- api
|
||||
- job-status
|
||||
- sse
|
||||
---
|
||||
# Получение статуса и событий задачи индексации
|
||||
|
||||
## Summary
|
||||
- Purpose: отдать текущее состояние job и поток событий её выполнения в рамках конкретной `RagSession`.
|
||||
- Actor: внешний клиент модуля RAG.
|
||||
- Trigger: polling или live-monitoring после запуска snapshot/change indexing.
|
||||
- Endpoint: `GET /api/rag/sessions/{rag_session_id}/jobs/{index_job_id}` и `GET /api/rag/sessions/{rag_session_id}/jobs/{index_job_id}/events`
|
||||
- Main entities: `RagSession`, `IndexJob`.
|
||||
- Main logic: чтение job по id, проверка принадлежности сессии, возврат status payload или SSE stream.
|
||||
- Main errors: `not_found` при отсутствии job или несовпадении `rag_session_id`.
|
||||
- Source of truth: `src/app/modules/rag/module.py`, `src/app/modules/rag/job_store.py`.
|
||||
|
||||
## Назначение
|
||||
|
||||
Документ описывает два связанных метода наблюдения: синхронный status endpoint и потоковый SSE endpoint. Оба работают поверх одной сущности `IndexJob`.
|
||||
|
||||
## Контекст
|
||||
|
||||
Create и changes endpoints возвращают только стартовый статус задачи, поэтому клиенту нужны отдельные методы для отслеживания выполнения. SSE-поток даёт live progress, а status endpoint нужен для простого polling.
|
||||
|
||||
## Технический use case
|
||||
|
||||
### Основной сценарий
|
||||
|
||||
1. Клиент вызывает status endpoint или открывает SSE stream по `index_job_id`.
|
||||
2. Endpoint читает job из `IndexJobStore`.
|
||||
3. Если job отсутствует или принадлежит другой `rag_session_id`, возвращается `not_found`.
|
||||
4. Status endpoint отдаёт снимок counters и error payload.
|
||||
5. SSE endpoint подписывается на `EventBus` c `replay=True` и транслирует `index_status`, `index_progress`, `terminal`.
|
||||
|
||||
### Альтернативные ветки
|
||||
|
||||
- При отсутствии новых событий SSE endpoint каждые 10 секунд отправляет `: keepalive`.
|
||||
- После события `terminal` поток завершается и отписывается от EventBus.
|
||||
|
||||
## Функциональные требования
|
||||
|
||||
### Request validation
|
||||
- `rag_session_id` и `index_job_id` обязательны как path parameters.
|
||||
- Job должна существовать и принадлежать переданной сессии.
|
||||
|
||||
### Processing rules
|
||||
- Status endpoint не подписывается на события и читает только текущее состояние job.
|
||||
- SSE endpoint использует `replay=True`, чтобы клиент получил уже опубликованные события.
|
||||
- Оба метода защищают от доступа к job другой сессии.
|
||||
|
||||
### State changes
|
||||
- Методы не меняют состояние job.
|
||||
|
||||
### Side effects
|
||||
- SSE endpoint создаёт временную подписку на EventBus.
|
||||
- При завершении или разрыве соединения выполняется `unsubscribe`.
|
||||
|
||||
## Contract
|
||||
|
||||
### Endpoint
|
||||
- Method: `GET`
|
||||
- Path: `/api/rag/sessions/{rag_session_id}/jobs/{index_job_id}` и `/api/rag/sessions/{rag_session_id}/jobs/{index_job_id}/events`
|
||||
- Auth: определяется внешним слоем приложения.
|
||||
- Idempotent: да.
|
||||
- Timeout: status endpoint короткий; SSE stream долгоживущий.
|
||||
- Retry: polling можно повторять безопасно; SSE можно переподключать.
|
||||
|
||||
### Request
|
||||
| Field | Type | Required | Constraints | Description |
|
||||
|------|------|----------|-------------|-------------|
|
||||
| `rag_session_id` | `string` | yes | path param | идентификатор сессии |
|
||||
| `index_job_id` | `string` | yes | path param | идентификатор задачи |
|
||||
|
||||
### Response
|
||||
| Field | Type | Description |
|
||||
|------|------|-------------|
|
||||
| `rag_session_id` | `string` | идентификатор сессии, только для status endpoint |
|
||||
| `index_job_id` | `string` | идентификатор задачи |
|
||||
| `status` | `IndexJobStatus` | текущее состояние job |
|
||||
| `indexed_files` | `integer` | число успешно обработанных файлов |
|
||||
| `failed_files` | `integer` | число файлов с ошибками |
|
||||
| `cache_hit_files` | `integer` | число cache hit |
|
||||
| `cache_miss_files` | `integer` | число cache miss |
|
||||
| `error` | `object \| null` | ошибка, если job завершилась с `error` |
|
||||
|
||||
### External contract refs
|
||||
- OpenAPI: status endpoint использует `response_model=RagSessionJobResponse`; SSE endpoint отдаёт `text/event-stream`.
|
||||
- Schema: `RagSessionJobResponse`.
|
||||
- DTO / serializer: `src/app/schemas/rag_sessions.py`.
|
||||
- Additional refs: `entity-rag-index-job`.
|
||||
|
||||
## Errors
|
||||
|
||||
| error_id | http_code | when | client_behavior | retry |
|
||||
|----------|-----------|------|-----------------|-------|
|
||||
| `not_found` | `404` | job отсутствует или не принадлежит переданной сессии | проверить id или создать новую задачу | no |
|
||||
|
||||
## Нефункциональные требования
|
||||
|
||||
### Security
|
||||
- Проверка `job.rag_session_id == rag_session_id` обязательна для обоих методов.
|
||||
|
||||
### Observability
|
||||
- Logs: отдельные логи чтения статуса не реализованы.
|
||||
- Metrics: отсутствуют.
|
||||
- Traces: отсутствуют.
|
||||
- Audit: история job хранится в `rag_index_jobs`, поток событий в памяти EventBus.
|
||||
|
||||
### Reliability
|
||||
- SSE heartbeat удерживает соединение активным.
|
||||
- `finally` блок гарантирует `unsubscribe`.
|
||||
|
||||
### Performance
|
||||
- Status endpoint работает как лёгкий запрос к БД.
|
||||
- SSE stream масштабируется числом активных подписчиков и объёмом событий.
|
||||
|
||||
## Связанные блоки логики
|
||||
- `logic-rag-indexing`
|
||||
|
||||
## Связанные сущности
|
||||
- `RagSession`
|
||||
- `IndexJob`
|
||||
|
||||
## Связанный код
|
||||
|
||||
### Files
|
||||
- `src/app/modules/rag/module.py`
|
||||
- `src/app/modules/rag/job_store.py`
|
||||
- `src/app/schemas/rag_sessions.py`
|
||||
|
||||
### Symbols
|
||||
- `RagModule.public_router.rag_session_job`
|
||||
- `RagModule.public_router.rag_session_job_events`
|
||||
- `IndexJobStore.get`
|
||||
|
||||
## Связанные документы
|
||||
- `arch-rag-package`
|
||||
- `entity-rag-session`
|
||||
- `entity-rag-index-job`
|
||||
|
||||
## История изменений
|
||||
|
||||
| Date | Source | Changes |
|
||||
|------|--------|---------|
|
||||
| 2026-03-13 | code | Задокументированы status и SSE endpoints для наблюдения за indexing job. |
|
||||
@@ -0,0 +1,214 @@
|
||||
---
|
||||
|
||||
## id: arch-rag-package
|
||||
title: Пакет RAG
|
||||
doc_type: architecture_overview
|
||||
domain: rag
|
||||
status: draft
|
||||
owner: system-analyst
|
||||
source_of_truth: code
|
||||
related_docs:
|
||||
- logic-rag-indexing
|
||||
- logic-rag-retrieval
|
||||
- entity-rag-session
|
||||
- entity-rag-index-job
|
||||
- api-rag-session-create
|
||||
- api-rag-session-changes
|
||||
- api-rag-session-job
|
||||
related_code:
|
||||
- src/app/modules/rag/module.py
|
||||
- src/app/modules/rag/services/rag_service.py
|
||||
- src/app/modules/rag/indexing_service.py
|
||||
- src/app/modules/rag/persistence/repository.py
|
||||
- src/app/modules/rag/persistence/schema_repository.py
|
||||
entities:
|
||||
- RagSession
|
||||
- IndexJob
|
||||
- RagDocument
|
||||
tags:
|
||||
- rag
|
||||
- indexing
|
||||
- retrieval
|
||||
- architecture
|
||||
|
||||
# Пакет RAG
|
||||
|
||||
## Summary
|
||||
|
||||
- Scope: модуль индексации проектных файлов, хранения RAG-слоёв и выдачи retrieval-контекста.
|
||||
- Purpose: построить индекс по документации и Python-коду и дать runtime доступ к релевантным фрагментам.
|
||||
- Main modules: `RagModule`, `RagService`, `IndexingOrchestrator`, `RagRepository`.
|
||||
- Main domains: RAG-сессии, задачи индексации, документы индекса, blob-cache, retrieval.
|
||||
- Main integrations: PostgreSQL/pgvector, GigaChat embeddings, FastAPI, EventBus, story context.
|
||||
- Key entrypoints: `/api/rag/sessions`, `/api/rag/sessions/{rag_session_id}/changes`, `/api/rag/sessions/{rag_session_id}/jobs/{index_job_id}`, `/api/rag/sessions/{rag_session_id}/jobs/{index_job_id}/events`.
|
||||
- Key data flows: snapshot indexing, incremental reindex, retrieval из `rag_chunks`.
|
||||
- Source of truth: код `src/app/modules/rag/*`.
|
||||
|
||||
## Назначение
|
||||
|
||||
Пакет `rag` отвечает за полный цикл подготовки retrieval-контекста для проекта: принимает снапшоты и изменения файлов, преобразует их в набор атомарных `RagDocument`, векторизует, сохраняет в БД и предоставляет доступ к индексированным данным другим частям системы.
|
||||
|
||||
## Контекст
|
||||
|
||||
Модуль используется как инфраструктурный слой для agent/runtime. На вход он принимает snapshot и изменения файлов проекта. На выходе формирует устойчивый индекс, ассоциированный с `rag_session_id`, и статус задач индексации, пригодный для опроса и SSE-подписки.
|
||||
|
||||
## Границы системы
|
||||
|
||||
### In scope
|
||||
|
||||
- Создание и хранение `RagSession`.
|
||||
- Постановка и выполнение задач snapshot/change indexing.
|
||||
- Индексация markdown-документации в слои `D1-D4`.
|
||||
- Индексация Python-кода в слои `C0-C4`.
|
||||
- Кэширование по `repo_id + blob_sha`.
|
||||
- Сохранение retrieval-документов в `rag_chunks`.
|
||||
- Выдача статуса задач и событий прогресса.
|
||||
- Нормализация webhook Gitea/Bitbucket и связывание коммитов со story.
|
||||
|
||||
### Out of scope
|
||||
|
||||
- Финальная генерация ответа пользователю.
|
||||
- Оркестрация LLM-диалога.
|
||||
- Управление git-репозиторием и загрузка файлов из внешних источников.
|
||||
- Политики маршрутизации intent/runtime вне собственного persistence/retrieval API.
|
||||
|
||||
## Архитектурная схема
|
||||
|
||||
`RagModule` собирает зависимости модуля и публикует HTTP endpoints. Для индексации он использует `RagSessionStore`, `IndexJobStore`, `IndexingOrchestrator` и `RagService`. `RagService` выбирает docs/code pipeline, обогащает документы метаданными файла, запрашивает embeddings и записывает результат через `RagRepository`. `RagRepository` агрегирует schema/session/job/document/cache/query репозитории.
|
||||
|
||||
## Основные модули
|
||||
|
||||
|
||||
| module | responsibility | depends_on | key_code_refs |
|
||||
| ---------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------ | ----------------------------------------------- |
|
||||
| `RagModule` | сборка зависимостей, публичный и internal API | `RagService`, `IndexingOrchestrator`, `RagSessionStore`, `IndexJobStore` | `src/app/modules/rag/module.py` |
|
||||
| `RagService` | синхронная бизнес-логика индексации файлов и cache reuse | docs/code pipeline, embedder, `RagRepository` | `src/app/modules/rag/services/rag_service.py` |
|
||||
| `IndexingOrchestrator` | асинхронный job lifecycle, retry, project lock, EventBus | `IndexJobStore`, `RagIndexer`, `EventBus`, `RetryExecutor` | `src/app/modules/rag/indexing_service.py` |
|
||||
| `DocsIndexingPipeline` | построение слоёв документации `D1-D4` | classifier, chunker, document builder | `src/app/modules/rag/indexing/docs/pipeline.py` |
|
||||
| `CodeIndexingPipeline` | построение слоёв кода `C0-C4` | AST parser, symbol/edge/entrypoint/role builders | `src/app/modules/rag/indexing/code/pipeline.py` |
|
||||
| `RagRepository` | единая точка persistence и retrieval | schema/session/job/document/cache/query repositories | `src/app/modules/rag/persistence/repository.py` |
|
||||
|
||||
|
||||
## Основные доменные области
|
||||
|
||||
- RAG session как граница индекса конкретного проекта или его временного снапшота.
|
||||
- Index job как жизненный цикл асинхронной индексации и канал наблюдения за прогрессом.
|
||||
- RagDocument как атом индекса, который попадает в retrieval-хранилище и в cache.
|
||||
- Repo webhook context как источник commit metadata для story и cache.
|
||||
|
||||
## Основные интеграции
|
||||
|
||||
|
||||
| integration | direction | purpose | protocol / transport | related_docs |
|
||||
| ------------------------ | --------- | --------------------------------------------------- | ---------------------------------- | -------------------------------------------------------------------------- |
|
||||
| PostgreSQL + pgvector | outbound | хранение документов, jobs, sessions и vector search | SQLAlchemy / SQL / pgvector | `logic-rag-retrieval` |
|
||||
| GigaChat embeddings | outbound | получение embedding для batch документов | HTTP client через `GigaChatClient` | `logic-rag-indexing` |
|
||||
| FastAPI | inbound | публичный HTTP API модуля | HTTP | `api-rag-session-create`, `api-rag-session-changes`, `api-rag-session-job` |
|
||||
| EventBus | outbound | публикация прогресса индексации и terminal events | in-process async events / SSE | `api-rag-session-job` |
|
||||
|
||||
|
||||
## Основные потоки
|
||||
|
||||
### Flow 1
|
||||
|
||||
1. Клиент вызывает `POST /api/rag/sessions` с `project_id` и snapshot файлов.
|
||||
2. `RagSessionStore` создаёт `rag_session_id`, а `IndexingOrchestrator` создаёт `IndexJob`.
|
||||
3. `RagService` фильтрует файлы, переиспользует cache по `blob_sha` или строит docs/code документы заново.
|
||||
4. Документы векторизуются, записываются в `rag_chunks`, а job получает финальный статус `done` или `error`.
|
||||
|
||||
### Flow 2
|
||||
|
||||
1. Клиент вызывает `POST /api/rag/sessions/{rag_session_id}/changes`.
|
||||
2. `IndexingOrchestrator` сериализует обработку по `rag_session_id`.
|
||||
3. `RagService` удаляет документы по `delete_paths`, пересобирает upsert-файлы и применяет изменения к индексу.
|
||||
4. Клиент читает статус и события задачи через job endpoints.
|
||||
|
||||
## Архитектурные решения и ограничения
|
||||
|
||||
### Key decisions
|
||||
|
||||
- Snapshot и incremental indexing используют один и тот же `RagService`, различаясь только стратегией записи.
|
||||
- Кэш документов привязан к `repo_id + blob_sha`, а не к `rag_session_id`, что позволяет переиспользовать embeddings между сессиями одного проекта.
|
||||
- Документация и код индексируются разными pipeline, но сохраняются в общую таблицу `rag_chunks`.
|
||||
- Асинхронность вынесена в `IndexingOrchestrator`, чтобы `RagService` оставался application-service без управления job lifecycle.
|
||||
|
||||
### Constraints
|
||||
|
||||
- Code indexing поддерживает только Python-файлы.
|
||||
- Docs indexing ориентирован на markdown и frontmatter YAML.
|
||||
- HTTP retrieval endpoint в модуле не публикуется.
|
||||
- Реальное retrieval API доступно через repository/runtime adapters, а не через публичный HTTP endpoint модуля.
|
||||
|
||||
### Risks
|
||||
|
||||
- Ошибки embeddings или временные сетевые сбои переводят job в `error` только после исчерпания retry.
|
||||
- Полное `replace_documents` для snapshot удаляет все документы сессии перед вставкой новых.
|
||||
- Retrieval ranking завязан на SQL-эвристики по layer, lexical match и metadata, поэтому качество зависит от корректности metadata builders.
|
||||
|
||||
## Нефункциональные аспекты
|
||||
|
||||
### Security
|
||||
|
||||
- Публичные endpoints не содержат собственной бизнес-авторизации внутри модуля и полагаются на внешний слой приложения.
|
||||
|
||||
### Reliability
|
||||
|
||||
- Проектный `asyncio.Lock` предотвращает параллельную индексацию одной `rag_session`.
|
||||
- `RetryExecutor` повторяет временные сбои индексации.
|
||||
|
||||
### Observability
|
||||
|
||||
- Logs: `RagService` пишет предупреждения по cache hit/miss и skipped files.
|
||||
- Metrics: явные метрики не выделены.
|
||||
- Traces: явная трассировка не реализована.
|
||||
- Audit: job status сохраняется в БД.
|
||||
|
||||
### Performance
|
||||
|
||||
- Embeddings отправляются батчами с размером из `RAG_EMBED_BATCH_SIZE`.
|
||||
- Cache reuse исключает повторную векторизацию неизменённых blob.
|
||||
|
||||
### Scalability
|
||||
|
||||
- Индекс хранится на уровне SQL-таблиц с векторными полями и индексами по session/layer/path.
|
||||
- При росте объёма данных узким местом остаются полнотабличные delete/insert по snapshot и SQL sorting retrieval.
|
||||
|
||||
## Связанные сущности
|
||||
|
||||
- `RagSession`
|
||||
- `IndexJob`
|
||||
- `RagDocument`
|
||||
|
||||
## Связанный код
|
||||
|
||||
### Files
|
||||
|
||||
- `src/app/modules/rag/module.py`
|
||||
- `src/app/modules/rag/services/rag_service.py`
|
||||
- `src/app/modules/rag/indexing_service.py`
|
||||
- `src/app/modules/rag/persistence/repository.py`
|
||||
- `src/app/modules/rag/persistence/schema_repository.py`
|
||||
|
||||
### Symbols
|
||||
|
||||
- `RagModule`
|
||||
- `RagService`
|
||||
- `IndexingOrchestrator`
|
||||
- `RagRepository`
|
||||
|
||||
## Связанные документы
|
||||
|
||||
- `logic-rag-indexing`
|
||||
- `logic-rag-retrieval`
|
||||
- `entity-rag-session`
|
||||
- `entity-rag-index-job`
|
||||
- `api-rag-session-create`
|
||||
- `api-rag-session-changes`
|
||||
- `api-rag-session-job`
|
||||
|
||||
## История изменений
|
||||
|
||||
|
||||
| Date | Source | Changes |
|
||||
| ---------- | ------ | ------------------------------------------------------------------- |
|
||||
| 2026-03-13 | code | Создан обзор архитектуры пакета `rag` на основе текущей реализации. |
|
||||
@@ -0,0 +1,154 @@
|
||||
---
|
||||
id: entity-rag-index-job
|
||||
title: Сущность IndexJob
|
||||
doc_type: domain_entity
|
||||
domain: rag
|
||||
status: draft
|
||||
owner: system-analyst
|
||||
source_of_truth: code
|
||||
related_docs:
|
||||
- arch-rag-package
|
||||
- logic-rag-indexing
|
||||
- entity-rag-session
|
||||
- api-rag-session-job
|
||||
related_code:
|
||||
- src/app/modules/rag/job_store.py
|
||||
- src/app/modules/rag/indexing_service.py
|
||||
- src/app/modules/rag/persistence/job_repository.py
|
||||
- src/app/modules/rag/persistence/schema_repository.py
|
||||
entities:
|
||||
- IndexJob
|
||||
- RagSession
|
||||
tags:
|
||||
- rag
|
||||
- indexing
|
||||
- job
|
||||
- domain-entity
|
||||
---
|
||||
# Сущность IndexJob
|
||||
|
||||
## Summary
|
||||
- Domain: rag
|
||||
- Purpose: представить асинхронную задачу индексации и её наблюдаемый статус.
|
||||
- Entity role: operational entity для выполнения snapshot/change indexing.
|
||||
- Main attributes: `index_job_id`, `rag_session_id`, `status`, `indexed_files`, `failed_files`, `cache_hit_files`, `cache_miss_files`, `error`.
|
||||
- Lifecycle: `queued -> running -> done|error`.
|
||||
- Invariants: job всегда принадлежит одной `RagSession`, статус хранится как enum `IndexJobStatus`.
|
||||
- Related APIs: создание job косвенно через session endpoints, чтение через job status endpoint и SSE endpoint.
|
||||
- Related logic: `IndexingOrchestrator`, retry, EventBus publishing.
|
||||
- Source of truth: `src/app/modules/rag/job_store.py`, `src/app/modules/rag/indexing_service.py`.
|
||||
|
||||
## Назначение
|
||||
|
||||
`IndexJob` хранит технический прогресс и итог выполнения индексации. Он нужен, чтобы API модуля мог вернуть результат не синхронно, а через опрос статуса и подписку на события.
|
||||
|
||||
## Контекст
|
||||
|
||||
Job создаётся на каждую snapshot- или changes-операцию. Сервис индексации обновляет его counters и публикует события прогресса в EventBus под ключом `index_job_id`.
|
||||
|
||||
## Роль в доменной модели
|
||||
|
||||
Это операционная сущность, которая связывает пользовательский запрос на индексацию с фактическим процессом обработки файлов. Она не хранит сам индекс, но управляет прозрачностью выполнения и ошибками.
|
||||
|
||||
## Атрибуты
|
||||
|
||||
| attribute | type | required | description | constraints |
|
||||
|-----------|------|----------|-------------|-------------|
|
||||
| `index_job_id` | `str` | yes | уникальный идентификатор задачи | primary key, non-empty |
|
||||
| `rag_session_id` | `str` | yes | ссылка на целевую RAG-сессию | non-empty |
|
||||
| `status` | `IndexJobStatus` | yes | текущее состояние задачи | `queued`, `running`, `done`, `error` |
|
||||
| `indexed_files` | `int` | yes | число успешно обработанных файлов | `>= 0` |
|
||||
| `failed_files` | `int` | yes | число файлов с ошибками | `>= 0` |
|
||||
| `cache_hit_files` | `int` | yes | число файлов, обслуженных из cache | `>= 0` |
|
||||
| `cache_miss_files` | `int` | yes | число файлов, потребовавших embeddings | `>= 0` |
|
||||
| `error` | `ErrorPayload \| None` | no | информация о необработанной временной ошибке после retry | optional |
|
||||
|
||||
## Состояния и жизненный цикл
|
||||
|
||||
### Основные состояния
|
||||
- `queued`
|
||||
- `running`
|
||||
- `done`
|
||||
- `error`
|
||||
|
||||
### Переходы состояний
|
||||
1. `IndexJobStore.create` создаёт job в состоянии `queued`.
|
||||
2. `IndexingOrchestrator._run_with_project_lock` переводит job в `running`.
|
||||
3. Успешная индексация переводит job в `done` и заполняет counters.
|
||||
4. Ошибка после исчерпания retry переводит job в `error` и заполняет `ErrorPayload`.
|
||||
|
||||
## Инварианты и ограничения
|
||||
|
||||
- Job не мигрирует между `rag_session_id`.
|
||||
- Финальные counters сохраняются в БД перед публикацией terminal event.
|
||||
- Ошибки уровня `TimeoutError`, `ConnectionError`, `OSError` считаются временными и оборачиваются в `index_retry_exhausted` только после retry exhaustion.
|
||||
|
||||
## Связи с другими сущностями
|
||||
|
||||
| entity | relation | description |
|
||||
|--------|----------|-------------|
|
||||
| `RagSession` | many-to-one | каждая задача относится к одной сессии |
|
||||
| `RagDocument` | indirect | job обновляет набор документов сессии, но не владеет ими напрямую |
|
||||
|
||||
## Использование в системе
|
||||
|
||||
### Related API
|
||||
- `POST /api/rag/sessions`
|
||||
- `POST /api/rag/sessions/{rag_session_id}/changes`
|
||||
- `GET /api/rag/sessions/{rag_session_id}/jobs/{index_job_id}`
|
||||
- `GET /api/rag/sessions/{rag_session_id}/jobs/{index_job_id}/events`
|
||||
|
||||
### Related UI
|
||||
- Прямого UI в репозитории не обнаружено.
|
||||
|
||||
### Related logic
|
||||
- `logic-rag-indexing`
|
||||
|
||||
### Related integrations
|
||||
- EventBus SSE stream
|
||||
- PostgreSQL таблица `rag_index_jobs`
|
||||
|
||||
## Функциональные требования
|
||||
|
||||
- Job должна создаваться до запуска фоновой задачи.
|
||||
- Публичный API обязан проверять принадлежность job указанной `rag_session_id`.
|
||||
- Progress events должны публиковаться в формате, достаточном для фронта или внешнего клиента.
|
||||
|
||||
## Нефункциональные требования
|
||||
|
||||
### Audit / history
|
||||
- `created_at` и `updated_at` сохраняются в таблице `rag_index_jobs`.
|
||||
|
||||
### Security
|
||||
- Доступ к job опирается на проверку связи `job.rag_session_id == requested rag_session_id`.
|
||||
|
||||
### Observability
|
||||
- SSE stream отдаёт `index_status`, `index_progress`, `terminal`.
|
||||
|
||||
## Связанный код
|
||||
|
||||
### Files
|
||||
- `src/app/modules/rag/job_store.py`
|
||||
- `src/app/modules/rag/indexing_service.py`
|
||||
- `src/app/modules/rag/persistence/job_repository.py`
|
||||
- `src/app/modules/rag/persistence/schema_repository.py`
|
||||
|
||||
### Symbols
|
||||
- `IndexJob`
|
||||
- `IndexJobStore.create`
|
||||
- `IndexJobStore.get`
|
||||
- `IndexJobStore.save`
|
||||
- `IndexingOrchestrator._run_with_project_lock`
|
||||
|
||||
## Связанные документы
|
||||
|
||||
- `arch-rag-package`
|
||||
- `logic-rag-indexing`
|
||||
- `entity-rag-session`
|
||||
- `api-rag-session-job`
|
||||
|
||||
## История изменений
|
||||
|
||||
| Date | Source | Changes |
|
||||
|------|--------|---------|
|
||||
| 2026-03-13 | code | Добавлено описание lifecycle и контракта сущности `IndexJob`. |
|
||||
@@ -0,0 +1,143 @@
|
||||
---
|
||||
id: entity-rag-session
|
||||
title: Сущность RagSession
|
||||
doc_type: domain_entity
|
||||
domain: rag
|
||||
status: draft
|
||||
owner: system-analyst
|
||||
source_of_truth: code
|
||||
related_docs:
|
||||
- arch-rag-package
|
||||
- logic-rag-indexing
|
||||
- api-rag-session-create
|
||||
- api-rag-session-changes
|
||||
- api-rag-session-job
|
||||
related_code:
|
||||
- src/app/modules/rag/session_store.py
|
||||
- src/app/modules/rag/persistence/session_repository.py
|
||||
- src/app/modules/rag/persistence/schema_repository.py
|
||||
entities:
|
||||
- RagSession
|
||||
tags:
|
||||
- rag
|
||||
- session
|
||||
- domain-entity
|
||||
---
|
||||
# Сущность RagSession
|
||||
|
||||
## Summary
|
||||
- Domain: rag
|
||||
- Purpose: связать индекс и связанные job с конкретным проектом или его рабочим снимком.
|
||||
- Entity role: корневая сущность области RAG indexing/retrieval.
|
||||
- Main attributes: `rag_session_id`, `project_id`, `created_at`.
|
||||
- Lifecycle: создаётся до первой индексации и используется как scope всех retrieval-запросов.
|
||||
- Invariants: `rag_session_id` уникален, `project_id` обязателен.
|
||||
- Related APIs: `POST /api/rag/sessions`, `POST /api/rag/sessions/{rag_session_id}/changes`, `GET /api/rag/sessions/{rag_session_id}/jobs/{index_job_id}`.
|
||||
- Related logic: snapshot indexing, change indexing, retrieval filtering.
|
||||
- Source of truth: `src/app/modules/rag/session_store.py`, таблица `rag_sessions`.
|
||||
|
||||
## Назначение
|
||||
|
||||
`RagSession` определяет границу индекса для проекта. Все документы, задачи и retrieval-запросы внутри `rag` привязаны к этой сущности.
|
||||
|
||||
## Контекст
|
||||
|
||||
Сессия используется и в новом API с UUID, и в legacy/internal режиме, где `project_id` может совпадать с `rag_session_id`. Через неё сервис восстанавливает `repo_id`, который затем участвует в кэшировании документов.
|
||||
|
||||
## Роль в доменной модели
|
||||
|
||||
`RagSession` является владельцем набора индексированных документов и асинхронных `IndexJob`. Без неё нельзя безопасно выполнять reindex или retrieval, потому что именно она задаёт scope таблицы `rag_chunks`.
|
||||
|
||||
## Атрибуты
|
||||
|
||||
| attribute | type | required | description | constraints |
|
||||
|-----------|------|----------|-------------|-------------|
|
||||
| `rag_session_id` | `str` | yes | уникальный идентификатор сессии | primary key, non-empty |
|
||||
| `project_id` | `str` | yes | идентификатор проекта или workspace | non-empty |
|
||||
| `created_at` | `timestamp with time zone` | yes | время создания записи в БД | default `CURRENT_TIMESTAMP` |
|
||||
|
||||
## Состояния и жизненный цикл
|
||||
|
||||
### Основные состояния
|
||||
- created
|
||||
- active
|
||||
- reused via legacy/internal API
|
||||
|
||||
### Переходы состояний
|
||||
1. `RagSessionStore.create(project_id)` создаёт новую сессию с UUID.
|
||||
2. `RagSessionStore.put(rag_session_id, project_id)` создаёт или обновляет сессию с заданным ключом.
|
||||
3. После создания сессия используется для indexing и retrieval до тех пор, пока не будет заменена новым идентификатором на уровне вызывающего сервиса.
|
||||
|
||||
## Инварианты и ограничения
|
||||
|
||||
- `project_id` не должен быть пустым.
|
||||
- Для retrieval и indexing используется только один `rag_session_id` за операцию.
|
||||
- `RagService._resolve_repo_id` использует `project_id` этой сущности как `repo_id` для cache scope.
|
||||
|
||||
## Связи с другими сущностями
|
||||
|
||||
| entity | relation | description |
|
||||
|--------|----------|-------------|
|
||||
| `IndexJob` | one-to-many | одна сессия может иметь много задач индексации |
|
||||
| `RagDocument` | one-to-many | все записи в `rag_chunks` привязаны к одной сессии |
|
||||
|
||||
## Использование в системе
|
||||
|
||||
### Related API
|
||||
- `POST /api/rag/sessions`
|
||||
- `POST /api/rag/sessions/{rag_session_id}/changes`
|
||||
- `GET /api/rag/sessions/{rag_session_id}/jobs/{index_job_id}`
|
||||
|
||||
### Related UI
|
||||
- Прямого UI в репозитории не обнаружено.
|
||||
|
||||
### Related logic
|
||||
- `logic-rag-indexing`
|
||||
- `logic-rag-retrieval`
|
||||
|
||||
### Related integrations
|
||||
- PostgreSQL таблица `rag_sessions`
|
||||
|
||||
## Функциональные требования
|
||||
|
||||
- Сессия должна создаваться до постановки snapshot job.
|
||||
- При change indexing запрос должен ссылаться на существующую сессию в новом публичном API.
|
||||
- Legacy/internal API может создавать запись с предсказуемым `rag_session_id`, равным `project_id`.
|
||||
|
||||
## Нефункциональные требования
|
||||
|
||||
### Audit / history
|
||||
- Время создания фиксируется в таблице `rag_sessions`.
|
||||
|
||||
### Security
|
||||
- Отдельных прав доступа на уровне сущности внутри модуля нет.
|
||||
|
||||
### Observability
|
||||
- Основная наблюдаемость сессии идёт через связанные `IndexJob`.
|
||||
|
||||
## Связанный код
|
||||
|
||||
### Files
|
||||
- `src/app/modules/rag/session_store.py`
|
||||
- `src/app/modules/rag/persistence/session_repository.py`
|
||||
- `src/app/modules/rag/persistence/schema_repository.py`
|
||||
|
||||
### Symbols
|
||||
- `RagSession`
|
||||
- `RagSessionStore.create`
|
||||
- `RagSessionStore.put`
|
||||
- `RagSessionStore.get`
|
||||
|
||||
## Связанные документы
|
||||
|
||||
- `arch-rag-package`
|
||||
- `logic-rag-indexing`
|
||||
- `api-rag-session-create`
|
||||
- `api-rag-session-changes`
|
||||
- `api-rag-session-job`
|
||||
|
||||
## История изменений
|
||||
|
||||
| Date | Source | Changes |
|
||||
|------|--------|---------|
|
||||
| 2026-03-13 | code | Добавлено описание сущности `RagSession` и её роли в границах индекса. |
|
||||
@@ -0,0 +1,164 @@
|
||||
---
|
||||
id: logic-rag-indexing
|
||||
title: Индексация файлов в RAG
|
||||
doc_type: logic_block
|
||||
domain: rag
|
||||
status: draft
|
||||
owner: system-analyst
|
||||
source_of_truth: code
|
||||
related_docs:
|
||||
- arch-rag-package
|
||||
- entity-rag-session
|
||||
- entity-rag-index-job
|
||||
- api-rag-session-create
|
||||
- api-rag-session-changes
|
||||
related_code:
|
||||
- src/app/modules/rag/indexing_service.py
|
||||
- src/app/modules/rag/services/rag_service.py
|
||||
- src/app/modules/rag/indexing/docs/pipeline.py
|
||||
- src/app/modules/rag/indexing/code/pipeline.py
|
||||
- src/app/modules/rag/persistence/document_repository.py
|
||||
entities:
|
||||
- RagSession
|
||||
- IndexJob
|
||||
- RagDocument
|
||||
tags:
|
||||
- rag
|
||||
- indexing
|
||||
- snapshot
|
||||
- changes
|
||||
---
|
||||
# Индексация файлов в RAG
|
||||
|
||||
## Summary
|
||||
- Purpose: превратить входной список файлов в набор индексируемых `RagDocument` и сохранить их в persistence.
|
||||
- Trigger: создание RAG-сессии, запрос изменений, internal snapshot/changes endpoints.
|
||||
- Inputs: `rag_session_id`, файлы snapshot или changed_files, progress callback.
|
||||
- Outputs: обновлённые записи в `rag_chunks`, `rag_session_chunk_map`, статистика indexed/failed/cache hit/cache miss.
|
||||
- Main entities: `RagSession`, `IndexJob`, `RagDocument`.
|
||||
- Main dependencies: `IndexingOrchestrator`, `RagService`, `DocsIndexingPipeline`, `CodeIndexingPipeline`, `GigaChatEmbedder`, `RagRepository`.
|
||||
- Side effects: SQL delete/insert, cache write, SSE events, job status update.
|
||||
- Source of truth: `src/app/modules/rag/indexing_service.py`, `src/app/modules/rag/services/rag_service.py`.
|
||||
|
||||
## Назначение
|
||||
|
||||
Блок обеспечивает управляемую индексацию файлов проекта в многослойный RAG-индекс. Он должен одинаково поддерживать полный snapshot и инкрементальные изменения, не допуская гонок внутри одной `rag_session_id`.
|
||||
|
||||
## Контекст
|
||||
|
||||
Индексация запускается через HTTP API модуля. `IndexingOrchestrator` отвечает за job lifecycle и progress events, а `RagService` за фактическую переработку файлов в документы. Для уменьшения стоимости embeddings используется cache по содержимому blob.
|
||||
|
||||
## Технический use case
|
||||
|
||||
### Основной сценарий
|
||||
|
||||
1. API создаёт `IndexJob` и передаёт управление в `IndexingOrchestrator`.
|
||||
2. `IndexingOrchestrator` фильтрует входной набор, ставит статус `running`, публикует стартовое событие и захватывает lock по `rag_session_id`.
|
||||
3. `RagService` определяет `repo_id`, фильтрует индексируемые файлы, проверяет cache по `blob_sha` и либо переиспользует документы, либо заново строит docs/code слои.
|
||||
4. Для новых документов `RagService` добавляет file metadata, запрашивает embeddings батчами и сохраняет документы через `RagRepository`.
|
||||
5. `IndexingOrchestrator` обновляет job counters, публикует финальный `index_status` и `terminal`.
|
||||
|
||||
### Альтернативные ветки
|
||||
|
||||
- Для `changes` операции с `op=delete` только удаляют документы по `path`, без повторной сборки.
|
||||
- Если файл не поддержан ни docs-, ни code-pipeline, сервис делает fallback в docs pipeline.
|
||||
- При временном сбое индексации `RetryExecutor` повторяет операцию; после исчерпания попыток job получает `error`.
|
||||
|
||||
## Функциональные требования
|
||||
|
||||
### Preconditions
|
||||
- `rag_session_id` уже существует либо создаётся до запуска indexing job.
|
||||
- Файлы передаются в виде словарей, совместимых со схемами `FileSnapshot` или `ChangedFile`.
|
||||
- Для cache reuse у файла должен быть `content_hash` или доступный `content`.
|
||||
|
||||
### Processing rules
|
||||
- Snapshot перед записью выполняет полную замену документов сессии через `replace_documents`.
|
||||
- Incremental changes отделяет `delete_paths` от upsert-файлов и применяет изменения через `apply_document_changes`.
|
||||
- `repo_id` выводится из `project_id` у сессии, а при отсутствии сессии fallback равен `rag_session_id`.
|
||||
- Для поддерживаемого markdown строятся docs-слои `D1-D4`.
|
||||
- Для поддерживаемого Python-кода строятся code-слои `C0-C4`.
|
||||
- Каждый документ получает metadata файла: `blob_sha`, `repo_id`, `artifact_type`, `section`, `doc_id`, `owner`, `system_component`, `last_modified`, `staleness_score`.
|
||||
|
||||
### Validation rules
|
||||
- До индексации snapshot/changes проходят фильтрацию через `filter_snapshot_files` и `filter_changes_for_indexing`.
|
||||
- Пустые или неподходящие файлы исключаются из обрабатываемого набора.
|
||||
- Вектор сохраняется только если размерность embedding совпадает с размерностью поля `vector` при retrieval.
|
||||
|
||||
### Output / result rules
|
||||
- Результат операции всегда выражается четырьмя счётчиками: `indexed_files`, `failed_files`, `cache_hit_files`, `cache_miss_files`.
|
||||
- Для snapshot весь набор документов сессии после операции должен соответствовать текущему переданному snapshot.
|
||||
- Для changes в индексе должны остаться только документы по актуальному состоянию изменённых путей.
|
||||
|
||||
### Side effects
|
||||
- Удаление и вставка строк в `rag_chunks`.
|
||||
- Запись `rag_session_chunk_map` для документов, имеющих `repo_id` и `blob_sha`.
|
||||
- Сохранение cache в `rag_blob_cache` и `rag_chunk_cache`.
|
||||
- Публикация SSE-событий прогресса и завершения задачи.
|
||||
|
||||
## Ограничения и условия вызова
|
||||
|
||||
- Одновременно может выполняться только одна indexing operation на `rag_session_id`.
|
||||
- Code indexing работает только для Python файлов, распознаваемых `PythonFileFilter`.
|
||||
- Docs indexing рассчитывает на markdown с возможным YAML frontmatter.
|
||||
- Метод `replace_documents` делает жёсткую замену индекса сессии и не подходит для конкурентного merge разных snapshot-источников.
|
||||
|
||||
## Нефункциональные требования
|
||||
|
||||
### Security
|
||||
- Модуль не валидирует источник файлов и не выполняет контентную санацию сверх собственных парсеров.
|
||||
|
||||
### Observability
|
||||
- Logs: фиксируются skipped files и режим обработки `cache` / `embed`.
|
||||
- Metrics: отдельные счётчики не выделены, но статистика сохраняется в job.
|
||||
- Traces: не реализованы.
|
||||
- Audit: `rag_index_jobs` и `rag_session_chunk_map` образуют журнал выполнения и происхождения chunk.
|
||||
|
||||
### Reliability
|
||||
- `asyncio.Lock` сериализует операции в рамках одной сессии.
|
||||
- `RetryExecutor` покрывает временные ошибки `TimeoutError`, `ConnectionError`, `OSError`.
|
||||
|
||||
### Performance
|
||||
- Embeddings обрабатываются батчами.
|
||||
- Cache hit исключает повторный парсинг и повторный вызов embedder.
|
||||
|
||||
## Связанные API / UI / integration points
|
||||
|
||||
- `POST /api/rag/sessions`
|
||||
- `POST /api/rag/sessions/{rag_session_id}/changes`
|
||||
|
||||
## Связанные сущности
|
||||
|
||||
- `RagSession`
|
||||
- `IndexJob`
|
||||
- `RagDocument`
|
||||
|
||||
## Связанный код
|
||||
|
||||
### Files
|
||||
- `src/app/modules/rag/indexing_service.py`
|
||||
- `src/app/modules/rag/services/rag_service.py`
|
||||
- `src/app/modules/rag/indexing/docs/pipeline.py`
|
||||
- `src/app/modules/rag/indexing/code/pipeline.py`
|
||||
- `src/app/modules/rag/persistence/document_repository.py`
|
||||
|
||||
### Symbols
|
||||
- `IndexingOrchestrator.enqueue_snapshot`
|
||||
- `IndexingOrchestrator.enqueue_changes`
|
||||
- `IndexingOrchestrator._run_with_project_lock`
|
||||
- `RagService.index_snapshot`
|
||||
- `RagService.index_changes`
|
||||
- `RagService._index_files`
|
||||
|
||||
## Связанные документы
|
||||
|
||||
- `arch-rag-package`
|
||||
- `entity-rag-session`
|
||||
- `entity-rag-index-job`
|
||||
- `api-rag-session-create`
|
||||
- `api-rag-session-changes`
|
||||
|
||||
## История изменений
|
||||
|
||||
| Date | Source | Changes |
|
||||
|------|--------|---------|
|
||||
| 2026-03-13 | code | Описана фактическая логика snapshot и incremental indexing пакета `rag`. |
|
||||
@@ -0,0 +1,150 @@
|
||||
---
|
||||
id: logic-rag-retrieval
|
||||
title: Retrieval и ранжирование RAG-документов
|
||||
doc_type: logic_block
|
||||
domain: rag
|
||||
status: draft
|
||||
owner: system-analyst
|
||||
source_of_truth: code
|
||||
related_docs:
|
||||
- arch-rag-package
|
||||
- entity-rag-session
|
||||
related_code:
|
||||
- src/app/modules/rag/persistence/repository.py
|
||||
- src/app/modules/rag/persistence/query_repository.py
|
||||
- src/app/modules/rag/persistence/retrieval_statement_builder.py
|
||||
- src/app/modules/rag/contracts/enums.py
|
||||
entities:
|
||||
- RagSession
|
||||
- RagDocument
|
||||
tags:
|
||||
- rag
|
||||
- retrieval
|
||||
- ranking
|
||||
- pgvector
|
||||
---
|
||||
# Retrieval и ранжирование RAG-документов
|
||||
|
||||
## Summary
|
||||
- Purpose: вернуть релевантные RAG-документы из `rag_chunks` для заданной сессии и набора фильтров.
|
||||
- Trigger: вызовы runtime adapters и внутренних retrieval-компонентов.
|
||||
- Inputs: `rag_session_id`, `query_embedding`, `query_text`, `layers`, path filters, preference filters, limit.
|
||||
- Outputs: список rows с `path`, `content`, `layer`, `title`, `metadata`, `span_start`, `span_end`, ranking fields.
|
||||
- Main entities: `RagSession`, `RagDocument`.
|
||||
- Main dependencies: `RagRepository`, `RagQueryRepository`, `RetrievalStatementBuilder`, PostgreSQL/pgvector.
|
||||
- Side effects: отсутствуют, retrieval только читает БД.
|
||||
- Source of truth: `src/app/modules/rag/persistence/query_repository.py`, `src/app/modules/rag/persistence/retrieval_statement_builder.py`.
|
||||
|
||||
## Назначение
|
||||
|
||||
Блок retrieval выбирает из индекса наиболее полезные документы по конкретному `rag_session_id`. Он объединяет в одном SQL векторную близость, lexical match, слой документа и структурные сигналы из metadata.
|
||||
|
||||
## Контекст
|
||||
|
||||
Публичный HTTP endpoint retrieval внутри `rag` помечен как deprecated, поэтому рабочий доступ к retrieval идёт через repository/runtime adapters. Это означает, что контракт фактически определяется SQL-builder и форматом rows, возвращаемых `RagQueryRepository`.
|
||||
|
||||
## Технический use case
|
||||
|
||||
### Основной сценарий
|
||||
|
||||
1. Клиент runtime вызывает `RagRepository.retrieve(...)`.
|
||||
2. `RagQueryRepository` строит SQL через `RetrievalStatementBuilder.build_retrieve`.
|
||||
3. SQL ограничивает поиск текущей `rag_session_id`, при необходимости слоями и path-фильтрами.
|
||||
4. База сортирует документы по `prefer_bonus`, `test_penalty`, `layer_rank`, `lexical_rank`, `structural_rank`, `distance`.
|
||||
5. Репозиторий возвращает rows с распарсенным `metadata_json`.
|
||||
|
||||
### Альтернативные ветки
|
||||
|
||||
- Для lexical fallback по коду используется `retrieve_lexical_code`, который работает только по слою `C0_SOURCE_CHUNKS`.
|
||||
- Для точного добора файлов используется `retrieve_exact_files`, который читает заданные `path` без векторного ранжирования.
|
||||
- Если `query_text` не даёт terms, lexical retrieval возвращает пустой результат без выполнения SQL.
|
||||
|
||||
## Функциональные требования
|
||||
|
||||
### Preconditions
|
||||
- В `rag_chunks` уже должны существовать документы нужной `rag_session_id`.
|
||||
- Для vector retrieval embedding документа должен быть ненулевым и совпадать по размерности с query embedding.
|
||||
|
||||
### Processing rules
|
||||
- Базовый фильтр retrieval всегда включает `rag_session_id = :sid`.
|
||||
- При наличии `layers` запрос ограничивается указанными слоями.
|
||||
- `path_prefixes` задают include-фильтр по `LIKE prefix%`.
|
||||
- `exclude_path_prefixes` и `exclude_like_patterns` исключают части дерева путей до сортировки.
|
||||
- `prefer_path_prefixes` и `prefer_like_patterns` формируют `prefer_bonus`, поднимая приоритет совпавших путей.
|
||||
- `prefer_non_tests` создаёт `test_penalty`, если путь попадает под test-паттерны.
|
||||
|
||||
### Validation rules
|
||||
- Path filters экранируются для корректной работы `LIKE`.
|
||||
- `retrieve_exact_files` нормализует и отбрасывает пустые пути до построения SQL.
|
||||
- `retrieve_lexical_code` не выполняет SQL, если query terms отсутствуют.
|
||||
|
||||
### Output / result rules
|
||||
- Каждый row содержит контент документа и технические поля ранжирования.
|
||||
- `metadata_json` всегда декодируется в словарь `metadata`.
|
||||
- Limit применяется на уровне SQL и ограничивает итоговый набор строк.
|
||||
|
||||
### Side effects
|
||||
- Побочных эффектов нет, кроме чтения из БД.
|
||||
|
||||
## Ограничения и условия вызова
|
||||
|
||||
- Retrieval работает только внутри одной `rag_session_id` и не агрегирует несколько сессий.
|
||||
- Layer ranking зашит в код SQL-builder и требует явного обновления при появлении новых слоёв.
|
||||
- Полноценный HTTP retrieval endpoint в модуле не публикуется.
|
||||
|
||||
## Нефункциональные требования
|
||||
|
||||
### Security
|
||||
- Retrieval не выполняет маскирование содержимого документов.
|
||||
|
||||
### Observability
|
||||
- Logs: отдельное логирование запросов retrieval не реализовано.
|
||||
- Metrics: метрики по latency и quality не выделены.
|
||||
- Traces: отсутствуют.
|
||||
- Audit: результат зависит только от состояния `rag_chunks` и входных фильтров.
|
||||
|
||||
### Reliability
|
||||
- Пустой или некорректный lexical search безопасно возвращает пустой набор.
|
||||
- `retrieve_exact_files` работает без embeddings и может использоваться как fallback.
|
||||
|
||||
### Performance
|
||||
- Основной ranking выполняется в одном SQL-запросе.
|
||||
- Для vector retrieval используются поля `embedding` и индексы по session/layer/path.
|
||||
|
||||
## Связанные API / UI / integration points
|
||||
|
||||
- Runtime retrieval adapters в `src/app/modules/agent/runtime/steps/retrieval/adapter.py`
|
||||
- Explain retrieval gateway в `src/app/modules/agent/runtime/steps/explain/layered_gateway.py`
|
||||
- HTTP retrieval endpoint отсутствует
|
||||
|
||||
## Связанные сущности
|
||||
|
||||
- `RagSession`
|
||||
- `RagDocument`
|
||||
|
||||
## Связанный код
|
||||
|
||||
### Files
|
||||
- `src/app/modules/rag/persistence/repository.py`
|
||||
- `src/app/modules/rag/persistence/query_repository.py`
|
||||
- `src/app/modules/rag/persistence/retrieval_statement_builder.py`
|
||||
- `src/app/modules/rag/contracts/enums.py`
|
||||
|
||||
### Symbols
|
||||
- `RagRepository.retrieve`
|
||||
- `RagRepository.retrieve_lexical_code`
|
||||
- `RagRepository.retrieve_exact_files`
|
||||
- `RagQueryRepository.retrieve`
|
||||
- `RetrievalStatementBuilder.build_retrieve`
|
||||
- `RetrievalStatementBuilder.build_lexical_code`
|
||||
|
||||
## Связанные документы
|
||||
|
||||
- `arch-rag-package`
|
||||
- `entity-rag-session`
|
||||
|
||||
## История изменений
|
||||
|
||||
| Date | Source | Changes |
|
||||
|------|--------|---------|
|
||||
| 2026-03-13 | code | Описан фактический retrieval contract и ranking SQL для пакета `rag`. |
|
||||
@@ -0,0 +1,32 @@
|
||||
# DOCS Intent Router MVP
|
||||
|
||||
## Supported Intents
|
||||
|
||||
- `DOCS_QA.API_METHOD_EXPLAIN`
|
||||
- `DOCS_DISCOVERY.LIST_API_METHODS`
|
||||
- `DOCS_DISCOVERY.FIND_DOCUMENTS_BY_DOMAIN`
|
||||
- `DOCS_GENERATION.GENERATE_OPENAPI`
|
||||
- `DOCS_FALLBACK.GENERAL_DOCS_QA`
|
||||
|
||||
## Routing Flow
|
||||
|
||||
1. `Stage A`: deterministic pre-routing нормализует запрос, извлекает anchors и scope, считает rule-based confidence.
|
||||
2. `Stage B`: confidence gating пропускает high-confidence кейсы напрямую и эскалирует ambiguous/weak запросы в LLM.
|
||||
3. `Stage C`: LLM classifier выбирает только один из 5 MVP саб-интентов и возвращает строгий JSON.
|
||||
4. После выбора саб-интента router всегда прикрепляет декларативный `retrieval_plan`.
|
||||
|
||||
## Confidence And Escalation
|
||||
|
||||
- `>= 0.8` и без конфликтующих сигналов: `routing_mode=deterministic`.
|
||||
- Ниже порога, при пересечении интентов, слабых anchors или коротком неоднозначном запросе: `routing_mode=llm_assisted`.
|
||||
- Если LLM недоступен или вернул невалидный класс: `routing_mode=llm_fallback` c fallback в `GENERAL_DOCS_QA`.
|
||||
|
||||
## Retrieval Plan Mapping
|
||||
|
||||
- `API_METHOD_EXPLAIN` -> `docs_api_method_explain_v1`
|
||||
- `LIST_API_METHODS` -> `docs_list_api_methods_v1`
|
||||
- `FIND_DOCUMENTS_BY_DOMAIN` -> `docs_find_documents_by_domain_v1`
|
||||
- `GENERATE_OPENAPI` -> `docs_generate_openapi_v1`
|
||||
- `GENERAL_DOCS_QA` -> `docs_general_docs_qa_v1`
|
||||
|
||||
`retrieval_plan` хранится декларативно в `src/app/modules/agent/intent_router_v2/docs_mvp/retrieval_plans.py`, а legacy `retrieval_spec.filters` обогащается теми же anchors и scope для совместимости с текущим runtime.
|
||||
@@ -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,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,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,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,105 @@
|
||||
`pipeline_setup_v3` это YAML-driven test harness для проверки agent pipeline на уровне сценариев, а не unit-тестов.
|
||||
|
||||
Как он работает:
|
||||
- Берёт один YAML-файл или директорию с YAML-кейсами.
|
||||
- Каждый кейс описывает:
|
||||
- `id`
|
||||
- `query`
|
||||
- `runner`
|
||||
- `mode`
|
||||
- `input`
|
||||
- `expected`
|
||||
- Если в `input` нет готового `rag_session_id`, harness сам получает его:
|
||||
- либо берёт из `input.rag_session_id`
|
||||
- либо индексирует `input.repo_path` в RAG и кеширует полученную сессию для одинакового `(repo_path, project_id)`
|
||||
|
||||
Какие режимы кейсов есть:
|
||||
- `router_only`
|
||||
Проверяется только роутинг, без retrieval и без LLM.
|
||||
- `router_rag`
|
||||
Проверяется роутинг плюс retrieval, но без полной генерации ответа.
|
||||
- `full_chain`
|
||||
Проверяется полный pipeline: router → retrieval → downstream pipeline/LLM → final answer.
|
||||
|
||||
Как устроен execution flow:
|
||||
1. Loader читает YAML и превращает каждый кейс в `V3Case`.
|
||||
2. Runner для каждого кейса резолвит `rag_session_id`.
|
||||
3. `AgentRuntimeAdapter` исполняет кейс в зависимости от `mode`.
|
||||
4. Возвращаются два объекта:
|
||||
- `actual`
|
||||
- `details`
|
||||
5. Validator сравнивает `actual/details` с `expected`.
|
||||
6. Writer сохраняет:
|
||||
- JSON с машинными результатами
|
||||
- Markdown с человекочитаемой диагностикой
|
||||
- итоговый `summary.md` по всему прогону
|
||||
|
||||
Что обычно лежит в `actual`:
|
||||
- `intent`
|
||||
- `sub_intent`
|
||||
- `graph_id`
|
||||
- `conversation_mode`
|
||||
- `rag_count`
|
||||
- `answer_mode`
|
||||
- `llm_answer`
|
||||
- `path_scope`
|
||||
- `doc_scope`
|
||||
- `entity_candidates`
|
||||
- `symbol_candidates`
|
||||
- `layers`
|
||||
- `filters`
|
||||
|
||||
Что лежит в `details`:
|
||||
- `router_result`
|
||||
- `retrieval_request`
|
||||
- `retrieval_result`
|
||||
- `rag_rows`
|
||||
- `diagnostics`
|
||||
- `llm_request`
|
||||
- `pipeline_steps`
|
||||
- иногда `validation`, `token_usage`, `runtime_trace`
|
||||
|
||||
Что умеют expectations:
|
||||
- `expected.router`
|
||||
Проверяет `intent`, `sub_intent`, `graph_id`, `conversation_mode`
|
||||
- `expected.retrieval`
|
||||
Проверяет:
|
||||
- пустой/непустой retrieval
|
||||
- минимум строк
|
||||
- наличие нужных слоёв
|
||||
- path/doc scope
|
||||
- symbol/entity candidates
|
||||
- фильтры
|
||||
- `expected.llm`
|
||||
Проверяет:
|
||||
- есть ли ответ
|
||||
- содержит ли ответ обязательные фразы
|
||||
- не содержит ли запрещённые фразы
|
||||
- `answer_mode`
|
||||
- `expected.pipeline`
|
||||
Проверяет в основном итоговый `answer_mode`
|
||||
|
||||
Что важно при формулировке нового test case для ChatGPT:
|
||||
- кейс должен описывать не “как реализовать код”, а “какой пользовательский сценарий проверяем”
|
||||
- у кейса должны быть:
|
||||
- понятный `query`
|
||||
- корректный `mode`
|
||||
- вход: `rag_session_id` или `repo_path`
|
||||
- минимально достаточные `expected`
|
||||
- не надо переописывать весь output, лучше проверять только ключевые инварианты
|
||||
|
||||
Хороший шаблон задания для ChatGPT:
|
||||
1. Укажи, для какого suite нужен кейс.
|
||||
2. Укажи `mode`: `router_only`, `router_rag` или `full_chain`.
|
||||
3. Дай пользовательский `query`.
|
||||
4. Опиши, что именно должно проверяться:
|
||||
- роутинг
|
||||
- retrieval layers/scope
|
||||
- answer mode
|
||||
- ключевые фразы в ответе
|
||||
5. Попроси вернуть YAML-фрагмент в формате `pipeline_setup_v3`.
|
||||
|
||||
Пример формулировки для ChatGPT:
|
||||
“Сформируй YAML test case для `pipeline_setup_v3` в режиме `full_chain`. Нужно проверить, что запрос `Объясни по документации как работает /health` маршрутизируется в docs-intent, retrieval использует docs layers, retrieval непустой, а ответ содержит `/health` и не содержит фраз про отсутствие данных.”
|
||||
|
||||
Если хочешь, я могу сразу подготовить тебе готовый prompt для ChatGPT, который будет генерировать новые кейсы в нужном формате.
|
||||
@@ -4,3 +4,4 @@ markers =
|
||||
router_rag: intent-router -> rag integration pipeline tests
|
||||
full_chain: intent-router -> rag -> llm integration pipeline tests
|
||||
code_qa_eval: CODE_QA golden evaluation harness (fixture + real-adapter; needs DB for full run)
|
||||
docs_qa_eval: DOCS_QA golden evaluation harness
|
||||
|
||||
@@ -0,0 +1,327 @@
|
||||
# Runtime Trace: 20260410-130611-31bb5d20c67b
|
||||
|
||||
- active_rag_session_id: 0ae059fe-076a-4aa4-abd4-31bb5d20c67b
|
||||
|
||||
## request
|
||||
```json
|
||||
{
|
||||
"request_id": "req_a14d483fd13b44fa98eb81dd6dd3ccdc",
|
||||
"session_id": "as_90d274870b1247d19694bbef1afa389a",
|
||||
"active_rag_session_id": "0ae059fe-076a-4aa4-abd4-31bb5d20c67b",
|
||||
"process_version": "v2",
|
||||
"created_at": "2026-04-10T13:06:11.385561+00:00",
|
||||
"message": "Какие методы апи есть в проекте"
|
||||
}
|
||||
```
|
||||
|
||||
## process.v2
|
||||
```json
|
||||
{
|
||||
"event": "intent_routed",
|
||||
"routing_domain": "DOCS",
|
||||
"intent": "DOC_EXPLAIN",
|
||||
"subintent": "API_EXPOSED",
|
||||
"normalized_query": "Какие методы апи есть в проекте",
|
||||
"target_terms": [],
|
||||
"anchors": {
|
||||
"entity_names": [],
|
||||
"file_names": [],
|
||||
"endpoint_paths": [],
|
||||
"target_doc_hints": [],
|
||||
"matched_aliases": [],
|
||||
"process_domain": null,
|
||||
"process_subdomain": null,
|
||||
"scope_type": "global",
|
||||
"candidate_domains": [],
|
||||
"candidate_subdomains": [],
|
||||
"candidate_entities": [],
|
||||
"candidate_apis": [],
|
||||
"signal_types": []
|
||||
},
|
||||
"confidence": 0.8500000000000001,
|
||||
"routing_mode": "llm_default",
|
||||
"llm_router_used": true,
|
||||
"reason_short": "Запрос явно касается перечисления доступных API-методов.",
|
||||
"rag_session_id": "0ae059fe-076a-4aa4-abd4-31bb5d20c67b"
|
||||
}
|
||||
```
|
||||
|
||||
## process.v2.pipeline
|
||||
```json
|
||||
{
|
||||
"event": "router_resolved",
|
||||
"domain": "DOCS",
|
||||
"intent": "DOC_EXPLAIN",
|
||||
"subintent": "API_EXPOSED",
|
||||
"confidence": 0.8500000000000001
|
||||
}
|
||||
```
|
||||
|
||||
## process.v2.pipeline
|
||||
```json
|
||||
{
|
||||
"event": "anchors_extracted",
|
||||
"signal_types": [],
|
||||
"endpoint_paths": [],
|
||||
"target_doc_hints": [],
|
||||
"matched_aliases": [],
|
||||
"target_terms": []
|
||||
}
|
||||
```
|
||||
|
||||
## process.v2.pipeline
|
||||
```json
|
||||
{
|
||||
"event": "alias_resolution",
|
||||
"resolved_aliases": [],
|
||||
"target_doc_hints": []
|
||||
}
|
||||
```
|
||||
|
||||
## workflow.v2.api_exposed
|
||||
```json
|
||||
{
|
||||
"event": "workflow_started",
|
||||
"workflow_id": "v2.docs_explain.api_exposed"
|
||||
}
|
||||
```
|
||||
|
||||
## workflow.v2.api_exposed
|
||||
```json
|
||||
{
|
||||
"event": "workflow_step_traced",
|
||||
"workflow_id": "v2.docs_explain.api_exposed",
|
||||
"step": {
|
||||
"id": "require_rag_session",
|
||||
"title": "Проверка RAG-сессии"
|
||||
},
|
||||
"input": {},
|
||||
"output": {
|
||||
"has_rag_session": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## process.v2.retrieval_policy
|
||||
```json
|
||||
{
|
||||
"event": "retrieval_plan_resolved",
|
||||
"profile": "api_exposed",
|
||||
"layers": [
|
||||
"D1_DOCUMENT_CATALOG"
|
||||
],
|
||||
"limit": 400,
|
||||
"filters": {
|
||||
"metadata.type": "api_method",
|
||||
"prefer_path_prefixes": [
|
||||
"docs/api/",
|
||||
"docs/endpoints/",
|
||||
"docs/methods/",
|
||||
"api/",
|
||||
"endpoints/",
|
||||
"methods/"
|
||||
],
|
||||
"target_doc_hints": [],
|
||||
"prefer_like_patterns": [
|
||||
"%api%",
|
||||
"%endpoint%",
|
||||
"%method%",
|
||||
"%эндпоинт%",
|
||||
"%метод%"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## process.v2.pipeline
|
||||
```json
|
||||
{
|
||||
"event": "retrieval_profile_selected",
|
||||
"profile": "api_exposed",
|
||||
"layers": [
|
||||
"D1_DOCUMENT_CATALOG"
|
||||
],
|
||||
"filters": {
|
||||
"metadata.type": "api_method",
|
||||
"prefer_path_prefixes": [
|
||||
"docs/api/",
|
||||
"docs/endpoints/",
|
||||
"docs/methods/",
|
||||
"api/",
|
||||
"endpoints/",
|
||||
"methods/"
|
||||
],
|
||||
"target_doc_hints": [],
|
||||
"prefer_like_patterns": [
|
||||
"%api%",
|
||||
"%endpoint%",
|
||||
"%method%",
|
||||
"%эндпоинт%",
|
||||
"%метод%"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## workflow.v2.api_exposed
|
||||
```json
|
||||
{
|
||||
"event": "workflow_step_traced",
|
||||
"workflow_id": "v2.docs_explain.api_exposed",
|
||||
"step": {
|
||||
"id": "resolve_retrieval_plan",
|
||||
"title": "Выбор retrieval-плана"
|
||||
},
|
||||
"input": {},
|
||||
"output": {
|
||||
"profile": "api_exposed"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## workflow.v2.api_exposed
|
||||
```json
|
||||
{
|
||||
"event": "workflow_step_traced",
|
||||
"workflow_id": "v2.docs_explain.api_exposed",
|
||||
"step": {
|
||||
"id": "fetch_rag_rows",
|
||||
"title": "Получение строк из RAG"
|
||||
},
|
||||
"input": {},
|
||||
"output": {
|
||||
"retrieved_row_count": 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## process.v2.evidence
|
||||
```json
|
||||
{
|
||||
"event": "evidence_assembled",
|
||||
"mode": "api_exposed",
|
||||
"endpoint_count": 3,
|
||||
"endpoints": [
|
||||
"GET /api/v1/clients/contacts-dgr",
|
||||
"GET /api/v1/clients/contacts-dgr/{contactid}",
|
||||
"POST /api/v1/clients/contacts-dgr"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## process.v2.pipeline
|
||||
```json
|
||||
{
|
||||
"event": "evidence_assembled",
|
||||
"mode": "api_exposed",
|
||||
"endpoint_count": 3
|
||||
}
|
||||
```
|
||||
|
||||
## workflow.v2.api_exposed
|
||||
```json
|
||||
{
|
||||
"event": "workflow_step_traced",
|
||||
"workflow_id": "v2.docs_explain.api_exposed",
|
||||
"step": {
|
||||
"id": "build_api_exposed_evidence",
|
||||
"title": "Сборка списка API"
|
||||
},
|
||||
"input": {},
|
||||
"output": {
|
||||
"endpoint_count": 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## workflow.v2.api_exposed
|
||||
```json
|
||||
{
|
||||
"event": "workflow_step_traced",
|
||||
"workflow_id": "v2.docs_explain.api_exposed",
|
||||
"step": {
|
||||
"id": "finalize_api_exposed_answer",
|
||||
"title": "Формирование ответа со списком API"
|
||||
},
|
||||
"input": {},
|
||||
"output": {
|
||||
"answer_length": 111
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## workflow.v2.api_exposed
|
||||
```json
|
||||
{
|
||||
"event": "workflow_trace_flushed",
|
||||
"workflow_id": "v2.docs_explain.api_exposed",
|
||||
"steps": [
|
||||
{
|
||||
"step_id": "require_rag_session",
|
||||
"title": "Проверка RAG-сессии",
|
||||
"input": {},
|
||||
"output": {
|
||||
"has_rag_session": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"step_id": "resolve_retrieval_plan",
|
||||
"title": "Выбор retrieval-плана",
|
||||
"input": {},
|
||||
"output": {
|
||||
"profile": "api_exposed"
|
||||
}
|
||||
},
|
||||
{
|
||||
"step_id": "fetch_rag_rows",
|
||||
"title": "Получение строк из RAG",
|
||||
"input": {},
|
||||
"output": {
|
||||
"retrieved_row_count": 3
|
||||
}
|
||||
},
|
||||
{
|
||||
"step_id": "build_api_exposed_evidence",
|
||||
"title": "Сборка списка API",
|
||||
"input": {},
|
||||
"output": {
|
||||
"endpoint_count": 3
|
||||
}
|
||||
},
|
||||
{
|
||||
"step_id": "finalize_api_exposed_answer",
|
||||
"title": "Формирование ответа со списком API",
|
||||
"input": {},
|
||||
"output": {
|
||||
"answer_length": 111
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## workflow.v2.api_exposed
|
||||
```json
|
||||
{
|
||||
"event": "workflow_completed",
|
||||
"workflow_id": "v2.docs_explain.api_exposed"
|
||||
}
|
||||
```
|
||||
|
||||
## process.v2.pipeline
|
||||
```json
|
||||
{
|
||||
"event": "answer_generated",
|
||||
"answer_mode": "deterministic",
|
||||
"answer_length": 111
|
||||
}
|
||||
```
|
||||
|
||||
## result
|
||||
```json
|
||||
{
|
||||
"status": "done",
|
||||
"answer": "GET /api/v1/clients/contacts-dgr\nGET /api/v1/clients/contacts-dgr/{contactid}\nPOST /api/v1/clients/contacts-dgr",
|
||||
"completed_at": "2026-04-10T13:06:13.326341+00:00"
|
||||
}
|
||||
```
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,9 @@
|
||||
__all__ = ["AgentRuntime"]
|
||||
|
||||
|
||||
def __getattr__(name: str):
|
||||
if name == "AgentRuntime":
|
||||
from app.core.agent.runtime import AgentRuntime
|
||||
|
||||
return AgentRuntime
|
||||
raise AttributeError(name)
|
||||
@@ -0,0 +1,22 @@
|
||||
__all__ = [
|
||||
"AgentProcess",
|
||||
"ProcessResult",
|
||||
"V1Process",
|
||||
"V2Process",
|
||||
]
|
||||
|
||||
|
||||
def __getattr__(name: str):
|
||||
if name in {"AgentProcess", "ProcessResult"}:
|
||||
from app.core.agent.processes.base import AgentProcess, ProcessResult
|
||||
|
||||
return {"AgentProcess": AgentProcess, "ProcessResult": ProcessResult}[name]
|
||||
if name == "V1Process":
|
||||
from app.core.agent.processes.v1.process import V1Process
|
||||
|
||||
return V1Process
|
||||
if name == "V2Process":
|
||||
from app.core.agent.processes.v2.v2_process import V2Process
|
||||
|
||||
return V2Process
|
||||
raise AttributeError(name)
|
||||
@@ -0,0 +1,26 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from dataclasses import dataclass
|
||||
from dataclasses import field
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from app.schemas.changeset import ChangeItem
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from app.core.agent.runtime.execution_context import RuntimeExecutionContext
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class ProcessResult:
|
||||
answer: str = ""
|
||||
changeset: list[ChangeItem] = field(default_factory=list)
|
||||
apply_changeset: bool = False
|
||||
|
||||
|
||||
class AgentProcess(ABC):
|
||||
version = ""
|
||||
|
||||
@abstractmethod
|
||||
async def run(self, context: "RuntimeExecutionContext") -> ProcessResult:
|
||||
raise NotImplementedError
|
||||
@@ -0,0 +1,3 @@
|
||||
from app.core.agent.processes.v1.process import V1Process
|
||||
|
||||
__all__ = ["V1Process"]
|
||||
@@ -0,0 +1,22 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from app.core.agent.processes.base import AgentProcess, ProcessResult
|
||||
from app.core.agent.processes.v1.workflow import V1FlowMainGraph
|
||||
from app.core.agent.processes.v1.workflow.flow_main import V1FlowContext
|
||||
from app.core.agent.utils.llm import AgentLlmService
|
||||
|
||||
|
||||
class V1Process(AgentProcess):
|
||||
version = "v1"
|
||||
|
||||
def __init__(self, llm: AgentLlmService, prompt_name: str = "v1_flow_main.answer") -> None:
|
||||
self._prompt_name = prompt_name
|
||||
self._workflow = V1FlowMainGraph(llm)
|
||||
|
||||
async def run(self, context) -> ProcessResult:
|
||||
flow_context = V1FlowContext(
|
||||
runtime=context,
|
||||
prompt_name=self._prompt_name,
|
||||
)
|
||||
flow_context = await self._workflow.run(flow_context)
|
||||
return ProcessResult(answer=flow_context.answer)
|
||||
@@ -0,0 +1,3 @@
|
||||
from app.core.agent.processes.v1.workflow.flow_main.graph import V1FlowMainGraph
|
||||
|
||||
__all__ = ["V1FlowMainGraph"]
|
||||
@@ -0,0 +1,7 @@
|
||||
from app.core.agent.processes.v1.workflow.flow_main.context import V1FlowContext
|
||||
from app.core.agent.processes.v1.workflow.flow_main.graph import V1FlowMainGraph
|
||||
|
||||
__all__ = [
|
||||
"V1FlowContext",
|
||||
"V1FlowMainGraph",
|
||||
]
|
||||
@@ -0,0 +1,13 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from app.core.agent.runtime.execution_context import RuntimeExecutionContext
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class V1FlowContext:
|
||||
runtime: RuntimeExecutionContext
|
||||
prompt_name: str
|
||||
prepared_message: str = ""
|
||||
answer: str = ""
|
||||
@@ -0,0 +1,24 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from app.core.agent.processes.v1.workflow.flow_main.context import V1FlowContext
|
||||
from app.core.agent.processes.v1.workflow.flow_main.steps.finalize_answer_step import FinalizeAnswerStep
|
||||
from app.core.agent.processes.v1.workflow.flow_main.steps.generate_answer_step import GenerateAnswerStep
|
||||
from app.core.agent.processes.v1.workflow.flow_main.steps.prepare_user_message_step import PrepareUserMessageStep
|
||||
from app.core.agent.utils.llm import AgentLlmService
|
||||
from app.core.agent.utils.workflow import WorkflowGraph
|
||||
|
||||
|
||||
class V1FlowMainGraph:
|
||||
def __init__(self, llm: AgentLlmService) -> None:
|
||||
self._graph = WorkflowGraph(
|
||||
workflow_id="v1.flow_main",
|
||||
source="workflow.v1",
|
||||
steps=(
|
||||
PrepareUserMessageStep(),
|
||||
GenerateAnswerStep(llm),
|
||||
FinalizeAnswerStep(),
|
||||
),
|
||||
)
|
||||
|
||||
async def run(self, context: V1FlowContext) -> V1FlowContext:
|
||||
return await self._graph.run(context)
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace: v1_flow_main
|
||||
|
||||
prompts:
|
||||
answer: |
|
||||
Ты полезный ассистент.
|
||||
Ответь на сообщение пользователя по существу.
|
||||
Не придумывай факты, если данных недостаточно.
|
||||
Если пользователь пишет по-русски, отвечай по-русски.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user