Перейти к содержимому
26 мая 2025 г.·7 мин чтения

Длинный контекст в LLM: когда хранить всю историю чата

Длинный контекст в LLM не всегда нужен целиком. Разберём, когда передавать всю историю чата, а когда хватит саммари и служебных меток.

Длинный контекст в LLM: когда хранить всю историю чата

Откуда берется лишний контекст

Лишний контекст появляется не в сложных сценариях, а в самых обычных чатах. Команда один раз выбирает простую схему: при каждом новом сообщении отправляет модели весь массив messages. На старте это удобно. Через 15-20 реплик запрос уже состоит в основном из того, что модель давно видела.

Чат растет быстро, потому что каждый новый вызов тащит за собой всю историю. Пользователь может задать короткий вопрос, но если до этого было 30 сообщений, система снова оплачивает и передает все 30. Через несколько шагов полезная часть промпта занимает все меньше места, а шум начинает мешать.

Шум создают не только сообщения пользователя. Его часто добавляет сама система: старые уточнения, которые уже не влияют на ответ, повтор одной и той же инструкции на каждом ходе, длинные результаты поиска и инструментов, вежливые реплики вроде "спасибо" или "продолжай", куски документации, вставленные "на всякий случай".

Проблема простая: модель не умеет заранее отделять мусор от важного. Она видит просто текст. Если в начале чата был неверный статус заказа, старое имя клиента или уже закрытая ветка обсуждения, модель может зацепиться именно за это. Поэтому длинный контекст иногда ухудшает ответ вместо того, чтобы сделать его точнее.

Токены уходят незаметно. Чаще всего их тратят на то, что почти не меняется от запроса к запросу: большие системные правила, полные профили клиентов, прошлые ответы ассистента, старые tool outputs. В API это быстро превращается в лишние деньги, особенно если запросов много и диалоги длинные.

Есть и вторая цена - скорость. Чем больше история, тем дольше сеть передает запрос, тем дольше модель читает вход и строит ответ. Разница между 3 тысячами и 30 тысячами токенов обычно видна сразу. Пользователь ждет дольше, а команда потом пытается экономить на длине ответа, хотя проблема была во входе.

Ориентир здесь простой: если человек сейчас спрашивает про новый адрес доставки, модели не нужен весь месяц переписки. Ей нужны актуальные данные, несколько последних реплик и короткая сводка о том, что уже решили.

Что модели действительно нужно помнить

Модели редко нужен разговор целиком. Гораздо полезнее отделить память, без которой ответ сломается, от текста, который только забивает окно контекста.

Обычно хватает четырех слоев памяти:

  • чего пользователь добивается прямо сейчас
  • какие факты нельзя менять или терять
  • какие решения уже приняли по ходу диалога
  • в каком виде нужно ответить

Текущая цель важнее почти всего остального. Если человек сначала просил "объяснить простыми словами", а потом уточнил "сделай короткий ответ для письма клиенту", модель должна держать в фокусе последнюю задачу. Иначе она даст формально правильный, но бесполезный ответ.

Факты, которые нельзя терять, лучше хранить отдельно от обычной переписки. Это может быть номер заказа, тариф, срок, согласованная версия договора, роль пользователя в системе. Когда такой факт один раз прозвучал и потом исчез из контекста, модель начинает достраивать картину сама. На практике это выглядит как уверенный, но неверный ответ.

Отдельно стоит хранить уже принятые решения. Пользователь выбрал язык интерфейса, отказался от лишних деталей, попросил считать бюджет в рублях, согласовал структуру отчета. Нет смысла каждый раз выводить это заново из длинной истории. Проще держать короткое состояние с пометкой "принято".

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

Хорошая рабочая формулировка звучит так: модель должна помнить не весь диалог, а текущее состояние разговора. Например, в поддержке провайдера после 20 сообщений для следующего шага часто нужны только цель "вернуть доступ", факт "двухфакторная аутентификация включена", решение "сбрасываем через администратора" и формат "короткая инструкция без технических деталей".

Если этого состояния нет, история выглядит полной, но ответ все равно промахивается.

Когда нужен весь диалог

Полную историю стоит отправлять тогда, когда смысл ответа живет в старых репликах, а не только в последнем сообщении. Уберете несколько фраз - и модель начнет догадываться вместо того, чтобы продолжать разговор по фактам.

Чаще всего это видно в диалогах, где все держится на точной формулировке. Пользователь пишет: "оставь тот же тон", "верни второй вариант" или "исправь только то, что обещал раньше". Короткое саммари сохранит тему, но почти наверняка потеряет слова, из-за которых меняется результат.

То же самое происходит в разговорах с постоянными ссылками назад. Если участники пишут "как выше", "по прошлому правилу", "не меняй таблицу из начала" или "оставь лимиты из первого сообщения", модели нужны исходные реплики. Иначе она нарушит ограничение, которое никто уже не повторяет вслух.

Еще один типичный случай - незавершенный разбор. Модель уже сравнила версии, отбросила одну гипотезу, зафиксировала исключение и теперь должна продолжить с этой точки. Саммари часто сглаживает такие детали. Для человека это мелочь, для модели - развилка, после которой ответ уходит не туда.

Полная история полезна и там, где нужно восстановить цепочку договоренностей. Это бывает в согласованиях, поддержке, внутренних чатах команды. Один участник разрешил упрощение, другой запретил менять формат, третий назвал срок. Если оставить только выжимку, модель может смешать роли или приписать обещание не тому человеку.

Весь диалог обычно нужен в четырех случаях: когда нельзя терять точные формулировки, когда новые сообщения постоянно ссылаются на старые, когда модель продолжает уже начатый анализ и когда важно восстановить, кто именно что сказал.

Если цена ошибки выше цены лишних токенов, экономить на истории не стоит.

Когда хватит саммари и метаданных

Полную историю не нужно тащить в каждый запрос. Если диалог длинный, но пользователь по сути решает одну задачу, модели часто хватает короткого саммари и нескольких служебных полей. Это дешевле и почти всегда быстрее.

Так работает повторяющийся сценарий: поддержка заказа, перенос встречи, смена тарифа, проверка статуса заявки. Формулировки у людей разные, но логика разговора одна. Старые реплики в таких цепочках редко меняют следующий ответ. Они просто съедают токены.

Полезный тест простой: если удалить первые 30-50 сообщений, а ответ почти не изменится, вся история уже не нужна. Модели важно помнить не сам путь, а итог на текущий момент.

Обычно хватает такого набора: роль пользователя или тип клиента, текущий статус задачи, последние подтвержденные решения, ограничения и факты, которые нельзя терять, плюс 2-4 последних сообщения для локального контекста.

Этого достаточно, когда старые сообщения не добавляют новых условий. Пользователь мог десять раз переспрашивать одно и то же, спорить о формулировке или уходить в сторону. Для следующего шага это шум, а не память.

Представьте длинный чат поддержки в банке. Сначала клиент объяснял проблему с картой, потом уточнял данные, потом ждал проверки, потом снова писал через час. Если сейчас активная тема одна - статус перевыпуска карты, - модели не нужен весь разговор с самого начала. Ей нужен текущий статус, роль клиента, что уже проверили, какое решение приняли и что нельзя обещать сверх правил.

Саммари здесь лучше писать как рабочую заметку, а не как пересказ беседы. Коротко и по делу: "клиент подтвержден", "карта заблокирована", "перевыпуск одобрен", "доставка до 3 рабочих дней", "не запрашивать повторную верификацию". Такая запись дает модели опору и не забивает окно контекста.

Именно на длинных чатах это дает заметный эффект: меньше токенов на входе, меньше шанс утянуть модель в старую ветку, проще контролировать ответ.

Как сжимать историю без потерь

Оставьте SDK и промпты
Поменяйте только base_url и проверьте новую политику памяти без переписывания кода.

Если отправлять модели весь чат без разбора, она тратит контекстное окно на приветствия, повторы и мелкие уточнения. Памяти вроде много, а пользы мало.

Нормальное сжатие начинается с разделения диалога на два слоя. Первый - факты, которые нельзя потерять. Второй - разговорный шум: вежливые фразы, дубли, промежуточные версии мысли, которые уже не влияют на ответ.

Рабочая схема

Сначала вынесите устойчивые факты: кто пользователь, какая у него задача, что уже проверили, к какому результату пришли. Потом отдельно сохраните открытые вопросы. Если в чате остался спорный момент, не прячьте его в общий текст. Лучше явно записать, что именно не подтверждено и какие есть версии.

Числа, сроки, имена, названия тарифов, номера заказов и другие точные данные удобно хранить в отдельных полях. Модели проще работать со структурой, чем искать одну дату внутри сорока сообщений. Туда же стоит добавить служебные метаданные: язык ответа, желаемый тон, формат результата, запрет на лишние детали, примерную длину ответа.

Саммари надо обновлять после заметного поворота в разговоре. Не стоит ждать конца диалога, иначе краткая версия быстро устареет. Если пользователь сначала просил объяснение, а потом попросил официальный ответ для клиента, это уже другой режим работы. Старая выжимка будет тянуть модель назад.

Хорошее саммари похоже на рабочую карточку, а не на литературный пересказ. Другой человек должен открыть его и за 15 секунд понять, что уже известно, что еще не решено и что модель должна сделать сейчас.

Есть еще одно важное правило: не скрывайте неопределенность. Если статус не подтвержден, сумма спорная или финальное решение еще ждут, так и напишите. Иначе модель сама заполнит пробелы.

Пример из поддержки

Возьмем обычный кейс. Клиент пишет в поддержку интернет-магазина и три дня обсуждает один заказ: сначала задержку доставки, потом частичный возврат, потом снова сроки, потому что посылка все же приехала. В чате уже тридцать сообщений, но для нового ответа большая часть переписки не нужна.

В начале диалога клиент несколько раз объяснял адрес, уточнял состав заказа и спрашивал, где курьер. Эти первые двадцать сообщений были полезны в моменте, но сейчас почти не влияют на решение. Если оператору или модели нужно ответить на вопрос "когда вернут деньги", длинная история только тратит токены и иногда путает ответ.

В такой ситуации лучше держать короткое саммари и несколько полей состояния: номер заказа, текущий статус доставки, статус возврата, обещанный срок выплаты и последнее действие со стороны поддержки.

Например, заметка может выглядеть так: "Заказ 54821. Доставка задержана на 2 дня. Клиент согласовал частичный возврат. Поддержка обещала возврат до 15 марта. Повторный вопрос клиента: деньги еще не пришли". После этого модель отвечает точнее, чем при передаче всей истории, потому что видит только то, что влияет на текущий шаг.

Полный чат стоит возвращать в спорных случаях. Если клиент пишет: "Ваш сотрудник обещал другое" или "Я не соглашался на частичный возврат", тогда важны уже сами формулировки. Здесь лучше подмешать исходные сообщения или весь фрагмент, где обсуждали условия. Иначе модель уверенно сошлется на саммари, а не на реальные слова клиента и оператора.

Для рабочей системы это удобный фильтр: обычный статусный вопрос идет по саммари и метаданным, спор о деталях - по полному логу.

Ошибки, которые ломают ответ

Платите по ставкам провайдеров
Сравнивайте режимы контекста и считайте расходы без наценки на API.

Проблема обычно не в том, что вы дали модели мало текста. Чаще вы дали текст, который спорит сам с собой.

Самая неприятная ошибка - потеря отрицания. В истории клиент пишет: "не переносите подписку на новый тариф", а в резюме остается: "клиент просил перенос на новый тариф". Исчезло одно слово, а смысл перевернулся полностью. Это уже не мелкая неточность, а поломка сжатия.

Не лучше и другая крайность: метаданные говорят одно, а история - другое. Например, поле priority=high осталось от старого состояния, хотя вопрос уже закрыли. Или в метаданных стоит "язык: русский", а последние сообщения идут на английском и вводят новую терминологию. Когда такие сигналы расходятся, модель смешивает версии.

Часто путаницу создает сама команда, когда хранит старую версию саммари. История уже изменилась, клиент уточнил задачу, оператор добавил ограничение, а в запрос по-прежнему уходит заметка двухчасовой давности. Для модели это почти то же самое, что работать по устаревшей карточке заказа.

Есть и тихая, но дорогая ошибка: отправлять полную историю и рядом ее пересказ. На первый взгляд так надежнее. На деле вы дублируете факты, тратите токены и повышаете риск расхождений между двумя источниками. Если пересказ хоть немного отличается от оригинала, модель может поверить именно ему.

Еще один частый сбой выглядит так: деталей много, а текущая цель размыта. Модель видит даты, роли, старые решения и оговорки, но не понимает, что именно нужно сделать на этом ходе. Тогда она отвечает гладко, но мимо.

Перед отправкой запроса полезно проверить четыре вещи: у вас должен быть один главный источник правды, саммари должно сохранять запреты и последние решения без потерь, метаданные не должны спорить с текстом, а текущая цель должна быть короткой и отдельной от остального контекста.

Если что-то из этого не сходится, не добавляйте еще контекст. Сначала уберите конфликт.

Быстрая проверка перед запросом

Перед отправкой запроса полезно потратить минуту на короткую проверку. Она часто спасает и качество ответа, и бюджет.

Если модели нужна точная цитата, не надейтесь на саммари. Жалоба клиента, формулировка оферты, номер заказа, дата обещанного ответа - такие детали лучше передавать из исходных сообщений. Саммари почти всегда сглаживает формулировки, а иногда меняет смысл одним словом.

То же правило работает, когда старые реплики прямо влияют на решение сейчас. Если пользователь уже подтвердил личность, отказался от звонка или выбрал тариф, модель должна видеть это явно. Иначе она начнет переспрашивать или даст ответ, который противоречит уже принятому шагу.

Для быстрых запросов обычно хватает пяти вопросов:

  • Нужна ли дословная цитата или точное число?
  • Меняют ли старые сообщения текущий ответ прямо сейчас?
  • Есть ли в саммари даты, обещания, исключения и последние решения?
  • Передали ли вы роль пользователя, статус кейса, ограничения и язык ответа?
  • Что в этом сценарии дороже: лишние токены или ошибка?

Последний вопрос часто решает все. Команды нередко режут историю слишком рано, чтобы сэкономить. Для обычного FAQ это нормально. Но если ошибка стоит дорого, такая экономия быстро становится мнимой. Один неверный ответ в поддержке, финтехе или внутреннем помощнике может потом стоить часов ручной проверки.

Хорошее саммари не должно быть коротким любой ценой. Оно должно сохранять факты, которые нельзя терять. А метаданные должны закрывать контекст, который не нужно пересказывать словами: кто пишет, на каком этапе диалог, что уже разрешено и что запрещено. Если сомневаетесь, лучше отправить чуть больше. Лишние токены часто дешевле, чем неверное действие.

Как понять, что схема работает

Проверьте память на проде
Сравните качество ответа, задержку и цену на реальных диалогах.

Проверять такую схему нужно на реальных диалогах, а не на двух удачных примерах из песочницы. Возьмите один и тот же набор чатов и прогоните его в двух режимах: с полной историей и с коротким саммари плюс метаданными. Только так видно, где длинная история действительно помогает, а где вы просто тратите токены.

Лучше собрать 50-100 диалогов из продакшена и обезличить их. Набор полезно разделить на две группы: рутинные обращения с прямым вопросом и сложные чаты, где смысл размазан по многим сообщениям, цель меняется по ходу разговора или есть ограничения вроде "не предлагай звонок".

Что мерить

Смотрите на связку показателей, а не на один:

  • качество ответа на одном и том же диалоге
  • число входных токенов
  • задержку до первого и полного ответа
  • случаи, где модель забыла ограничение или перепутала факты

Качество удобно оценивать по короткой шкале: ответ верный, частично верный или неверный. Отдельно полезно отмечать, сохранила ли модель детали из прошлых сообщений: номер заказа, уже сделанные шаги, тон ответа, запрет на повторные вопросы.

Если команда работает через RU LLM, оба режима легко прогонять через один OpenAI-совместимый эндпоинт и сравнивать без переписывания SDK и промптов. Плюс аудит-трейлы помогают потом разбирать спорные случаи и видеть, где именно сжатие исказило смысл.

Рутинные чаты обычно спокойно живут на саммари и метаданных. Сложные ломаются тише: модель отвечает уверенно, но теряет одну старую оговорку, и текст уже нельзя отправлять клиенту. Поэтому отдельно собирайте все случаи, где саммари исказило условие, запрет или исключение. Это и есть ваш реальный список рисков.

Хороший тестовый пример выглядит так: в полном диалоге клиент сначала просит возврат, потом соглашается на обмен, но только без доплаты. Короткое саммари может оставить "клиент согласен на обмен" и потерять условие про доплату. Формально ответ выглядит нормально, по смыслу он уже неверный.

Рабочий результат обычно довольно предсказуем: на простых чатах саммари почти не роняет качество, зато заметно сокращает токены и задержку. На сложных чатах полная история выигрывает чаще. Если вы видите именно такую картину, схема годится для продакшена.

Что делать в рабочей системе

Память для чата лучше строить не как один общий механизм, а как два режима с понятным переключением. Для части запросов нужен полный диалог, потому что модель опирается на формулировки, оговорки и ход обсуждения. Для других хватает короткого саммари, нескольких метаданных и последних реплик.

Начните с простого деления по типу задачи. Если пользователь редактирует текст, спорит о деталях договора, уточняет требования или возвращается к старым обещаниям ассистента, держите полный контекст. Если задача похожа на статусный вопрос, типовой саппорт, классификацию или короткую справку по уже известным фактам, включайте сжатый режим.

Правило можно зафиксировать совсем просто. Полный режим нужен, пока диалог короткий или пока важны точные слова пользователя. Сжатый режим подходит, когда хватает саммари, фактов о пользователе, статуса задачи и 2-4 последних реплик. Если токены растут, а новые сообщения почти ничего не добавляют, диалог пора сжимать. Если модель начала путать даты, цифры и ограничения, стоит временно вернуть полный лог.

Без замеров такие правила быстро расползаются. На каждый запрос полезно считать хотя бы три вещи: сколько токенов ушло, сколько занял ответ и как часто модель ошиблась из-за потери контекста. Ошибкой стоит считать не только явную фактическую промашку. Сюда же входят повторные вопросы, забытые ограничения, пропавшие числа и ответы не в том тоне.

Если команда уже использует RU LLM, удобно сравнивать оба режима в одной и той же интеграции: менять политику памяти, а не весь стек вызова. Это особенно полезно для команд с российскими требованиями по данным и аудиту, где важно не только качество ответа, но и то, как запросы проходят через продакшен-контур.

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

Обычно уже после первой выборки становится ясно, где полная история действительно помогает ответу, а где просто сжигает токены.

Часто задаваемые вопросы

Как понять, что в чате уже слишком много лишнего контекста?

Смотрите на две вещи: растут токены и падает точность. Если новый вопрос короткий, а в запрос уходит почти весь старый чат, вы уже платите за шум. Еще один сигнал — модель цепляется за старые статусы, имена или решения, хотя тема уже сменилась.

Что модели действительно нужно помнить между сообщениями?

Обычно модели хватает текущей цели, нескольких фактов, которые нельзя терять, уже принятых решений и требований к ответу. Добавьте 2–4 последние реплики, если без них теряется локальный смысл. Остальное держите вне основного промпта, пока оно не понадобится.

Когда лучше передавать весь диалог целиком?

Полную историю отправляйте, когда смысл держится на точных словах из старых реплик. Это нужно для цитат, споров о договоренностях, ссылок вроде «как выше» и продолжения разбора, где одна старая оговорка меняет весь ответ.

В каких случаях хватает саммари и метаданных?

Если пользователь решает одну задачу, а старые сообщения почти не меняют следующий шаг, хватит короткой выжимки, метаданных и последних реплик. Так часто работают статусы заказа, перенос встречи, смена тарифа и обычные вопросы поддержки.

Как сделать саммари без потери смысла?

Пишите саммари как рабочую заметку, а не как пересказ беседы. Зафиксируйте, что уже известно, что решили, что еще не подтверждено и что модель должна сделать сейчас. Числа, сроки, имена и номера лучше вынести в отдельные поля, чтобы не искать их по всему чату.

Что лучше вынести в метаданные, а не держать в переписке?

Отдельно храните точные данные и ограничения, которые не должны пропасть между ходами. Сюда обычно входят номер заказа, статус кейса, язык ответа, тон, формат, роль пользователя и запреты вроде «не предлагать звонок» или «не запрашивать повторную проверку».

Почему длинный контекст иногда ухудшает ответ, а не помогает?

Потому что модель читает все как обычный текст и не умеет сама надежно отделять мусор от нужного. Старые ошибки, закрытые ветки и повторяющиеся инструкции начинают спорить с текущей задачей. В итоге ответ может стать медленнее, дороже и хуже по смыслу.

Стоит ли отправлять полный лог и саммари одновременно?

Обычно нет. Когда вы отправляете и лог, и пересказ рядом, вы дублируете факты, тратите токены и создаете риск расхождения между двумя версиями. Лучше выбрать один главный источник правды для этого хода и не смешивать его без причины.

Как быстро проверить контекст перед запросом к модели?

Перед отправкой проверьте простую вещь: нужен ли сейчас дословный фрагмент, меняют ли старые реплики ответ, не устарело ли саммари и совпадают ли метаданные с реальным состоянием диалога. Если видите конфликт, не добавляйте еще текст — сначала уберите противоречие.

Как проверить, что схема сжатия дает результат в продакшене?

Сравните два режима на реальных диалогах: полный лог против саммари с метаданными. Потом посмотрите на качество ответа, входные токены, задержку и число промахов по фактам или ограничениям. Если на простых чатах качество почти не падает, а токенов и задержки меньше, схема работает.