Память ИИ между сессиями: как устроен Claude-Mem
Память ии на бумаге звучит красиво, а на моём сервере её просто не существовало: каждую новую сессию агент начинал с чистого листа и не помнил ничего. Ни того, что мы вчера чинили nginx-stream на bridge-сервере, ни того, почему в llm-router появился новый провайдер, ни того, какие тесты падали до начала работы над фичей. Он заново лазил по файлам, заново читал KNOWLEDGE.md, заново открывал для себя очевидные вещи - и всё это сжигая тысячи токенов на восстановление контекста, который уже был добыт неделю назад.
Это фундаментальная проблема всех LLM-агентов: у них нет долговременной памяти. Контекстное окно живёт ровно одну сессию, а потом обнуляется. Именно эту дыру и закрывает проект, о котором пойдёт речь — Claude-Mem, специализированный observer-инструмент, который наблюдает за рабочими сессиями агента и превращает их в структурированную, доступную для поиска память для будущих сессий. В этой статье я разберу, как он устроен, какие проблемы решает и какие цифры мы получили на реальном рабочем сервере.
Что такое observer-сессия и зачем она нужна
Ключевая идея Claude-Mem проста, но неочевидна: разделить того, кто делает работу, и того, кто её запоминает. Есть основная (primary) сессия — тот самый агент, который реально выполняет команды: чинит VPN, пишет спеки, гоняет тесты, деплоит контейнеры. И есть отдельный наблюдатель — observer, — который не имеет доступа к инструментам вообще. Его единственная задача — смотреть на поток событий из основной сессии и записывать, что было изучено, построено, починено, задеплоено или сконфигурировано.
Формально это выглядит так. Observer получает сообщения в специальной обёртке:
<observed_from_primary_session>
<what_happened>Bash</what_happened>
<occurred_at>2026-06-01T14:44:57.365Z</occurred_at>
<working_directory>/home/deploy/projects/llm-router</working_directory>
<parameters>{"command":"git log --oneline -5 && ls tests/unit/pool/"}</parameters>
<outcome>{"stdout":"9384cf6 docs(plan): C.4 patch..."}</outcome>
</observed_from_primary_session>И на основе этого потока он генерирует наблюдение (observation) — компактный структурированный объект:
<observation>
<type>discovery</type>
<title>Test Baseline Before Phase B: 9 Failed Files, 26 Failed Tests</title>
<subtitle>Pre-Phase B test run shows existing failures not caused by pool-resilience work.</subtitle>
<facts>
<fact>Test baseline: 9 failed files, 39 passed, 3 skipped (51 total)</fact>
<fact>Test baseline: 26 failed tests, 450 passed, 24 skipped (500 total)</fact>
<fact>Suite duration 7.57s; failures pre-existing on branch</fact>
</facts>
</observation>Обратите внимание на дисциплину формулировок. Инструкция для observer'а звучит категорично: «Record what was LEARNED/BUILT/FIXED/DEPLOYED/CONFIGURED, not what you (the observer) are doing». Это критично. Соблазн записать «агент запустил команду git log» огромен, но такая запись бесполезна для будущего. Полезна запись факта: «на ветке 9router-fork до начала работы уже падало 26 тестов — это не наша регрессия». Через неделю именно этот факт спасёт от часа паники «что я сломал?».
Проблема, которую пришлось решать
Первая версия наблюдателя столкнулась с двумя категориями сложностей — концептуальной и технической.
Концептуальная проблема — шум против сигнала. Основная сессия за один рабочий день порождает сотни событий: pwd, ls, rg --files, чтение файлов, запуски линтера. Если записывать каждое, память превратится в свалку, по которой невозможно искать. Логи наглядно показывают этот антипаттерн — десятки повторяющихся вызовов pwd и rg --files -g 'KNOWLEDGE.md', каждый из которых падал с ошибкой песочницы. Записывать такое дословно бессмысленно. Observer должен агрегировать: не «двадцать раз вызвали pwd», а «рабочая директория — /home/deploy/projects, sandbox блокирует запись». Один факт вместо двадцати событий.
Техническая проблема — доступ и устойчивость. Observer работает в режиме «только чтение потока», без собственных инструментов. Это осознанное архитектурное решение: наблюдателю нельзя дать возможность что-то сломать в основной сессии. Но это же означает, что вся информация должна приходить готовой во входящих сообщениях — никакого «дай-ка я сам загляну в файл». В логах видно и другую суровую реальность продакшена: часть попыток основной сессии отваливалась с сообщением про отключённый доступ к подписке, часть команд блокировалась песочницей Codex. Наблюдатель обязан пережить это молча — зафиксировать то, что реально произошло, и не выдумывать то, чего не было.
Как устроено решение
Собранная система работает по конвейеру из трёх стадий.
Стадия 1 — захват. Хук SessionStart поднимает контекст в начале каждой сессии, а по ходу работы события основной сессии стримятся наблюдателю. Каждое наблюдение получает свой тип из фиксированного словаря: bugfix (●), feature (◆), refactor (↻), change (✓), discovery (○), decision (⚖), плюс отметки безопасности security_alert (⚠) и security_note (⚷). Типизация — не украшение: она позволяет потом фильтровать «покажи все архитектурные решения по проекту» отдельно от «покажи все багфиксы».
Стадия 2 — хранение и индексация. Наблюдения складываются в базу с числовыми ID и таймстампами, доступную через MCP-сервер (Model Context Protocol). Появляется API-поверхность: get_observations([IDs]) для точечного разворачивания, observation_search и smart_search для семантического поиска, timeline для хронологии проекта. То есть память — не плоский текстовый лог, а полноценная searchable-структура, которую можно запрашивать так же естественно, как базу данных.
Стадия 3 — инъекция в будущую сессию. Вот где всё окупается. В начале новой сессии агент получает не сырые логи прошлого, а компактный дайджест:
### Jun 30, 2026
22122 4:31a ○ likedog-ru had zero blog automation before this session
22123 " ⚖ Blog automation ported from gptweb with key adaptations
22124 " ◆ Database schema extended with 5 new tables for pipeline
22132 " ● curl inline -d payload crashes on large JSON; fixed with temp file
Stats: 50 obs (22,706t read) | 469,328t work | 95% savings
Одна строка на наблюдение: ID, время, тип-иконка, заголовок. Хочешь подробностей по конкретному пункту — разворачиваешь его через get_observations([22132]) и получаешь полный факт: «Large JSON payloads via curl -d inline fail on OS arg length limits; must use temp file + @/tmp/file pattern». Это классический паттерн прогрессивного раскрытия: сначала дешёвый обзор, детали — по требованию.
Дисциплина безопасности как часть дизайна
Отдельно стоит подчеркнуть слой, без которого такой инструмент нельзя выпускать в прод. Наблюдатель по определению видит всё: команды, вывод, содержимое файлов, SSH-сессии. В логах мелькают и хостнеймы bridge-серверов, и пути к конфигам nginx-stream, и куски приватной инфраструктуры. Правило железное: в память никогда не попадают пароли, токены, API-ключи, JWT-секреты, реальные логины и email, cookie, содержимое .env, строки подключения к БД, внутренние IP. Если наблюдатель встречает учётные данные, он абстрагирует их — записывает «через сервисный ключ» вместо самого ключа, «bridge-сервер» вместо адреса. Специальные типы security_alert и security_note существуют именно для того, чтобы отмечать чувствительные находки, не раскрывая их содержимого. Память, которая утекает секретами, хуже, чем отсутствие памяти.
Результат в цифрах
Самая красноречивая метрика лежит прямо в дайджесте: 95% экономии токенов. В накопленной истории проекта — около 469 000 токенов реальной работы (все те чтения файлов, диффы, выводы тестов), но чтобы поднять этот контекст в новой сессии, агенту нужно прочитать всего ~22 700 токенов сжатых наблюдений. Двадцатикратное сжатие без потери сути.
Что это даёт на практике:
- Нулевой холодный старт. Новая сессия начинается не с «а что тут вообще происходит», а с готовой картой: какие проекты трогали, что уже сделано, где грабли. В логах хорошо видно, как это работает — агент, продолжающий работу над блог-автоматизацией likedog.ru, сразу знает, что «likedog.ru had zero blog automation before this session» и что пайплайн надо портировать из соседнего gptweb.ru.
- Грабли не наступаются дважды. Однажды пойманный баг «curl с inline -d падает на длинных JSON» записан навсегда. Следующая сессия не потратит полчаса на переоткрытие — она увидит готовый факт и решение (temp file +
@/tmp/file). - Сохраняется контекст решений. Не просто «что сделали», а «почему именно так». Записи типа
decisionфиксируют развилки: почему автоматизацию портировали с адаптацией, а не переписали; почему для likedog выбрали прямой доступ к БД через PostgREST вместо нового Next.js-кода.
На реальном рабочем сервере, где параллельно живут десятки проектов — от SEO-сервиса до VPN-инфраструктуры и llm-router, — этот инструмент из приятного бонуса превращается в необходимость. Держать весь этот контекст в голове человека невозможно; держать его в контекстном окне одной сессии — тоже. Промежуточный слой структурированной памяти оказывается единственным работающим решением.
Выводы и уроки
Первый и главный урок: память для AI-агента — это не логи, а курируемые факты. Разница принципиальна. Лог фиксирует, что происходило («вызвали git log»). Память фиксирует, что стало известно («на ветке падало 26 тестов до нашей работы»). Первое растёт линейно и бесполезно; второе сжимается и накапливает ценность. Разделение ролей «делатель» и «наблюдатель» — именно тот механизм, который заставляет систему производить факты, а не шум. Наблюдатель, лишённый инструментов, физически не может «делать» — ему остаётся только осмыслять и записывать.
Второй урок — про формат. Типизация наблюдений и прогрессивное раскрытие (обзор → детали по запросу) оказались не косметикой, а несущей конструкцией. Именно они дают то самое двадцатикратное сжатие. Если бы агент в начале сессии получал все 469k токенов сырья, экономии не было бы вовсе — он бы утонул. Компактный дайджест с возможностью развернуть нужное — это то, что делает память практически применимой, а не теоретически полезной.
Третий урок — про устойчивость к реальности. Продакшен-логи полны провалов: заблокированные песочницей команды, отвалившийся доступ к подписке, десятки бессмысленных повторов pwd. Хорошо спроектированный observer не ломается на этом и не засоряет память мусором — он агрегирует шум в один факт и продолжает работать. Инструмент, который требует идеального входного потока, в продакшене бесполезен.
Четвёртый урок, который я вынес как инженер: безопасность памяти надо проектировать с нуля, а не прикручивать потом. Как только вы создаёте систему, которая наблюдает за всем и всё запоминает, вы создаёте и идеальную мишень для утечки секретов. Правила фильтрации чувствительных данных, абстрагирование учёток, отдельные типы для security-находок — это не опциональный слой, а обязательная часть контракта. Память, которой нельзя доверять хранение секретов, не имеет права видеть секреты. Заложить это в дизайн дёшево; отмывать утёкшую память — невозможно.
Полезные ссылки по упомянутым технологиям: документация Claude и Anthropic API, спецификация Model Context Protocol (MCP), документация Claude Code, Vitest — фреймворк для тестов, фигурирующий в логах, практика Test-Driven Development.

AI-инженер, предприниматель, маркетолог. Основатель feberra.com и x10seo.ru. 13 лет в перфоманс-маркетинге, 3 года в системной интеграции AI в бизнес.