Ты уже несколько часов вбиваешь в модель детали проекта: идеи, видение, как ты хочешь, чтобы всё работало. Файлы, зависимости, решения. Она кивает, отвечает по делу.
Потом — БАМ, сообщение 40, и она предлагает ровно то, что ты отверг в сообщении 5.
Ну и глаз да глаз за этими LLM-ами, что тут скажешь!
Поздравляю — вы упёрлись в контекстное окно.
Это всё, что модель «видит» в процессе разговора: ваши сообщения, её ответы, системные инструкции, описания инструментов, содержимое прочитанных файлов. Один большой кусок текста, измеряемый в токенах.
Но у всего есть предел, и у контекстного окна тоже. Некоторые модели сейчас поддерживают размах контекстного окна до ~1M токенов в отдельных конфигурациях API. Звучит внушительно, пока не осознаёшь: один файл на 2000 строк — это уже ~20k токенов. Пять файлов… и вы уже потратили 100k на контекст.
Также LLM ничего не помнит между вызовами. Каждый раз, когда ты отправляешь сообщение, клиент (Claude Code, Cursor, ChatGPT) собирает всю историю и отправляет её модели одним куском. Модель читает, генерирует ответ и забывает всё. То, что выглядит как «память», — это память клиента, а не модели. Он просто пересылает историю.
sequenceDiagram participant Client as Client<br/>(Claude Code / Cursor / ChatGPT) participant LLM as LLM<br/>(stateless) Note over Client: Stores history rect rgb(197, 224, 203) Note left of Client: Call 1 Client->>LLM: system prompt + tools + project files + msg1 LLM-->>Client: resp1 Note right of LLM: Forgets everything end Note over Client: History: msg1 + resp1 rect rgb(197, 224, 203) Note left of Client: Call 2 Client->>LLM: system prompt + tools + project files + msg1 + resp1 + msg2 LLM-->>Client: resp2 Note right of LLM: Forgets everything end Note over Client: History: msg1 + resp1 + msg2 + resp2 rect rgb(197, 224, 203) Note left of Client: Call 3 Client->>LLM: system prompt + tools + project files + msg1 + resp1 + msg2 + resp2 + msg3 LLM-->>Client: resp3 Note right of LLM: Forgets everything end Note over Client: Stores everything Note over LLM: Stores nothing
Окей, история отправляется полностью. Тогда почему модель всё равно «забывает»?
Причин три:
1. Размытие внимания.
Модель распределяет внимание по всем токенам. При 1000 токенах каждый имеет свой вес. При 500 000 — вес размазан, и если всё одинаково важно, то ничего не важно. Ключевая инструкция физически есть в контексте, но модель на неё просто не обращает внимания.
Примерно как ты перестаёшь замечать детали в огромном документе.
2. Эффект “lost in the middle”.
Модель лучше всего «помнит» начало и конец контекста. Середина — слепое пятно. Если твоё ключевое решение оказалось на токене 200 000 из миллиона… ну что ж, удачи тебе с этим.
3. Накопление мусора.
Каждая неудачная попытка, каждый прочитанный файл, каждый длинный вывод команды остаётся в контексте. После часа работы значительная часть окна — иногда условные 60% — это хлам от провалившихся попыток. Модель видит всё это разом и не может отличить полезное от мусора.
Когда окно заполняется полностью, происходит одно из двух: либо самые старые сообщения обрезаются, либо начинается компакция. В Claude Code это компакция: отдельный LLM-вызов, который сжимает старую историю в короткое резюме.
Но детали теряются навсегда: точные значения, конкретные строки кода, причины, по которым те или иные подходы были отвергнуты, — всё исчезает.
После компакции модель может уверенно галлюцинировать по обрывкам. И самое неприятное: она не знает, чего она не знает.
Ладно, теперь понятно, почему контекст разваливается. Что с этим делать?
У меня есть несколько правил:
- Добавляй файл только если он нужен для текущей задачи — не «на всякий случай». Лишний контекст не помогает, он размывает внимание.
- Если инструкция должна закрепиться — помести её в главный конфиг-файл клиента:
CLAUDE.md,.cursorrulesи подобные.
Так не придётся повторять модели одно и то же снова и снова. Можно спокойно перезапускать сессии, поскольку клиент загрузит эти инструкции заново в начале следующей.
Эти файлы обычно оказываются в самом начале контекста. Если это начало не меняется, сервер может переиспользовать уже выполненные вычисления (если кэш ещё не истёк). Что экономит и время, и токены. - Переключаешься на другую задачу? Начни новую сессию. Шум от предыдущей задачи просачивается в качество ответов на следующую.
- Компакция — это не обязательно плохо. Если ты работаешь над той же задачей и разговор просто затянулся — пусть компакция делает своё дело. Суть задачи остаётся в резюме. Теряются неудачные попытки и конкретные детали. Но ты же следуешь правилу 2 — так что всё в порядке!
- Вся агентная архитектура — субагенты, MCP, ленивая загрузка инструментов, файлы памяти — это разные способы обойти одну и ту же проблему: контекст конечен, и он портится. Подробнее — в mcp и agents.
- Видишь странное поведение в длинной сессии? Это симптом испорченного контекста. Почисти контекст или начни новую сессию.
Но что насчёт кэша?
Здесь часто путаются: клиент (Claude Code, Cursor и подобные) всё равно каждый раз отправляет полный контекст по сети. Кэшируется не передача данных. Кэшируются вычисления на стороне сервера.
Когда модель получает 100k токенов, она не читает их как текст. Она выполняет огромное количество матричных вычислений. Сервер проверяет, что уже было посчитано в прошлый раз, и пересчитывает только новое. Под капотом провайдеры могут переиспользовать уже вычисленные части промпта через механизмы prompt caching / KV-cache. Так что та часть контекста, которая не изменилась, может не пересчитываться с нуля каждый раз.
flowchart TD A["User / Client (Claude Code, Cursor)<br/>sends full context, every request over the network"] --> B["Server receives N tokens"] B --> C{"Is cached prefix<br/>still valid? TTL not expired?"} C -->|"No — expired or prefix changed"| F["Recompute context<br/>(full matrix pass)"] C -->|"Yes — same prefix, still within TTL"| D["Reuse cached K/V<br/>for the unchanged prefix"] D --> G["Compute only new tokens<br/>added after the cached prefix"] F --> H["Generate response"] G --> H classDef client fill:#dee3c6,stroke:#758879,stroke-width:1.5px,color:#2d2d30 classDef server fill:#e3d7c6,stroke:#8b7e7a,stroke-width:1.5px,color:#2d2d30 classDef decision fill:#ddc6e3,stroke:#7e7a8b,stroke-width:1.5px,color:#2d2d30 classDef cached fill:#c5e0cb,stroke:#758879,stroke-width:1.5px,color:#2d2d30 classDef compute fill:#e3c6d2,stroke:#8b7a87,stroke-width:1.5px,color:#2d2d30 classDef response fill:#c5e0cb,stroke:#758879,stroke-width:1.5px,color:#2d2d30 class A client class B server class C decision class D,G cached class F compute class H response
Это важно на практике: провайдеры реализуют кэш по-разному. Стоит следить за тем, как долго кэш хранится на сервере. Это может меняться со временем, но понимание этих ограничений может сыграть тебе на руку.
Если кэш живёт час или пять минут, можно постараться не уходить на долгий кофе прямо посреди сессии, чтобы сэкономить. Но не жертвуй качеством сессии ради денег.
Потому что планирование, чтение своих планов и чёткая формулировка мыслей и идей — куда важнее, а в конечном счёте может быть и дешевле, чем объяснять LLM, что она делает не то, и пытаться подтолкнуть её в нужную сторону.
Один совет на этот счёт: сохрани планы, выйди из сессии, внимательно их перечитай, сформулируй мысли и начни новую сессию с чистого листа.
У всего есть своя польза и свой компромисс — нужно просто найти правильный.