TL;DR
Урезание контекста из истории диалога с 10 найденных фрагментов до 3 экономит две трети токенов при умеренном снижении оценки ответа, а раздувание контекста вдвое (с 10 до 20 фрагментов) почти удваивает расходы ради крошечного прироста. При этом популярный приём экономии — оставлять в памяти только сообщения пользователя и несколько последних реплик — отлично работает для прямых указаний, но полностью слепнет, когда пользователь коротко соглашается с предложением бота.
В чём корень проблемы: в живом диалоге клиент редко повторяет параметры заказа целиком. Если ассистент написал «Могу предложить трансфер на шаттле», а пользователь ответил «Да, берём этот вариант», то удаление старых реплик ассистента ради экономии токенов стирает сам предмет согласия. В результате агент помнит факт согласия, но не знает, на что именно согласился клиент, и точность сборки состояния диалога падает почти до нуля.
Как настроить память агента на практике: для поиска по длинной истории (RAG) ограничивайтесь 3–5 релевантными фрагментами вместо 10–20 — это отсекает информационный шум и даже помогает модели чаще честно отвечать «нет данных», когда ответа в базе нет. А если вы сжимаете историю чата, удаляя реплики ассистента, обязательно сохраняйте те сообщения бота, на которые ссылается или с которыми соглашается пользователь, либо добавляйте в системный промпт инструкцию явно фиксировать принятые предложения.
Схема метода
КОНТУР 1: Поиск по длинной истории (RAG-бюджет)
ШАГ 1: Ранжируй историю диалога по запросу (например, BM25 по кускам текста с соседями)
ШАГ 2: Передавай модели-читателю топ-3 или топ-5 фрагментов вместо топ-10/20 → Экономия 48–68% токенов и меньше галлюцинаций на вопросах без ответа
КОНТУР 2: Выборочное хранение реплик диалога (Retention Policy)
ШАГ 1: Сохраняй все реплики пользователя + последние 3 сообщения диалога (экономия ~30% токенов)
ШАГ 2: Проверь, есть ли в репликах пользователя короткие согласия или отсылки («давай этот вариант», «беру предложение №2»)
ШАГ 3: Для каждой такой отсылки оставь в контексте исходную реплику ассистента с предложением → Полное восстановление параметров заказа
Настройка бюджета выполняется в конвейере памяти агента, а правило отслеживания принятых предложений задаётся в системном промпте.
Пример применения
Задача: Вы настраиваете ИИ-ассистента консьерж-сервиса или бронирования командировок (например, для корпоративных клиентов Ozon Travel или Авиасейлс для бизнеса). Диалоги длинные: сотрудник обсуждает билеты, отель, трансфер и время выезда. Чтобы не переплачивать за токены и не терять ранние требования клиента в длинном окне, вам нужно задать системную инструкцию по сборке итогового состояния заказа из истории переписки.
Промпт (системная инструкция агенту):
Ты — агент сборки параметров бронирования из истории диалога. Твоя задача — заполнить текущее состояние заказа по слотам: {услуга}, {локация}, {время}.
Правила работы с историей сообщений:
1. Самое позднее прямое требование пользователя всегда имеет приоритет и перезаписывает старые значения.
2. Предложения ассистента сами по себе НЕ меняют состояние заказа.
3. Предложение ассистента вступает в силу ТОЛЬКО в том случае, если пользователь явно принял его в следующей или более поздней реплике (в том числе по ссылке или короткому согласию).
4. Если значение для слота невозможно однозначно установить из видимой истории или ссылка ведёт на отсутствующее сообщение, верни `null` (или ответь «Нет доступной информации»), не додумывай значение.
Результат:
Модель проигнорирует непринятые варианты, которые бот просто перечислял в ходе беседы, но корректно подтянет параметры из тех предложений ассистента, которые клиент подтвердил коротким согласием, и вернёт честный null вместо галлюцинации, если нужный фрагмент переписки был обрезан.
Почему это работает
Когда в контекст модели загружают всю переписку целиком или по 10–20 найденных кусков истории, возникают две беды: раздувание счёта за токены и размывание внимания на мусорных репликах. На вопросах, где правильного ответа в истории вообще нет (требуется отказ от ответа), большой бюджет контекста подсовывает модели кучу косвенно похожих фраз, и она начинает выдумывать ответ вместо честного отказа. Сокращение выдачи до 3–5 лучших фрагментов убирает этот шум.
Вторая закономерность связана с тем, как устроены диалоговые состояния. Если просто обрезать историю по новизне (оставлять только хвост последних сообщений), агент быстро забывает базовые требования, которые клиент озвучил в начале разговора. Фильтрация «оставить все сообщения пользователя + последние 3 реплики» решает эту проблему для прямых команд и на длинной дистанции даже обыгрывает полную историю за счёт удаления болтовни бота.
Однако такая фильтрация разрывает связки «предложение бота → согласие клиента». Без реплики ассистента фраза пользователя «Принимаю вариант из сообщения 13» повисает в воздухе. Как только исследователи возвращали в контекст всего одно недостающее сообщение ассистента, на которое ссылался пользователь, точность восстановления состояния мгновенно взлетала с 3 из 64 до 42 из 64.
Шаблон промпта
Шаблон инструкции для агента или суммаризатора памяти, работающего с длинной историей переписки:
Проанализируй историю диалога и восстанови актуальные параметры задачи по полям: {список_полей}.
Строгие правила извлечения из истории:
1. Учитывай все прямые требования пользователя в хронологическом порядке: новое требование заменяет старое.
2. Не включай в итог варианты, которые предлагал ассистент, если пользователь их не подтвердил.
3. Если пользователь подтвердил предложение ассистента косвенно («да, давай так», «согласен на этот вариант»), восстанови конкретное значение из того сообщения ассистента, к которому относится согласие.
4. Если данных в истории недостаточно или исходное сообщение с предложением отсутствует в контексте, укажи `{фраза_отказа}` (или `null` для JSON-поля).
Что подставлять в плейсхолдеры:
- {список_полей} — целевые параметры, которые агент должен помнить (например: тариф, город_доставки, срок).
- {фраза_отказа} — стандартный ответ при нехватке данных (например, Нет доступной информации).
Ограничения
⚠️ Слепое удаление реплик ассистента убивает контекст согласий: Политика «хранить только сообщения пользователя + 3 последних» даёт 0 из 64 полных совпадений по тексту, если ключевой параметр задан через согласие клиента с предложением бота.
⚠️ Слабые 7B-модели не справляются с отслеживанием состояния: В эксперименте по удержанию сообщений модель Mistral-7B-Instruct-v0.3 провалилась почти в ноль (от 0 до 5 правильных полных состояний из 64) во всех режимах, включая полную историю без сжатия. Для надёжного трекинга слотов нужна модель уровня не ниже Qwen2.5-14B.
⚠️ LLM-судьи ошибаются без доступа к исходнику диалога: Стандартная автоматическая оценка по рубрикам (без передачи судье полной истории переписки) часто штрафует правильные отказы от ответа и не ловит расхождения с исходным текстом.
Как исследовали
Авторы провели два крупных эксперимента и один аудит системы оценивания. В первом эксперименте они взяли бенчмарк длинной диалоговой памяти BEAM (1 100 вопросов по историям объёмом 100K и 500K, из которых 990 вопросов имеют ответ, а 110 требуют отказа «Нет доступной информации»). Поисковик BM25 и модель-читатель Qwen2.5-14B-Instruct были зафиксированы, а менялось только число подаваемых в промпт фрагментов: 1, 3, 5, 10 или 20 кусков текста. Переход с 10 фрагментов на 3 сократил расход токенов читателя на 67,78% при потере всего 5,45 балла (с 48,88 до 43,43 по 100-балльной шкале), а переход на 5 фрагментов сэкономил 48,4% токенов при потере лишь 2,48 балла. Напротив, увеличение контекста с 10 до 20 фрагментов сожгло на 96,24% больше токенов ради прибавки в 2,39 балла. При этом на вопросах, требующих отказа от ответа, уменьшение бюджета с 10 до 3 фрагментов даже повысило балл на +11,36 пункта (+14,29 на тире 500K).
Во втором эксперименте исследователи проверили, почему стандартным оценкам LLM-судей нельзя слепо верить. Оказалось, что базовый судья (gpt-4.1-mini), видящий только рубрику и ответ кандидата без исходной переписки, нередко ставит 0 баллов за совершенно правильный отказ «No information available», а попытка внедрить нового судью с проверкой по исходнику провалила 9 из 31 контрольных синтетических тестов (пройдено 22 из 31).
В третьем эксперименте авторы собрали 128 контролируемых диалогов (2 304 запроса к Qwen2.5-14B и Mistral-7B), где нужно было восстановить три слота (item, place, duration). В половине диалогов пользователь называл предмет прямо («set item = shuttle»), а в другой половине — принимал более раннее предложение бота по номеру («accept item from e13»). Сжатие истории до сообщений пользователя и трёх последних реплик сэкономило ~30% токенов и на прямых требованиях у Qwen2.5-14B дало 52 из 64 точных ответов — лучше и простой обрезки по новизне (13 из 64), и даже полной истории (33 из 64, либо 41 из 64 с подсказкой в промпте). Но на диалогах с отсылкой к предложению бота этот же метод рухнул до 2–3 из 64, пока авторы точечно не вернули в контекст само принятое сообщение ассистента (что сразу подняло результат до 42 из 64).
Адаптации и экстраполяции
🔧 Техника: Переписывание коротких согласий перед архивацией истории → сжатие без потери ссылок
Если ваша система хранит в долгосрочной памяти только реплики пользователя ради экономии 30% токенов, перед удалением старой реплики ассистента склейте короткое согласие пользователя с сутью предложения:
Вместо удаления реплики бота: Ассистент: Предлагаю шаттл до западного терминала на вечер. Пользователь: Да, оформляй этот вариант. Записываем в сжатую историю пользователя: Пользователь: Да, оформляй этот вариант [принято предложение ассистента: item = шаттл].Так вы сохраняете экономию токенов от фильтрации по ролям и полностью устраняете провал на отсылках.
Ресурсы
- Исследование: How Much Conversation History Does an AI Agent Need? (arXiv:2611.09662v1)
- Авторы: Danny Kim (Pembroke Pines Charter High School), Fernando Koch, Ph.D. (Florida Atlantic University)
