Пятислойная иммутабельная память для ИИ-агента: почему одной векторной базы никогда не хватит
Попытка хранить всю долговременную память ИИ-агента в одном векторном индексе проваливается, потому что точный поиск по словам, семантическая близость, многошаговый обход связей и история смены решений требуют физически разных структур данных. Инкрементальный индекс SQLite FTS5 с ранжированием BM25 поверх 66 995 сессий и 538 956 сообщений (1,35 ГБ) избавил от падений среды разработки и ускорил старт сессии с 15 секунд до десятых долей секунды. Для защиты памяти от деградации внедрены детерминированная санитизация ключей через UUID5, битемпоральная запись без удаления старых фактов и ночной цикл консолидации с затуханием по распределению Вейбулла.

- Объём эпизодического индекса: 66 995 сессий и 538 956 сообщений в базе SQLite FTS5 размером 1 353 МБ
- База второго мозга и эмбеддингов: 10 019 структурированных карточек знаний и `brain.db` объёмом 2,37 ГБ
- Скорость старта после отказа от тяжёлых хуков: падение латентности инициализации с 5–15 с до < 0,2 с
- Пороги ночной консолидации: склейка дублей при косинусном сходстве ≥ 0,70 и детектор противоречий с порогом 0,40 без вызова LLM
Точкой отсчёта для моей архитектуры памяти стал глухой краш редактора кода. При попытке открыть историю диалогов с ИИ-агентом процесс Extension Host превысил лимит памяти и рухнул вместе с терминалом. За полгода работы накопилось 2,45 ГБ сырых JSONL-логов сессий, и расширение на старте пыталось прочитать их заголовки с диска. Вдобавок заводская настройка `cleanupPeriodDays=30` молча удаляла сессии старше месяца — пока я не заменил её на `99999`, часть зимнего архива исчезла.
Ревизия показала, что две из четырёх моих баз памяти мертвы, так как требовали ручного запуска демонов. Главное же открытие состояло в том, что «память агента» — это пять разных классов вопросов, и под каждый нужен свой движок.
Почему SQLite FTS5 выиграл у
Qdrant и grep на полумиллионе сообщений?
Для эпизодической памяти («где мы обсуждали настройку вебхуков три месяца назад») `grep` по гигабайтам текста был слишком медленным, а подъём локального `Qdrant` с `fastembed` на старте сессии тормозил запуск на 5–15 секунд и сжирал сотни мегабайт RAM.
Победил встроенный в Python движок SQLite FTS5 с ранжированием BM25 и режимом `WAL`. Индексатор `search_chats.py` сверяет `file_mtime` с таблицей `sessions`: если расхождение меньше секунды, файл пропускается. Сырые логи старше 14 дней и дампы свыше 20 МБ уезжают в холодный архив — рабочий каталог похудел с 2,45 ГБ до 527 МБ, краши прекратились, а индекс вырос до 66 995 сессий и 538 956 сообщений (290 544 от человека и 248 412 от ассистента) при весе 1 353 МБ. Для критичных справочников (вроде 20-главной инструкции, собранной из 2 240 сообщений и 177 расшифрованных через Deepgram голосовых заметок) действует 4-уровневое резервирование: конспект в рабочей памяти, указатель в `MEMORY.md` (строго до 200 строк и ~22 КБ), правило маршрутизации и векторный слепок.
Зачем нужен детерминированный UUID5 в векторной базе и как работает
битемпоральность?
Когда точных слов в запросе нет (человек спрашивает «чем мыть фрукты без химии», а в базе заметка про щелочной режим ионизатора `pH 11.5`), вступает семантический слой на эмбеддингах (размерность 384 локально и 1536 для книг). В жизни идентификаторы документов выглядят как строки `knowledge:42` или `session/2026-04-10/msg-17` с кириллицей, но векторный движок Qdrant требует в качестве `point_id` либо целое число, либо строгий UUID. Случайный `uuid4()` плодит дубликаты при переиндексации, поэтому мы ввели детерминированный `uuid5` поверх пространства имён DNS:
```python import uuid
def to_deterministic_point_id(raw_doc_id: str) -> str: # Превращает любую строку с кириллицей и спецсимволами в стабильный ASCII UUID5 return str(uuid.uuid5(uuid.NAMESPACE_DNS, raw_doc_id))
point_id = to_deterministic_point_id(doc_id) payload = {**metadata, "doc_id": doc_id, "content": text_chunk} ```
Одна и та же строка всегда даёт идентичный UUID, превращая повторную запись в идемпотентный `upsert`, а исходный ключ сохраняется в `payload`.
Чтобы агент помнил историю смены решений («почему весной мы выбрали другой движок?»), мы позаимствовали идею из Datomic и запретили `UPDATE` с затиранием прошлого. Каждая связь имеет поля `valid_from`, `valid_to` и `ingested_at`, а в базе второго мозга также счётчики востребованности `use_count` и `last_used`. Когда решение устаревает, у старого ребра проставляется `valid_to`, и рядом вставляется новая запись со ссылкой `supersedes`.
Как алгоритмический сон с кривой
Вейбулла очищает память от противоречий?
Чтобы база не превращалась в свалку, фоновый пайплайн консолидации (`dream` и модули `sleeptime`) периодически проводит уборку в три этапа:
1. Кластеризация дублей (SHMR): матрица косинусной близости на эмбеддингах размерности 1024 (`Qwen3-Embedding-0.6B` в LanceDB) схлопывает записи со сходством `>= 0.70`. 2. Селективное затухание по распределению Вейбулла: мимолётные наблюдения (`observation`) затухают за 336 часов (~2 недели), рабочие факты — за 2 160 часов, а личные предпочтения (`preference`), процедуры и паттерны ошибок (`error_pattern`) защищены списком `EXEMPT_TYPES`. 3. Поиск противоречий без LLM: детерминированный сканер ищет конфликты за 7 дней по взвешенным сигналам (`negation: 0.35`, `antonym: 0.25`, `numeric: 0.25`, `temporal: 0.15`) при пороге `0.40`.
Эта пятислойная схема памяти (SQLite FTS5, LanceDB и темпоральный граф) встроена в ядро [Nomad AI](https://nomadnet.ai) и облачной платформы [agent.nomadnet.ai](https://agent.nomadnet.ai). Курс по инженерии памяти доступен в [Hamidun Academy](https://academy.hamidun.com) (72-часовой триал), а скрипты индексации лежат в библиотеке [Vibe Club](https://hamidun.com/club).
- 28 окт. 2026 г.AdaPRA поднял Qwen 80B на 24,5 пункта в data science-лидербордах
- 28 окт. 2026 г.AOS-Bench показал: агенты с разницей 0,6 пункта доставляют 54% и 68% задач
- 28 окт. 2026 г.CuraLoc ищет баги в репозиториях одним планом и тратит на 90% меньше токенов
- 28 окт. 2026 г.Wired за сутки протестировал 6 ИИ-агентов: Dots лидирует, Gemini Spark провалил обед
Вопросы и ответы по материалу
Почему SQLite FTS5 выиграл у Qdrant и grep на полумиллионе сообщений?
Для эпизодической памяти («где мы обсуждали настройку вебхуков три месяца назад») `grep` по гигабайтам текста был слишком медленным, а подъём локального `Qdrant` с `fastembed` на старте сессии тормозил запуск на 5–15 секунд и сжирал сотни мегабайт RAM. Победил встроенный в Python движок SQLite FTS5 с ранжированием BM25 и режимом `WAL`. Индексатор `search_chats.py` сверяет `file_mtime` с таблицей `sessions`: если расхождение меньше секунды, файл пропускается. Сырые логи старше 14 дней и дампы свыше 20 МБ уезжают в холодный архив — рабочий каталог похудел с 2,45 ГБ до 527 МБ,
Зачем нужен детерминированный UUID5 в векторной базе и как работает битемпоральность?
Когда точных слов в запросе нет (человек спрашивает «чем мыть фрукты без химии», а в базе заметка про щелочной режим ионизатора `pH 11.5`), вступает семантический слой на эмбеддингах (размерность 384 локально и 1536 для книг). В жизни идентификаторы документов выглядят как строки `knowledge:42` или `session/2026-04-10/msg-17` с кириллицей, но векторный движок Qdrant требует в качестве `point_id` либо целое число, либо строгий UUID. Случайный `uuid4()` плодит дубликаты при переиндексации, поэтому мы ввели детерминированный `uuid5` поверх пространства имён DNS: ```python impo
Как алгоритмический сон с кривой Вейбулла очищает память от противоречий?
Чтобы база не превращалась в свалку, фоновый пайплайн консолидации (`dream` и модули `sleeptime`) периодически проводит уборку в три этапа: 1. Кластеризация дублей (SHMR): матрица косинусной близости на эмбеддингах размерности 1024 (`Qwen3-Embedding-0.6B` в LanceDB) схлопывает записи со сходством `>= 0.70`. 2. Селективное затухание по распределению Вейбулла: мимолётные наблюдения (`observation`) затухают за 336 часов (~2 недели), рабочие факты — за 2 160 часов, а личные предпочтения (`preference`), процедуры и паттерны ошибок (`error_pattern`) защищены списком `EXEMPT_TYPES
Соберите рабочего ИИ-агента или сервис своими руками без ручного кода
В Академии Жемала Хамидуна (academy.hamidun.com) открыт бесплатный 72-часовой тест-драйв: интерактивные скетч-уроки по Claude Code и Cursor, живой Tech Radar и готовые шаблоны агентов.
Главное из мира ИИ — раз в неделю
7 ключевых событий недели, отобранных вручную. Без шума, репостов и пресс-релизов.
Готово! Проверьте почту — мы отправили подтверждение.