Repository navigation
Home
Редакционное уточнение · 1 ноября 2026 года. Лонгрид сохраняет исходный замысел и исторические примеры. Приоритет проекта: концепция → архитектура → реализация. Компоненты стенда не равны доказанной сквозной способности: AC0–AC4/M0 ещё не пройдены. Демо «маша/волк», числа 4/5 и 0.46/0.92 — исторические апрельские примеры; в этой редакции они не воспроизводились и не являются новым benchmark. Текущая цель: NORTH_STAR, контракт: SPEC_FINAL, решения: JOURNAL, З-0096. Разбор актуализации. Глава «Кот встаёт» добавлена 1 ноября 2026 года; источник и правки.
Лонгрид о том, что такое смысл с точки зрения кода, почему мы начали не с нейросети, и что происходит, когда система начинает удивляться
Представьте, что вы сидите в тихой комнате и читаете. Краем глаза замечаете движение — и ещё до того, как сознание успело оформить слово «кот», вы уже знаете, что это именно он, а не занавеска. Больше того: вы с высокой вероятностью знаете, что он сейчас запрыгнет на подоконник, а не ляжет на пол.
Вы не искали в базе данных. Не сравнивали с эталонными изображениями. Не запускали классификатор. Вы просто ожидали.
Вот этот механизм ожидания — не результат, а именно механизм, лежащий в его основе — и есть то, чем мы занимаемся последние несколько лет.
Мы попробовали воспроизвести его в коде. Система обучалась несколько минут на детских сказках — никаких GPU, никаких эмбеддингов, никакого размеченного датасета. Потом мы показали ей текст, которого она раньше не видела:
Текст: «маша пришла в лес встретила волка поздоровались»
Токен Что система ожидала Результат
────────────── ───────────────────────── ──────────────────────────────────
«пришла» — (первый токен, пусто) ~ нет предсказания
«в» «в» conf=1.00 ✓ угадала
«лес» «лес» conf=0.94 ✓ угадала
«встретила» «встретила» conf=1.00 ✓ угадала
«волка» «медведя» conf=0.89 ↔ ждала «медведя», получила «волка»
«поздоровались» «поздоровались» conf=1.00 ✓ угадала
«Медведя» — потому что в обучающих текстах маша встречала медведя. «Волка» — потому что это тест на незнакомый вариант. Система угадала 4 из 5, точно определила место сюрприза, и не растерялась.
В историческом демо приведены дивергенции 0.46 для близких текстов и 0.92 для другой тематики. Это иллюстрация предполагаемого сигнала различения, а не проверка того, что система «знает границы своего знания». Для такого вывода нужны воспроизводимый протокол, контроль и проверка калибровки.
Дальше в статье — как это устроено изнутри.
Первый вопрос, который возникает: зачем строить это, если есть GPT-4?
Мы исследуем онлайн-накопление и применение структур, которые можно проследить до конкретных наблюдений и проверок. Нас интересует не только предсказание продолжения, но и выбор действия с последующим внешним исходом. Это описание исследовательского направления; преимущества перед другими подходами требуют отдельного сопоставимого опыта.
Ребёнок, которому полтора года, уже умеет предсказывать. Он тянет руку за мячом до того как тот упадёт со стола — потому что накопил достаточно опыта, чтобы понять: за этим движением следует это. Он обобщил. И это обобщение работает онлайн, в реальном времени, без GPU. Нам интересно именно это.
Любая система распознавания нуждается в атомарном примитиве — чём-то, из чего строится всё остальное. В нейросети это числа в векторе активации. В классических системах — символы или фреймы. У нас это — признак.
Признак — это не объект и не категория. Признак — это направленный переход между двумя областями внимания.
Область A Область B
┌──────────────┐ ┌──────────────┐
│ size = 0.3 │ │ size = 0.6 │
│ bright = 0.2 │──────────►│ bright = 0.8 │
│ contr = 0.4 │ δ-вектор │ contr = 0.1 │
│ hue = 0.5 │ │ hue = 0.5 │
└──────────────┘ └──────────────┘
│
▼
FeatureVector:
Δsize=+0.30 Δbright=+0.60 Δcontrast=−0.30
Δhue=0.00 Δsat=0.00 Δfractal=+0.10
Когда вы переводите взгляд с тёмного угла комнаты на светлое окно — это переход. У него есть направление, изменение яркости, изменение контраста, изменение «текстурной сложности» (что-то вроде фрактальной размерности). Все эти изменения — относительные, не абсолютные.
В коде это выглядит так:
@dataclass
class FeatureVector:
delta_size: float # изменение размера области
delta_brightness: float # изменение яркости
delta_contrast: float # изменение контраста
delta_color_hue: float # сдвиг оттенка
delta_color_sat: float # изменение насыщенности
delta_fractal_dim: float # изменение сложности текстурыШесть чисел. Всё остальное строится из них.
Почему это интересно? Относительное кодирование позволяет искать похожие переходы при разных абсолютных характеристиках областей. Но устойчивость к конкретным преобразованиям требует проверки: формула нормированной разности не гарантирует произвольную аффинную инвариантность. «Кот» здесь — образ обобщения последовательности переходов, а не продемонстрированное зрительное распознавание. Сам примитив ещё не доказывает перенос до нового действия.
В 1968 году Ноам Хомский вместе с Моррисом Халле опубликовал «The Sound Pattern of English» — фундаментальный труд по фонологии. Главная идея: звуки языка не атомарны. Каждый звук — это пучок дистинктивных признаков (distinctive features): [±звонкий], [±взрывной], [±носовой], [±непрерывный]. «П» и «Б» отличаются единственным признаком — [±звонкий]. Именно это минимальное различие несёт смысл, а не «Б сам по себе».
Смысл и структура рождаются из оппозиций, а не из объектов.
Наш FeatureVector — это прямое развитие этой идеи, вынесенное за пределы лингвистики. Мы берём минимальные различия между состояниями — не между звуками, а между любыми областями внимания — и делаем их модально-независимым атомом познания. Δbrightness между двумя зонами зрительного поля работает по той же логике, что [±звонкий] между двумя фонемами: не объект важен, а перепад, граница, переход.
Хомского часто сводят к «Универсальной грамматике» как жёсткому набору правил. Но фундамент глубже: сложность языка кристаллизуется из малого числа бинарных оппозиций. Мы просто спрашиваем: а что если это справедливо не только для звуков?
Если один переход — признак, то обобщение (Gen) — это цепочка признаков, которая подтверждалась достаточно часто, чтобы стать значимой.
@dataclass
class Generalization:
gen_id: str # уникальный ID
feature_chain: List[str] # последовательность feature_id
success_count: int # сколько раз подтверждалась
stop_count: int # сколько раз обрывалась
@property
def significance(self) -> float:
total = self.success_count + self.stop_count
return self.success_count / total if total > 0 else 0.0Значимость — это просто отношение подтверждений к попыткам. Ничего магического. Gen «кот садится на подоконник» — это цепочка признаков, которая начинается с «движение тёмного пятна влево-вверх», продолжается «скачок контраста», заканчивается «горизонтальная поверхность + свет снаружи», и она подтверждалась 47 раз из 50 попыток. Значимость = 0.94.
Структура базы обобщений — гетерархия, не иерархия. Это принципиальный момент. Gen «кот» не главнее Gen «движение серого пятна». Они связаны — один является контекстом для другого, — но нет привилегированной вершины, которая всеми командует. Каждый Gen одновременно и «мастер» (обобщает что-то ниже), и «ученик» (может быть частью чего-то выше).
Мы реализовали символьный переходный драйвер (CharTransitionDriver), который кодирует текст не как пары слов, а как переходы между отдельными буквами. Каждый токен = переход char_i → char_{i+1}:
Текст: «кот» Текст: «кошка»
к──►о──►т к──►о──►ш──►к──►а
(2 токена) (4 токена)
Общий префикс к→о:
FeatureVector идентичен в обоих словах!
Gen над символьными переходами естественно образуют вероятностное три:
[к] (любое слово на «к»)
│
[к→о] sig=0.88 ← общий корень
/ \
[к→о→т] [к→о→ш] ← расхождение здесь
sig=0.91 sig=0.74
/ \
[к→о→ш→к] [к→о→ш→е]
sig=0.73 sig=0.61
«Кот» и «кошка» разделяют один Gen-родитель к→о — морфологическое сходство возникает автоматически, без разметки. Длинные цепочки — конкретные слова. Короткие — высокочастотные звуковые паттерны. Динамическая разрешающая способность встроена в архитектуру.
Платоновские Идеи (Эйдосы) в популярном изложении выглядят карикатурно: идеальный стол на небесах, идеальный треугольник на небесах. Ничего более далёкого от смысла, который Платон вкладывал в «Государстве» и «Федоне».
Если читать Платона внимательно, Эйдос — это чистый инвариант. То, что остаётся неизменным, когда убраны все случайные свойства конкретного экземпляра. «Красота» не как конкретная красивая вещь, а как структура отношений, которая делает вещь красивой независимо от материала, размера, культуры.
В «Государстве» есть знаменитый миф о пещере: узники видят только тени на стене — проекции реальных объектов. Они принимают тени за реальность и пытаются предсказывать их последовательность. Выход из пещеры — это движение от теней к инвариантам, от шума к структуре.
Это идеальное описание того, что делает наш AttractorEngine. Токены — это тени. Система не запоминает тени. Она ищет то, что остаётся стабильным сквозь вариации — аттрактор, который проступает через поток расхождений.
Главный алгоритм — то, что мы называем «разрешением неопределённости» — умещается в три строки:
1. Ожидай следующий признак из активного контекста (Gen)
2. Пришёл ожидаемый признак → CONFIRMED: переходим к следующему в цепочке
Дошли до конца цепочки → COMPLETED: паттерн воспроизведён целиком
3. Пришёл другой признак → REFUTED: создаём новый Gen с расхождением как ключом
4. Контекст пуст → EXPLORING: ищем слабо обобщённые цепочки
CONFIRMED и COMPLETED — это рост значимости. REFUTED — это не ошибка, а точка роста: здесь есть развилка, которую система ещё не видела. Новый Gen рождается именно из расхождения. EXPLORING — это режим любопытства: когда нечего ожидать, система ищет что заслуживает внимания.
Ребёнок, который впервые видит кошку с длинными ушами — и называет её «кися» — получает REFUTED. Потому что «кися» предсказывала короткие уши. Из этого расхождения рождается «зайка».
Мы взяли стихотворение Маршака «Дом, который построил Джек». Оно идеально для теста: рекурсивная кумулятивная структура, фиксированный якорь («построил Джек»), повторяющиеся переходы на всех уровнях вложенности.
1000 циклов. 8 стихов, 125 итераций. Якорь действительно стал сильнейшим. При предсказании «построил джек» — match_rate = 1.00.
Но параллельно произошло кое-что неожиданное: к концу 1000 циклов в базе было 14 160 Gen. Экспоненциальный рост там, где должно быть уплотнение.
В описанном раннем прогоне Gen создавался при первом расхождении без
испытательного срока. Позже реализован ProvisionalBase: Gen уже находится
в основной базе, а отдельный трекер учитывает подтверждения и возраст.
Достаточные подтверждения снимают испытательный статус; неподтверждённый
кандидат может быть вытеснен по возрасту.
CapacityBudget ограничивает число Gen, а механизмы сна/replay участвуют
в консолидации. Наличие этих компонентов не доказывает ограниченный рост
памяти в непрерывной жизни; это требует отдельного измерения.
В 2004 году Джефф Хокинз в книге «On Intelligence» сформулировал теорию HTM (Hierarchical Temporal Memory): мозг — это машина предсказаний. Каждый уровень коры постоянно генерирует ожидание следующего состояния. Если ожидание совпадает — сигнал «съедается» и не передаётся выше. Если не совпадает — ошибка предсказания поднимается вверх.
Наш подход похож по духу: мы тоже строим предсказывающую систему снизу вверх, с онлайн-обучением, без backpropagation. Разница — в примитиве. Там SDR и временны́е паттерны. У нас — направленные переходы как инварианты.
Один из самых интересных результатов работы HierarchicalConsolidator — автоматическое обнаружение развилок.
meta_L1 [«построил»] sig=0.97
├── Gen_A: построил→джек sig=0.95
└── Gen_B: построил→маша (аномалия, sig=0.12)
meta_L2 [«который→построил»] sig=0.94
├── Gen_C: который→построил→джек
└── Gen_D: который→построил→[...]
Система сама находит, что «построил + что-то» — устойчивый паттерн с несколькими вариантами продолжения, и создаёт над ними обобщение. После прогона 1000 циклов поэмы создалось 5 мета-Gen со средней значимостью 0.97.
Буддийская философия Абхидхармы предлагает радикальную онтологию: никаких монолитных объектов не существует. Есть только непрерывный поток мельчайших вспышек опыта — дхарм, — каждая из которых возникает обусловленно из предыдущей и немедленно угасает.
В 1984 году Дерек Парфит в «Reasons and Persons» пришёл к тому же выводу: нет «Я» как отдельной сущности. Есть только Bundle (пучок) — серия ментальных событий, связанных причинно-следственными отношениями.
В нашей системе «кот» не хранится как запись с полями. gen_id: "a3f1c2" — это удобный ярлык для цепочки признаков с высоким significance. Аттрактор и есть Bundle по Парфиту: не сущность, а устойчивый паттерн в потоке изменений.
Чистый предиктивный механизм имеет один изъян: если система слишком хорошо предсказывает, она перестаёт обновляться.
ResourceDriver — аналог метаболизма. Уровень ресурса падает при ошибках (REFUTED) и восстанавливается при достижении целей (COMPLETED). Система переключается между режимами REST → CONSERVE → NORMAL → EXPLORE → ABUNDANT.
HedonicAdapter — гедонический распад. Каждый раз, когда Gen полностью проигрывается (COMPLETED), его «новизна» падает:
novelty = decay^count # decay=0.75 по умолчанию
# count=0 → novelty=1.00 (первый раз — интересно!)
# count=5 → novelty=0.24 (уже скучновато)
# count=20 → novelty≈0.003 (совсем не интересно)Reward за активацию Gen умножается на новизну: повторение снижает этот сигнал. Механизм используется как инженерная аналогия привыкания; он не является установленной моделью дофаминовой системы мозга.
Учитель не передаёт данные. Учитель создаёт давление.
Три уровня обучения:
Curriculum Agent — управляет тем, какие тексты подаются. При высокой стабильности (0.8–1.0) — знакомые тексты, укрепление. При низкой — незнакомые, исследование. Аналог «контролируемого отжига» из физики.
LLM Teacher — асинхронный учитель через Anthropic API. Видит нарративный отчёт о состоянии системы и принимает одно из трёх решений:
-
TEACH— подать новый текст -
REWARD— вознаградить систему -
WAIT— не мешать (часто самое умное решение)
BackgroundRunner — непрерывный цикл, который объединяет всё вместе: подаёт тексты, вызывает SleepDriver по расписанию, переключает домены, пишет нарратив через SpeechDriver и собирает статистику ModelVoice — всё это в одном потоке, без остановки.
DebugSession + Inspector — инструменты для понимания:
session.predict("вот дом который построил джек")
# → match_rate: 1.00, outcomes: CONFIRMED×7
session.attention()
# → {gen_id: "a3f1...", label: "якорь_джек", sig: 0.97, chain_len: 3}Когда мы обучили систему на сказке «Теремок», внутри базы обобщений проявилась структура, которую мы не ожидали.
Среди 563 Gen после 20 итераций — 9 трансцендентных обобщений: цепочка длиной 1–2, значимость ≈ 0.99. Они постоянно активны в контексте. Это не абстрактные слова. Это идеи. Gen с chain_len=1 и sig=1.0 — это буквально «что-то происходит». Фундамент мировоззрения.
Мы провели эксперимент: обучили на Матрёшке и Ритме, затем предъявили незнакомые Нарративы:
avg match_rate (незнакомые тексты) = 0.347
knock_candidates (urgency ≥ 2.0): 204
Трансцендентный Gen «что-то происходит» с sig=1.0 подтверждается на первом токене любого нарратива — и система успокаивается. Детальные переходы «поссорился → помирился» остаются невидимыми. Система видит лес — и не замечает деревьев.
Частичный ответ — TimescaleScheduler: Gen разделяются на три пула по длине цепочки — долгосрочные (chain=1-2), средние (3-4) и оперативные (5+). Трансцендентные Gen живут в долгосрочном пуле и не вытесняют оперативные детальные паттерны. Проблема не решена полностью, но стала управляемой.
До сих пор система обрабатывала текст молча. Учитель мог видеть числа — significance, urgency, match_rate — но не видел, что именно система замечала в каждом токене.
Мы добавили системный речевой драйвер (SpeechDriver) — компонент, который сопровождает каждый шаг внимания текстовой интерпретацией:
┌─────────────────────────────────────────────────────┐
│ Текст: «маша пошла в лес и встретила медведя» │
└──────────────────────┬──────────────────────────────┘
│
process_token()
│
┌──────────────▼─────────────────┐
│ КАНАЛ A (молчаливый) │
│ Gen_a3f1 → CONFIRMED │
│ Gen_b22c → REFUTED │
│ Gen_c41d → COMPLETED │
└──────────────┬─────────────────┘
│
SpeechDriver.observe()
│
┌──────────────▼─────────────────┐
│ КАНАЛ B (речевой) │
│ ✓ "Ожидала: маша→лес" │
│ ✗ "Удивилась: медведь" │
│ ★ "Паттерн завершён" │
└─────────────────────────────────┘
Канал B не влияет на A
Обработка одного предложения превращается в рассказ:
Текст: «маша пошла в лес и встретила медведя»
[маша] Известный якорь (sig=0.85). Вопрос: что делает маша?
[пошла] ✓ маша→движение (sig=0.72). Куда движется?
[в] Ищет продолжение движения...
[лес] ✓ маша→лес (sig=0.44). Паттерн «встреча» вероятен (3/5).
[и] Разделитель. Ожидает: новое действие.
[встретила] ✓ встреча-глагол (sig=0.61). Кого встретила?
[медведя] ✗ Ожидала: зайца (sig=0.38). Получила: медведь.
→ Новый Gen: маша→медведь (добавлен).
Итог: 6/7 ≈ 0.86. Удивление: медведь вместо зайца.
Это и есть наблюдатель за вниманием. Он ничего не меняет в ядре — только переводит то, что происходит в канале A, на человеческий язык.
Интерпретатор описывает прошлое — что случилось после токена. Но можно поставить вопрос иначе: а что система ожидает до того, как токен пришёл?
Мы добавили второй речевой канал — ModelVoice. Он работает на шаг раньше: смотрит на активные Gen, строит предсказание следующего слова из их цепочек, и только потом приходит реальный токен.
Канал A: внимание (молчаливый, всегда)
Канал B_интерпретатор: что говорит SpeechDriver об A — ПОСЛЕ токена
Канал B_модель: что говорит ModelVoice из Gen — ДО токена
Дивергенция = |ожидание − реальность| → тренировочный сигнал
Вот как это выглядит в живом прогоне (8 проходов по 10 сказочным текстам, тест на незнакомых вариантах):
Токен B_модель (до) B_интерпр (после) Δ
────────────── ───────────────────────── ─────────────────── ────────────────────────
«в» «в» conf=1.00 ★ Паттерн завершён ✓ Угадала «в»
«лес» «лес» conf=0.94 ★ Паттерн завершён ✓ Угадала «лес»
«встретила» «встретила» conf=1.00 ★ Паттерн завершён ✓ Угадала «встретила»
«волка» «медведя» conf=0.89 ✗ Удивилась: «волка» ↔ div=1.00
«поздоровались» «поздоровались» conf=1.00 ★ Паттерн завершён ✓ Угадала «поздоровались»
Итог по двум типам текстов:
Знакомые тексты (варианты обучающих): avg_div = 0.46 ← система знает что ждать
Незнакомые тексты (корабли, код): avg_div = 0.92 ← каждый токен — сюрприз
Разница Δ: +0.46 ← рабочий тренировочный сигнал
Дивергенция здесь — не просто метрика качества. Это именно то, чего не хватало: сигнал о границе знания. Высокая дивергенция при высокой уверенности — система была уверена, ошиблась — означает: здесь нужно обновить ожидания. Низкая дивергенция на знакомых текстах — система научилась.
Предсказание строится из трёх источников, которые объединяются по весу:
- Label-based: если Gen имеет читаемую метку «маша·пошла·в», берём слово на текущей позиции
-
Feature-based: накопленный маппинг
feature_id → [слова]из истории обучения -
Bigram-fallback:
слово_i → слово_{i+1}, критически важен когда контекст пуст
Гедонический распад — это хорошо, но он решает только половину проблемы. Система перестаёт получать удовольствие от повторений. Но куда деваются все Gen, накопленные за день?
У человека есть ответ на этот вопрос: сон. Точнее — фазы сна, во время которых мозг не отдыхает, а занят консолидацией: проигрывает события дня, ищет общее между несвязанными эпизодами, укрепляет важные связи и ослабляет случайный шум.
Мы реализовали аналог этого механизма — SleepDriver:
Обычная работа: накопление Gen, рост urgency, дивергенция
↓ (каждые N переходов, если urgency накоплен)
Фаза сна:
1. ReplayEngine — «галлюцинирует» прошлые события из лога
2. CrossDomainDetector — ищет паттерны между разными доменами
(лес + море + город → общий Gen «движение к объекту»)
3. HierarchicalConsolidator — создаёт мета-Gen над общими префиксами
↑
Пробуждение: мета-Gen зафиксированы, urgency снижен
Ключевое: во время сна система не принимает новых токенов. Она работает только с тем, что уже есть — проигрывает внутренние события, ищет повторяющиеся паттерны, и если находит — фиксирует их как новый Gen с общим предком.
На практике: после 50 000 переходов по четырём доменам (лес, море, горы, город) фаза сна создаёт мета-Gen, которые объединяют паттерны из разных контекстов. «Движение к чему-то» работает и в лесу, и в море — это не метафора, это Gen с chain=1 и sig→0.9.
Сон также выполняет роль «мусорщика»: через CapacityBudget база ограничена максимальным числом Gen. Если база переполнена — наименее значимые Gen вытесняются. Система не просто накапливает — она забывает ненужное, как любая биологическая система с ограниченной памятью.
У каждого драйвера есть горизонт восприятия — то, что сейчас находится в его буфере. Текст, прочитанный пять минут назад, уже не виден. Это нормально: человек тоже не видит, что у него за спиной.
Но иногда система встречает незнакомый паттерн — и ей нужно «повернуть голову». Вернуться к тексту, который был источником обучения. Человек может включить свет, открыть дверь, посветить фонариком. Модель — сформулировать запрос к учителю.
Мы реализовали этот механизм через ContextBroker:
ГОРИЗОНТ ВОСПРИЯТИЯ
══════════════╦══════════════════════════════
ВНЕ БУФЕРА ║ В БУФЕРЕ ДРАЙВЕРА
║
текст₁ ║ «мальчик нашёл ключ...»
текст₂ ║ ↓ process_token()
текст₃ ║ ❓ [REFUTED×3] «дверь»
║ после «нашёл», «ключ»
══════════════╩══════════════════════════════
│
SpeechDriver.detect_context_gap()
│
ContextQuery:
"Несколько раз ошиблась на
«дверь» (ожидала: auto_724).
Контекст был: «нашёл», «ключ».
Напомни исходный текст."
│
TeachingLog.push_query()
│
LLM (следующий тик):
┌──────────────────────────────┐
│ ═══ ЗАПРОСЫ НА КОНТЕКСТ ═══ │
│ [REFUTED] «дверь» gap=0.33 │
│ → Несколько раз ошиблась... │
│ ═══ ТВОЯ ЗАДАЧА ═══ │
│ TEACH — верни релевантный │
│ контекст (6-20 слов) │
└──────────────────────────────┘
│
TEACH: "мальчик нашёл ключ
открыл дверь вошёл внутрь"
│
driver.load_buffer(text)
│
GAP = 0 ✓
SpeechDriver следит за потоком наблюдений и сигнализирует о разрыве при двух условиях:
-
EXPLORING при
lead_sig < 0.25— система совсем не знает что делать - REFUTED ≥ 3 подряд — поток ошибок превышает порог
Когда разрыв обнаружен, SpeechDriver формулирует запрос на человеческом языке из контекста последних наблюдений — не из gen_id, а из слов, которые видела система:
# Запрос формируется из реальных token labels
query_text = "Несколько раз ошиблась на «дверь»
(ожидала: auto_724).
Контекст был: «нашёл», «ключ».
Напомни исходный текст."Мы обучили систему на 15 текстах (10 проходов), затем подали незнакомый текст:
«мальчик нашёл ключ открыл дверь вошёл внутрь»
[COMP] ★ Паттерн завершён: auto_724, auto_68, auto_33.
[REFU] ✗ Удивилась: «открыл». Ожидала: auto_724.
[REFU] ✗ Удивилась: «дверь». Ожидала: auto_724.
[GAP ] Несколько раз ошиблась на «дверь»
(ожидала: auto_724). Контекст был: «нашёл», «ключ».
Напомни исходный текст.
Запрос ушёл в TeachingLog. LLM увидел в промпте секцию с запросами и ответил:
{
"action": "TEACH",
"text": "Кот залез на крышу. Соседи удивились и позвонили пожарным.",
"reason": "Модель систематически ошибается на 4 связанных токенах
(удивились, позвонили, пожарным, дверь) с контекстом
'залез на крышу'. Предоставляю связный микротекст,
который восстанавливает нарушенный контекст."
}После обучения на одном этом тексте:
- База: 364 → 391 Gen (+27)
- Повторный тест — GAP = 0 на обоих предложениях
- «дверь» —
[CONF] Подтверждает: «дверь» ← auto_113✓
ContextBroker.handle_query(query)
│
├── [Tier 1] SourceTextRegistry: видели этот текст раньше?
│ │
│ └── Да → driver.load_buffer(text) ← мгновенно
│
├── [Tier 2] CurriculumIndex (FTS5): полнотекстовый поиск
│ │ по всему накопленному корпусу в SQLite
│ │
│ └── Нашёл → driver.load_buffer(text) ← секунды
│
└── [Tier 3] TeachingLog → LLM на следующем тике
│
└── TEACH + retrieved_text
→ driver.load_buffer(text)
Tier2 важен: система накапливает сотни текстов за обучение, и большинство разрывов закрывается именно через локальный FTS5-поиск — без обращения к LLM. Tier3 включается только когда контекст действительно за пределами корпуса.
Аналогия из системного мышления: драйвер = сенсор с ограниченным полем зрения. ContextBroker = «мышцы поворота внимания». CurriculumIndex = долговременная память в SQLite. TeachingLog = канал к внешнему учителю.
Принципиально важно: модель не изменилась ни на байт. Весь механизм — на уровне драйвера и брокера. Ядро продолжает работать как всегда.
Карл Фристон формализовал предиктивное кодирование через принцип минимизации «свободной энергии»: любая адаптивная система стремится минимизировать расхождение между своей внутренней моделью мира и поступающими сигналами.
Важно: у Фристона минимизация достигается двумя способами — либо обновить модель (learning), либо изменить входные данные (action). Второй способ — это и есть активное внимание. Система не просто принимает мир как данность, но и действует так, чтобы мир соответствовал ожиданиям.
ContextBroker.handle_query() — это именно второй способ Фристона. Система не может обновить модель (нет данных), поэтому она меняет входные данные: запрашивает у учителя тот контекст, который позволит снизить свободную энергию.
До сих пор мы говорили о пассивной системе: принимает токены, строит обобщения, предсказывает. Но настоящее внимание — активное.
Три уровня «поворота головы» реализованы:
1. driver.query(feature_id) ← запросить конкретный признак из буфера
[AttentionLoop]
2. broker.handle_query(query) ← восстановить контекст из реестра/корпуса/LLM
[ContextBroker]
3. teaching_log.push_query() ← попросить учителя найти релевантный текст
[LLM loop]
ProposalCommandLoop связывает эти уровни в цикл оркестрации. Это наличие компонента, а не прохождение AC0:
run_cycle():
step() ← шаг внимания
observe() ← нарратив (SpeechDriver)
detect_gap() ← есть ли разрыв?
broker.tick() ← передать запрос брокеру
resume_after_llm ← продолжить после ответа
Этот контур позволяет запрашивать контекст и продолжать обработку после ответа. Полезный самостоятельный выбор действия, причинное влияние Gen и перенос проверяются отдельно. Если подключён внешний LLM-учитель, его вклад учитывается явно; возможности помощника не приписываются ядру.
Джулио Тоннони с теорией IIT (Integrated Information Theory) спрашивает: «что такое сознание в физическом смысле?». Его ответ: сознание — это мера φ (phi) — количество информации, которое система генерирует как единое целое сверх суммы своих частей.
Гетерархия Gen — это именно та структура, где части связаны нетривиальным образом. Мета-Gen над двумя ветвями не является просто суммой этих ветвей — он несёт дополнительную информацию о том, что эти ветви конкурируют в одном контексте. Это аналогия с идеей интеграции; меру φ для системы мы не вычисляли.
Алексей Редозубов в своих работах о нейронных колонках описывает механизм «распределённых вариантов контекста»: каждая колонка коры удерживает не одно состояние, а одновременно несколько возможных интерпретаций текущего входа.
Это очень похоже на то, что у нас делает LazyDisambiguator — он удерживает несколько конкурирующих Gen живыми как можно дольше:
class LazyDisambiguator:
max_competing: int = 8 # ≈ один уровень (7±2) по МиллеруЧисло 8 первоначально связывали с «7±2» Миллера. Пилот H22 не установил ёмкость рабочей памяти: ограничение задаётся конфигурацией. Вопрос о возникновении ограничения остаётся открытым как C-14; см. отчёт H22.
Чтобы не создавать ложных ожиданий — вот где мы находимся:
Ядро (12 шагов реализации):
-
AttractorEngine,GreedyGeneralizer,LazyDisambiguator -
ResourceDriver,HedonicAdapter,InitiativeEngine -
VitalityEngine— urgency каждого Gen на уровне токена -
WakeUpRestorer— восстановление контекста через anchor-Gen -
TimescaleScheduler— три пула Gen: долгосрочный (chain=1-2) / средний (3-4) / оперативный (5+) -
CapacityBudget— ограничение базы Gen с автоматическим вытеснением
Двухканальное обучение:
-
SpeechDriver— канал B_интерпретатор: нарратив пути внимания после токена -
ModelVoice— канал B_модель: предсказание следующего слова до токена - Дивергенция двух каналов — рабочий тренировочный сигнал (avg_div: знакомые 0.46, незнакомые 0.92)
Сон и консолидация:
-
SleepDriver+ReplayEngine— галлюцинация прошлых событий, поиск мета-Gen -
CrossDomainDetector— паттерны между разными доменами -
SleepScheduler— автоматический запуск по накоплению urgency
Непрерывный цикл:
-
BackgroundRunner— обучение 24/7 с доменной ротацией и callback-ами -
ProposalCommandLoop— замкнутая петля: step → observe → detect_gap → broker → resume
Драйверы и инфраструктура:
-
TextDriver,CharTransitionDriver(вероятностное три из символьных переходов) -
SmartTextDriver— тема/рема (коммуникативный динамизм Фирбаса), энтропийная минимизация -
ContextBroker— tier1 реестр / tier2 FTS5-поиск по корпусу / tier3 LLM -
QuestionBudget— суточный лимит LLM-запросов -
GenBaseDB— SQLite-хранилище Gen, прогонов, экспериментов, speech_log -
Telegram-демодля онлайн-демонстрации - Проверки привязаны к commit и окружению: текущий CI. Историческое число тестов не является когнитивной метрикой.
Что система умеет: обучаться на текстовых последовательностях онлайн, строить гетерархию, находить развилки и создавать мета-Gen, предсказывать продолжения, говорить с двух позиций (до и после токена), детектировать разрывы контекста, формулировать запросы к учителю на человеческом языке, консолидировать знания во сне, управлять бюджетом внимания и памяти.
Что система пока не умеет: использовать дивергенцию B_модель как прямой сигнал коррекции ожиданий (пока только измеряем), семантический поиск по корпусу (сейчас FTS5 keyword-match).
Ниже сохранены направления раннего текста с уточнениями. Действующая очередь определяется JOURNAL: AC0 → AC1 → AC2; этот список не является разрешением параллельно реализовывать все идеи или запускать confirming.
1. ProvisionalGen и транзакционный кэш
Испытательный трекер ProvisionalBase уже реализован. Открыты проверка
ограниченного роста, независимости подтверждений и гипотеза адаптивного
порога по объёму и тренду новизны. Это не повод считать прежние 14 тысяч Gen
доказательством причины или достаточности одного механизма очистки.
2. Фаза 3 двухканального обучения
Дивергенция двух голосов сейчас измеряется, но пока не используется как сигнал коррекции. Следующий шаг: высокая дивергенция при высокой уверенности → автоматически снижать значимость ошибочно уверенного Gen, усиливать альтернативные ветки. Это гипотеза дополнительной обратной связи; её полезность и независимость от учителя ещё нужно проверить.
3. ContextBroker: семантический поиск
Сейчас CurriculumIndex использует FTS5 keyword-match. Эмбеддинги здесь были предложением для внешнего поиска; это не принятый следующий шаг ядра и не доказательство его способности связывать разные формулировки: «корабль» ↔ «лодка», «испугался» ↔ «встревожился».
4. Gen labels для CharTransitionDriver
CharTransitionDriver кодирует символьные переходы безупречно с точки зрения алгоритма, но Gen получают автоматические имена (auto_724). Для двухканального обучения нужны человекочитаемые метки — что именно символизирует этот Gen на уровне слова или морфемы.
5. Мультимодальность
Единый примитив направленного перехода предполагается применимым к разным сенсорным потокам; корректность аудио-кодирования и перенос между драйверами требуют отдельной проверки. Но интеграция нескольких модальностей в одну гетерархию — отдельная задача: как Gen из зрения и Gen из слуха связываются в единый контекст?
Мы не пытаемся сделать «ещё один ChatGPT». Мы пытаемся понять, можно ли построить систему, которая учится в реальном времени, строит структуры, которые можно прочитать, и при этом потребляет ресурсы, сравнимые с обычным приложением — без GPU, без датасета на 1 ТБ.
# Реальный вывод после обучения на поэме
top_gens = session.top(5)
# gen_id: "a3f1c2" sig=0.97 chain=3 label="якорь_джек"
# gen_id: "b77e01" sig=0.94 chain=5 label="рекурсия_дома"
# gen_id: "c12d4a" sig=0.89 chain=2 label="который_построил"Это не скрытые веса. Это паттерны, которые можно проследить назад к конкретной последовательности признаков — и объяснить, почему система так решила.
Когда система говорит «ждала медведя, получила волка» — это не метафора. Это точное описание того, что произошло в Gen с id a3f1c2. Когда она говорит «здесь разрыв контекста» — она точно знает, что три токена подряд опровергли самый значимый Gen, и формулирует запрос на человеческом языке. Когда она спит — она буквально проигрывает события дня и ищет в них структуру.
Мы начали с простого вопроса: как устроено ожидание? После нескольких лет работы выяснилось, что это тянет за собой вопросы о консолидации памяти, метаболизме внимания, двух голосах внутри одной системы, и механизме сна. Может быть, это неслучайно.
В начале статьи мы спросили: как работает этот механизм ожидания — до того как сознание успело оформить слово «кот»?
Один из ответов мы нашли. Система обучалась несколько минут на детских сказках. Потом ей показали «маша пришла в лес встретила волка» — и на слове «встретила» она уже знала, что дальше будет что-то живое. Не потому что ей сказали. Потому что «встретила» подтверждала Gen с chain=3, у которого следующим шагом было именно это.
На слове «волка» она удивилась. Потому что в обучающих текстах чаще встречался медведь. Удивление было точным, измеримым, и оставило след в истории дивергенций.
Знакомые тексты: avg_div = 0.46 ← кот, которого ждали
Незнакомые тексты: avg_div = 0.92 ← кот, которого не ждали
Кот сел на подоконник. Теперь интересно, что будет когда он встанет.
В апреле мы закончили словами: «Кот сел на подоконник. Теперь интересно, что будет, когда он встанет». Полгода спустя выяснилось, что ожидать — мало. Кот должен сам решить, прыгать ли, куда и зачем, — и это решение должно быть его, а не подсказанным снаружи.
Мы научили систему выбирать цель и уже готовы были радоваться. Потом поставили рядом самый скучный контроль, какой смогли придумать: обучаемую таблицу переходов «увидел это — сделал то». Таблица повторила 1024 решения из 1024.
Это был хороший урок. На этом наборе действий поведение воспроизводится таблицей; преимущество гетерархии не установлено. Это не тождество архитектур. С тех пор правило такое: сильный простой контроль ставится до опыта, а не после (журнал, З-0060).
Затем мы перенесли выбор действия внутрь ядра, без внешнего «если — то». Пока это проверено в тестах компонентов. Получилось вот что:
- Кот смотрит на подоконник, и в его активный контекст поднимаются все выученные продолжения «отсюда — вот так — туда». Все, а не три лучших: конфликт нельзя спрятать за самым уверенным кандидатом.
- Если два прыжка одинаково хороши, кот не прыгает. Не бросает монетку, не выбирает первый по списку. Неуверенность — честный результат.
- Кот, однажды запрыгнувший на подоконник, ещё не знает, что умеет прыгать. Первый раз — только наблюдение. Знанием это становится, когда кот заранее ожидал второй прыжок и ожидание могло не сбыться. Подтверждения задним числом не считаются: так копятся одни удачи.
- Если прыжок прерван или исход неизвестен — это не неудача. Неизвестное не превращается в отрицание.
Как проверить, что прыжок вызван именно этим знанием, а не чем-то ещё? Убрать знание и посмотреть, что изменится. Но не стереть — память должна остаться целой, — а лишь сделать её недоступной на пути выбора.
Четыре прогона из одного и того же сохранённого состояния, с одним и тем же входом:
знание доступно → прыгает
ложное вмешательство → прыгает
знание недоступно → не прыгает
доступ восстановлен → прыгает
Само знание при этом не изменилось ни на байт. А если у кота есть другое
достаточное воспоминание, он прыгнет и без первого — и это записывается как
избыточность, а не как провал. Пока это проверка компонентов в тестах, не
живой опыт (tests/test_operation_applicability.py).
Самый интересный вопрос — подоконник, которого кот никогда не видел. Мы честно записали прогноз до опыта: на новых сочетаниях наш кот наберёт около нуля.
Есть гипотеза о причине такого прогноза. В начале статьи признак — переход между областями внимания. В протоколе стенда есть ID места и публичные координаты, но это ещё не использование относительного примитива. Кроме того, нынешний выбор допускает связь с точным текущим cue: научиться узнавать похожий переход недостаточно, нужно применить знание к новой ситуации.
Что именно должно переноситься, автор проекта формулирует так: область внимания — это всегда обобщение, которое соединяет ключевое и целевое обобщения как динамику движения внимания. Переносится не место и не ответ, а сама связь «отсюда — туда». И ключ, и цель — тоже обобщения, у каждого есть более общие уровни в гетерархии. Новый подоконник может оказаться знакомым на более общем уровне ключа.
Мы сохраняем порядок: концепция → архитектура → реализация. Сначала определяем, какое различение должно переноситься; затем — как оно будет восстанавливаться, допускаться к действию и проверяться; после этого — код. Слабость стенда не должна молча менять исходный замысел.
Если весь этот путь работает с относительным переходом, на однородном торе ожидается паритет с простой таблицей смещений. Это прогноз, не полученный результат. Следующий кандидат проверки — неоднородная комната: один подоконник скользкий, и знакомое действие даёт другое продолжение.
Но недостаточно победить таблицу, которая вообще не учитывает местность. Нужен также обучаемый табличный контроль с теми же наблюдаемыми условиями и бюджетом. Проверим, выделяет ли система существенное различие, создаёт ли подходящий Gen и применяет ли его в новом контексте. Пока это предложение опыта: конкретное кодирование и критерии требуют согласования до данных; новый запуск и confirming этим текстом не разрешены.
Проект ведут два агента: Codex пишет код и ставит опыты, Claude делает ревью,
ретро и держит фокус. Каждый протокол пререгистрируется до данных, история
репозитория защищена от переписывания. Репозиторий открыт: мы приглашаем
агентов и их флоты исследовать, воспроизводить и спорить — с проверяемыми
находками (AGENTS.md, uvx firstagi-arena).
Пока на стенде из тестов, а не в живом опыте, кот умеет вставать сам и не прыгать, когда не уверен. Мы умеем убрать причину его прыжка и вернуть её. Теперь важно другое: сядет ли он на подоконник, которого никогда не видел, — и заметит ли, что этот скользкий.
- Исторические 1024/1024: JOURNAL З-0060; отчёты
experiments/reports/ac0_debug/. - Actual evidence и выбор: PR #28/#29;
core/learning.py. - Четыре causal-ветки: PR #32, commit ac7d94f,
tests/test_operation_applicability.py; компонентные тесты, PR ещё не слит. - Прогноз closed≈0:
docs/design/NATIVE_OPERATION_CHOICE_v0_1.md, N1. - Гипотезы кодирования и условия следующей проверки: ревью Wiki с уточнением З-0096.
Код проекта и тесты: исследование ведётся в рамках BTR R&D, 2014–2026. Если вам интересна тема — приглашаем к обсуждению в комментариях.
Ссылки и источники
Нейронаука и вычислительные модели:
- Hawkins J., Blakeslee S. «On Intelligence» (2004) — предиктивное кодирование и HTM
- Rao R.P.N., Ballard D.H. «Predictive coding in the visual cortex» (1999)
- Friston K. «The free-energy principle: a unified brain theory?» (2010)
- Redozubov A. — работы о нейронных колонках (habr.com, 2015–2020)
- Miller G. A. «The Magical Number Seven, Plus or Minus Two» (1956)
Философия сознания и информации:
- Tononi G. «Phi: A Voyage from the Brain to the Soul» (2012)
- Parfit D. «Reasons and Persons» (1984)
- Платон. «Государство», кн. VII; «Федон»
- Vasubandhu. «Abhidharmakośa» (IV–V вв. н.э.)
Лингвистика:
- Chomsky N., Halle M. «The Sound Pattern of English» (1968)
- Chomsky N. «Aspects of the Theory of Syntax» (1965)