ChatGPT забыл имя персонажа, которое вы дали три сообщения назад. Вот почему — и что с этим делать
Разбираем, как устроено контекстное окно LLM, почему модель теряет начало диалога и что сделать разработчику, чтобы это не ломало продукт.

Вы объяснили задачу, уточнили детали, согласовали стиль. А потом модель начинает противоречить сама себе. Это не баг и не деградация качества — это контекстное окно. Разберём, как оно устроено, где ломается и как выстраивать логику приложения с учётом этого ограничения.
Почему модель вообще не помнит — она же такая умная
Большинство современных чат-ботов работают на LLM архитектуры Transformer (Decoder-only). У этой архитектуры нет памяти в человеческом смысле — совсем. Каждый раз, когда вы отправляете новое сообщение, модель не «продолжает думать» — она заново читает весь диалог с нуля.
Иллюзия памяти создаётся программно: приложение берёт историю переписки и подставляет её в промпт перед вашим новым вопросом. Это работает — но только пока диалог умещается в контекстное окно. Как только история перестаёт влезать, часть её обрезается или сжимается, и модель начинает «забывать».
Что такое токен и почему русский текст дороже английского
Прежде чем говорить о размере окна, нужно понять единицу измерения — токен. Это не слово и не буква, а технический фрагмент текста из словаря токенизатора конкретной модели. Одно и то же слово в разных моделях может разбиваться по-разному.
Ориентир от OpenAI из документации: один токен — примерно 4 символа, около ¾ английского слова; 100 токенов — примерно 75 слов. Но это для английского. Большинство популярных моделей обучались преимущественно на английских текстах, поэтому английские слова токенизатор «знает» крупными блоками, а русские дробит мельче.
Грубый пример: английское the — один токен. Русское «несвоевременность» легко разваливается на четыре-пять токенов. Практический вывод: один и тот же текст на русском весит в токенах в полтора-два раза больше, чем на английском. Это напрямую влияет на то, сколько диалога влезет в контекстное окно вашего приложения.
Как self-attention связывает токены — и почему это дорого
После токенизации каждый токен превращается в числовой вектор (эмбеддинг). Дальше в работу вступает механизм self-attention: для каждого токена модель вычисляет, насколько важен каждый другой токен в последовательности.
Возьмём предложение: «Петя положил ноутбук в рюкзак, потому что он боялся дождя». Чтобы понять, кто боится дождя — Петя или ноутбук — модель должна связать местоимение «он» с правильным существительным через несколько позиций. В длинном диалоге та же задача, только масштаб другой: модели нужно удерживать связи через сотни и тысячи токенов.
Вычислительная сложность self-attention растёт квадратично с длиной последовательности. Удвоили контекст — вычислений стало в четыре раза больше. Именно поэтому большие контекстные окна дороже в инференсе и медленнее отвечают.
Что происходит, когда окно переполняется
Разные провайдеры и фреймворки обрабатывают переполнение по-разному. Вот три основных стратегии:
Обрезка (truncation) — самая простая. Старые сообщения просто выбрасываются. Модель теряет начало диалога, но продолжает работать. Проблема: вместе с обрезанными сообщениями уходит системный промпт или ключевые вводные.
Суммаризация — приложение периодически сжимает историю в краткое резюме и подставляет его вместо полного диалога. Детали теряются, но общий контекст сохраняется.
Скользящее окно — в контекст попадают только N последних сообщений. Предсказуемо, но слепо к важности конкретных фрагментов.
Пример конфига для LangChain с ограничением истории по количеству токенов:
```python from langchain.memory import ConversationTokenBufferMemory from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o")
memory = ConversationTokenBufferMemory( llm=llm, max_token_limit=3000, # оставляем буфер под системный промпт и ответ return_messages=True ) ```
Ключевой момент: max_token_limit должен быть заметно меньше лимита модели. Если у модели окно 8 192 токена, а вы выделяете под историю 7 500 — места на системный промпт и сам ответ почти не остаётся.
Как структурировать промпт, чтобы важное не терялось
Модели неодинаково «внимательны» к разным частям контекста. Эмпирически подтверждено: информация в начале и в конце контекста влияет на ответ сильнее, чем информация в середине. Это называют «lost in the middle» эффектом.
Практические правила:
- Системный промпт с ролью и ограничениями — всегда в начало, он должен пережить любую обрезку.
- Ключевые факты (имена, параметры, договорённости) — повторяйте в последнем пользовательском сообщении, не надейтесь, что модель «вспомнит» их из середины диалога.
- Для длинных сессий используйте явные маркеры в промпте:
```text [КОНТЕКСТ ЗАДАЧИ] Продукт: мобильное приложение для трекинга еды Стек: React Native, FastAPI, PostgreSQL Текущая задача: рефакторинг модуля авторизации
[ИСТОРИЯ РЕШЕНИЙ]
- Решили использовать JWT с refresh-токенами
- Отказались от OAuth из-за требований заказчика
[ТЕКУЩИЙ ВОПРОС] ... ```
Где это ломается в продакшне
Агенты с длинными цепочками инструментов. Каждый вызов инструмента добавляет токены в контекст. Через 10-15 шагов агент может «забыть» исходную задачу или начать противоречить ранним решениям.
Многоязычные приложения. Если системный промпт на английском, а пользователь пишет на русском — история диалога расходует токены быстрее, чем вы рассчитывали при проектировании.
RAG без контроля размера чанков. Если в контекст подтягиваются большие фрагменты документов (retrieval-augmented generation), они вытесняют историю диалога. Оптимальный размер чанка зависит от модели, но обычно 300-500 токенов — рабочий ориентир.
Стриминг без буфера. При стриминге ответа легко не заметить, что модель начала «галлюцинировать» детали из-за потери контекста — ответ выглядит уверенно, но противоречит тому, что было в начале сессии.
Что попробовать дальше
Если контекстное окно становится узким местом в вашем приложении, следующий шаг — внешняя память. Идея: выносить факты и договорённости из диалога в отдельное хранилище и подтягивать только релевантные фрагменты через векторный поиск.
Инструменты для старта: Mem0 (управляемая память для агентов), Zep (долгосрочная память с автоматической суммаризацией), pgvector (если хочется держать всё в своём PostgreSQL). Все три интегрируются с LangChain и LlamaIndex без переписывания архитектуры с нуля.
Понимание того, как работает контекстное окно — это не академическая история. Это база, без которой сложно объяснить, почему ваш агент ведёт себя непредсказуемо, и ещё сложнее это починить.