В RAG-системах снова всплыло контекстное голодание: модель может получить правильные документы на этапе поиска, но так и не увидеть нужный фрагмент в финальном промпте. По данным The New Stack, популярная query decomposition — разбиение сложного запроса на подзапросы — не лечит проблему, а переносит её в блок упаковки контекста. Для команд, которые строят AI-поддержку, внутренние базы знаний и корпоративных ассистентов, это неприятная новость: добавили «умную» архитектуру, а качество ответов всё равно пляшет.
Автор материала Кайоде Оджо разбирает типичный сценарий RAG-пайплайна: пользователь задаёт составной вопрос, система делит его на несколько намерений, ищет релевантные фрагменты по каждому из них, а затем собирает ограниченное окно контекста для LLM. На бумаге всё выглядит здраво. Поиск получает более простые запросы, ретривер меньше промахивается, модель должна отвечать точнее. Но дальше начинается менее эффектная, зато критичная часть — allocator, или упаковщик контекста. Именно он решает, какие найденные куски попадут в промпт, а какие останутся за бортом.
Главный вывод анализа: если правильное свидетельство попало в упакованный контекст, ответ закрывал соответствующий вопрос в 100% случаев — 261 из 261 проверенных эпизодов в обеих группах эксперимента. То есть генераторная модель, получив нужную опору, справлялась стабильно. Проблема была не в том, что LLM «не поняла» документ, а в том, что документ или его важная часть не доходили до модели.
Оджо проверял реальные ответы службы поддержки: было сгенерировано 80 ответов на основе упакованных контекстов, а затем каждый ответ оценивался по отдельным поднамерениям. Генерация и оценка не знали, из какого варианта пайплайна пришёл контекст. Картина получилась практичная и немного злая: когда поднамерение оставалось без нужного фрагмента, модель всё равно пыталась ответить в 48,1% случаев. Ещё в 45,6% она явно обозначала пробел чем-то вроде обещания уточнить вопрос отдельно. Полностью молчала только в 6,3% случаев.
Это важнее, чем кажется. Контекстное голодание редко выглядит как пустой ответ или честное «не знаю». Для пользователя оно чаще маскируется под уверенную, но неподкреплённую реплику. В саппорте это может означать неверный совет по биллингу, в HR-боте — неправильную интерпретацию политики отпусков, во внутреннем инженерном ассистенте — ссылку на несуществующую процедуру деплоя. Метрика «ответ был дан» здесь почти бесполезна: надо смотреть, был ли ответ обеспечен нужным контекстом.
Query decomposition при этом не стоит списывать в мусорную корзину. Она действительно может повысить точность поиска по отдельным частям сложного сообщения. Но если после этого система складывает результаты в одно окно по грубой общей релевантности, слабое место просто переезжает дальше по конвейеру. Пятый вопрос пользователя может проиграть первому, потому что первые результаты заняли весь бюджет токенов. Снаружи это выглядит как «модель забыла часть запроса», хотя на деле allocator не зарезервировал место под каждое намерение.
Практический совет из анализа звучит менее модно, чем очередной новый ретривер, зато ближе к продакшену: давать каждому поднамерению минимальный бюджет и выбирать фрагменты по оценке релевантности именно к этому фрагменту запроса, а не ко всему исходному сообщению. Оджо также предлагает переранжировать результаты против конкретного подзапроса. Это противоречит интуитивному подходу «держим главный запрос главным», но в эксперименте именно несопоставимость оценок между разными фрагментами оказалась полезной: она мешает одному намерению съесть весь контекстный бюджет.
Ещё один трезвый пункт — не превращать дедупликацию в религию. В рассмотренном корпусе почти одинаковые фрагменты съедали около 1% бюджета. Дедупликация всё равно нужна, но она не объясняет, почему система игнорирует часть пользовательского вопроса. Если команда несколько недель шлифует удаление похожих чанков, а не измеряет покрытие по поднамерениям, она оптимизирует самый заметный, но не самый болезненный дефект.
Для разработчиков вывод простой: логировать надо не только top-k, latency и итоговый текст ответа. Нужна метрика покрытия по каждому sub-intent: получил ли каждый смысловой кусок пользовательского запроса хотя бы один релевантный passage в финальном контексте. Если поднамерение получило ноль фрагментов, это почти прямой сигнал, что модель сейчас начнёт импровизировать. Для бизнеса это означает, что оценка RAG-систем должна смещаться от красивых демо к наблюдаемому пайплайну: что нашли, что выбросили, что упаковали, почему именно так.
Следующий этап зрелости RAG, похоже, будет не про ещё более длинные контекстные окна и не про магическое «разбей запрос на части». Конкурировать будут команды, которые умеют управлять дефицитом внимания модели как инженерным ресурсом: считать токены, резервировать место под намерения, проверять покрытие и ловить неподкреплённые ответы до того, как их увидит пользователь. И да, это скучнее, чем поставить новый агентный фреймворк. Зато именно скучные места чаще всего и держат продакшен.