Архитектура эволюционирующего интеллекта

Phase 21.5–40.12 — Самосовершенствующаяся система скиллов для Arc OS. Статус: Production-ready. Sage Worker (автономное улучшение) + бенчмарки (A/B тестирование) + Marketplace Discovery + семантический поиск NotebookLM.


Обзор

Arc OS работает на федеративной архитектуре ботов, где дочерние боты проксируют сообщения пользователей в Claude CLI. Phase 21.1 ввела отслеживание качества (логи выполнения, кнопки обратной связи). Phase 21.5 замыкает петлю: система теперь валидирует собственный вывод, запоминает исправления, фокусирует контекст и автономно предлагает улучшения.

Семь столпов образуют слой интеллекта:

Сообщение пользователя
    │
    ├─► Context Router ──► SKILLS_HINT (топ-5 релевантных скиллов)
    │
    ├─► Learnings ──► блок LEARNINGS (прошлые исправления)
    │
    ▼
buildGsdPrompt() ──► Claude CLI ──► Ответ
                                        │
                                        ├─► Binary Evals ──► Warning-сноски
                                        │
                                        └─► Quality Tracker ──► Метрики
                                                                   │
                                                          Nightly Improve ──► Одобрение CEO

Столп 1: Binary Eval Engine

Модуль: shared/evals.ts Файлы спеков: skills/<name>/<name>.evals.json

Что делает

Каждый скилл может объявлять правила валидации в JSON-файле. После того как Claude генерирует ответ, eval engine проверяет его по всем применимым правилам. Провалы дают неблокирующие warning-сноски, добавляемые к сообщению в Telegram.

Типы правил

Тип Проверяет Пример использования
string_contains Ответ содержит буквальную строку Убедиться, что JSON-вывод имеет поле "verdict"
string_not_contains Ответ НЕ содержит строку Заблокировать --force в инструкциях git
regex_match Ответ соответствует regex-паттерну Убедиться, что аудит системы упоминает disk/RAM/CPU
regex_not_match Ответ НЕ соответствует regex Предотвратить паттерны утечки учётных данных
max_length Длина ответа <= N символов Поддерживать краткость вывода
min_length Длина ответа >= N символов Обеспечить содержательные ответы

Уровни серьёзности

Как eval'ы влияют на метрики

Результаты eval'ов логируются вместе с событиями качества. Когда nightly improvement loop обнаруживает скилл с низким процентом успеха, паттерны провала eval'ов помогают определить корневую причину без AI-анализа.

Пример eval-файла

{
  "version": 1,
  "skill": "code-review",
  "rules": [
    { "id": "cr-001", "name": "Must return JSON verdict", "type": "string_contains", "value": "\"verdict\"", "severity": "warning" },
    { "id": "cr-002", "name": "No console.log debug", "type": "regex_not_match", "pattern": "console\\.log\\(", "severity": "warning" }
  ]
}

Принцип проектирования

Вдохновлён фреймворком eval'ов Anthropic's Skill Creator: декларативные утверждения о выводах, без AI в петле валидации. Бинарный pass/fail устраняет неоднозначность.


Столп 2: Context Router

Модуль: shared/context-router.ts Источник данных: skills/_registry.json (поля triggers + keywords)

Что делает

Перед построением GSD prompt роутер оценивает каждый зарегистрированный скилл относительно сообщения пользователя. Топ-5 совпадений вставляются как блок SKILLS_HINT, настраивая Claude фокусироваться на релевантных возможностях.

Алгоритм скоринга

Для каждого скилла:
  score = 0
  для каждого trigger:   если сообщение содержит trigger  → score += 2
  для каждого keyword:   если сообщение содержит keyword  → score += 1

Сортировать по score DESC → взять топ 5

Trigger-совпадения дают больше очков, потому что trigger'ы — явные сигналы вызова (напр., "review", "deploy"). Keyword'ы обеспечивают более широкое семантическое соответствие (напр., "OWASP", "Docker").

Почему advisory, а не фильтрация

Роутер только advisory. Claude CLI всё равно загружает все скиллы через CLAUDE.md. Причины:

  1. Безопасность: жёсткая фильтрация через --allowedTools или мутации симлинков рискует сломать работающую сессию при неверной классификации сообщения роутером.
  2. Стабильность: никаких мутаций файловой системы на работающем процессе.
  3. Деградация без критического отказа: если роутер падает, у Claude всё ещё есть полный доступ к скиллам.

Экономия контекстного окна

Без роутера все 23 скилла конкурируют за внимание в prompt'е. Блок SKILLS_HINT говорит Claude "фокусируйся на этих 3-5" — снижая нерелевантную активацию скиллов и удерживая ответы по теме. Это контекстное прайминирование, а не сокращение контекста.


Столп 3: Reflect Loop (Persistent Learnings)

Модуль: shared/learnings.ts Хранение: {PROJECT_CWD}/learnings.md

Что делает

Когда CEO нажимает "Fix It" или "👎", система фиксирует правило обучения и сохраняет его в markdown-файл. При каждом последующем сообщении накопленные learnings вставляются в GSD prompt как блок LEARNINGS.

Pipeline: событие → обучение

CEO нажимает 🛠️ Fix It
    │
    ├─► addLearning(source: "fixit", rule: "Fix requested for: <context>")
    │
    └─► projectLearnings перезагружаются с диска

CEO нажимает 👎
    │
    ├─► addLearning(source: "negative", rule: "Negative feedback on: <context>")
    │
    └─► qualityTracker.logFeedback(positive: false)

Формат файла learnings

# Learnings

> Auto-generated. Injected into GSD prompt at session start.

## Rules

- [2026-04-03T14:22:00Z] [fixit] Always use t-call for translations in Odoo QWeb
- [2026-04-03T15:10:00Z] [negative] Avoid sudo in deployment scripts

Вставка в prompt

Функция formatForPrompt() берёт самые последние learnings (до 2000 символов), переворачивает их (сначала самые новые) и форматирует как:

LEARNINGS (past corrections — follow these rules):
- Avoid sudo in deployment scripts
- Always use t-call for translations in Odoo QWeb

Принцип проектирования

Вдохновлён Claude Reflect System: исправления не просто фиксируют текущий ответ — они становятся постоянными правилами, предотвращающими регрессию. Система накапливает "иммунную память" со временем.


Столп 4: Karpathy Loop (Nightly Self-Improvement)

Модуль: scripts/nightly-improve.ts Расписание: ежедневно в 03:00 UTC через cron Состояние: mcp-server/state/improvement-proposals.json

Что делает

  1. Читает config/bot_registry.json для перечисления всех дочерних ботов
  2. Для каждого дочернего: читает quality-metrics.json из его директории состояния
  3. Вызывает findUnderperformingSkills() — фильтрует скиллы, где:
    • applied_count >= 3 (минимальный размер выборки)
    • И либо success_rate < 80%, ИЛИ feedback_negative > feedback_positive
  4. Читает learnings.md для связанных паттернов исправлений
  5. Генерирует предложения на основе шаблонов (детерминировано, без AI)
  6. Отправляет CEO сводный отчёт в Telegram
  7. Отправляет карточки отдельных предложений с inline-кнопками Approve/Reject

Флоу одобрения CEO

Nightly script ──► Telegram: Proposal Card
                        │
           ┌────────────┼────────────┐
           ▼                         ▼
    ✅ Одобрить                 ❌ Отклонить
           │                         │
    Бэкап skill.md              Пометить как отклонённое
    как skill.v1.md             в proposals.json
    (макс. 3 версии)
           │
    Пометить как одобренное
    в proposals.json

Версионирование скиллов

При одобрении master-бот создаёт версионные бэкапы:

Принцип проектирования

Вдохновлён Karpathy's AutoResearch Loop: изменить → проверить → сохранить/отбросить → повторить. Критическое отличие: предложения основаны на шаблонах и требуют одобрения человека. Никакой автономной перезаписи скиллов — CEO остаётся финальным авторитетом.


Phase 36+ — Семантический слой NotebookLM

Phase 36.3 добавила пятый канал обратной связи: Google NotebookLM как долгосрочная семантическая память.

CRM Events (закрытие задачи, обновление вики)
    │
    └─► fire-and-forget POST к bridge /sync
                                    │
                                    ▼
                          NotebookLM Bridge (:19213)
                            ├── SyncWorker (asyncio.Queue, 3 попытки)
                            └── notebooklm-py → Google NotebookLM
                                    │
                                    ▼
                          Ноутбук обновлён новым источником
                                    │
              ┌─────────────────────┤
              ▼                     ▼
    инструмент ask_notebooklm     Neural Skill Generator
    (Cloud PM chat, 15с)          (POST /skills/generate, 30с)
              │                     │
              ▼                     ▼
    Семантический ответ в      Markdown-скилл для
    контексте проекта          ревью + сохранения (Phase 36.6)

Phase 36.6 добавила Neural Skill Generator: CEO задаёт цель извлечения, bridge запрашивает NotebookLM через структурированный AI Architect prompt, возвращает строгий Markdown Rulebook, который можно сохранить как скилл.

Phase 36.7 вынесла ноутбуки в боковую панель UI (зелёная/красная точка статуса, количество источников, внешняя ссылка).


Столп 6: Sage Worker (Phase 40.11c)

Модуль: shared/sage.ts Триггер: POST /api/crm/sage/analyze или scripts/nightly-improve.ts

Что делает

Sage — автономный движок улучшения скиллов. Анализирует скиллы с помощью метрик качества + обратной связи пользователей (learnings), затем генерирует конкретный улучшенный контент через Anthropic API (модель Haiku для экономии). Результаты хранятся как skill_update_requests (PR) в базе данных для ревью CEO.

Флоу

Запрос Sage Analyze
    │
    ├─► Загрузить активные скиллы из БД (skillQueries)
    ├─► Сопоставить с метриками качества (readMetrics)
    ├─► Приоритизировать неэффективные (findUnderperformingSkills)
    │
    ▼ Для каждого целевого скилла (макс. 5):
    ├─► Загрузить контент скилла + форк (если скоупирован по проекту)
    ├─► Загрузить метрики качества (success rate, счётчики обратной связи)
    ├─► Загрузить связанные learnings (исправления пользователей)
    ├─► Пропустить если уже существует pending PR
    ├─► Построить prompt (контент + метрики + learnings)
    ├─► Вызвать Anthropic API (Haiku, таймаут 30с)
    ├─► Разобрать ответ (NO_CHANGE = пропустить)
    ├─► Вставить skill_update_request (proposed_by: 'sage')
    └─► Автозапуск бенчмарка (Столп 7) для нового PR

Почему CRM-эндпоинт, а не воркер

Sage нужен прямой доступ к БД (skillQueries, benchmarkQueries) — воркеры запускаются как subprocess'ы без подключения к БД. Sage не получает сообщения пользователей; это фоновый анализатор, чей вывод = строки в БД, а не чат-текст.


Столп 7: Data-Driven Approvals — Benchmarks (Phase 40.11d)

Модуль: shared/sage.ts (runBenchmark()) БД: shared/migrations/005_skill_benchmarks.ts API: POST /api/crm/sage/benchmark, GET /api/crm/skill-updates/:id/benchmarks

Что делает

До того как CEO одобряет PR от Sage, система доказывает, что изменение работает. Генерирует 3 тестовых сценария, прогоняет оба — старый и новый контент скилла — через них (слепой A/B тест) и использует LLM judge для определения лучшего. Комбинированный скоринг: eval_rules детерминированный (60%) + LLM judge (40%).

Флоу бенчмарка

Запустить бенчмарк (requestId)
    │
    ├─► Загрузить skill_update_request (current_content + proposed_content)
    ├─► Загрузить eval_rules из БД
    │
    ▼ Сгенерировать 3 тестовых сценария (Haiku)
    │
    ▼ Для каждого сценария:
    ├─► Запустить старый контент скилла → old_output
    ├─► Запустить новый контент скилла → new_output
    ├─► Рандомизировать порядок A/B (предотвращение position-bias)
    ├─► LLM Judge оценивает оба (1-10) + причина
    ├─► Детерминированный eval_rules скоринг (если доступен)
    ├─► Комбинированный счёт: eval 60% + LLM 40%
    └─► Сохранить в таблицу skill_benchmarks
    │
    ▼ Обновить метаданные PR
    ├─► verdict: PASSED / FAILED / TIE
    ├─► improvement_pct: ((new_avg - old_avg) / old_avg * 100)
    └─► BenchmarkBadge виден в заголовке PR на фронтенде

Фронтенд: Battle Mode

SkillEvolution.jsx → компонент BenchmarkReport:


Карта файлов

shared/
├── evals.ts              ← Столп 1: Binary Eval Engine
├── context-router.ts     ← Столп 2: Context Router (routeContextFromDb)
├── learnings.ts          ← Столп 3: Reflect Loop
├── quality.ts            ← Расширен: findUnderperformingSkills()
├── sage.ts               ← Столпы 6+7: Sage Worker + Benchmarks (runSageAnalysis, runBenchmark)
├── db.ts                 ← SQLite SSOT: skillQueries, benchmarkQueries, chatQueries
├── migrations/
│   ├── 004_skill_system.ts     ← skills_global, forks, evolution_logs, update_requests
│   └── 005_skill_benchmarks.ts ← skill_benchmarks (результаты A/B тестов)
├── crm-routes.ts         ← CRM API: 55+ эндпоинтов (Sage + бенчмарки + эволюция скиллов)
└── ui_templates.ts       ← Расширен: improvementProposal()

scripts/
├── nightly-improve.ts    ← Столп 4: Karpathy Loop (теперь использует Sage + DB)
└── migrate-skills-to-db.ts ← Nuclear migration: файлы → DB

clients/
├── arc-cli.ts            ← ARC CLI (Phase 31.5): login, start, projects
└── knowledge-mcp.ts      ← Deprecated (Phase 38 → CLI subcommands)

services/
└── notebooklm-bridge/    ← Столп 5: семантический поиск NotebookLM (Phase 36.3)
    ├── main.py           ← FastAPI (:19213), /query, /sync, /notebooks/init, /health
    └── seed_knowledge.py ← Массовый импорт существующих знаний

frontend/src/crm/pages/
└── SkillEvolution.jsx    ← Двухпанельный UI: explorer + detail (Content/Evals/Evolution/PRs)
                             BenchmarkBadge, BenchmarkReport, Battle Mode, кнопка Sage analyze

child-bot/bot.ts          ← Интеграция: startup + GSD prompt + eval footnotes + /learnings
child-bot/ingest-watcher.ts ← Авто-инgest: fs.watch на raw/ → CRM inbox (Phase 28)
master-bot/bot.ts         ← Интеграция: триггер nightly cron Sage