ducklm/ARCHITECTURE.md

348 lines
8.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ARCHITECTURE
Этот документ фиксирует целевую архитектуру `ducklm` как локального event-driven multi-model execution runtime.
`TASK_3.md` — это директива для ИИ-кодера.
`ARCHITECTURE.md` — это короткая инженерная карта системы: что является ядром, какие есть слои, как течёт управление, где принимаются решения, а где только исполняются переходы.
## 1. Core Principle
Система строится вокруг `Runtime Loop Controller`.
Центр системы:
- не `router`
- не `orchestrator`
- не `execution engine`
Центр системы:
- `runtime loop`
Именно он замыкает жизненный цикл задачи:
```text
task
-> state load/create
-> context build
-> orchestration decision
-> plan/directive
-> execution
-> critic
-> memory policy
-> checkpoint
-> next step / complete / fail
```
## 2. Layer Model
Целевая форма системы:
```text
Client / CLI / API
|
v
Runtime Loop Controller
|
+--> State Store / Checkpoints
+--> Context Builder
+--> Router
+--> Orchestrator / Planner
+--> Execution Engine / Scheduler
| |
| +--> Tool Layer
| +--> Coder
|
+--> Critic
+--> Memory Write Policy
+--> Memory Store + Vector Index
+--> Event Bus + Event Store
+--> Streaming Projection
```
Принцип:
- `runtime loop` координирует
- `router` рекомендует
- `orchestrator` думает
- `execution engine` исполняет
- `tools/coder` делают работу
- `critic` оценивает
- `memory policy` решает запись
- `event bus` фиксирует историю
- `state store` даёт resume
## 3. Responsibility Boundaries
### Runtime Loop Controller
Отвечает за:
- task lifecycle
- state transitions
- вызов компонентов в правильном порядке
- применение decision objects
- checkpointing
- completion / failure path
Не отвечает за:
- policy reasoning
- raw tool execution
- prompt assembly inline
### Router
Это `policy evaluator + decision suggester`.
Контракт:
```text
(input state + assembled context) -> ExecutionDirective
```
Свойства:
- pure function
- no side effects
- no tool execution
- no state mutation
### Orchestrator / Planner
Отвечает за:
- orchestration reasoning
- deciding whether planning is needed
- generating plan JSON
- returning structured directives
Не отвечает за:
- execution
- direct state mutation
- tool invocation
### Execution Engine / Scheduler
Отвечает за:
- step scheduling
- task graph traversal
- step execution coordination
- calling tool/coder adapters
- reporting structured results
Не отвечает за:
- ownership of global lifecycle
- high-level policy
### Critic
Отвечает за:
- evaluation of tool/coder outputs
- returning structured scores and explanation
Не отвечает за:
- final memory write decision
- execution retry policy
### Memory Write Policy
Отвечает за:
- deterministic decision about storing memory
- dedup / merge / skip behavior
Не отвечает за:
- semantic retrieval
- critic scoring
## 4. Decision Model
Все decision-producing components должны возвращать структурированные объекты.
Базовый контракт:
```json
{
"type": "plan|tool|coder|respond|replan|store_memory|request_permission|complete|fail|noop",
"payload": {},
"requires_permission": false,
"confidence": 0.0,
"reason": "string"
}
```
Это главный антихаосный инвариант системы.
Следствие:
- компоненты не исполняют решения напрямую
- компоненты не мутируют state напрямую
- runtime loop применяет решения и переводит систему дальше
## 5. Execution Flow
Нормальный путь выполнения:
1. Клиент отправляет task.
2. Runtime loop создаёт или загружает task state.
3. Публикуется `task_received`.
4. Context builder собирает execution context.
5. Router возвращает decision object.
6. Orchestrator возвращает direct action или plan.
7. План валидируется и преобразуется в task graph.
8. Execution engine выбирает следующий шаг.
9. Tool или coder исполняет шаг через adapter.
10. Result возвращается в runtime loop.
11. Critic возвращает evaluation suggestion.
12. Memory policy возвращает decision по записи.
13. State checkpoint сохраняется.
14. Event bus фиксирует события.
15. Runtime loop выбирает `continue / replan / complete / fail`.
## 6. Task Graph Model
Внешний planner может вернуть список шагов.
Внутри runtime план должен жить как task graph:
```json
{
"nodes": [
{
"id": "step-1",
"kind": "tool",
"tool": "shell_exec",
"args": {"command": "hostnamectl"},
"depends_on": []
}
]
}
```
Сейчас допускается sequential DAG execution.
В будущем это даёт путь к parallel scheduling без переписывания модели.
## 7. Event Backbone
Система event-driven.
`EventBus` нужен не только для стриминга, а как внутренняя хребтовая шина.
Минимальные свойства:
- ordering per task
- monotonic sequence per task
- durable append to event store
- replay capability
- consumer idempotency
Минимальная модель доставки:
- `at least once`
Правило идемпотентности:
- событие дедуплицируется по `task_id + sequence`
Streaming layer — это projection от event bus, а не источник правды.
## 8. State Persistence
Так как runtime задуман как long-running autonomous system, in-memory lifecycle недостаточен.
Нужны:
- task state store
- checkpoint store
- resume from crash/restart
Минимальная стратегия:
- checkpoint after critical transitions
- latest valid checkpoint is resumable
Primary choice для MVP:
- `SQLite`
## 9. Async and Isolation
LLM loop не должен блокироваться долгими tool operations.
Поэтому нужны:
- async execution adapters
- timeout wrappers
- cancellation handling
- bounded concurrency
Для опасных или тяжёлых операций нужен отдельный sandbox layer.
Особенно для:
- `shell_exec`
- browser/web fallback
- generated helper scripts
## 10. Memory Architecture
Memory — отдельная подсистема хранения, а не JSON dump.
Рекомендуемая форма:
- metadata store: `SQLite`
- vector index: `FAISS` или `hnswlib`
Два разных процесса:
- retrieval
- write decision
Это специально разделено.
`critic` только оценивает.
`memory write policy` принимает финальное решение.
Минимальная логика записи должна быть детерминированной:
```text
(critic_score + memory_type + runtime_weight + dedup_state + safety_state) -> decision
```
## 11. Failure Model
Система должна быть устойчивой к частичным сбоям.
Ожидаемые controlled failure paths:
- invalid planner output -> replan or fail
- tool timeout -> retry or fail
- critic failure -> fallback policy
- memory failure -> skip write and continue where safe
- streaming failure -> sync fallback
Главный принцип:
- subsystem failure не должен автоматически означать runtime collapse
## 12. Why This Shape
Эта архитектура нужна, чтобы система не деградировала в один из плохих вариантов:
- `router-god-object`
- `runtime loop with hidden policy logic`
- `LLM that directly executes tools`
- `streaming instead of event model`
- `critic as memory authority`
- `in-memory only autonomous runtime`
Если держать эти границы жёстко, проект остаётся расширяемым.
Если границы размыть, система быстро превратится в трудноотлаживаемый procedural agent.