Все статьи

Память ИИ-агента: как устроена долговременная память

Как устроена долговременная память ИИ-агента: файловое дерево заметок вместо базы, доступ через read, grep и list, ранжированный манифест поверх дерева, ночная дистилляция сессий раз в сутки. Три неочевидных решения: заметка ключуется темой, а не сессией; факт проходит проверку на выводимость из транскрипта и при сомнении не пишется; устаревшее не удаляется, а тускнеет по периоду полураспада. Плюс раздел, которого почти нигде нет: почему собственная память агента является каналом доставки инъекций.

СА

Сам Решу

20 августа 2026 г. · 7 мин чтения

Содержание

Коротко. Долговременная память агента у нас устроена как среда, а не как база данных: файловое дерево заметок, по которому агент ходит теми же действиями, что и по любым другим файлам — read, read_many, grep, list. Раз в сутки сессии дистиллируются в это дерево фоновой задачей. Три решения в этом контуре стоит назвать отдельно, потому что они неочевидны: заметка ключуется темой, а не сессией; каждый факт проходит проверку на выводимость из транскрипта и при сомнении не пишется; ничего не удаляется — устаревшее тускнеет в ранжировании по периоду полураспада. И ещё один раздел, который в разговорах про память агентов почти не звучит: почему запись в собственную память является каналом доставки инъекций.

Задача: десятая сессия должна быть умнее первой

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

Проблема при этом двойная. Агенту мало знать факт — ему нужно знать, что этот факт вообще существует и как до него дойти. И, дойдя, нужно понимать, актуален ли он и откуда взялся. Одинокий факт без источника и без соседей стоит мало: его нельзя перепроверить и нельзя обновить.

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

Память как среда

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

Действий четыре, и все они файловые: read — прочитать заметку целиком, read_many — забрать несколько за один ход, grep — найти по содержимому, list — посмотреть, что вообще есть. Поверх дерева лежит манифест: компактный список того, что известно, с ранжированием. Он отвечает на первый из двух вопросов — «что этот факт вообще существует», — и без него grep бесполезен: нельзя искать то, о существовании чего не знаешь.

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

Ночная дистилляция

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

Записывается результат атомарным батчем: либо приезжает весь набор правок, либо не приезжает ничего. Полуприменённая память хуже пустой — в ней заметки ссылаются на то, чего нет.

Ничего из этого не удаляет заметки. Дистилляция переписывает и добавляет; вычёркивание — отдельный разговор, и мы к нему ещё вернёмся.

Три решения, которые мы принимали осознанно

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

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

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

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

Память как канал отмывания инъекций

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

Механика такая. Всё, что агент читает из веб-страницы, чужого MCP-сервера или чужой CRM, приходит на один ход и в огороженном виде: это данные, не команды. Но в тот момент, когда агент записывает вычитанное в файл собственной памяти, тот же текст возвращается без ограды, в стабильном префиксе, под директивой, которая называет его собственной памятью агента. Злоумышленник для этого не нужен: достаточно добросовестного пересказа враждебной страницы.

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

Что дальше

Четыре вещи, по убыванию соотношения «эффект / работа»:

  1. Индекс памяти в первое сообщение. Манифест у нас уже есть, вопрос только в том, чтобы он приезжал в стартовый контекст, а не по запросу. Пока агент должен догадаться сходить за списком, часть памяти для него не существует.
  2. Цитаты как рёбра. Заметки проверяются против источника на входе, но ссылка на источник не живёт в теле заметки как навигационный элемент. Это разные вещи: первое — гарантия при записи, второе — возможность перепроверить через месяц.
  3. Staged-дерево при ночной дистилляции. Мы пишем атомарным батчем, но набор правок собирается по одной заметке за раз. Обновлять граф целиком правильнее, особенно когда правки взаимозависимы: новая заметка и переписанная соседняя должны приезжать как одно изменение.
  4. Парный замер. Самое неудобное и самое нужное. У нас нет числа, которое говорит, сколько стоит наша память — включённая против выключенной, на одних и тех же вопросах. Пока такого числа нет, любые улучшения памяти делаются на вкус.

Честно о границах

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

Частые вопросы

Чем это отличается от RAG? Ретривал достаёт куски, похожие на запрос. Заметка — это компилируемый офлайн артефакт: она написана заранее, привязана к теме и к источнику, связана с соседями и переживает много сессий. Ретривал отвечает «что похоже на вопрос», память — «что известно по этой теме». Одно не заменяет другое: сырьё для заметок всё равно нужно искать.

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

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

Что происходит, когда факт меняется — например, человек сменил работу? Заметка о теме переписывается, а не дополняется. Старое утверждение не остаётся рядом с новым как альтернативная версия — иначе в памяти окажутся оба, и агент будет выбирать между ними случайно.

Видит ли агент чужую память? Нет. Дистилляция фанится по организациям, и дерево заметок принадлежит организации, а не общей куче.

Применить на практике

Подключите свои сервисы и поручите эту задачу ИИ-агенту — без ручной рутины и таблиц.