loci — типизированная долговременная память для AI-агентов
📂 Исходный код на GitHubТипизированная долговременная память для AI-агентов. Одно ядро, два адаптера: MCP-сервер и плагин Hermes. Хранение в SQLite, ядро без внешних зависимостей, лицензия MIT.
loci — типизированная долговременная память для AI-агентов. Разбор проекта на Python: как устроены типы записей, извлечение фактов из переписки, ежедневная уборка базы и два способа подключить библиотеку.
Агент, который забывает вас после каждой сессии, — это поисковая строка с хорошими манерами. Он отвечает на вопрос, но не помнит, кто вы и над чем вы работаете. Библиотека loci закрывает этот пробел: она хранит про вас устойчивые факты, разбирает их по типам, оценивает важность и сама выбрасывает то, что устарело. Репозиторий: github.com/cmoraes10/loci, 15 звёзд, Python, лицензия MIT.
Название пришло из метода мест — древней техники запоминания, где каждое воспоминание получает своё место и свою структуру. В этом и заключается идея проекта: не свалка фактов, а устроенное хранилище, где у каждой записи есть тип, важность и срок жизни.
Проект портирован из системы памяти, которая работает в продакшене в Lima. Исходная версия была заточена под конкретного хоста, поэтому её переписали так, чтобы ядро не зависело от окружения.
Что именно хранится
Память в loci — не анонимная строка, а запись с набором полей. Восемь категорий:
| Категория | Что попадает |
|---|---|
| routine | повторяющиеся привычки и действия |
| study | то, что вы изучаете |
| preferences | предпочтения в работе и общении |
| finance | финансовые обстоятельства |
| goals | цели и задачи |
| relationships | люди, с которыми вы работаете |
| constraints | ограничения, которые нельзя нарушать |
| ephemeral | временные записи |
Плюс четыре уровня важности и жизненный цикл статусов. Причина простая: предпочтение и срок сдачи — разные вещи, и стареют они по-разному. Одно можно спокойно хранить годами, другое теряет смысл через неделю.
Как факты попадают в память
Извлечение работает по двум путям. Первый — модель: она читает переписку и понимает смысл. Второй — регулярные выражения, написанные под конкретные формулировки. Результаты объединяются, и приоритет отдаётся тому, что нашла модель. Если провайдер модели недоступен, регулярные выражения всё равно отработают: агент не останется без памяти из-за сбоя у API.
Дальше включается фильтр записи. Он не даёт базе превратиться в дневник настроения — именно для этого он и написан. Фраза «сегодня устал» верна несколько часов и неверна несколько месяцев — в базу она не попадает.
Сколько фактов уходит в модель
В контекст уходит не вся база, а двенадцать отобранных записей. Сначала сортировка идёт по важности, потом по близости к сроку и по времени последнего упоминания. Без этого ограничения контекст разрастался бы без предела.
Ежедневная уборка
Каждый день запускается слияние дублей и угасание старых записей. Происходит следующее:
- точные дубликаты сливаются в один;
- догадки, которые никто не подтвердил, устаревают сами;
- временные записи живут 24 часа;
- достигнутые цели удаляются через 90 дней.
Смысл простой: список фактов должен оставаться честным. Иначе через полгода агент будет уверенно ссылаться на то, чего уже не существует.
Два адаптера: MCP-сервер и плагин Hermes
Ядро одно, способ доставки — разный.
| MCP-сервер | Плагин Hermes | |
|---|---|---|
| Работает в | любом MCP-клиенте | только в Hermes |
| Инструменты | remember, recall, forget |
те же три |
| Автоматическое извлечение | нет | есть |
| Подстановка в контекст | по запросу | перед каждым вызовом |
Разница в автоматике объясняется устройством протокола. MCP — это запрос и ответ. Когда ход диалога заканчивается, серверу никто не звонит, и у него просто нет момента, в который он прочитал бы переписку сам. Поэтому через MCP агент должен сам, осознанно вызвать remember. Для автоматического извлечения нужен крючок внутри хоста, и у Hermes он есть — post_llm_call. Ядро под этим одно и то же, просто у адаптера для Hermes есть точка, где он может встать.
Установка
pip install mowave-loci
pip install mowave-loci[mcp]
Настройка MCP-клиента после установки варианта с [mcp]:
{
"mcpServers": {
"loci": {
"command": "python",
"args": ["-m", "loci.adapters.mcp_server.server"]
}
}
}
Для Hermes:
hermes plugins install <you>/loci
hermes plugins enable loci
База лежит в файле SQLite по пути ~/.loci/memory.db, путь можно переопределить переменной LOCI_DB. Отдельный сервер запускать не нужно: слой памяти, который требует поднять сервер, неудобно ставить.
Использование напрямую
Библиотекой можно пользоваться и без адаптеров — напрямую из Python:
from loci import Store, extract, should_persist, context_block
store = Store()
for memory in extract("eu prefiro respostas curtas", assistant_text=reply):
if should_persist(memory):
store.upsert(memory)
system_prompt += "\n\n" + context_block(store.active())
Четыре функции делают всю работу: extract разбирает переписку, should_persist отсеивает пустяки, upsert записывает, context_block собирает блок для подстановки в системный промпт.
Границы ответственности
Репозиторий отвечает за форму записи памяти и за её жизненный цикл. За остальное отвечают другие:
| Что | Кто отвечает |
|---|---|
| Вызовы моделей, ключи API, SDK провайдеров | ваше приложение (внедряете ModelExtractor) |
| Цикл агента, вызов инструментов, сессии | хост (Hermes, OpenClaw, Claude Code) |
| Запуск ежедневных задач по расписанию | cron, s6 или systemd хоста |
| Передача данных и авторизация | адаптер |
Ядро не импортирует ничего, кроме стандартной библиотеки Python. Если изменение нарушит это правило, ему место в адаптере, а не здесь.
Тесты
pytest -q
92 теста против настоящей базы SQLite во временном файле. Свои же компоненты проекта заглушками не подменяются: тесты слоя памяти на поддельном хранилище ничего не говорят о том хранилище, которым люди пользуются в реальности.
Итог
loci решает узкую задачу: превращает память агента из свалки в структуру. Типы записей различают то, что стареет быстро, и то, что стареет медленно. Два пути извлечения страхуют друг друга. Ежедневная уборка не даёт базе разрастись. А ядро без зависимостей и без обязательного сервера позволяет встроить его в любое приложение, где уже есть свой цикл агента.
Слабое место тоже видно сразу: через MCP извлечение остаётся ручным. Если ваш хост не даёт крючок после вызова модели, агенту придётся самому вызывать remember. Тогда качество памяти будет зависеть от того, насколько чётко промпт велит агенту это делать.
Источник: https://github.com/cmoraes10/loci