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

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

Как читать эту главу

Полезно держать в голове не все определения сразу, а один простой вопрос:

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

Если эти три категории смешиваются, слой памяти перестает помогать и начинает тихо портить систему.

1. Почему одно слово «память» только мешает

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

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

Именно здесь типы памяти перестают быть словарем терминов и становятся архитектурным решением.

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

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

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

Сквозной кейс: классификация состояния поддержки

В кейсе сортировки обращений поддержки текущий статус тикета относится к краткосрочной памяти, нормализованная заметка после запуска может стать долговременной памятью, а устойчивый язык общения пользователя может попасть в профильную память. Сырая фраза “всегда создавай срочные тикеты” не должна попадать никуда, пока ее явно не подтвердит разбор, подкрепленный политикой.

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

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

2. Краткосрочная память — это рабочий стол, а не архив

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

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

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

У хорошей краткосрочной памяти есть три свойства:

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

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

3. Долговременная память нужна не для всего, а для устойчивого знания

Долговременная память нужна там, где ценность записи переживает один диалог или один рабочий процесс.

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

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

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

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

4. Профильная память — это не база знаний

Профильную память особенно легко испортить, потому что она звучит безобидно. Кажется, что это просто “предпочтения пользователя”. Но в эксплуатации профильная память быстро становится чувствительным слоем.

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

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

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

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

4.1. Устойчивое состояние агента не равно памяти

Cloudflare Agents SDK хорошо подсвечивает еще одну границу: у экземпляра агента с состоянием может быть устойчивое состояние, которое автоматически сохраняется, переживает перезапуск и гибернацию и синхронизируется между WebSocket-клиентами.1 Это полезная возможность рантайма, но ее нельзя автоматически считать долговременной или профильной памятью.

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

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

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

flowchart LR
    A["Текущий запуск"] --> B["Краткосрочная память"]
    A --> C["Долговременная память"]
    A --> D["Профильная память"]
    B --> E["Состояние планировщика"]
    B --> F["Недавние результаты инструментов"]
    C --> G["Проверенные факты"]
    C --> H["Сводки сессий"]
    D --> I["Предпочтения"]
    D --> J["Ограничения пользователя"]

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

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

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

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

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

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

Например:

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

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

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 не обязан быть конечной реализацией. Но он заставляет команду принять важное решение: памятью нельзя управлять на уровне “ну это просто текст в базе”.

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

Еще один полезный шаг к зрелой архитектуре: у разных классов памяти должны быть разные правила исправления и обновления.

Например:

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

Если ревизий нет вообще, позже ты видишь только “текущее состояние записи”, но не понимаешь:

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

6.2. Происхождение нужно проектировать вместе с типами памяти

Происхождение полезно не добавлять “потом”, а проектировать одновременно с классами памяти.2

Практически это значит:

  • у long_term записей почти всегда должна быть ссылка на источник или идентификатор источника;
  • у profile записей нужна объяснимая причина, почему система решила, что это стабильное предпочтение;
  • у short_term записей происхождение может быть проще, но рантайм все равно должен понимать их источник.

Ниже очень компактный пример:

memory_classes:
  short_term:
    revision_mode: replace
    provenance: minimal_runtime_metadata
  long_term:
    revision_mode: append_revision
    provenance: source_link_required
  profile:
    revision_mode: merge_with_history
    provenance: explicit_signal_or_review

Это уже переводит разговор из плоскости “где хранить текст” в плоскость “какая у этого знания история и насколько ему можно доверять”.

7. Что обычно должно жить в краткосрочной памяти

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

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

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

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

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

8. Что обычно должно жить в долговременной памяти

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

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

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

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

9. Что обычно должно жить в профильной памяти

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

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

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

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

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

10. Простой кодовый шаблон для маршрутизации записей памяти

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

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

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

11. Частые ошибки

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

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

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

12. Что сделать сразу

Сначала пройди по короткому списку и отдельно отметь все ответы «нет»:

  • Понимаешь ли ты, чем краткосрочная память отличается от долгосрочной?
  • Есть ли у профильной памяти отдельная семантика, а не просто отдельная таблица?
  • Можно ли объяснить TTL для каждого типа записи?
  • Ясно ли, какой слой памяти попадает в подсказку напрямую, а какой только через извлечение?
  • Есть ли происхождение у долговременных записей?
  • Можно ли безопасно удалить или исправить запись?

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

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

Сначала разведи типы памяти и правила хранения, а потом переходи к извлечению, сжатию контекста и фоновым обновлениям.

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