🧠 Слой 0: Always-On Autonomous Loop (Ствол мозга)¶
Подробное описание архитектуры и работы¶
Статус: ✅ Этап B завершён (Scheduler + ResourceMonitor реализованы)
✅events.py— все типы событий + EventFactory
✅contracts.py— общие сквозные типы (Modality, Task, EncodedPercept, FusedPercept, TraceChain, BrainOutput)
✅event_bus.py— typed pub/sub шина событий
✅scheduler.py— тик-планировщик (heapq, 4 приоритета, адаптивный tick 100/500/2000ms) · 11/11 тестов
✅resource_monitor.py— CPU/RAM мониторинг, 4 политики деградации, гистерезис · 13/13 тестов
⬜attention_controller.py— контроллер внимания (Этап H.1)
Что такое автономный цикл в биологии¶
Ствол мозга — самая древняя часть мозга. Он работает непрерывно, даже во сне: - поддерживает дыхание, сердцебиение, температуру тела - маршрутизирует сигналы между телом и корой - управляет циклами сна/бодрствования - никогда не «выключается»
Ключевой принцип: мозг — это не программа, которую запускают и останавливают. Это живой процесс, который существует непрерывно.
Роль в искусственном мозге¶
Внешний мир (файлы, пользователь, события)
│
▼
┌─────────────────────────────────────────────────────────────┐
│ AUTONOMOUS LOOP (Ствол мозга) │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Scheduler (Тик-планировщик) │ │
│ │ clock-driven тики + event-driven обработка │ │
│ │ приоритетная очередь задач │ │
│ └──────────────────────┬───────────────────────────────┘ │
│ │ │
│ ┌──────────────────────▼───────────────────────────────┐ │
│ │ EventBus (Шина событий) │ │
│ │ publish/subscribe для всех модулей │ │
│ │ типизированные события (PerceptEvent, MemoryEvent…) │ │
│ └──────────────────────┬───────────────────────────────┘ │
│ │ │
│ ┌──────────────────────▼───────────────────────────────┐ │
│ │ ResourceMonitor (Гомеостаз) │ │
│ │ CPU/RAM мониторинг → graceful degradation │ │
│ │ динамический бюджет вычислений │ │
│ └──────────────────────┬───────────────────────────────┘ │
│ │ │
│ ┌──────────────────────▼───────────────────────────────┐ │
│ │ AttentionController (Таламус) │ │
│ │ бюджет внимания по модальностям │ │
│ │ goal-driven + salience-driven переключение │ │
│ └──────────────────────┬───────────────────────────────┘ │
└─────────────────────────┼───────────────────────────────────┘
│
▼
Все остальные модули мозга
(Perception → Encoders → Fusion → Memory → Cognition → Output)
Компонент 1: Scheduler — Тик-планировщик¶
Файл: brain/core/scheduler.py
Аналог: Циркадные ритмы + ретикулярная формация ствола мозга
Два режима работы¶
CLOCK-DRIVEN (регулярные тики):
каждые T мс → запустить когнитивный цикл
T = 100 мс (10 Hz) при нормальной нагрузке
T = 500 мс при CPU > 70%
T = 2000 мс при CPU > 85% (graceful degradation)
EVENT-DRIVEN (по событию):
новый файл → немедленно запустить Perception
сообщение пользователя → немедленно запустить Cognitive Core
RAM > 85% → немедленно запустить ConsolidationEngine.cleanup()
Приоритетная очередь задач¶
class TaskPriority(Enum):
CRITICAL = 0 # угроза целостности системы (RAM > 90%)
HIGH = 1 # пользовательский ввод, срочные события
NORMAL = 2 # обычный когнитивный цикл
LOW = 3 # replay, consolidation, self-reflection
IDLE = 4 # метрики, дашборд, cleanup
Структура Task (реализовано в brain/core/contracts.py ✅)¶
@dataclass
class Task(ContractMixin):
"""Унифицированная задача для scheduler/event loop."""
task_id: str # "task_a1b2c3"
task_type: str # "think" | "consolidate" | "perceive" | ...
payload: Dict[str, Any] = {} # параметры задачи
priority: float = 0.5 # числовой приоритет (0.0–1.0)
status: TaskStatus = PENDING # PENDING | RUNNING | DONE | FAILED
trace_id: str = "" # сквозной trace
session_id: str = "" # ID сессии
cycle_id: str = "" # ID тика
⚠️ MVP-упрощение: поля
module,action,deadline,created_at,retry_count,max_retriesиз ранних спецификаций не реализованы.priority— числовойfloat, а неTaskPriorityenum (enum используется только вScheduler.enqueue(task, priority=TaskPriority.NORMAL)). Расширенная модель Task будет добавлена при реализации Этапа F (Cognitive Core).
Цикл планировщика (реализовано ✅)¶
# Реальный API Scheduler (brain/core/scheduler.py):
bus = EventBus()
scheduler = Scheduler(bus)
# Регистрация обработчика задачи
def handle_think(task: Task) -> Any:
return {"result": "thought"}
scheduler.register_handler("think", handle_think)
# Добавление задачи в очередь
scheduler.enqueue(
Task(task_id="t1", task_type="think", payload={"query": "нейрон"}),
priority=TaskPriority.NORMAL,
)
# Один тик вручную (возвращает сводку)
info = scheduler.tick(resource_state=resource_monitor.check())
# Основной цикл (блокирующий, с адаптивным интервалом)
scheduler.run(
max_ticks=None, # бесконечно
resource_provider=resource_monitor.check # адаптация tick по CPU
)
# Остановка из другого потока
scheduler.stop()
✅ Реализовано полностью:
get_tick_interval()адаптирует тик по CPU и RAM: NORMAL (CPU<70%, RAM<22GB)=100ms, DEGRADED (CPU 70–85%, RAM 22–28GB)=500ms, CRITICAL (CPU>85%, RAM 28–30GB)=2000ms, EMERGENCY (RAM>30GB)=5000ms. Все 4 уровня реализованы вSchedulerConfig(поляtick_emergency_ms,ram_*_gb).
Компонент 2: EventBus — Шина событий¶
Файл: brain/core/event_bus.py
Аналог: Нейромедиаторы — химические сигналы между отделами мозга
Принцип работы¶
Модуль A публикует событие:
event_bus.publish(PerceptEvent(text="нейрон", source="user"))
│
▼
EventBus маршрутизирует подписчикам:
├── Encoders.on_percept(event)
├── WorkingMemory.on_percept(event)
└── Logger.on_any(event)
Типы событий (из brain/core/events.py ✅)¶
# Уже реализовано в Фазе 1.4:
PerceptEvent # новый входящий стимул (text/image/audio)
MemoryEvent # операция с памятью (store/retrieve/forget)
CognitiveEvent # когнитивное событие (goal/plan/decision)
LearningEvent # событие обучения (update/replay/hypothesis)
SystemEvent # системное событие (start/stop/error/resource)
API (✅ реализовано в brain/core/event_bus.py)¶
⚠️ MVP-решение: строковый API. EventBus использует строковые
event_typeи произвольныйpayload: Any. Это намеренное упрощение для MVP — не требует импорта конкретных классов событий. В будущем (Этап C/D) будет добавлен адаптер для передачи dataclass-событий (PerceptEvent,SystemEvent) напрямую через шину.
from brain.core import EventBus, BusStats
bus = EventBus()
# Сигнатура handler: (event_type: str, payload: Any, trace_id: str) -> None
def on_percept(event_type: str, payload, trace_id: str):
print(f"[{trace_id}] {event_type}: {payload}")
# Подписка на строковый тип события
bus.subscribe("percept", on_percept)
# Wildcard — получать ВСЕ события (для логирования)
bus.subscribe("*", logger_handler)
# Публикация (payload — любой объект: dict, dataclass, str)
n_handled = bus.publish(
event_type="percept",
payload={"text": "Что такое нейрон?", "modality": "text"},
trace_id="t-001",
)
# Отписка
bus.unsubscribe("percept", on_percept)
# Статистика
stats: BusStats = bus.stats
# stats.published_count, stats.handled_count, stats.error_count, stats.dropped_count
# Observability
print(bus.status())
# {'subscribed_types': ['percept', '*'], 'total_handlers': 2,
# 'published_count': 1, 'handled_count': 1, 'error_count': 0, 'dropped_count': 0}
Гарантии доставки¶
СИНХРОННЫЙ ВЫЗОВ:
publish() вызывает все handlers в текущем потоке (в рамках тика).
Ошибка одного handler логируется и НЕ прерывает остальных.
WILDCARD ("*"):
Подписчик на "*" получает все события любого типа.
Используется для BrainLogger и MetricsCollector.
DROPPED:
Если для event_type нет ни одного подписчика — dropped_count++.
Событие не теряется молча: счётчик виден в status().
Компонент 3: ResourceMonitor — Монитор ресурсов (Гомеостаз)¶
Файл: brain/core/resource_monitor.py
Аналог: Гипоталамус — поддержание гомеостаза (температура, давление, ресурсы)
Принцип работы¶
Каждые 5 секунд (фоновый поток):
│
▼
ResourceMonitor.check()
│
├── CPU usage (psutil.cpu_percent)
├── RAM usage (psutil.virtual_memory)
├── Thread count (threading.active_count)
└── Model memory (оценка по размерам загруженных моделей)
│
▼
ResourceState(cpu_pct, ram_gb, ram_pct, threads, models_gb)
│
▼
Применить политику деградации:
├── NORMAL (CPU < 70%, RAM < 22 GB) → tick=100ms, все модули активны
├── DEGRADED (CPU 70–85%, RAM 22–28 GB) → tick=500ms, отключить replay
├── CRITICAL (CPU > 85%, RAM > 28 GB) → tick=2000ms, только core функции
└── EMERGENCY (RAM > 30 GB) → принудительная выгрузка моделей
Таблица политик деградации¶
| Состояние | CPU | RAM | Tick | Отключить |
|---|---|---|---|---|
| NORMAL | < 70% | < 22 GB | 100 мс | — |
| DEGRADED | 70–85% | 22–28 GB | 500 мс | ReplayEngine, SelfSupervised |
| CRITICAL | > 85% | 28–30 GB | 2000 мс | Learning Loop, Vision/Audio |
| EMERGENCY | любой | > 30 GB | 5000 мс | Все кроме Memory + Output |
Структура ResourceState (реализовано в brain/core/contracts.py ✅)¶
@dataclass
class ResourceState(ContractMixin):
"""Снимок ресурсного состояния системы."""
cpu_pct: float = 0.0 # загрузка CPU 0–100%
ram_pct: float = 0.0 # использовано RAM в %
ram_used_mb: float = 0.0 # использовано RAM в MB
ram_total_mb: float = 0.0 # всего RAM в MB
available_threads: int = 1 # доступных потоков
ring2_allowed: bool = True # разрешены тяжёлые ветки (CPU < 85%)
soft_blocked: bool = False # мягкая блокировка (CPU > 70%)
⚠️ MVP-упрощение: поля
ram_gb,ram_available_gb,models_gb,policy,timestampиз ранних спецификаций не реализованы в текущем контракте.policyиtimestampдоступны черезResourceMonitor.status()иDegradationPolicy. Будут добавлены в контракт при реализации Этапа H (AttentionController).
Graceful Degradation¶
EMERGENCY (RAM > 30 GB):
1. Выгрузить Vision Encoder (освободить ~600 MB)
2. Выгрузить Audio Encoder (освободить ~1.5 GB)
3. Принудительный ConsolidationEngine.aggressive_cleanup()
4. Уведомить через SystemEvent(level="CRITICAL", ...)
5. Если RAM > 31 GB → выгрузить Text Encoder (fallback: navec)
Компонент 4: AttentionController — Контроллер внимания¶
Файл: brain/core/attention_controller.py
Аналог: Таламус — маршрутизация и фильтрация потоков внимания
Два контура внимания¶
GOAL-DRIVEN ATTENTION (сверху вниз):
Текущая цель: "ответить на вопрос о нейронах"
│
▼
Приоритет: текст > изображения > аудио
Бюджет CPU: 60% на text encoder, 30% на memory, 10% на остальное
Фильтр: игнорировать нерелевантные входы
SALIENCE-DRIVEN ATTENTION (снизу вверх):
Новый стимул с высоким salience (urgency=0.9)
│
▼
Прервать текущую задачу
Переключить внимание на новый стимул
Обновить бюджет CPU
Бюджет вычислений по модальностям¶
class AttentionBudget:
"""
Распределение вычислительных ресурсов по модальностям.
Сумма всегда = 1.0 (100% доступного CPU).
"""
text: float # доля CPU для текстовой обработки
vision: float # доля CPU для визуальной обработки
audio: float # доля CPU для аудио обработки
memory: float # доля CPU для операций с памятью
cognition: float # доля CPU для когнитивного ядра
# Примеры бюджетов:
BUDGET_TEXT_FOCUSED = AttentionBudget(
text=0.50, vision=0.10, audio=0.05, memory=0.25, cognition=0.10
)
BUDGET_MULTIMODAL = AttentionBudget(
text=0.30, vision=0.25, audio=0.20, memory=0.15, cognition=0.10
)
BUDGET_DEGRADED = AttentionBudget(
text=0.70, vision=0.00, audio=0.00, memory=0.20, cognition=0.10
)
Адаптация бюджета¶
При CPU > 70%:
→ vision = 0, audio = 0 (самые дорогие модальности)
→ text += 0.3 (самая дешёвая модальность)
При новом срочном событии (salience > 0.8):
→ cognition += 0.2 (больше ресурсов на обработку)
→ memory -= 0.1 (временно снизить фоновые операции)
При idle (CPU < 30%):
→ replay += 0.2 (использовать простой для обучения)
→ metrics += 0.1 (обновить дашборд)
Жизненный цикл мозга¶
python main.py
│
▼
[INIT]
1. Создать EventBus
2. Создать ResourceMonitor (запустить фоновый поток)
3. Создать Scheduler
4. Инициализировать все модули (Memory, Encoders, Cognition, ...)
5. Загрузить состояние из JSON (если есть)
6. Опубликовать SystemEvent(event="brain_started")
│
▼
[MAIN LOOP] ← Scheduler.run()
while brain.is_alive:
check_resources()
process_events()
execute_tasks()
run_idle_tasks()
sleep(tick_interval)
│
▼
[SHUTDOWN] ← SIGINT / SIGTERM / /выход
1. Опубликовать SystemEvent(event="brain_stopping")
2. Дождаться завершения текущих задач (timeout=10с)
3. Сохранить состояние в JSON
4. Остановить фоновые потоки (ConsolidationEngine, ResourceMonitor)
5. Опубликовать SystemEvent(event="brain_stopped")
6. Выход
Взаимодействие с другими модулями¶
Autonomous Loop — это ИНФРАСТРУКТУРА, не слой обработки.
Все остальные модули зависят от него:
EventBus:
← Perception публикует PerceptEvent
← Memory публикует MemoryEvent
← Cognition публикует CognitiveEvent
→ Все модули подписываются на нужные события
Scheduler:
→ запускает Perception (по событию или по таймеру)
→ запускает Cognitive Core (по событию)
→ запускает ConsolidationEngine (каждые 30с)
→ запускает ReplayEngine (каждые 30 мин при idle)
→ запускает MetricsCollector (каждые 60с)
ResourceMonitor:
→ уведомляет Scheduler об изменении политики
→ уведомляет AttentionController об изменении бюджета
→ уведомляет ConsolidationEngine о необходимости cleanup
Ресурсный бюджет (CPU-only, 32 GB RAM)¶
| Компонент | RAM | CPU | Поток |
|---|---|---|---|
| Scheduler | ~1 MB | < 1% | 1 (main) |
| EventBus | ~2 MB | < 1% | 1 (main) |
| ResourceMonitor | ~1 MB | < 1% | 1 (daemon) |
| AttentionController | ~1 MB | < 1% | 1 (main) |
| Итого | ~5 MB | < 2% | 2 потока |
Autonomous Loop намеренно минималистичен — он не должен потреблять ресурсы, нужные для мышления.
Статус реализации¶
| Компонент | Статус | Файл |
|---|---|---|
BaseEvent + все dataclasses событий |
✅ Реализовано | brain/core/events.py |
contracts.py — общие типы |
✅ Реализовано | brain/core/contracts.py |
EventBus — typed pub/sub шина |
✅ Реализовано | brain/core/event_bus.py |
Scheduler |
✅ Реализовано (11/11 тестов) | brain/core/scheduler.py |
ResourceMonitor |
✅ Реализовано (13/13 тестов) | brain/core/resource_monitor.py |
AttentionController |
⬜ Этап H.1 | brain/core/attention_controller.py |