Когнитивно‑символьный ИИ с проверяемым знанием

Я начал делать Oblivion не потому, что мне хотелось написать ещё один чат. Меня всё время беспокоил другой вопрос: что вообще остаётся внутри системы после того, как она дала ответ? Допустим, она прочитала книгу. Потом вторую. Потом тысячу документов. Мне мало того, что через месяц она сможет уверенно пересказать прочитанное. Я хочу открыть её состояние и увидеть: этот факт появился отсюда, вот здесь другой источник ему противоречит, здесь данных пока недостаточно, а этот старый вывод после появления новых данных нужно пересмотреть.

Из этого постепенно и вырос Oblivion Mind. Я строю его как когнитивно‑символьную систему. Для меня важен не сам ответ, а то, что система успела построить, связать и проверить до того, как этот ответ появился. Позже этот вопрос пришлось проверять уже не на условном примере: один из больших прогонов прошёл по 3000 книг. Ниже я отдельно покажу, что именно этот тест проверил — и чего он не доказывает.

Ответ — не главное

Представим, что в статье встретилась фраза: «Вещество X вызывает эффект Y при условии Z». Для поиска этого достаточно. Фразу можно положить в индекс и потом найти. Для системы знаний всё только начинается.

Что такое X? Что именно здесь считается Y? Действительно ли речь идёт о причине или автор просто увидел корреляцию? При каких условиях результат воспроизводится? Кто вообще сделал это утверждение?

Потом появляются ещё более неприятные вопросы. Есть ли другие источники? Они действительно независимы или пять сайтов перепечатали один материал? Есть ли работа с противоположным результатом? Не изменилось ли что‑нибудь за последние годы? Вот этим я и занимаюсь. Мне хочется, чтобы система хранила не только само утверждение, но и контекст вокруг него: откуда оно взялось, насколько подтверждено, с чем конфликтует и можно ли сейчас использовать его в дальнейших выводах.

Иногда правильный ответ — «не знаю»

Это одна из вещей, которые я заложил в проект довольно рано. Если система не может надёжно выбрать один вариант, она не обязана это делать. На практике это означает, что внутри могут оставаться состояния вроде «неизвестно», «неоднозначно», «нужно проверить», «источники расходятся». Для обычного интерфейса это не всегда удобно. Пользователь задаёт вопрос и хочет ответ, а не рассказ о том, почему система сомневается.

Но если строить долгоживущую базу знаний, ситуация меняется. Один случайный выбор сегодня завтра может оказаться основанием для десятка других выводов. Ошибка начинает жить своей жизнью. Поэтому я скорее оставлю вопрос открытым, чем тихо превращу предположение в факт.

Это уже работающая система

Здесь обычно возникает вполне справедливый вопрос: всё это пока проектирование или Oblivion уже существует? Работающий runtime есть. Правда, нынешнее состояние проекта я бы не назвал удобным. Базовый фундамент уже закрыт и работает, а вот нижние уровни понимания текста сейчас проходят довольно серьёзную переделку. Некоторые старые возможности поэтому я сознательно перестал считать доказанными только на том основании, что они когда‑то выдавали результат.

В августе 2026 года я закрыл базовый production‑фундамент. Финальный regression‑прогон прошёл 355 тестов из 355. Падений и пропусков не было. Проверялась не только возможность запустить бинарник. Я отдельно проверял сохранение состояния, полный перезапуск, повторное открытие графа знаний и работу с уже существующими production‑данными.

После этого тот же фундамент запускался уже как обычная система. В одном runtime поднялись девять предметных областей, был открыт существующий граф знаний и учтены 3323 документа. То есть это не схема из блоков в README. Система действительно работает, просто сейчас я довольно глубоко переделываю то, как она понимает входную информацию.

Девять областей, но не девять «личностей»

Сейчас в Oblivion есть наука, история, экономика, политика, психология, философия, религия, программирование и литература. Изначально здесь очень легко было бы пойти по популярному пути: сделать несколько агентов, каждому дать роль, потом заставить их разговаривать друг с другом. Я выбрал другой вариант. Если историческая часть системы уже знает объект, экономика не должна создавать себе второго такого же объекта только потому, что встретила его в другом контексте. Память должна быть общей.

То же касается истории изменений. Если новое знание разрушает старое предположение, это должно быть видно всей системе, а не только одному модулю. Поэтому разные области у меня могут работать по‑разному, но конечная картина мира у них одна.

В какой‑то момент пришлось вернуться почти к началу

На ранних версиях Oblivion уже умел извлекать информацию, складывать её в граф, работать с предметными областями и поддерживать состояние. Проблема стала заметна позже. Представим, что в самом низу неправильно определили значение слова. Затем его связали не с тем действием. Из этого получился неправильный факт. А дальше система совершенно логично построила вывод.

Сам вывод может выглядеть безупречно. Только основание у него ложное. Когда таких слоёв становится много, отлаживать это сверху уже бессмысленно. Поэтому я на время перестал гнаться за новыми функциями и полез вниз: морфология, структура предложения, действия, участники, отношения, значение конкретного употребления слова, сущности. До причинности и более глубокого знания ещё нужно добраться, но теперь каждый следующий кусок должен опираться на предыдущий, а не заново интерпретировать текст как ему удобно.

Важно уточнить: эта нижняя цепочка — не серия запросов к LLM. Она работает на явных структурных ограничениях, словарных и семантических источниках, а результаты сохраняются вместе с состоянием решения и причиной, по которой оно было принято или остановлено. Вероятностный метод при необходимости может предложить кандидата, но сам кандидат ещё не становится знанием. Дальше он проходит те же ограничения и проверки, что и остальные варианты. Если сильно упростить текущую часть конвейера, она выглядит так:

исходный документ      ↓
структура текста      ↓
значение конкретного употребления      ↓
упоминания      ↓
документные сущности      ↓
кандидаты идентичности
если оснований не хватает:
AMBIGUOUS / UNRESOLVED / DEFERRED

На этом схема специально обрывается: надёжное объединение сущностей между документами и более высокие уровни проверки я ниже отдельно отмечаю как ещё не решённые задачи.

Что показал прогон на десяти миллионах элементов

Один из первых больших тестов новой цепочки вообще не проверял «интеллект». Вопрос был намного скучнее: можем ли мы провести большой объём данных через систему и ничего не потерять? Для прогона я взял 3000 книг. На входе получилось 10 073 369 элементов. На выходе система учла те же 10 073 369. Молча потерянных элементов — ноль. Неучтённых — тоже ноль.

На этом можно было бы остановиться, но мне не нравилась идея, что один и тот же процесс создаёт результат и сам же подтверждает его правильность. Поэтому после завершения я отдельно запустил повторную проверку уже сохранённых данных. Она заново открыла результат и прошла по тем же 3000 источникам. Число снова сошлось: 10 073 369 из 10 073 369.

Здесь важно не приписывать тесту лишнего. Он не доказал, что система поняла десять миллионов фактов. Он вообще этого не проверял. Он доказал только то, для чего был сделан: на этом участке данные не исчезли незаметно, а результат после завершения процесса можно заново открыть и проверить. Для дальнейшей работы мне именно это и было нужно.

Сейчас работа уже идёт не только с синтаксисом

После этого я пошёл дальше. Теперь система разбирается не только с тем, где находится предложение и какие слова связаны между собой. Появилась задача понять конкретное употребление и начать собирать сущности.

Возьмём простой текст: «Иван Петров возглавил лабораторию. Позже руководитель проекта покинул институт. Его место заняла Анна». Человек довольно быстро начинает связывать куски текста между собой. Но для программы здесь масса вопросов.

«Руководитель проекта» — это Иван Петров? К кому относится «его»? Если фамилия Иван Петров встретится ещё раз в другом документе, это тот же человек или просто тёзка?

Такие вещи у меня уже проходят через рабочий pipeline. В одном реальном прогоне предыдущий слой передал 166 semantic‑записей. Следующий сформировал 108 упоминаний и 108 документных сущностей. После сохранения данные удалось нормально открыть повторно. На другом документе было 98 входных записей, из которых получилось 65 упоминаний и 65 сущностей.

Это не 108 правильно распознанных сущностей. Я специально разделяю эти вещи. Такие цифры пока показывают, что сам конвейер живой: он получает реальные данные, создаёт объекты, сохраняет их и может восстановить состояние. Насколько правильно принято каждое отдельное решение — уже другой тест.

А можно ли потом вернуться к исходному месту

Да. Это ещё одна вещь, которую я не хотел терять по дороге. Один из сохранённых semantic‑record выглядит примерно так. Я оставил только поля, которые понятны без внутренней документации проекта.

{  "record_kind": "SEMANTIC_OCCURRENCE_SENSE",  "semantic_record_id": "semantic-record:sha256:0d341ec2...",  "source_document_id": "sem3b_rucoco_v1_0c2be293...",  "original_byte_start": 1801,  "original_byte_end": 1805,  "parent_record_id": "semantic-record:sha256:552c0dd7..."
}

То есть после нескольких стадий обработки у меня остаётся не просто новый объект с красивым ID. Я всё ещё могу понять, к какому документу он относится и из какого диапазона исходного текста вырос. В полной записи есть ещё хеши payload и другие служебные поля. В статью тащить их целиком смысла нет. Для меня здесь важнее сам принцип: если потом обнаружится ошибка, должно быть куда вернуться.

Сомнение тоже остаётся в данных

На этом уровне появилась ещё одна полезная неприятность. Иногда есть два варианта, и оба выглядят правдоподобно. Можно было бы всегда выбирать тот, у которого score чуть выше. Так проще жить дальше по pipeline. Я этого не делаю.

Если оснований недостаточно, неопределённость сохраняется вместе с кандидатами. Это может уменьшать количество автоматически «решённых» случаев, зато потом можно вернуться к такому месту после появления новых данных. Для меня это намного важнее.

Вот как это выглядит в реальном JSON

С этими состояниями я довольно быстро столкнулся на обычных текстах. Если смотреть только на итоговый счётчик, разницы между ними почти не видно, а внутри она существенная. Например, «потребовались» в одном из прогонов прошло дальше без приключений: смысл выбран, следующий уровень может использовать запись.

{  "exact_span": "потребовались",  "lemma": "потребоваться",  "disposition": "RESOLVED",  "reasoning_allowed": true
}

А со словом «плыла» получилось иначе. После структурной проверки осталось несколько совместимых вариантов. Я не стал заставлять систему выбирать один только потому, что так удобнее продолжить pipeline.

{  "exact_span": "плыла",  "lemma": "плыть",  "disposition": "AMBIGUOUS",  "reasoning_allowed": false
}

Есть ещё более показательный случай — «отказаться». Кандидаты на смысл у системы были, но ни один не подошёл к структуре конкретного предложения. Поэтому готового смысла здесь нет и дальше такая запись не идёт.

{  "exact_span": "отказаться",  "lemma": "отказаться",  "disposition": "UNRESOLVED",  "blocking_reasons": [    "sem3_no_structurally_compatible_source_sense"  ],  "reasoning_allowed": false
}

И совсем другой тип остановки — «Источник». Здесь проблема возникла раньше: система не смогла нормально закрепить запись за областью предложения. Я в таком случае не хочу, чтобы следующий уровень делал вид, будто всё хорошо.

{  "exact_span": "Источник",  "lemma": "источник",  "disposition": "DEFERRED",  "reasoning_allowed": false
}

Мне здесь как раз нравится не число успешных ответов, а то, что причины остановки остаются разными. AMBIGUOUS — это не то же самое, что UNRESOLVED, а DEFERRED — ещё один случай. Если всё свести к одному false, потом уже не понять, что именно произошло.

А теперь плохие цифры

У проекта есть результаты, которыми приятно хвастаться. Но есть и те, которые сразу показывают объём оставшейся работы. Один из независимых morphology/development‑прогонов дал 92,889% покрытия словарными кандидатами. Если написать только эту цифру, всё будет выглядеть отлично.

Но дальше становится интереснее. Правильная лемма вообще находилась среди кандидатов в 77,113% случаев. А когда система должна была самостоятельно выбрать итоговый вариант, правильный результат получился в 72,072%. Вот эти 72% мне на самом деле намного полезнее первых 92%.

Когда я полез смотреть ошибки, выяснилось, что 934 слова вообще остались без подходящего словарного кандидата. В 1986 случаях правильной леммы не было среди предложенных вариантов. Ещё в 662 случаях правильный вариант был, но система выбрала другой.

Последняя категория особенно показательна. Там словарь свою работу сделал. Нужный ответ уже был перед глазами. Ошибка появилась позже — при выборе по контексту. Особенно много неприятностей дают имена собственные, сокращения, иностранные слова, URL и редкие формы. Так что одной «точности морфологии» здесь на самом деле нет. Есть несколько разных проблем, которые приходится чинить отдельно.

«Поднять» оказалось хорошим примером

Русский язык быстро отбивает желание решать всё одним словарём. Человек поднял коробку. Банк поднял ставку. Исследование подняло вопрос. Ветер поднял волну.

Лемма одна — «поднять». Но если мы строим знание о мире, эти четыре употребления нельзя считать одним и тем же действием. В одном случае объект физически переместился. В другом изменилось числовое значение. В третьем вообще речь идёт о введении темы в обсуждение.

Поэтому сейчас отдельная задача — понять смысл именно данного употребления. И здесь всё пока далеко от идеала. Иногда после всех структурных ограничений остаются несколько допустимых значений. В такой ситуации система не выбирает одно случайно. Случай остаётся неоднозначным.

Бывает и обратное: варианты есть, но ни один нельзя подтвердить достаточно уверенно. Тогда я тоже не разрешаю превращать это в готовое знание. Да, из‑за этого часть информации остаётся нерешённой. Но неверный смысл, положенный в общий граф, для меня опаснее.

Сущности оказались ещё неприятнее

С именами всё становится сложнее. Два Александра Иванова вполне могут быть разными людьми. А один Сергей Иванов в нескольких предложениях может оказаться «Ивановым», «директором», «предпринимателем» и просто «он». Машине нужно как‑то понять, где разные слова говорят об одном объекте, а где одинаковые слова — о разных.

Поэтому сейчас я специально держу этот уровень консервативным. Сущности внутри документов уже формируются. Неоднозначные варианты тоже сохраняются. Но автоматическое объединение объектов между разными документами я пока не считаю решённой задачей. Если приходится выбирать между двумя ошибками, я предпочту какое‑то время хранить одного человека как две сущности, чем склеить двух разных людей в одного. Вторую ошибку потом намного тяжелее распутывать.

Когда связь кажется очевидной, а merge всё равно не происходит

На этом уровне у меня появился хороший реальный пример. В одном документе есть упоминание «30-летняя Сандра Альбрехт», а позже — «она». Для человека связь выглядит почти очевидной. Система тоже не проходит мимо: она строит coreference‑кандидат и видит, что совпадают женский род и единственное число, а полное имя находится раньше в том же документе. Я сократил запись до полей, которые нужны для понимания. Для читаемости два внутренних mention_id здесь заменены на соответствующие им текстовые фрагменты; статус решения, причина и evidence оставлены из машинного артефакта.

{  "antecedent": "30-летняя Сандра Альбрехт",  "referring_mention": "она",  "supporting_evidence": [    "compatible_gender=FEM",    "compatible_number=SG",    "document_local_preceding_mention",    "reference_requires_antecedent_candidate"  ],  "status": "AMBIGUOUS",  "reason": "candidate_evidence_insufficient_for_identity_merge"
}

То есть кандидат есть, основания для него тоже есть, но автоматического объединения всё равно не происходит.
Само упоминание «30-летняя Сандра Альбрехт» при этом никуда не пропадает. В данных оно остаётся отдельной сущностью со статусом UNRESOLVED_SINGLETON, а её состояние помечено как REVERSIBLE.

Вот здесь как раз очень легко самому вмешаться и сказать: ну очевидно же, что «она» — это Сандра. Я этот фрагмент тоже читаю именно так. Но если система сама ещё не набрала достаточно оснований для объединения, значит объединения быть не должно.

При этом она не держит открытыми вообще все варианты подряд. Если кандидат уже противоречит базовым признакам, например не сходится род или число, он отбрасывается через REJECTED_BY_HARD_NEGATIVE и дальше не участвует.

{  "disposition": "REJECTED_BY_HARD_NEGATIVE",  "negative_evidence": [    "incompatible_gender=MASC_vs_FEM",    "incompatible_number=PL_vs_SG"  ]
}

На большом прогоне это стало видно уже не на одном примере. Было 64 документа, 20 376 входных семантических записей и 13 385 упоминаний. Кандидатов на междокументную идентичность набралось 39 938.

{  "input_document_count": 64,  "input_sem3_record_count": 20376,  "mention_count": 13385,  "document_entity_count": 13385,  "cross_document_candidate_count": 39938,  "resolved_cross_document_identity_count": 0,  "destructive_merge_count": 0,  "silent_drop_count": 0,  "cold_reopen_verification": "PASS"
}

А подтверждённых междокументных объединений — ноль. Для меня это не «успех распознавания сущностей», и я так его не считаю. Это просто честный текущий результат: кандидаты уже появляются, а разрешать им менять идентичность объектов система пока не умеет достаточно надёжно.

Что начнёт болеть при масштабе

Чем дальше я двигаюсь с сущностями и источниками, тем меньше меня пугает сама сложность отдельного правила и тем больше — количество возможных сравнений. Наивный вариант здесь очевиден: взять все документы, все сущности или все утверждения и начать сравнивать каждый объект с каждым. На маленьком наборе это ещё можно пережить. На большом — уже нет.

В одном из текущих прогонов по 64 документам система построила 39 938 кандидатов на междокументную идентичность. При этом подтверждённых междокументных объединений не было вообще, как и разрушительных merge. Само это число не доказывает какой‑то особый класс вычислительной сложности, но хорошо показывает практическую проблему: глобальная проверка «каждый с каждым» очень быстро становится плохой идеей.

Поэтому масштабирование здесь для меня — это не попытка научиться быстрее перебирать все пары. Скорее наоборот: нужно как можно раньше понять, какие пары вообще имеют смысл проверять. Для этого понадобятся индексы, локальность, типизированные ключи, временные окна, разбиение по сущностям и предикатам, а также инкрементальный пересчёт только затронутых участков. Если новый источник касается одного узкого фрагмента картины мира, нет никакой причины заново пересматривать весь граф.

Есть и более неприятная проблема — ошибочное объединение сущностей. Пропустить merge плохо, но ошибочно склеить два разных объекта обычно хуже: после этого неправильная идентичность начинает заражать факты, события и последующие выводы. Состояние идентичности уже хранится как обратимое: в артефактах есть REVERSIBLE‑состояния и отдельные identity revisions. Но полного rollback уже принятого merge с автоматическим пересчётом всех зависимых результатов я пока не считаю готовой возможностью.

Это как раз следующий кусок работы. Если гипотеза идентичности была отозвана, система должна уметь найти более поздние утверждения, которые от неё зависели, и пересчитать только затронутую часть. Иначе rollback будет косметическим: саму запись мы отменили, а последствия старого решения уже останутся в памяти.

Похожая проблема возникает и с самоизменением. Если когда‑нибудь система начнёт предлагать сотни небольших изменений, ручное approve/reject по одному быстро превратит человека в самое медленное место конвейера. Я не думаю, что решение здесь — просто убрать человека. Скорее нужен разный режим для разного риска: мелкие изменения можно гонять через shadow и автоматические тесты, спорные собирать в понятные батчи, а действительно опасные оставлять на ручное решение.

И ещё одна вещь, за которой я стараюсь следить уже сейчас: верхний уровень не должен молча чинить ошибки нижнего. Если слой сущностей начинает компенсировать плохой разбор предложения, а следующий слой — компенсировать ошибки сущностей, система быстро превращается в набор исключений, где уже невозможно понять владельца ошибки. Поэтому каждый уровень должен либо принять вход по своему контракту, либо остановиться и вернуть проблему туда, где она возникла.

Для меня все эти риски сводятся к одной мысли: при большом масштабе мало иметь хороший граф и хорошие правила. Нужны ещё индексы, локальность, provenance, обратимое состояние, граф зависимостей и инкрементальный пересчёт. Иначе сама память со временем станет сложнее системы, которая должна ею пользоваться.

Иногда проблема вообще не в ИИ, а в памяти

Есть и совсем приземлённые вещи. Одна из независимых холодных проверок большого прогона на 3000 источниках съедала около 20 ГБ оперативной памяти. Сам writer в какой‑то момент доходил примерно до 10 ГБ. Проверка прошла, но мне очевидно, что это слишком дорого. Я зафиксировал это как технический долг. В данном случае у меня приоритет простой: сначала добиться корректного воспроизводимого результата, а потом уже уменьшать стоимость проверки. Иначе очень легко ускорить код так, что потом никто не сможет доказать, что оптимизированная версия делает ровно то же самое.

Тесты иногда действительно ломают планы

Были случаи, когда я был уверен, что этап практически готов, а тест говорил обратное. Один пример вообще оказался довольно смешным. Проверка проходила при ручном запуске, но падала, когда её запускал зарегистрированный тестовый контур.

Разобрался — оказалось, что они работают из разных каталогов и видят разные данные. Сам алгоритм здесь был ни при чём. Проблема была в том, что тест фактически проверял не ту среду.

Были и большие прогоны, которые просто не дошли до финального подтверждения. Я не стал использовать их как успешные результаты. Они так и остались неудачными прогонами. Новый статус появился только после повторного чистого запуска и отдельной проверки результата. Иначе слово «проверяемый» в названии подхода быстро потеряло бы смысл.

А где вообще начинается настоящее понимание

Есть пример, который мне нравится именно своей простотой. Система знает, что кот съел мышь. Отдельно она знает, что мышь была отравлена. Ни один источник не пишет, что с котом что‑то случилось.

Должна ли система сама поставить его состояние под вопрос? Если да, то на каком основании? Здесь уже недостаточно просто хранить связанные факты. Нужна модель причин, состояний и условий.

И вот это для меня намного интереснее самого графа знаний. Граф — просто структура хранения. Настоящая проблема начинается тогда, когда из нескольких известных вещей нужно получить новое следствие и при этом не придумать лишнего. Эта часть проекта ещё впереди.

Противоречие не обязательно нужно немедленно устранять

Ещё один пример. Одна работа утверждает, что препарат эффективен. Другая сообщает, что статистически значимого эффекта не найдено.

Что должна сделать система? Выбрать более новую статью? Посчитать число источников? Усреднить мнение?

Я бы не делал ничего из этого автоматически. Сначала нужно понять, сравнимы ли вообще исследования. Может отличаться выборка, дозировка, методика или критерий результата. Один текст может оказаться пересказом другого. Пока мы этого не знаем, наличие двух несовместимых утверждений само по себе является полезной информацией. Поэтому противоречие я не считаю дефектом базы знаний. Дефект — это когда система не замечает, что оно есть.

Что делать, когда Oblivion сам регулярно ошибается в одном месте

Вот здесь начинается та часть проекта, ради которой мне вообще интересно всё это строить. Сейчас, если алгоритм плохо работает на каком‑то классе случаев, я нахожу проблему, исправляю код, добавляю тесты и запускаю всё заново. Это обычная разработка. Но в дальнейшем я хочу, чтобы часть этого цикла могла запускаться самой системой. Не в смысле «ИИ увидел ошибку и тут же переписал себя».

Сначала нужно хотя бы научиться замечать устойчивый класс проблем. Например, система несколько раз встречает похожие конструкции и каждый раз оставляет их unresolved. Это уже сигнал. Дальше можно собрать такие случаи вместе, попробовать несколько объяснений, поискать контрпримеры и проверить новый вариант отдельно.

Если он действительно улучшает ситуацию — хорошо. Если ломает старые случаи — откатить. Для меня это намного ближе к развитию понимания, чем обычная генерация патча по текстовому описанию ошибки.

А если существующих областей знаний окажется мало

Похожий вопрос возникает выше. Сейчас девять предметных областей определены заранее. Но очевидно, что весь мир так вручную не разложишь. Поэтому есть отдельное направление, где система должна в будущем уметь заметить: некоторый устойчивый класс информации плохо укладывается в существующую структуру.

Важно, что одного незнакомого слова для этого недостаточно. Новая область должна появляться не потому, что система встретила новый термин, а потому, что накопилась структура, которую старые модели описывают плохо. Что дальше — отдельный вопрос. Это может оказаться просто новым поддоменом. А может потребоваться действительно новая область знаний. Эта часть ещё не готова. И здесь я пока сам не знаю хорошего универсального критерия того, когда заканчивается «мы просто мало знаем» и начинается «нам не хватает самих понятий».

Самоизменение я тоже не хочу превращать в магию

Следующий очевидный вопрос: если система увидела собственный недостаток, почему бы не дать ей переписать код? Потому что написать новый код — самая простая часть этой проблемы. Гораздо сложнее доказать, что он лучше.

Поэтому активная версия Oblivion не должна изменяться непосредственно. Новый вариант сначала создаётся отдельно. Его можно собрать, прогнать через тесты, сравнить со старой версией, посмотреть на регрессии. И только после этого вообще решать, нужен ли такой вариант. Пока последнее слово при переключении остаётся за человеком. Мне кажется, это нормальное ограничение на нынешнем этапе.

Научное знание упирается ещё и в числа

Текстом всё не заканчивается. Если система должна работать с наукой, ей придётся понимать не только слова. Есть единицы измерения, точные и приблизительные значения, формулы, погрешности, условия эксперимента. Утверждение «температура выросла на 10» вообще ничего не значит, пока мы не знаем единицу, исходную точку и условия измерения.

Поэтому количественный слой у меня вынесен в отдельное направление. Дальше цель довольно понятная: теория даёт предсказание, потом появляется наблюдение. Если они расходятся, возникает вопрос. И вот способность заметить такое расхождение для меня интереснее, чем способность красиво пересказать саму теорию. Эта часть пока относится к будущим этапам.

Если убрать всю внутреннюю нумерацию этапов, состояние примерно такое. Есть работающий production‑фундамент. Финальная проверка — 355 из 355 тестов. В едином runtime работают девять предметных областей. Один из production‑запусков учитывал 3323 документа.

Отдельный большой прогон прошёл по 3000 источникам и провёл через входной контур 10 073 369 элементов без тихих потерь. После завершения сохранённые данные были повторно открыты и проверены другим проходом. Выше уже работают механизмы, которые переходят от структуры текста к значениям употреблений, упоминаниям и сущностям. Но я ещё не считаю решёнными более сложные вещи: надёжное объединение сущностей между документами, независимость источников, причинность, условия применимости, противоречия и пересмотр старого знания. То есть фундамент уже не теория. Но до системы, которую я хочу получить в итоге, ещё довольно далеко.

Что мне самому сейчас непонятно

Есть несколько вопросов, на которые код пока ответа не дал. Например, где именно заканчивается хороший языковой анализ и начинается модель мира? Вернёмся к коту и отравленной мыши. Чтобы поставить состояние кота под сомнение, системе уже мало просто понимать два предложения. Ей нужно знать что‑то о причинной связи между ядом, употреблением пищи и возможными последствиями.

Другой вопрос ещё сложнее. Как понять, что системе не хватает не факта, а самого способа описания происходящего? Если новое явление плохо укладывается в существующую картину мира, когда нужно продолжить собирать данные, а когда — признать, что существующая система понятий недостаточна? Есть и совсем практическая проблема. Сейчас критические изменения подтверждаю я.

А что будет, если когда‑нибудь система начнёт формировать и проверять сотни гипотез быстрее, чем человек успеет их просмотреть? В какой‑то момент человек сам может стать самым медленным звеном. У меня пока нет готовых ответов на эти вопросы. И, пожалуй, именно поэтому мне всё ещё интересно заниматься Oblivion.

Что я хочу получить

В конечном итоге мне нужна система, которой можно задать не только вопрос «какой ответ?», но и «откуда ты это знаешь?». Чтобы она могла показать источник. Показать, как поняла его. Сказать, где есть другой вариант. Признать противоречие. Не спрятать незнание за уверенной формулировкой.

А если появляются новые данные — пересмотреть старые выводы. И в какой‑то момент самой заметить, что определённый класс вещей она постоянно понимает плохо. Мне совершенно нормально, если такая система иногда ответит: «Я не знаю». Гораздо хуже, если она не умеет отличать знание от догадки. Поэтому главный вопрос Oblivion Mind для меня сейчас не в том, насколько хорошо система разговаривает.

Мне интереснее другое: можно ли построить когнитивно‑символьную систему, которая накапливает знания, умеет их проверять, пересматривать и постепенно развивать, не теряя при этом путь от исходного источника до конечного вывода? Пока я пытаюсь ответить именно на это.

Если тема зайдёт, буду писать дальше. Там ещё много чего можно показать отдельно: как система путается в сущностях, где остаётся неоднозначность, как я подхожу к причинности, противоречиям и пересмотру старого знания. Если что‑то из этого интересно больше остального — напишите в комментариях.