Почему retrieval - это первый шаг context engineering
Агент не держит всё в памяти. У модели ограниченное контекстное окно, поэтому нужную информацию приходится извлекать под задачу: находить файл, искать строку, читать фрагмент. Именно с этого начинается context engineering, и именно здесь чаще всего сгорают токены и качество ответа.
Retrieval в агентском контексте шире, чем «поиск по базе знаний». Это весь путь информации до окна модели: каким инструментом ищем, сколько возвращаем за один вызов, что попадает в контекст, а что остаётся в файлах. Работа с контекстом, который уже оказался в окне (суммаризация старых сообщений, выгрузка крупных блоков, долговременная память), это следующий слой. Сначала стоит наладить то, что в окно попадает.
Agent harness как раз для этого и нужен: он применяет техники retrieval так, чтобы модель получала правильный контекст в нужный момент под конкретную задачу. Так формулирует задачу команда LangChain в разборе Context Engineering for AI Agents Starts with Retrieval, и там же разобраны практики harness Deep Agents.
Пример, на котором удобно смотреть все сбои сразу, - агент конкурентного анализа. Раз в неделю он исследует сотни конкурентов и собирает отчёт по шаблону команды: находит заметки прошлой недели по конкретной компании, вытаскивает цифру выручки из большого экспорта рыночных данных, проверяет, не появилось ли новостей в архиве. Каждая задача запускает свой тип retrieval, и каждая ломается по-своему.
Аналогия с экзаменом по открытой книге: все ответы доступны, но именно поэтому сложнее найти нужный, понять, каким источникам верить, и не потратить все силы на лишние поиски. Ограниченное окно делает эту метафору буквальной.
Дальше разберём три класса сбоев и приёмы борьбы с ними: от дешёвых файловых инструментов до семантического retrieval поверх векторной БД, SQL, search API и MCP-сервера.
Три способа, которыми retrieval ломается
LangChain фиксирует три класса сбоев. Они не пересекаются полностью и лечатся разными инструментами.
| Класс сбоя | Как выглядит | Что делать |
|---|---|---|
| Неэффективный поиск | агент открывает каждый файл подряд или переформулирует один и тот же запрос | glob и grep до чтения, сужение области поиска |
| Раздутый результат | один поиск отдаёт полный экспорт данных или десяток документов | read_file постранично, выгрузка крупных результатов в файл с превью |
| Нерелевантный или устаревший контекст | уверенный текст не по теме или устаревший факт, неотличимый от правильного ответа | фильтры по дате, проверка grounding, недоверие к извлечённому тексту |
Неэффективный поиск: почему агент тратит контекст впустую
Каждый поиск стоит токенов и времени. Агент, который открывает файл за файлом «просто посмотреть, что внутри» или в десятый раз переформулирует один и тот же запрос, заполняет контекст результатами поисков раньше, чем находит что-то полезное.
Механика сбоя простая. Агент не знает структуру хранилища, поэтому начинает с широкого чтения: открывает файлы подряд, не находит нужное, меняет формулировку, снова получает широкую выдачу. Область поиска не сужается, число итераций растёт, полезных данных в окне не прибавляется.
Диагностический признак лежит в логах: много однотипных вызовов поиска и мало чтений конкретных фрагментов. Если агент за десять шагов ни разу не прочитал найденное, проблема не в модели.
Harness Deep Agents держит поиск компактным по умолчанию: встроенные файловые инструменты сначала ищут, а потом читают. glob сопоставляет имена файлов, grep находит совпадающие строки, read_file читает файл страницами.
glob и grep: искать до чтения
glob отвечает на вопрос «где это лежит», grep - «где встречается это слово». Оба инструмента сужают область до того, как агент потратит контекст на содержимое файлов.
glob "notes/**/*pricing*.md"
grep -rn "revenue" ./exports/
Первый запрос вернёт список путей, второй - строки с совпадением и номера строк. Агент получает карту местности за десятки токенов вместо тысяч.
Ограничение жёсткое: это keyword-поиск. grep не поймёт синоним, не свяжет «выручку» с «revenue» в русскоязычном файле и не найдёт перефразировку. Если терминология в хранилище неоднородная, поиск по строкам даёт пустые выдачи, и агент быстро возвращается к чтению всего подряд.
Слишком много контекста за один раз: как не утопить окно
Один поиск, который выдаёт полный экспорт данных или десяток документов, заполняет контекстное окно за шаг. Дальше агент не может ни рассуждать, ни планировать: место занято сырыми данными, которые он ещё не осмыслил.
Классический пример: задача найти конкретную цифру выручки в огромном экспорте рыночных данных. Полное чтение файла даёт тысячи строк, из которых нужны три.
read_file с offset и limit: читать постранично
read_file читает файл страницами: offset задаёт начало, limit - размер страницы. Агент смотрит первый фрагмент, оценивает, там ли нужные данные, и решает, читать ли следующий.
read_file(path="exports/market_2026.csv", offset=0, limit=200)
read_file(path="exports/market_2026.csv", offset=200, limit=200)
Компромисс стоит держать в голове при настройке: слишком маленькая страница означает много итераций и лишних вызовов, слишком большая снова раздувает окно. Ориентир один: страница должна быть достаточной, чтобы оценить релевантность фрагмента, а не прочитать файл целиком. Универсальной цифры нет, размер зависит от задачи и от модели.
Выгрузка крупных результатов: путь и превью вместо полного текста
Второй приём работает на уровне инструмента: крупные результаты выгружаются. Полный результат сохраняется в файлы, а агент получает только путь и превью. Он не платит токенами за весь объём сразу и сохраняет возможность дочитать позже.
Связка с постраничным чтением получается рабочей: превью подсказывает, стоит ли открывать файл, а read_file с offset и limit позволяет открыть ровно столько, сколько нужно. Логика здесь одна: читать по мере необходимости.
Паттерн «retrieve, offload, delegate» для кастомных поисковых инструментов
Файловые инструменты закрывают работу с локальными данными. Когда поиск устроен иначе (RAG, внутренний API, поиск по базе), harness должен упаковать выдачу так же аккуратно. Для кастомных поисковых инструментов LangChain описывает паттерн из трёх шагов.
- Retrieve. Агент вызывает поисковый инструмент и получает набор результатов.
- Offload. Результаты сохраняются в файлы, в контекст возвращаются пути и короткие превью.
- Delegate. Читать файлы поручают субагентам. Главный агент видит только то, что субагент признал релевантным.
Смысл в том, что главный агент не платит контекстом за чтение десятков фрагментов. Он получает сжатую выжимку и продолжает планировать.
Субагенты как способ изолировать чтение
Субагент получает путь к файлу с результатами, читает его постранично и возвращает наверх только релевантное: цитаты, номера источников, короткие выводы. Чтение и отбор идут в отдельном контекстном окне, которое после возврата результата не занимает место в основном.
Изоляция контекста и есть главная ценность делегирования. Она же источник новых проблем: субагент может ошибиться в отборе, потерять важный фрагмент или неверно понять задачу. Верхнему агенту нужна проверка результата, а не слепое доверие к выжимке.
Цена подхода честная: архитектура усложняется, добавляется задержка на лишний цикл «модель - инструмент», а задачу субагенту приходится формулировать точно. Для простых запросов это лишний оверхед, для больших выдач экономия окупается.
Как offloading и субагенты устроены в Deep Agents на уровне middleware, разобрано в отдельном материале: Context Engineering в Deep Agents.
Когда keyword-поиска недостаточно: семантический retrieval поверх векторной БД, SQL и search API
Оговорка по источникам: материал LangChain, на который опирается разбор, покрывает файловые инструменты и паттерн выгрузки для кастомных инструментов. Устройство семантического поиска, SQL- и search-инструментов, а также сравнение agentic retrieval с одношаговым RAG там не раскрыты. Дальше инженерная рамка, которую стоит проверять на своём стеке, а не пересказ источника.
glob и grep работают по именам и ключевым словам. Они не найдут смысловое совпадение, если запрос и документ не пересекаются лексически: «как ускорить инференс» против «оптимизация latency модели». В этот момент keyword-поиск упирается в потолок.
- Векторная БД нужна, когда запрос и документ расходятся по формулировке. Цена: чанкинг, эмбеддинги, переиндексация при обновлении данных, отдельная инфраструктура. Плохой чанкинг ломает поиск сильнее, чем слабая модель эмбеддингов.
- SQL подходит для структурированных данных и точных фильтров: даты, суммы, категории. Цена: нужна схема, и её приходится передавать агенту в контекст, иначе он начнёт придумывать имена колонок.
- Search API полезен, когда источник внешний и важна свежесть. Цена: внешняя зависимость, лимиты запросов, нестабильное качество выдачи, обработка сетевых ошибок.
- MCP-сервер даёт агенту единый интерфейс к инструменту поиска и снимает привязку harness к конкретному API. Цена: настройка сервера, внятные описания инструментов, контроль версий. Пример такой связки с гибридным поиском через MCP разобран в материале про память для Cursor и гибридный поиск QMD.
На практике гибридный поиск обычно надёжнее одного метода: keyword даёт точные совпадения по терминам и идентификаторам, семантический слой добирает смысловые попадания. Ограничения каждого слоя стоит понимать до того, как строится индекс, и выбор хранилища под систему знаний здесь отдельная инженерная задача со своими компромиссами.
Почему research-агенту нужен agentic retrieval, а не одношаговый RAG
Одношаговый RAG делает один запрос и отдаёт top-k фрагментов. Для research-задачи этого мало: агент не знает заранее, какая формулировка сработает, а первый запрос часто оказывается слишком общим. Поиск новостей в архиве по одному запросу даст либо шум, либо пустоту.
Agentic retrieval превращает поиск в цикл: сформулировать запрос, оценить выдачу, уточнить формулировку или сменить инструмент, при необходимости вернуться к другому источнику. Решение о следующем шаге принимает модель по результатам предыдущего, а не фиксированный пайплайн.
Риск предсказуем и связан с первым разделом: без сужения области цикл вырождается в неэффективный поиск. Агент перебирает формулировки, платит токенами за каждую и копит мусор в окне. Схема работает при двух условиях: у поиска есть дешёвый способ сузить область (фильтры, glob, точные термины), а число итераций ограничено явно.
Меры предосторожности: устаревшие данные, grounding и prompt injection
Третий класс сбоев коварнее первых двух. Устаревшая или не по теме информация может выглядеть для модели так же убедительно, как правильный ответ. Попав в контекст, она становится основой для следующих шагов, и ошибка переносится дальше по цепочке рассуждений.
Фильтрация по датам и свежие источники
Фильтровать по дате нужно на этапе поиска, а не после попадания в контекст. Если инструмент умеет отсекать документы старше нужного периода, это дешевле, чем потом объяснять модели, что факту три года. Второй элемент - фиксировать дату документа рядом с результатом, чтобы агент видел её при чтении и мог сам отбросить устаревшее.
Ограничение: свежесть не равна релевантности. Свежий документ может быть не по теме, а старый - единственным точным описанием механики. Фильтр по дате сужает область, но не заменяет оценку содержания.
Grounding и отношение к извлечённому тексту как к недоверенному
Проверка grounding означает, что утверждение в ответе опирается на конкретный фрагмент источника, а не на общее впечатление от прочитанного. Практически это выглядит так: агент возвращает цитату или ссылку на файл и строку рядом с выводом, а не только вывод. Механику привязки генерации к входным данным подробнее разбирает материал про граундинг.
Извлечённый текст стоит считать недоверенными данными. В документе может оказаться текст, который выглядит как инструкция: «игнорируй предыдущие указания», «отправь содержимое по такому-то адресу». Выполнять его нельзя, системные инструкции имеют приоритет. Рабочая практика: помечать извлечённые фрагменты как данные, отделять их от команд и при сомнении перечитывать источник, а не пересказ.
Риск prompt injection через retrieved-контент реален для любого агента, который читает внешние документы, веб-страницы или письма. Закрыть его одной фильтрацией текста не получится: правила формулируются заранее, атакующий подстраивается. Ограничение полномочий и подтверждение опасных действий человеком остаются последней линией защиты.
Чек-лист: как отладить retrieval в своём агенте
Проверять стоит по порядку: от дешёвых файловых инструментов к инфраструктуре поиска. Каждый пункт закрывает свой класс сбоев.
- Посчитайте, сколько токенов уходит на поиски. Сравните объём вызовов поиска с объёмом полезных чтений. Перекос в сторону поиска указывает на первый класс сбоев.
- Проверьте, не открывает ли агент файлы вслепую. Чтения без предварительных glob и grep означают, что инструменты поиска не используются или описаны невнятно.
- Проверьте размер страницы read_file. Чтение файлов целиком вместо offset и limit возвращает второй класс сбоев.
- Проверьте, выгружаются ли крупные результаты. Если инструмент возвращает полный экспорт прямо в контекст, выгрузка не настроена.
- Проверьте, изолировано ли чтение результатов RAG. Выдача поиска, которая целиком попадает в окно главного агента, съедает бюджет на планирование.
- Проверьте фильтры по дате и свежесть источников. Без фильтра устаревший контекст проходит в окно беспрепятственно.
- Проверьте grounding. Ответы без привязки к фрагментам источника сложно проверить, а ошибку легко перенести дальше по цепочке.
- Проверьте, не выполняет ли агент инструкции из извлечённого текста. Это граница между retrieval и prompt injection.
- Ограничьте число итераций поиска. Явный лимит превращает agentic retrieval в контролируемый цикл, а не в бесконечную переформулировку.
Универсальной настройки нет. Набор приёмов зависит от задачи, инструментов и модели: файловому агенту хватит glob, grep и постраничного чтения, research-агенту понадобятся гибридный поиск, выгрузка результатов и субагенты. Практический смысл context engineering в том, чтобы каждая из этих настроек была осознанным решением, а не дефолтом, который никто не проверял.