Потеря контекста в Qwen 2.5: руководство по управлению памятью для AI-агентов | AiManual
AiManual Logo Ai / Manual.
23 Фев 2026 Гайд

Почему ваш Qwen 2.5-агент забывает всё через 20 минут и как это починить

Практическое решение для потери контекста в агентских циклах на Qwen 2.5. Агрессивная обрезка контекста, работа с KV-cache и пайплайн для продакшена.

Контекст горит раньше, чем вы думаете

Вы запускаете своего агента на Qwen 2.5 14B. Он бодро начинает задачу, первые 5-10 шагов выглядят осмысленно. А потом — словно сносит крышу. Агент забывает первоначальную цель, начинает повторяться или генерировать откровенный бред. Вы проверяете логи: контекстное окно заполнено лишь на 70%. Что происходит?

Деградация контекста в моделях с длинным контекстом — известный, но редко обсуждаемый в лоб факт. Модель теряет связность не когда окно переполнено, а гораздо раньше. Для Qwen 2.5 точка слома — примерно 60-70% от заявленного лимита в 32K токенов.

В теории все рапортуют о миллионах токенов. На практике ваш агент начнет "глючить" уже после 20-22 тысяч. И если вы не управляете контекстом вручную, то вся затея с автономными агентами рассыпается как карточный домик.

Виноват не размер окна, а механизм внимания

Забудьте про красивые цифры в 128K или 1M токенов. Проблема в архитектуре трансформера. Механизм внимания софтмакс плохо масштабируется на сверхдлинные последовательности. Самые ранние токены в контексте получают экспоненциально малый вес, просто "растворяются" в шуме.

💡
Если вам интересны технические детали, почему так происходит, у нас есть разбор в статье "KV-cache в долговременной памяти: почему всё ломается и как это починить". Коротко: KV-cache — это кэш ключей и значений для ускорения генерации — тоже страдает при длинных контекстах, что усугубляет проблему.

Производители моделей борются с этим через улучшенные позиционные эмбидинги (RoPE, YaRN). Но для Qwen 2.5, особенно в локальном развертывании, это лишь отодвигает проблему, а не решает её. Особенно если вы используете 4-битную или 8-битную квантизацию — она дополнительно "съедает" стабильность длинного контекста.

Агрессивная обрезка — единственное работающее решение

Ожидание, что модель сама справится с памятью, — путь в никуда. Встроенные системы "памяти" в большинстве локальных LLM — это просто обёртки над векторной БД, которые работают медленно и прерывают поток рассуждений. Они не подходят для агентов, где каждый миллисекунд на счету.

Решение грубое, но эффективное: резать контекст заранее, не дожидаясь симптомов.

1Определите критический порог для своей задачи

Для начала проведите стресс-тест. Запустите агента в цикле и отслеживайте, после какого количества токенов качество ответов начинает падать. Не доверяйте общим цифрам. Для кодинга сломаться может на 18K, для анализа документов — на 24K. Запишите это число. Это ваш личный лимит, который всегда будет меньше заявленного.

Наша практика с Qwen 2.5 14B (загруженной через llama.cpp с контекстом 32K) показывает: для задач планирования и выполнения (agentic workflow) безопасный лимит — 19 200 токенов. Как только история диалога приближается к этой отметке, пора действовать.

2Спроектируйте стратегию обрезки

Резать всё подряд нельзя. Нужна эвристика, что важно, а что можно выкинуть. Вот иерархия ценности частей контекста в агентском цикле:

  1. Системный промпт и первоначальная цель. Это святая святых. Удалять нельзя никогда.
  2. Результаты последних 3-5 действий (tool calls). Без них агент потеряет нить текущей операции.
  3. Критические промежуточные выводы, которые модель сделала сама в процессе рассуждения.
  4. Ранняя история действий. Её можно сжать или выбросить, если она не ссылается на текущий шаг.
  5. Подробные raw-ответы от инструментов (API, поиска). Часто их можно суммировать в одно предложение.

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

def aggressive_trim(context_messages, current_token_count, threshold=19000):
    """Агрессивно обрезает контекст, сохраняя самое важное."""
    if current_token_count < threshold:
        return context_messages
    
    # 1. Всегда сохраняем системный промпт (первое сообщение)
    system_message = context_messages[0]
    
    # 2. Сохраняем последние N сообщений (действия и их результаты)
    recent_messages = context_messages[-10:]  # Эмпирическое значение
    
    # 3. Пытаемся найти и сохранить ключевые выводы агента (сообщения, где есть "Итак:", "Вывод:" и т.д.)
    key_insights = [msg for msg in context_messages[1:-10] if is_key_insight(msg)]
    
    # 4. Собираем новый контекст
    new_context = [system_message] + key_insights + recent_messages
    
    # 5. Логируем факт обрезки
    logger.warning(f"Контекст обрезан с {current_token_count} токенов до ~{estimate_tokens(new_context)}")
    
    return new_context

3Интегрируйте обрезку в цикл агента

Теперь встройте эту логику в каждый шаг вашего агентского пайплайна. Схема выглядит так:

# Псевдокод основного цикла
context = [system_prompt]
while task_not_complete:
    # 1. Проверяем длину текущего контекста
    token_count = count_tokens(context)
    
    # 2. Агрессивно обрезаем, если приближаемся к лимиту
    context = aggressive_trim(context, token_count, threshold=19200)
    
    # 3. Генерируем следующий шаг (действие или ответ) с обновлённым контекстом
    next_action = qwen.generate(context)
    
    # 4. Получаем результат действия (от инструмента, пользователя и т.д.)
    result = execute_action(next_action)
    
    # 5. Добавляем и действие, и результат в историю
    context.append({"role": "assistant", "content": next_action})
    context.append({"role": "user", "content": result})
    # ... цикл повторяется

Ключевой момент — обрезка происходит ДО того, как качество упадет, а не после. Это превентивная мера.

Где спрятаны грабли: нюансы, которые всё сломают

Вы можете скопировать код выше и всё равно наступить на эти грабли.

ОшибкаПоследствиеКак избежать
Обрезка без учёта структуры сообщенийМодель получает битые JSON или непарные теги, генерация ломается.Всегда обрезайте по целым сообщениям, а не по произвольным токенам. Проверяйте, что последнее сообщение не обрезано посередине.
Игнорирование KV-cache инвалидацииПосле обрезки модель может ссылаться на "призрачные" токены из старого кэша, выдавая абсурд.При сильной обрезке (удалении более 20% контекста) сбрасывайте KV-cache полностью. В llama.cpp это llama_kv_cache_clear. В других бэкендах ищите аналоги.
Слишком частая обрезкаАгент тратит всё время на "перезагрузку" контекста, теряет связность.Настройте порог обрезки так, чтобы она срабатывала не чаще, чем каждые 5-7 шагов агента. См. статью "Контекстный инжиниринг".

Самый болезненный нюанс — работа с инструментами (tools). Если агент вызвал инструмент, а вы обрезали контекст до того, как получили результат, агент "забудет", что он вообще что-то вызывал. Поэтому в стратегии обрезки (шаг 2) мы жёстко сохраняем последние сообщения, куда как раз и попадают вызовы и результаты инструментов.

FAQ: вопросы, которые вы хотели задать, но боялись

Почему бы просто не использовать модель с контекстом 128K?

Потому что проблема не в числе, а в архитектуре. Деградация контекста есть у всех моделей. Кроме того, 128K-модель требует космических ресурсов VRAM для KV-cache. На 16 ГБ карте вы её просто не запустите с таким контекстом. Подробнее в разборе "Агенты на 16 ГБ VRAM".

А встроенные функции памяти в LM Studio или Ollama не решат проблему?

Нет. Часто это просто отдельный чат-интерфейс или медленная RAG-система. Они не интегрированы напрямую в поток генерации агента. Вашему агенту в середине цикла не скажут: "Подожди, я сейчас поищу что-то в векторах". Управление должно быть детерминированным и моментальным. На эту тему есть целая статья — "AI Memory - это обман?".

Можно ли обойтись без обрезки, используя суммирование (summarization)?

Можно, но это дорого и медленно. Каждый раз запускать ещё одну LLM для суммирования истории — это удваивает latency и нагрузку. Для продакшн-агента, который должен работать в реальном времени, агрессивная обрезка по чётким правилам почти всегда выигрывает у суммирования по соотношению цена/качество. Хотя для архивных задач, где важны все детали, суммирование — вариант. Про его плюсы и минусы мы писали здесь.

Это решение работает только для Qwen 2.5?

Принцип агрессивной превентивной обрезки работает для любой LLM, которая демонстрирует деградацию контекста. Для Qwen 2.5 мы эмпирически вывели порог в ~60% от заявленного окна. Для другой модели, например, новой версии от Mistral (партнёрская ссылка на сервис аренды GPU, где её можно протестировать), порог может быть другим. Суть — найти свой порог и резать, не дожидаясь слома.

Что будет дальше? Память как отдельная служба

Ручное управление контекстом — это костыль. Но костыль, который сегодня позволяет вашим агентам работать. Будущее — за выделенными Memory OS, как в Amazon Bedrock AgentCore, где память управляется отдельным модулем. Но пока такие системы сложны и дороги для локального развертывания.

До тех пор возьмите за правило: доверяйте заявленным цифрам контекста только на 50-60%. И режьте без сомнений. Ваш агент этого не почувствует, но будет работать в разы стабильнее. Иногда чтобы помнить главное, нужно безжалостно забывать второстепенное.

Подписаться на канал