В первом посте я рассказывал, как за несколько дней собрал пилот бота и быстро нарастил функциональность: Марафон, Лента, консультант, MCP-хранилища, многоязычность. Всё работает, первые пользователи тестируют, сделал концептуальное описание бота. Но сейчас я упёрся в стену.
Планов громадье, хочу добавить новые возможности:
1. Заметочник — отправлять себе заметки прямо из бота в Aisystant, Obsidian или Notion
2. Задачник — решать простенькие задачи по системному мышлению в крошках времени
3. Тест ступени ученика — диагностика на входе, чтобы понять, с какого уровня начинать
4. FPFkids — помощник взрослым, которые обучают детей первым принципам.
5. Экзокортекс-помощник — консультант, который помогает настроить личный экзокортекс
6. Полноценная многоязычность — сейчас локализация в одном файле, это не масштабируется
И тут я понял: текущая архитектура не выдержит.
Марафон живёт в bot.py (монолит на 3000+ строк), Лента — в отдельной папке engines/feed/, консультант размазан по коду. Каждая новая фича будет увеличивать хаос. Добавить Задачник? Куда — в bot.py? В engines/? Создать engines/practice/? А как он будет связан с консультантом?
Классическая ситуация: быстрый старт создал технический долг, который теперь блокирует развитие. Еще неделю назад я даже сомневался в возможности создать бота, а сейчас уже вплотную подошел к архитектуре.
Три варианта, которые я рассматриваю
Вариант 1: Модульная архитектура (Plugin-based)
Идея простая: каждая фича — отдельный модуль в своей папке. Модули независимы, подключаются через registry.
modules/
├── marathon/
├── feed/
├── notes/
├── practice/
├── exocortex/
└── fpfkids/
Плюсы: легко добавлять новое, один человек = один модуль. Минусы: модули начнут дублировать код, непонятно как связывать общие вещи (цифровой двойник, экономика токенов, ORY идентификация пользователя).
Вариант 2: Domain-Driven Design (DDD)
Классический подход для сложных систем: выделяем «домены» (области знания), каждый домен имеет свои сущности, сервисы, репозитории.
src/
├── domain/
│ ├── learning/ # Всё про обучение
│ ├── notes/ # Заметки
│ ├── assessment/ # Диагностика
│ └── economy/ # Токены, подписки
├── application/ # Use cases
└── infrastructure/ # Telegram, БД, API
Плюсы: чёткие границы, хорошо масштабируется на команду. Минусы: высокий порог входа, нужно заранее продумать все домены, избыточно для текущего размера.
Вариант 3: Гибрид — то, на чём я остановился.
Взял из обоих подходов:
∙ Модули по типу взаимодействия (не по домену)
∙ Общее ядро для сквозных вещей
∙ Feature flags для безопасной миграции
Ключевое решение: три типа сущностей
Долго не мог понять, как назвать и сгруппировать фичи. «Режим»? «Модуль»? «Функция»?
Пробовал разные классификации, пока не нащупал критерий — характер взаимодействия с пользователем:
— Мастерские (workshops/). Строгая структура, заранее известный путь, пользователь идёт по шагам
| Мастерская | Что изготавливается |
|---|---|
| Марафон | Мастерство ученика за 14 дней |
| Экзокортекс | Настроенный личный экзокортекс |
| FPFkids | Система обучения ребёнка |
| Задачник | Навык через программу задач |
Ключевое: есть программа, есть шаги, есть результат-артефакт.
— Консультанты (consultants/). Гибкая структура, по запросу, без жёсткого плана
| Консультант | Как работает |
|---|---|
| Общий (?) | Любой вопрос в любой момент |
| Лента | Push-контент по выбранным темам |
| Тест ступени | Диагностика по запросу |
Ключевое: нет строгой последовательности, пользователь сам решает когда и что.
— Утилиты (utilities/). Одно действие — один результат
| Утилита | Действие |
|---|---|
| Заметочник | /. текст → сохранено |
| Экспорт | /export → файл в Obsidian |
Ключевое: атомарное действие, никакого состояния.
Важное архитектурное решение: единый консультант
Изначально думал сделать отдельных консультантов: «Консультант по экзокортексу», «Консультант по детям», «Консультант по задачам».
Но это, по моему, неправильно. Консультант должен быть один — как умный помощник, который знает про всё.
Решение: консультант маршрутизирует вопросы к базам знаний мастерских:
Пользователь: "? Как организовать заметки в Obsidian?"
│
▼
[Консультант]
│
Определяет тему → "экзокортекс"
│
Ищет сначала в: workshops/exocortex/knowledge/
Потом в: core/knowledge/base/
│
▼
[Ответ с контекстом]
Пользователь не думает «к какому консультанту обратиться». Он просто спрашивает — система сама находит релевантную базу знаний.
** Целевая структура репо**
aist_bot/
├── bot.py # Только точка входа
│
├── workshops/ # 🔨 Мастерские
│ ├── marathon/
│ ├── exocortex/
│ │ └── methodology/ # Таблицы, практики
│ ├── fpfkids/
│ │ └── scenarios/ # Сценарии обучения
│ └── practice/
│ └── problem_bank/ # Банк задач
│
├── consultants/ # 💬 Консультанты
│ ├── main/ # Общий (?)
│ │ └── router.py # Маршрутизация по базам
│ ├── feed/
│ └── assessment/ # Тест ступени
│
├── utilities/ # 🔧 Утилиты
│ ├── notes/
│ └── export/
│ └── adapters/ # Obsidian, Notion, Markdown
│
├── core/
│ └── knowledge/ # Загрузка и поиск по базам
│
├── i18n/ # Локализация
│ ├── ru/
│ ├── en/
│ └── es/
│
└── config/
└── features.yaml # Feature flags
Как мигрировать без поломок
Главный страх: сломать работающего бота во время рефакторинга.
Решение — Strangler Fig Pattern + Feature Flags.
Принцип: новый код растёт рядом со старым. Тестирую локально с flag=true. В проде — false. Когда готово — переключаю. Если что-то пошло не так — откатываю флагом.
План на ближайшие недели (с учетом того, что не смогу выделять много времени на развитие бота).
| Неделя | Что делаю |
|---|---|
| 1 | Создаю структуру папок, базовые классы, feature flags |
| 2 | Выношу Марафон из bot.py → workshops/marathon/ |
| 3 | Выношу Ленту → consultants/feed/ |
| 4 | Переделываю локализацию → i18n/ с YAML-файлами |
| 5 | Создаю Заметочник → utilities/notes/ |
| 6 | Создаю Тест ступени → consultants/assessment/ |
| 7+ | Новые мастерские: Экзокортекс, FPFkids, Задачник |
Что это даст
После миграции смогу быстро добавлять новые возможности:
Заметочник — написал /note мысль про экзокортекс → заметка сохранилась, можно экспортировать в Obsidian.
Тест ступени — на входе бот определяет уровень: «случайный ученик», «практикующий», «систематический». Контент адаптируется.
Задачник — в крошках времени решаешь задачи по системному мышлению. Есть готовые банки задач + генерация персональных через Claude.
Экзокортекс-мастерская — пошаговая программа: аудит текущего состояния → выбор инструментов → настройка → практика. Не просто «советы», а изготовление результата.
FPFkids — для родителей и наставников: как объяснить ребёнку концепцию, какое упражнение дать, как проверить понимание.
Полная многоязычность — интерфейс и контент на русском, английском, испанском (и легко добавить другие).
Рефлексия
Это типичная ситуация в разработке: быстрый MVP создаёт технический долг. Можно игнорировать и продолжать наращивать функциональность с риском закопаться в хаосе. Можно остановиться и переписать с нуля (убьёт мотивацию).
Я выбрал третий путь: пока бот будет тестироваться на Марафоне для новичков, а я буду делать инкрементальную миграцию с сохранением работоспособности. Дольше, но надёжнее.
Интересно, что в процессе проектирования архитектуры я лучше понял сам продукт и его ценность. Разделение на «Мастерские / Консультанты / Утилиты» — это не просто техническое решение. Это модель того, как люди взаимодействуют с инструментом развития:
- Иногда нужна программа с шагами (Мастерская)
- Иногда нужен ответ на вопрос (Консультант)
- Иногда нужно быстро что-то сделать (Утилита)
Хорошая архитектура отражает реальность использования. Так что сейчас это мой главный объект внимания.
P.S. на 17:00 того же дня
После публикации наш архитектор Андрей Смирнов предложил другой подход — State Machine.
Идея: один Python-файл = одно состояние. Пользователь всегда находится в конкретном стейте (marathon_question, consultant, notes). Состояние хранится в базе данных. Все переходы описаны в одной таблице:
marathon_question:
correct: marathon_task # Верный ответ → задание
incorrect: marathon_question # Неверный → повторяем
skip: marathon_task
Что это даёт:
∙ Явная модель — вся логика переходов в одном файле
∙ Всегда понятно, где пользователь сейчас (user.current_state)
∙ Легко добавлять новые сценарии — создал стейт, добавил строку в таблицу
∙ Готовность к ЦД и Ory — состояние уже централизовано, заменить хранилище на Цифровой двойник — одна точка изменения
Разница в сроках небольшая (+1-2 недели на создание движка), но архитектура получается чище и масштабируемее.
Решил идти этим путём. Подготовил с Claude обновлённый план миграции на 7-9 недель — MIGRATION_PLAN_V2.md.
