Часть 1. Детерминированный движок рассуждения на конечной таблице операции (в перспективе — замена LLM)
Когда речь заходит о больших языковых моделях, все сразу отмечают их талант к сочинению и пересказу текстов. Но вот встроить такую модель в реальный продукт — задача куда более каверзная, чем кажется на первый взгляд. На практике вылезают три системных «подводных камня», из‑за которых работать с ними бывает откровенно неудобно.
Первый камень — непредсказуемость. Представьте: вы посылаете модели один и тот же запрос дважды — а в ответ получаете два разных варианта. И это не случайность, а закономерность. Виной тому целый веер причин: от "памяти" о предыдущих диалогах (контекст) до тонких настроек генерации и естественного "плавания" внутренних весов модели. В итоге результат зависит не только от вашего запроса, но и от кучи невидимых факторов.
Второй момент — проблема с проверкой. В обычном программном коде мы чётко знаем: вот входные данные, вот ожидаемый вывод, вот критерии успеха. С языковыми моделями такой ясности нет. Как доказать, что ответ "правильный", если у задачи может быть десяток равноценных решений? Где та грань, за которой креативность превращается в выдумку?
Третий сюрприз ждёт после обновлений. Допустим, вы полгода отлаживали интеграцию, подобрали идеальные параметры, написали кучу тестов — и тут разработчики выпускают новую версию модели. И вдруг всё начинает работать иначе: прежние запросы дают странные ответы, тесты падают один за другим. Дело в том, что даже небольшие изменения в обучении модели могут кардинально поменять её "стиль" и логику. Предсказать, как именно она поведет себя в вашем сценарии, почти невозможно — а значит, каждое обновление грозит превратиться в марафон по починке сломавшегося
Этот проект строится по принципиально иной схеме. Его "интеллектуальное ядро" работает совсем не так, как языковые модели. Вместо вероятностной магии — жёсткая детерминированная логика.
В основе его лежит чёткий, осязаемый объект — таблица операций (таблица конечной магмы). Именно она задаёт поведение системы: никаких сюрпризов, никаких "творческих трактовок". Что записано в таблице — то и будет выполнено.
Чтобы гарантировать надёжность, в системе предусмотрены два стража качества:
валидаторы — проверяют корректность на каждом шаге;
регрессионный контур — следит, чтобы после изменений ничего не «поплыло».
Важно понимать: речь не идёт о том, чтобы вычеркнуть LLM из процесса навсегда. Языковая модель вполне может остаться в команде — но на другой роли. Мне она представляется скорее как вежливый переводчик: она принимает человеческий текст, понимает его смысл и аккуратно упаковывает в структурированные данные для основного ядра.
Итак, если сейчас LLM выступает в роли «решателя» — того, кто думает и принимает решения. Я предлагаю, чтобы эту функцию взяло на себя табличное ядро. К нему добавляются:
процедуры замыкания — механизмы, которые доводят решение до логического конца;
тестовый контур — система проверок, гарантирующая стабильность.
Получается чёткая цепочка: LLM‑интерфейс переводит запрос в структуру → табличное ядро вычисляет ответ по жёстким правилам → валидаторы и тесты следят за чистотой процесса. Никакой неопределённости — только предсказуемость и контроль.
Как корректно воспроизвести архив
Архив плоский (без верхней директории). Поэтому самый надёжный способ распаковки — так:
mkdir MP_YANTRA_CORE_iter116
unzip MP_YANTRA_CORE_iter116.zip -d MP_YANTRA_CORE_iter116
cd MP_YANTRA_CORE_iter116
python TOOLS/bootstrap.py
Ожидаемое поведение: bootstrap возвращает PASS по ядру. HTTP-слой (FastAPI) опционален и не должен ломать нулевой прогон.
Запуск в ChatGPT (без локальной установки)
Если у вас нет желания поднимать Python-окружение локально, архив можно прогнать прямо в ChatGPT — нужен режим выполнения кода (Advanced Data Analysis / Code Interpreter).
Создайте новый чат и прикрепите файл
MP_YANTRA_CORE_iter116.zipпервым сообщением.Напишите:
Следуй инструкциям в файле
DOCS/00_NEW_CHAT_PROTOCOL.mdиз загруженного архива.
Дальше ChatGPT выполнит “канонический прогон” из протокола: распаковку, bootstrap (PASS/FAIL), обязательные демонстрации и сформирует отчёты.
Примечание: чтобы ознакомиться с более широким контекстом проекта, воспользуйтесь навигацией по разделам DOCS/ и GRAPH/INDEX/*
1) Главный объект: таблица бинарной операции
Корректные названия:
“таблица бинарной операции на конечном множестве (operation table);”
“в терминах алгебры: таблица операции конечной магмы (magma operation table; часто говорят «таблица Кэли»);”
“по-инженерному: lookup table / transition table.”
Формально: есть конечный алфавит состояний P и функцияop: P x P -> P, заданная таблицей. Здесь L3 означает |P| = 3, L4 означает |P| = 4, то есть это просто размер конечного алфавита состояний.
2) Две реальные таблицы из архива (L3 и L4)
2.1. L3 (3x3): базовый кадр на трёх состояниях
Файл: SPEC/TABLES/L3_STAR_SUN_A.json
Алфавит: P = {A, B, C}, операция *.
Симметрия таблицы — это такое переименование элементов, при котором сама операция не меняется. Поясню более формально: есть отображение σ: P → P, и если для любых a, b из P выполняется σ(op(a, b)) = op(σ(a), σ(b)), то σ сохраняет структуру таблицы. Такое σ называется автоморфизмом.
То есть все "правильные" преобразования σ, которые сохраняют операцию op, вместе образуют группу. Все эти автоморфизмы вместе образуют группу, которую обозначают Aut(op). В проекте она используется, чтобы:
уменьшить число перебираемых вариантов (факторизация по симметриям);
проверять корректность таблиц и их инварианты в валидаторах.
Фактически Aut(op) — это подгруппа Sym(P), то есть полного множества всех перестановок элементов P.
|
A |
B |
C |
|---|---|---|---|
A |
A |
A |
A |
B |
B |
C |
A |
C |
C |
A |
B |
Примеры вычислений:
B * C = AC * B = AB * B = C
2.2. L4 (4x4): прикладной кадр “статусов/ремонта”
Файл: SPEC/TABLES/L4_KAP_SR_NEG_SUN_v1.json
Алфавит: P = {S, NEG, R, SUN}, операция *.
|
S |
NEG |
R |
SUN |
|---|---|---|---|---|
S |
NEG |
R |
SUN |
S |
NEG |
R |
SUN |
NEG |
NEG |
R |
SUN |
S |
NEG |
R |
SUN |
SUN |
SUN |
SUN |
SUN |
Примеры:
S * R = SUNR * NEG = SSUN * x = SUN(вся строка SUN)x * SUN = x(столбец SUN возвращает метку строки)
3) Минимальные определения
3.1. Алфавит состояний
Инженерно: небольшой набор дискретных меток состояния.
Строго: конечное множество
P,n = |P|.
3.2. Табличная операция
Инженерно: lookup-table:
(x, y) -> z.Строго: функция
op: P x P -> P, заданная таблицей (таблица Кэли конечной магмы).
Суть в том, что ни одно алгебраическое свойство — ни ассоциативность, ни коммутативность, ни наличие нейтрального элемента — не считается верным заранее.Даже если оно кажется очевидным или типичным для таких операций.
3.3. Эпизод и замыкание
Эпизод — это просто набор меток состояний длины m (формально элемент Pm).
В демо чаще берётся m = 3, то есть эпизод — это тройка состояний, описывающая локальное «окно» системы.
Замыкание — это детерминированная функция F: Pm → Pm, которую система применяет к эпизоду снова и снова.
Поскольку множество Pm конечно, итерации не могут продолжаться бесконечно — рано или поздно состояние повторится.
В этот момент процесс входит либо в фикс‑точку (стабильное состояние), либо в цикл (устойчивый повтор).
Это чистая дискретная динамика — без эвристик и интерпретаций: всё вычисляется точно и однозначно.
4) Как ядро использует таблицу (псевдокод)
# op — таблица: P x P -> P
# state — m-канальный эпизод: (x1, x2, ..., xm)
function step(state):
x1' = op(x1, x2)
x2' = op(x2, x3)
...
xm' = op(xm, x1)
return (x1', x2', ..., xm')
function closure(state, limit):
seen = map() # состояние -> индекс
for t in 0..limit:
if state in seen:
return cycle(seen[state]..t)
seen[state] = t
state = step(state)
return "no_converge_within_limit"
Смысл: таблица задаёт локальную редукцию, а замыкание превращает её в устойчивый вычислительный режим (фикс/цикл + трасса).
5) PASS/FAIL: что это означает для читателя
PASS (ok: true) означает:
процедуры исполнимы;
входы/выходы соответствуют схемам;
результат воспроизводим;
регрессионные эталоны не сломаны.
FAIL означает: есть структурированная ошибка с контекстом (что именно нарушено и где).
6) Быстрый запуск (после bootstrap): демо + публичный отчёт
Демо согласования/дрейфа (верная команда для текущего релиза):
python TOOLS/mp_engine_cli_v1.py run-bridge-v2 \
--input RAW/CONVECTION_BRIDGE_EXAMPLES/convection_bridge_l4_drift_v2.json \
> REPORTS/habr_bridge_internal.json
Экспорт публичного отчёта (стабильный JSON-контракт):
python TOOLS/mp_engine_cli_v1.py export-public-report \
--in REPORTS/habr_bridge_internal.json \
--out REPORTS/habr_bridge_public.json
Файл REPORTS/habr_bridge_public.json — удобная “витрина результата” для статьи и для интеграции (контракт не зависит от внутренней структуры модулей).
Часть 2. Как этим пользоваться в продукте: сценарии, интеграция, отчётность
В первой части была зафиксирована сама модель: конечный набор меток состояний, таблично заданная бинарная операция, механизм замыкания и учёт симметрий.
Плюс был показан базовый запуск ядра — от распаковки архива до первого PASS/FAIL.
Во второй части речь уже про практику: как именно использовать движок в продукте, какие задачи он решает, как выглядит результат в публичном JSON-отчёте и как подключить ядро как сервис.
0) Важная практическая деталь про распаковку архива
Архив плоский (без верхней директории). Чтобы команды из статьи воспроизводились одинаково у всех, используйте такой шаблон:
mkdir MP_YANTRA_CORE_iter116
unzip MP_YANTRA_CORE_iter116.zip -d MP_YANTRA_CORE_iter116
cd MP_YANTRA_CORE_iter116
python TOOLS/bootstrap.py
После bootstrap можно запускать демо/CLI/сервис.
1) Сценарий A: согласование меток двух источников (label alignment), без «семантики текста»
Задача
Есть два источника (два агента/сервиса/подсистемы), которые выдают «одно и то же», но в разных кодировках меток. Например:
один пишет статусы как
S, R, -, ☼,другой — тем же алфавитом, но «сдвинутым» или переименованным.
Движок решает инженерно корректную задачу: подобрать отображение σ (переименование меток), которое лучше всего согласует наблюдения, причём:
класс допустимых σ ограничен (чтобы не «подгонять мощностью»),
результат сопровождается метриками и witnesses (эпизодами, которые реально различают гипотезы).
Запуск на готовом примере из архива
python TOOLS/mp_engine_cli_v1.py run-bridge-v2 \
--input RAW/CONVECTION_BRIDGE_EXAMPLES/convection_bridge_l4_drift_v2.json \
> REPORTS/habr_bridge_internal.json
python TOOLS/mp_engine_cli_v1.py export-public-report \
--in REPORTS/habr_bridge_internal.json \
--out REPORTS/habr_bridge_public.json
Что смотреть в результате (публичный отчёт)
Откройте REPORTS/habr_bridge_public.json. Ключевые поля:
result.global.best_sigma— лучшая гипотеза σ (в примере σ имеет параметры вида{u, t}: это конкретный класс переименований, заданный данными);result.global.best.stabilityиresult.global.best.mismatches— метрика качества согласования;result.uncertainty.witnesses— короткий список «свидетельств», которые отличают топ-гипотезы.
Мини-выдержка (сокращённо по смыслу):
{
"schema": "REPORT_PUBLIC_V1",
"result": {
"global": {
"best_sigma": {"u": 1, "t": 2},
"best": {"stability": 0.5, "mismatches": 6}
},
"uncertainty": {
"witnesses_count": 8,
"witnesses": [
{"eid":"01", "obs":["S","-","☼"], "top1": {...}, "top2": {...}},
...
]
}
}
}
Инженерный смысл witnesses: вместо спора «кто прав» появляется проверяемый вопрос: каких данных не хватает, чтобы устойчиво выбрать одну гипотезу σ и отбраковать конкурирующую.
Примечание: в public-отчёте список witnesses может быть ограничен по длине, полный набор остаётся во внутреннем отчёте.
2) Сценарий B: дрейф и смена режима (change-point) как оптимизация
Задача
Даже если два источника в целом «согласуемы», отображение σ может меняться по времени: обновили прошивку, поменяли правила статусов, переключили режим обработки.
Вместо того чтобы выбирать «одну σ на всё», движок делает разбиение на сегменты, где σ стабильна, и выдаёт границы смены режима.
Что смотреть в отчёте
В REPORTS/habr_bridge_public.json:
result.segments.count— сколько сегментов найдено;result.segments.boundaries— список границ между сегментами.
Пример поля границы (по смыслу):
"boundaries": [
{"between":[5,6], "prev_sigma":{"u":3,"t":0}, "next_sigma":{"u":1,"t":2}}
]
Инженерная интерпретация:
на эпизодах 0..5 лучшая σ одна,
на эпизодах 6..N — другая,
это и есть «событие смены режима», которое удобно превращать в алерт/событие аудита.
3) Сценарий C: детерминированный «policy kernel» в дискретном пространстве (вместо вероятностного решателя)
Задача
Нужно ядро принятия решения/диагностики, которое:
детерминировано (одинаковый вход → одинаковый результат),
покрывается регрессией,
объясняется трассой вычисления, а не пост-фактум комментариями.
Таблично заданная бинарная операция здесь выступает как инженерный оператор редукции/композиции состояний. Сверху накладывается детерминированное замыкание (итератор), которое приводит эпизод к фикс-точке или циклу — и это уже используется как «решение».
Почему таблица не обязана быть ассоциативной — и это нормально
Ассоциативность означает, что результат не зависит от расстановки скобок:
(a b) c == a (b c).
Для вычислительного контроллера это часто лишнее ограничение:
В продуктовых правилах порядок объединения важен.
В реальном пайплайне вы почти всегда агрегируете сигнал по этапам: вход → нормализация → ремонт → финал. Неассоциативность позволяет таблице «помнить» порядок композиции и тем самым реализовывать приоритеты.Ассоциативность резко сужает пространство конструкций.
Если вы хотите одновременно иметь «поглотитель» (состояние, которое доминирует) и «правую единицу» (состояние, которое не меняет), то требование ассоциативности быстро превращается в набор жёстких алгебраических ограничений, которые вам как инженеру чаще не нужны.В движке скобки фиксированы алгоритмом.
Замыкание — это конкретный детерминированный итератор. Он не «переставляет скобки», он применяет правило обновления каналов строго по схеме. Поэтому ассоциативность здесь не «обязательная корректность», а отдельное свойство, которое имеет смысл вводить только если оно нужно прикладной области — и тогда оно оформляется как проверяемый аудит/гейт.
Так, если потребовать ассоциативность, L4-таблица схлопнется в тривиальную. В нашей L4-таблицеSUN — левый поглотитель (SUN x = SUN) и одновременно правая единица (x SUN = x). При ассоциативности для любого x: x = x SUN = (SUN x) SUN = SUN (x SUN) = SUN x = SUN. Значит, все элементы равны SUN, т.е. структура вырождается. Поэтому неассоциативность здесь не “недостаток”, а необходимое условие нетривиального поведения.
Иными словами: в этой архитектуре "математическая корректность" достигается не через навешивание чужих аксиом, а через честное именование структуры (конечная магма) и через валидируемые контракты.
4) Как подать свои данные: два «канонических» входа
В проекте идея простая: ядро не обязано понимать текст, оно обязано работать на каноническом формате. Поэтому входы стандартизованы.
4.1. CONVECTION_BRIDGE_INPUT_V2 — когда у вас уже есть эпизоды «до/после»
Смотрите примеры в:
RAW/CONVECTION_BRIDGE_EXAMPLES/convection_bridge_l4_drift_v2.jsonRAW/CONVECTION_BRIDGE_EXAMPLES/convection_bridge_l3_const_sigma_v1.json
Это удобный формат, если данные уже приведены к дискретным меткам.
4.2. EPISODE_STREAM_V1 — поток эпизодов (и адаптер)
Если у вас поток эпизодов, его можно прогнать через встроенный адаптер:
вход: RAW/EPISODE_STREAM_EXAMPLES/episode_stream_l4_drift_v2.json
запуск:
python TOOLS/mp_engine_cli_v1.py run-episode-stream \
--input RAW/EPISODE_STREAM_EXAMPLES/episode_stream_l4_drift_v2.json \
> REPORTS/habr_stream_internal.json
python TOOLS/mp_engine_cli_v1.py export-public-report \
--in REPORTS/habr_stream_internal.json \
--out REPORTS/habr_stream_public.json
5) Интеграция как HTTP-сервис (опционально)
HTTP-слой намеренно вынесен как необязательный: ядро не зависит от веб-фреймворков. Но если нужно встроить в продукт, сервисный слой уже есть.
Установка зависимостей сервиса
pip install -r requirements.txt
Запуск сервиса
python TOOLS/serve_api_v1.py --host 127.0.0.1 --port 8000
Проверка
curl http://127.0.0.1:8000/health
Вызов расчёта (публичный контракт)
curl -X POST http://127.0.0.1:8000/run/bridge/public \
-H "Content-Type: application/json" \
--data @RAW/CONVECTION_BRIDGE_EXAMPLES/convection_bridge_l4_drift_v2.json
Ответ — JSON в формате REPORT_PUBLIC_V1 (тот же, что генерирует export-public-report).
6) Docker Compose (если хочется «одной командой»)
В архиве есть Dockerfile и docker-compose.yml:
docker compose up --build
Это удобный путь для демонстрации и для интеграционных тестов.
Итоги
Я собрал и выложил детерминированный движок рассуждения, который работает не на вероятностях текста, а на конечной дискретной модели: есть метки состояний, таблично заданная бинарная операция и чёткий контур воспроизводимости — спецификации, валидаторы, регрессия.
Такой подход даёт то, чего трудно добиться в LLM-парадигме: одинаковый вход всегда даёт одинаковый выход, а любое отклонение фиксируется тестами.
1. В чём инженерская уникальность
Детерминизм как базовая гарантия.
Я не объясняю результат словами — я его вычисляю по конечному объекту. При тех же входных данных поведение не дрейфует.
Строгость процедурная, а не декларативная.
Не нужно верить в красивую теорию: всё зафиксировано контрактами (SPEC/), проверено валидаторами (VALIDATOR/), задокументировано в отчётах (REPORTS/) и удержано регрессией (REGRESSION/).
Истина проекта — в корректности процедур и их воспроизводимости.
Никакой подмены математики словами.
Базовая структура называется тем, чем она является: таблица конечной магмы — таблица Кэли, без обещаний про ассоциативность, группу или поле.
Если свойство важно — оно оформляется как аудит или гейт, и при нарушении я предъявляю контрпример.
Прикладные задачи решаются на дискретных данных, без “семантики текста”.
Согласование схем меток (σ-alignment) и поиск смены режима (change-points) выполняются как вычислимые процедуры с метриками и конкретными свидетелями (witnesses), а не как интерпретации.
2) Что в основе работы: замыкание как вычислительный механизм (и почему это важно)
В основе моего движка лежит идея, которую в инженерных системах почти никогда не делают центральной — замыкание. Я не просто применяю правило один раз, а строю итератор на конечном множестве состояний и гоню процесс до устойчивого результата.
Схема такая:
вход кодируется в эпизод (элемент Pm), далее — детерминированное обновление по табличному правилу, после чего включается замыкание: итерации идут, пока система не стабилизируется — не выйдет на фиксированную точку или цикл. Уже это устойчивое состояние я и принимаю за результат.
Почему это важно.
Результат задаётся не единичным шагом, а аттрактором — устойчивой формой поведения в конечной динамике. Из-за этого поведение системы становится воспроизводимым: если вход тот же, то и аттрактор будет тем же. В обычных rule engine итог часто зависит от порядка применения правил или случайностей пайплайна, а здесь порядок фиксирован и уходит в устойчивый режим через замыкание.
Да, математически замыкание — простая идея.
Но я утверждаю, что в прикладных «движках решений» его почти не используют как основной вычислительный принцип. Здесь же оно — архитектурное ядро, за счёт чего система работает не как набор if-else и не как генератор текста, а как дискретная динамика с аттракторами.
3) Почему это не ИИ
Я не заявляю, что создал “искусственный интеллект”. Я построил решатель, который можно держать под контролем.
Мои отличия от классического rule engine:
я работаю не только с правилами, но и с устойчивыми режимами (фикс/цикл) как с результатом;
я использую согласование схем (поиск σ) и выдаю не только ответ, но и witnesses — минимальные эпизоды, которые различают конкурирующие гипотезы;
я фиксирую результат в стабильном контракте
REPORT_PUBLIC_V1, пригодном для CI и интеграции;я держу строгий режим воспроизводимости: PASS/FAIL — это про процедуры, а не про “впечатление”.
4) Как я позиционирую это относительно LLM (чтобы не вводить в заблуждение)
Я не утверждаю, что движок "понимает" текст или может заменить собеседника. Суть в другом: LLM хорош как интерфейс для генерации и объяснений, но для детерминированного решения задач (с тестами и регрессией) нужен иной тип решателя.
5) Что читатель может проверить сам
Я сделал так, чтобы проверка была не риторикой, а практикой.
Нулевой прогон (bootstrap) сразу даёт PASS или FAIL.
Демо запускается одной командой.
Результаты фиксируются в публичном отчёте стандартного формата.
Проще говоря: это не «концепт», а исполняемый артефакт, который можно запустить, проверить и сверить результаты.
AleGen
Попытался въехать, но своим недалёким умом так и не понял: как это можно использовать на практике в связке с LLM. Объясните, пожалуйста.
fireSparrow
У меня при чтении этой статьи сложилось впечатление, что этот "Решатель" - что-то вроде "Корчевателя".
rusfbm Автор
Если совсем просто: LLM — это "мягкий" интерфейс (Soft), а движок — "жесткое" ядро (Hard). LLM может сочинять, но не умеет гарантировать. Движок не умеет сочинять, но гарантирует результат.
rusfbm Автор
Кроме того, в статье я больше по верхам прошелся (L3/L4), но сейчас ядро уже работает с более сложными логиками, например, в L7-режиме. Там алгоритмически выделяется до 108 вычислимых состояний. Если такую стейт-машину попробовать запихнуть в системный промпт LLM, она поплывет моментально, контекста не хватит удержать правила.
Поэтому архитектурно я сейчас двигаюсь к понятию роя микроядер. Идея в том, что вместо одной большой модели у вас работают тысячи/миллионы/миллиарды маленьких детерминированных решателей.
Каждое такое микроядро — это крошечный движок со своей таблицей и жестким контрактом. И общаются они между собой не текстом, а артефактами проверки. Один возвращает инвариант (типа, проверил структуру, тут цикл длины 2, все стабильно). Другой кидает witness — контрпример, почему одна гипотеза хуже другой. Третий предлагает атом ремонта — конкретное действие, как исправить стык в графе.
Получается такой полный аналог нейросети, только вывернутый наизнанку. В нейронке у вас миллиарды весов и вероятности, и вы не знаете, почему именно сработал конкретный нейрон. Это черный ящик. А здесь у вас может быть рой из миллионов микроядер, но каждое действие внутри — это проверяемая алгебраическая операция по таблице. Вход -> миллион строгих проверок и замыканий -> Выход с доказательством.
Так что цель не в том, чтобы научить LLM думать — это дорого и нестабильно. Цель в том, чтобы оставить LLM роль интерфейса и креатива, а функцию мышления и контроля отдать вот этому рою. Это, на мой взгляд, единственный путь получить прозрачную инженерную систему вместо стохастической.
rusfbm Автор
Смотри, фишка тут в разделении ответственности. LLM круто работает как интерфейс (понимает естественный язык) и генератор идей, но она плывет, когда нужна строгая логика или гарантии. Табличное ядро эту строгость возвращает. На практике схем обычно три:
LLM как переводчик в канон. Пользователь пишет проблему текстом, LLM перегоняет это в JSON-структуру (эпизод). Движок этот JSON прогоняет через таблицу и выдает строгий результат (или ошибку). А LLM потом просто пересказывает этот технический отчет на человеческий язык. В итоге — пользователю удобно, а под капотом математика, которая не придумывает отсебятину.
Фильтрация галлюцинаций (самое полезное). Допустим, нужно построить план действий. LLM предлагает 5 вариантов. С виду все ок, но по факту два из них нарушают бизнес-логику (нельзя, например, перейти из статуса А в Б без визы). Движок проверяет каждый вариант. Те, что дали FAIL — выкидываем. Пользователю отдаем только верифицированные сценарии. Превращаем «похоже на правду» в «гарантированно работает».
Работа со сложными стейт-машинами. Этот движок сейчас у меня работает не только с L3, L4-логикой (см. таблицы конечной магмы), но и с L5, L6, L7-логиками. Так, в L7 выделяется 108 каналов — это, по сути, очень навороченный конечный автомат. Засунуть такую логику в системный промпт нереально, модель запутается и начнет галлюцинировать. Поэтому LLM тут только классифицирует вход (попали в такое-то состояние), а саму траекторию и переходы считает жесткое табличное ядро.
Короче, LLM используем для общения и креатива, а движок — там, где нужна железобетонная логика и регрессионные тесты.
rusfbm Автор
Кстати, если углубиться в архитектуру (про что в статье только намеки), то сейчас я пришел к концепции роя микроядер. Это как раз к вопросу, чем это отличается от обычной нейросети.
Представьте, что вместо одного монолита LLM у вас работают тысячи мелких детерминированных решателей. Каждое такое микроядро — это крошечный движок с фиксированной таблицей и своим контрактом.
Они между собой общаются не текстом, а артефактами проверки: — Инварианты (проверил структуру, все стабильно). — Witnesses (свидетели) — когда одно ядро находит контрпример, почему одна гипотеза хуже другой. — Атомы ремонта — конкретные предложения, как исправить стык, если логика нарушена.
Получается полный аналог нейросети, только вывернутый наизнанку. В нейронке у вас миллиарды весов и вероятности, и вы не знаете, почему сработал конкретный нейрон (условно). Это черный ящик. А здесь — рой микроядер, где каждое действие — это проверяемая алгебраическая операция по таблице.
То есть вход -> миллион строгих проверок и замыканий -> выход с доказательством.
Поэтому я и не пытаюсь научить LLM "думать" сложные вещи (например, на 108 состояниях в L7 она моментально поплывет). Я оставляю ей интерфейс, а функцию контроля и удержания траектории отдаю вот этому рою.
rusfbm Автор
Вообще, про архитектуру роя и взаимодействие ядер я могу написать отдельную статью, если тема интересна. Это тянет на принципиально новый подход к построению сетей.
Там идея в том, чтобы собрать аналог нейросети, но полностью детерминированный. Вместо нейронов с весами — микроядра с таблицами. Вместо backpropagation — обмен артефактами проверки (свидетелями и атомами ремонта).
Это дает систему, которая масштабируется как нейросеть, но не является «черным ящиком». Каждое решение в ней можно размотать до исходной логики. Особенно это критично на сложных режимах (L3 и выше), которые я упоминал — там LLM просто теряет контекст, а такая сеть держит структуру жестко.
Поясню про сложность. В настоящее время в индустрии даже про L4-логику практически ничего не знают. Академическая наука сейчас только подбирается к осознанию L3 (тернарных структур).
Вот цитата из моей статьи «Алгебраическое различение и тернарные структуры»:
То есть то, что я использую в движке — это прикладная реализация математики, которая сейчас находится на переднем крае (а уровни L5–L7 вообще пока terra incognita).
Для тех, кому интересно, на чем это базируется, привожу список публикаций, которые приближаются к пониманию моей логики L3 (но до L4+ там еще не дошли):
Burris, S., & Sankappanavar, H. P. A Course in Universal Algebra. Springer, 1981.
Linckelmann, M. The Block Theory of Finite Group Algebras. Cambridge University Press, 2018.
Sitharam, M., Wang, M., & Willoughby, J. Handbook of Geometric Constraint Systems Principles. Springer, 2018.
Goodman, R., & Wallach, N. Symmetry, Representations, and Invariants. Springer, 2009.
Fiore, T. M., & Noll, T. Commuting Groups and the Topos of Triads. In: Mathematics and Computation in Music. MCM 2011. Springer.
Halász, K. Colorings of Cayley Tables of Finite Groups. Simon Fraser University, MSc Thesis, 2017.
Babai, L. Automorphism Groups, Isomorphism, Reconstruction. In: Handbook of Combinatorics, Elsevier, 1995.
Я намеренно не перегружал основную статью этой теорией, чтобы не смещать фокус с инженерного применения на чистую алгебру, но база у проекта именно такая.