Маркетологи продают вам контекстные окна на миллионы токенов. Инженеры, которые катят инференс на дефицитном железе внутри закрытых контуров, смотрят на это с нервным тиком. Если вы возьмете стандартный бенчмарк Needle in a Haystack и подадите LLM 64 тысячи токенов истории переписки, она радостно найдет нужный факт. Но на потоке в 500 конкурентных сессий этот же фокус пробьет лимиты по VRAM за 12 минут. Задержка на первый токен (TTFT) улетит за 8 секунд. Заказчик посмотрит на счет за железо и потребует оптимизации. Вы обрежете окно. И тогда бот начнет задавать одни и те же вопросы на каждой новой сессии.
Тема «Память ИИ-агента: почему ассистент забывает клиента между сессиями и что стоит чинить» — это вопрос не экономики API, а фундаментальной архитектуры. Закидывать всю историю в окно — значит сжигать вычислительные ресурсы ради лени разработчиков.
Три слоя вместо бездонного окна
Настоящая long-term memory LLM не строится на плоском массиве текста. Человеческий мозг не прокручивает всю жизнь перед тем, как ответить на вопрос «какой кофе вы любите?». У агента должна быть аналогичная иерархия. Рабочая память — это scratchpad в текущем окне контекста. Здесь живет задача, системный промпт и последние пять-семь реплик. Эпизодическая память агента — это сырая история обращений, конкретных инцидентов и решений, которая хранится отдельно. Семантическая, или структурная память — это выжимка фактов: профиль клиента, его статус, предпочтения, сформированные в граф понятий. Разделение этих слоев — единственный способ заставить систему работать в реальном времени.
Зачем векторизовать каждый чих пользователя? Незачем.
Вместо того чтобы держать терабайты диалогов в векторном поиске, семантика сжимается в саммари и отправляется в графовую базу данных. Если клиент полгода назад сказал, что у него собака породы корги, это факт (узел), связанный с клиентом (ребро). Векторная база нужна только для эпизодов: «какие шаги мы предпринимали для починки роутера в марте?». Когда бот обрабатывает новый запрос, легковесный классификатор решает, что именно подтянуть в рабочую память: кусок графа, векторный слепок инцидента или просто сгенерировать ответ из текущего контекста.
Вектор, граф и забывание как фича
Попытка хранить вечно абсолютно всё приведет к тому, что память агента утонет в мусоре и спровоцирует тяжелейшие галлюцинации. При плотной векторизации релевантность начинает падать уже после десяти тысяч эпизодов на одного пользователя. Шум подавляет сигнал.
Забывание — это критически важная фича.
У каждой записи должен быть строгий TTL (Time-To-Live) и механизм приоритизации. Незначительные диалоги сгорают через неделю, оставляя после себя лишь крошечное саммари. Транзакционные решения остаются в векторе на год. Структурные связи в графе живут до тех пор, пока не будут перезаписаны новыми фактами. Выстраивая эту архитектуру, вы неизбежно сталкиваетесь с дилеммой: MemAgent против внешней инфраструктуры. Подход MemAgent, где память интегрирована на уровне скрытых состояний модели или хитрых key-value кэшей на диске, дает минимальную задержку. Но стоимость поддержания этих состояний на сотни тысяч клиентов делает проект нерентабельным. Внешняя векторная база (Qdrant, Milvus) или граф бьют по latency из-за сетевых походов, но стоят в десятки раз дешевле. На edge-девайсах и on-premise железе гибридный подход выигрывает всегда.
А потом приходит аудит ФСТЭК.
Когда вы проектируете эпизодическую память в кровавом энтерпрайзе под 152-ФЗ, помните: PII (персональные данные) нельзя хранить как угодно и где угодно. Если агент радостно сжал паспортные данные в плотный эмбеддинг или сложил в узлы графа без связи с реляционной базой — вы труп. Пользователь имеет право на забвение. Удалить факт из изолированного векторного пространства или, того хуже, из дообученных весов модели, не разрушив структуру — та еще боль. Данные в долгой памяти должны маскироваться до векторизации, а ключи-идентификаторы связываться с защищенным контуром.
def route_memory(user_id, current_query, pii_vault):
# 1. Скрываем PII перед любой работой с памятью
safe_query = pii_vault.mask(current_query)
# 2. Детект намерений: нужен ли долгий контекст?
intent = intent_classifier(safe_query)
if intent == 'factual_recall':
# Структурная память (быстрая, дешевая, точная)
return graph_db.query_profile(user_id)
elif intent == 'historical_context':
# Эпизодическая память с жестким фильтром по времени
return vector_db.search(safe_query,
filter={"user": user_id, "ttl_days": {"$lt": 90}},
top_k=3)
# Текущего scratchpad достаточно (RAG не нужен)
return None
Внедрение такого роутера спасает бюджет. Для наглядности — матрица архитектуры памяти, которую мы используем при проектировании высоконагруженных инференс-систем.
| Тип памяти агента | Оптимальное хранилище | Влияние на Latency (p99) | Стоимость и сложность |
|---|---|---|---|
| Рабочая (Scratchpad) | Контекст LLM (GPU VRAM) | Минимальное (TTFT) | Экспоненциальный рост от длины окна |
| Семантическая (Факты) | Graph DB / Relational | + 20-50 мс | Дешево, легко обновлять и удалять (152-ФЗ) |
| Эпизодическая (История) | Vector DB + Саммаризатор | + 100-300 мс (поиск + реранк) | Средняя (требует фоновой LLM для сжатия) |
Оценка на корп-задачах: не на глаз, а в цифрах
Понять, что агент забывает контекст, легко — клиент начинает материться в чате. Сложнее доказать, что ваша новая архитектура памяти работает лучше лобового увеличения контекста. Публичные бенчмарки здесь бесполезны.
Вам нужен LongMemEval-подобный фреймворк, натравленный на ваши собственные исторические данные. Моделируете сессию из 50 шагов, раскидываете по времени намеренные смены фактов (например, клиент сменил тариф на 15-м шаге) и замеряете две метрики: точность извлечения факта на 50-м шаге и время генерации ответа. Если бот помнит старый тариф — сломался TTL. Если бот тупит 10 секунд — сломался роутер памяти. Если бот выдал конфиденциальную информацию из сессии другого пользователя — вы криво настроили теннантность в векторной базе. RAG решает задачу извлечения статичных документов, но он не заменит эволюционирующую память профиля.
Архитектура памяти агента под бизнес-задачу — это жесткий компромисс между деньгами, задержкой и качеством. Проектировать mlops-пайплайны, которые элегантно жонглируют графами и векторами в закрытом контуре — это инженерия. Пытаться запихнуть весь мир в 128k контекста — это просто лень.