Перейти к содержанию

Глава 6. Краткосрочная, долгосрочная и профильная память

1. Почему одно слово “memory” только мешает

Как только в системе появляется память, у команды возникает искушение называть одним словом вообще все, что не помещается в текущий prompt. Это удобная абстракция для разговора, но плохая абстракция для архитектуры.

На практике у тебя почти всегда есть как минимум три разных слоя:

  • short-term memory для текущего run или короткой серии шагов;
  • long-term memory для устойчивых знаний, summaries и фактов;
  • profile memory для предпочтений, ролей и привычек конкретного пользователя или аккаунта.

Если эти слои не развести, агент начинает:

  • возвращать в prompt слишком много старого шума;
  • путать предпочтения пользователя с фактами о мире;
  • сохранять transient observations как долговременную истину;
  • ломать explainability, потому что уже непонятно, откуда взялся тот или иной кусок контекста.

2. Short-term memory это рабочий стол, а не архив

Short-term memory удобнее всего представлять как рабочий стол агента. Это не “история навсегда”, а то, что помогает ему не потерять текущую нить.

Обычно сюда попадает:

  • промежуточный план;
  • результаты последних tool calls;
  • временные hypotheses;
  • selected context chunks для текущего run;
  • state для многошагового workflow.

У хорошей short-term memory есть три свойства:

  • она ограничена по размеру;
  • она имеет короткое время жизни;
  • ее можно без боли потерять после завершения задачи.

Если в short-term memory начинают жить “вечные” записи, это уже знак, что у тебя нет модели данных, а есть просто переполненный buffer.

3. Long-term memory нужна не для всего, а для устойчивого знания

Long-term memory нужна там, где ценность записи переживает один диалог или один workflow.

Это может быть:

  • подтвержденный факт о бизнес-сущности;
  • summary прошлой сессии;
  • накопленное знание о ходе долгого кейса;
  • извлеченная и нормализованная заметка для будущего retrieval.

Но есть важный фильтр: если запись нельзя разумно использовать позже без полного исходного контекста, скорее всего, ей не место в long-term memory.

Именно здесь команды часто переоценивают полезность “сырых” сохранений. В long-term memory лучше хранить не поток всего подряд, а осмысленные и типизированные записи.

4. Profile memory это не knowledge base

Profile memory особенно легко испортить, потому что она звучит безобидно. Кажется, что это просто “предпочтения пользователя”. Но в production profile memory быстро становится чувствительным слоем.

Сюда обычно относятся:

  • язык общения;
  • формат ответов;
  • рабочая роль;
  • допустимые каналы действий;
  • устойчивые предпочтения интерфейса или взаимодействия.

Важно, что profile memory отвечает на вопрос “как лучше работать с этим человеком”, а не “что истинно в мире”.

Если агент начинает складывать сюда произвольные факты, profile memory превращается в мутную смесь персонализации, слухов и случайных наблюдений.

Разные типы памяти решают разные задачи и не должны сливаться в один storage

flowchart LR
    A["Current run"] --> B["Short-term memory"]
    A --> C["Long-term memory"]
    A --> D["Profile memory"]
    B --> E["Planner state"]
    B --> F["Recent tool outputs"]
    C --> G["Validated facts"]
    C --> H["Session summaries"]
    D --> I["Preferences"]
    D --> J["User constraints"]

5. Хорошая архитектура задает для каждого слоя свой вопрос

Это очень помогает при проектировании:

  • short-term memory: что нужно помнить прямо сейчас, чтобы не потерять задачу?
  • long-term memory: что стоит сохранить, потому что это пригодится позже?
  • profile memory: что про этого пользователя или аккаунт действительно стабильно и полезно?

Если запись не отвечает ни на один из этих вопросов, возможно, ее вообще не нужно сохранять.

6. У каждого слоя должны быть свои правила записи и чтения

Самая частая архитектурная ошибка здесь в том, что один и тот же pipeline пишет и читает все типы памяти одинаково. Но это почти всегда неверно.

Например:

  • short-term memory можно читать свободнее, но хранить очень недолго;
  • long-term memory должна требовать provenance и tenant checks;
  • profile memory должна быть особенно строгой к privacy, consent и explainability.

Нормальная система не только знает, что хранит, но и как именно каждая категория попадает в prompt.

memory_classes:
  short_term:
    ttl: "2h"
    read_path: "runtime_only"
    write_policy: "immediate"
  long_term:
    ttl: "90d"
    read_path: "retrieval_with_filters"
    write_policy: "validated_only"
  profile:
    ttl: "365d"
    read_path: "personalization_only"
    write_policy: "explicit_or_high_confidence"

Такой YAML не обязан быть конечной реализацией. Но он заставляет команду принять важное решение: памятью нельзя управлять на уровне “ну это просто текст в базе”.

7. Что обычно должно жить в short-term memory

Полезный practical rule: short-term memory должна помогать агенту действовать сейчас, а не становиться источником долгосрочной истины.

Хорошие кандидаты:

  • текущий план;
  • статус подзадач;
  • результаты последних двух-трех инструментальных вызовов;
  • рабочие заметки о том, что уже проверено;
  • временные candidate summaries.

Плохие кандидаты:

  • предпочтения пользователя “навсегда”;
  • неочищенные документы;
  • большие логи;
  • чувствительные данные без TTL;
  • неподтвержденные факты, которые потом будут повторяться как истина.

8. Что обычно должно жить в long-term memory

Long-term memory нужна для повторного использования знаний, а не для архивации всей активности.

Туда разумно складывать:

  • подтвержденные факты;
  • аккуратные summaries с provenance;
  • состояния долгих кейсов;
  • нормализованные knowledge records;
  • ссылки на документы, а не сами огромные payloads целиком.

Очень полезный принцип: в long-term memory чаще стоит хранить компактный record и ссылку на источник, чем пытаться превращать хранилище памяти в бессрочный dump всего контента.

9. Что обычно должно жить в profile memory

Profile memory хороша тогда, когда помогает агенту быть удобнее, но не начинает принимать решения за пользователя на основе сомнительных догадок.

Хорошие примеры:

  • “предпочитает короткие ответы”;
  • “обычно работает на русском”;
  • “для изменений production-данных требует подтверждение”;
  • “получает отчеты в конце дня”.

Плохие примеры:

  • выводы о мотивации или характере;
  • случайные предположения из одной сессии;
  • чувствительные персональные данные без явной причины;
  • догадки, которые потом используются как факт.

10. Простой кодовый шаблон для routing memory records

Ниже очень простой пример, который показывает саму идею: запись сначала классифицируется, и только потом идет в соответствующий storage.

from dataclasses import dataclass


@dataclass
class MemoryRecord:
    kind: str
    content: str
    confidence: float


def select_memory_bucket(record: MemoryRecord) -> str | None:
    if record.kind in {"plan_step", "tool_result", "working_note"}:
        return "short_term"
    if record.kind in {"validated_fact", "session_summary", "case_state"} and record.confidence >= 0.8:
        return "long_term"
    if record.kind in {"language_preference", "format_preference", "approval_preference"}:
        return "profile"
    return None

Этот пример специально очень прямой. На практике rules будут богаче, но сама идея должна остаться такой же: память сначала классифицируется, а не бездумно складывается в общий контейнер.

11. На чем чаще всего ломаются команды

Обычно проблемы выглядят так:

  • profile memory начинает подменять authorization;
  • long-term memory набивается шумом;
  • short-term memory становится слишком большой и дорогой;
  • retrieval возвращает записи без учета их класса;
  • никто не может объяснить, почему в ответе появился именно этот кусок контекста.

Все это не “дефекты модели”. Это архитектурные дефекты memory layer.

12. Практический чеклист

Если хочешь быстро проверить свой дизайн, пройди по вопросам:

  • Понимаешь ли ты, чем short-term memory отличается от long-term?
  • Есть ли у profile memory отдельная семантика, а не просто отдельная таблица?
  • Можно ли объяснить TTL для каждого типа записи?
  • Ясно ли, какой слой памяти попадает в prompt напрямую, а какой только через retrieval?
  • Есть ли provenance у долговременных записей?
  • Можно ли безопасно удалить или исправить запись?

Если на эти вопросы сложно ответить, архитектуру памяти стоит упростить и развести по ролям.

13. Что читать дальше

Следующий шаг в этой части очень естественный: после типов памяти нужно разобрать, как именно агент вытаскивает нужные куски обратно в prompt и почему compaction иногда важнее, чем “больше retrieval”.