AI-инжиниринг
Memory для чатботов: как LLM помнит контекст - buffer, summary, vector memory
Цели урока
- Понять, почему LLM не имеет встроенной памяти и как это решается на backend
- Реализовать Buffer Memory и Window Memory для простых чатботов
- Освоить Summary Memory для длинных разговоров с суммаризацией
- Применять Vector (episodic) Memory как RAG по истории разговора
- Спроектировать Hybrid Memory с PostgreSQL persistence для production
Предварительные знания
- RAG pipeline и vector search
- Chat Completions API
LLM не помнит ничего. Каждый запрос - чистый лист. Иллюзия памяти в ChatGPT - это просто весь контекст диалога передаётся заново каждый раз. Character.ai делает это для 20 миллиардов сообщений в день. MemGPT (Letta) пошёл дальше: LLM сам управляет своей памятью, сам решает что записать и что забыть. Retention чатбота без правильной памяти - 15%. С hybrid memory architecture - 60%.
- ChatGPT использует window memory + server-side persistence в PostgreSQL - каждый chat хранится и может быть продолжен через месяц
- Character.AI обрабатывает 20B+ сообщений/день - personality memory между сессиями реализована через vector store + entity extraction
- Intercom AI Support - hybrid memory с vector search по истории тикетов клиента, агент знает все прошлые обращения
- MemGPT (Letta, 2023) - LLM сам управляет своей памятью: main context + archival storage + recall storage, entity extraction из разговора
Память родилась из ограничения context window
Отслеживание состояния диалога - старая задача из task-oriented чатботов, но память как забота LLM пришла вместе с эпохой ChatGPT. Когда ChatGPT запустился 30 ноября 2022 года, его context window был около 4096 токенов - как только разговор перерастал этот объём, самые ранние реплики выталкивались и модель их просто забывала. Именно это жёсткое ограничение - причина существования всех memory-архитектур. **LangChain** (Harrison Chase, октябрь 2022) дал первые широко используемые абстракции памяти - buffer, window и summary memory - готовые паттерны вместо ручного управления историей. В 2023 году **MemGPT** (Charles Packer с коллегами, UC Berkeley) пошёл дальше: рассматривать context window как RAM операционной системы и позволить LLM подгружать факты из внешнего хранилища и выгружать обратно, самому решая что хранить. Позже проект стал Letta.
Stateless LLM: почему модель забывает всё
LLM не помнит ничего. Каждый запрос - чистый лист. Иллюзия памяти в ChatGPT - это просто весь контекст диалога передаётся заново при каждом вызове. Character.ai делает это для 20 миллиардов сообщений в день. Не магия - инженерия.
Это не баг и не ограничение реализации. LLM **stateless по архитектуре** - как HTTP без cookies. Каждый `chat.completions.create()` - независимая математическая операция: вектора пришли, вектора ушли, никакого состояния не осталось. Память - это инженерная надстройка поверх stateless API, не встроенная функция модели.
Проблема не только в принципе - в масштабе. Передавать всю историю каждый раз значит платить за каждый токен каждого прошлого сообщения. 50K tokens в истории × 1000 запросов/день × `2.5 USD/1M` input = **`125 USD` в день** только на контекст. Вот где начинается настоящая инженерия памяти.
| Проблема | Описание | Последствие |
|---|---|---|
| Context window limit | GPT-4o: 128K tokens ~ 200 страниц. Разговор на 500 сообщений может превысить лимит | Ошибка API или обрезка контекста |
| Стоимость | Каждый токен в messages оплачивается. 50K tokens x 2.5 USD/1M = 0.125 USD за запрос | Расходы растут линейно с длиной разговора |
| Latency | Больше tokens - дольше processing. 100K tokens = 2-5 секунд дополнительной задержки | UX деградирует на длинных разговорах |
| Lost in the middle | LLM хуже обрабатывает информацию в середине длинного контекста | Ранние сообщения 'забываются' даже если переданы |
"Lost in the middle" - исследование Stanford (2023): LLM хорошо помнит начало и конец контекста, но теряет информацию в середине. При 100+ сообщениях accuracy падает на 20-30% для фактов из середины разговора.
LLM запоминает разговор между сессиями - как человек после встречи
Модель stateless по архитектуре. Любая память между сессиями - инженерная надстройка: база данных + Redis + вектора. Без этого каждая сессия - первое знакомство
ChatGPT 'помнит' прошлые разговоры потому что OpenAI хранит их в базе и подгружает релевантное в системный промпт. Это RAG над историей чатов, а не встроенная память модели. Убери базу данных - и GPT-4o ничем не отличается от свежего инстанса без единого воспоминания
Почему LLM не помнит предыдущие сообщения между API-вызовами?
Buffer Memory: полная история сообщений
Самый простой подход: хранить **все** сообщения и передавать при каждом запросе. Это **Buffer Memory** - модель видит полную историю разговора. Никакой хитрости, никакого сжатия - просто растущий список.
Buffer Memory честен: ничего не теряет и ничего не скрывает. Именно поэтому его используют для коротких сессий с кодогенерацией - когда каждая строка диалога критична. Но цена этой честности растёт линейно. Сообщение #100 тащит за собой сообщения #1-99 как якорь.
| Плюсы | Минусы |
|---|---|
| Полный контекст - ничего не теряется | Стоимость растёт линейно: 100 сообщений x 0.002 USD = 0.20 USD за запрос |
| Простейшая реализация | Context window переполняется на длинных разговорах |
| Модель видит весь ход диалога | Lost in the middle: ранние сообщения деградируют |
| Подходит для коротких сессий (10-20 сообщений) | Не подходит для customer support (100+ сообщений за сессию) |
Map в памяти Node.js - только для прототипов. В production - PostgreSQL или Redis. При рестарте сервера Map обнуляется, и все разговоры теряются.
Разговор длится 200 сообщений. При использовании Buffer Memory стоимость каждого нового запроса...
Window Memory: скользящее окно последних N сообщений
Зачем передавать весь разговор, если последние 10-20 сообщений содержат 90% нужного контекста? **Sliding window** - это та же логика, что в трансформерах при обработке длинных документов: берём окно фиксированного размера и двигаем по тексту. **Window Memory** хранит только последние N сообщений (или K tokens) и отбрасывает всё за пределами окна.
Более точный вариант - лимит по tokens, а не по количеству сообщений:
Window Memory - хороший default для большинства чатботов. Рекомендация: maxTokens = 25% от context window модели. Для GPT-4o (128K) - 32K tokens на историю, остальное для system prompt + RAG context + generation.
При Window Memory с лимитом 20 сообщений. На сообщении #50 пользователь ссылается на тему из сообщения #5. Результат?
Summary Memory: LLM как компрессор истории
Window Memory теряет ранние сообщения молча. **Summarization memory** решает это иначе: вместо удаления старых сообщений - сжать их через тот же LLM. Дешёвая модель (gpt-4o-mini, `0.15/1M` tokens) компрессирует 50 сообщений в 2-3 параграфа, сохраняя ключевые факты. Дорогая модель получает компакт - и не видит разницы.
Суммаризация запускается по порогу - это принципиально. Дополнительный LLM call после каждого сообщения убьёт latency. Но по порогу в 2000 tokens - это нечастая операция, почти незаметная для пользователя. Ошибки суммаризации накапливаются как в испорченном телефоне - поэтому для критичных данных нужен другой подход.
| Плюсы | Минусы |
|---|---|
| Фиксированная стоимость - summary не растёт бесконечно | Потеря деталей при суммаризации |
| Ключевые факты сохраняются | Дополнительный LLM call для суммаризации (+latency, +cost) |
| Подходит для длинных разговоров (100+ сообщений) | Ошибки суммаризации накапливаются ('испорченный телефон') |
| Контролируемый размер контекста | Сложнее дебажить - какие факты потерялись? |
Суммаризация теряет нюансы. Пользователь сказал 'бюджет примерно `50K USD`, но может быть `70K USD` если включить маркетинг'. Summary: 'бюджет `50`-70K'. Потерян контекст 'если включить маркетинг'. Для критичных данных - лучше vector memory.
Summary Memory суммаризирует старые сообщения когда...
Vector Memory: семантический поиск по истории
Buffer тонет в стоимости. Window теряет прошлое. Summary теряет детали. **Episodic (vector) memory** - принципиально другой подход: каждое сообщение сохраняется как embedding через `text-embedding-3-small` (1536 dim, `0.02/1M` tokens), и при каждом запросе HNSW-индекс за 3 мс находит **семантически близкие** фрагменты из всей истории. RAG, только по собственному разговору.
Именно этот принцип лёг в основу **MemGPT** (теперь Letta) - системы, где LLM сам управляет своей памятью: решает что записать в long-term storage, что вытащить обратно, что забыть. Entity extraction поверх вектора - ещё один слой: из разговора автоматически извлекаются именованные сущности (имена, компании, задачи) и хранятся отдельно. Пользователь упомянул 'наш стартап TokenFlow' - следующий сеанс уже знает контекст.
| Плюсы | Минусы |
|---|---|
| Находит релевантный контекст из любой точки истории | Embedding call для каждого сообщения (+latency, +cost) |
| Масштабируется на 1000+ сообщений | Теряет последовательность - сообщения вырваны из порядка |
| Работает как RAG по собственной истории | Сложнее реализация - нужна vector DB |
| Фиксированный размер контекста | Не подходит для пошаговых инструкций (важен порядок) |
Vector Memory при обработке нового сообщения...
Hybrid Memory и PostgreSQL Persistence
Каждый тип memory закрывает что-то одно. Production-решение - **hybrid**: Window даёт immediate context, Summary держит сжатую историю, Vector вытаскивает семантически близкое из любой точки. Три слоя, один запрос. Именно так работают enterprise AI-ассистенты - и именно поэтому они не забывают, что клиент говорил три месяца назад.
PostgreSQL schema для production
Сравнение всех стратегий memory - когда применять:
| Стратегия | Длина разговора | Cost | Accuracy | Сценарий |
|---|---|---|---|---|
| Buffer | < 20 сообщений | $$$ | 100% | Короткие задачи: генерация кода, перевод |
| Window (last N) | Любая | $ | 70-80% | Customer support, casual chat |
| Summary | 20-200 сообщений | $$ | 80-85% | Консультации, coaching, длинные сессии |
| Vector (episodic) | Любая | $$ | 85-90% для relevant | Техническая поддержка, knowledge workers |
| Hybrid | Любая | $$$ | 90-95% | Production chatbots, AI assistants |
Начинать с Window Memory (самый простой). Если пользователи жалуются на 'забывчивость' - добавить Summary. Если нужна точность для конкретных фактов - добавить Vector. Hybrid - для production AI-ассистентов. Redis идеален для session storage: O(1) доступ к последним сообщениям, TTL на устаревшие сессии, pub/sub для streaming.
Memory в чатботе - это про сохранение всей истории сообщений. Чем длиннее буфер, тем умнее бот.
Memory - это управление компромиссом между context window, стоимостью и релевантностью. Hybrid-подход (Window + Summary + Vector) почти всегда даёт лучшее качество при меньшей стоимости, чем простое расширение буфера.
Интуиция от человеческой памяти: «помнить больше = понимать лучше». У LLM не так: лишние сообщения в контексте размывают attention, добавляют шум при retrieval и линейно растят стоимость. После 20-30 ходов чистый буфер начинает проигрывать summary-стратегии по точности ответа, не только по цене.
Hybrid Memory комбинирует три источника контекста. Какой из них отвечает за 'модель помнит факт из сообщения #5 при обработке сообщения #150'?
LLM запоминает разговор между сессиями - как человек после встречи
Модель stateless по архитектуре. Любая память между сессиями - инженерная надстройка: база данных + Redis + вектора. Без этого каждая сессия - первое знакомство
ChatGPT 'помнит' прошлые разговоры потому что OpenAI хранит их в базе и подгружает релевантное в системный промпт. Это RAG над историей чатов, а не встроенная память модели. Сама модель не изменилась - изменился контекст, который ей передали
Ключевые выводы
- LLM API stateless - каждый вызов начинается с нуля, 'память' - ответственность backend
- Buffer Memory: полная история, идеально для коротких задач, дорого и медленно для длинных разговоров
- Window (sliding) Memory: последние N сообщений - разумный default для 80% чатботов
- Summary Memory: gpt-4o-mini сжимает историю по порогу - сохраняет суть, теряет нюансы
- Vector (episodic) Memory: text-embedding-3-small + HNSW = RAG по собственной истории, entity extraction сверху
- Hybrid (Window + Summary + Vector) - production standard; Redis для session storage, PostgreSQL с pgvector для persistence
Вопросы для размышления
- В каком сценарии чатбота Buffer Memory оправдан даже при 50+ сообщениях - и что это говорит о задаче?
- Как entity extraction поверх vector memory меняет качество ответов по сравнению с 'сырыми' векторами сообщений?
- MemGPT позволяет LLM самому решать что запомнить. Какие failure modes у такой архитектуры?
Что дальше
Memory позволяет чатботу помнить контекст. Следующий шаг - дать ему возможность действовать: вызывать функции, обращаться к API, выполнять задачи.
- Tool Calling — Как LLM вызывает функции - function calling, tool use, structured actions
- Agent Fundamentals — От чатбота к агенту - planning, reasoning, tool use в цикле
- Caching & Optimization — Как кешировать ответы и снизить стоимость memory-heavy чатботов
Связанные уроки
- aie-04-tokens-context-window — Context window limit - причина зачем нужна память
- aie-09-embeddings — Vector memory строится на similarity search по embeddings
- aie-16-tool-calling — Memory + tool use = полноценный персистентный агент
- aie-17-agent-fundamentals — Долгосрочная память - ключевой компонент агента
- aut-07-attention-memory — Working vs long-term memory - та же архитектурная дилемма
- prob-17 — Summary memory - аппроксимация истории как Марков-процесс
- db-19-redis