Перейти к содержимому
TelegramGitHub

AI Engineering, глава 6: RAG и агенты

Главная мысль: Модели нужен правильный контекст для каждого запроса. RAG достаёт этот контекст из внешних данных. Агент идёт дальше: он сам выбирает инструменты, планирует шаги и проверяет результат.

В прошлой главе мы писали инструкции. Они одинаковы для всех запросов. Контекст другой для каждого запроса. Автор сравнивает его с feature engineering в классическом ML: мы даём модели данные, нужные для ответа.

Конвейер RAG: индексация документов (chunking, embeddings, vector store) и онлайн-запрос (retriever, rewrite, rerank, prompt, модель, ответ)

Система RAG (retrieval-augmented generation) состоит из двух частей:

  • Retriever находит нужные куски данных во внешнем хранилище.
  • Generator (модель) пишет ответ по этим кускам и вопросу.

У retriever две функции. Indexing готовит данные заранее (offline). Querying ищет по запросу (online). Способ индексации зависит от способа поиска.

Пример: бот поддержки получает вопрос про экспорт в Parquet. Retriever берёт страницу про тарифы, модель отвечает по ней.

Зачем RAG, если контекст моделей растёт: данных всегда больше, чем влезет в контекст. Длинный контекст модель использует плохо. Каждый токен стоит денег и добавляет latency.

Если база знаний меньше 200 000 токенов (около 500 страниц), Anthropic советует класть её в prompt целиком, без RAG.

Retrieval считает, насколько каждый документ подходит к запросу. Идея старая: на ней стоят поисковики. BM25 остаётся сильной базой для сравнения. Слово «документ» ниже значит и chunk.

Term-based (lexical)Embedding-based (semantic)
Как ищетПо ключевым словамПо близости смысла
ПримерыBM25, ElasticsearchEmbedding model + vector database
Скорость и ценаБыстро и дёшевоДороже: embeddings, хранение, vector search
Сильная сторонаТочные термины, коды ошибок, названия продуктовЖивые формулировки запросов
Слабая сторонаНе понимает смысл: «transformer» найдёт и фильмМожет «размыть» точные ключи вроде кода ошибки
УлучшениеМало настроекМожно дообучить модель и retriever

Как работает term-based поиск:

  • TF (term frequency): чем чаще слово в документе, тем документ важнее.
  • IDF (inverse document frequency): чем в большем числе документов слово, тем оно менее информативно. Слова «для» и «при» почти не важны.
  • TF-IDF объединяет обе идеи. BM25 добавляет поправку на длину документа.
  • Данные хранят в inverted index: слово -> список документов.

Как работает embedding-based поиск:

  1. Chunks превращают в embeddings. Их кладут в vector database.
  2. Запрос превращают в embedding той же моделью.
  3. Находят k ближайших векторов.

Точный перебор (k-NN) медленный. На больших данных используют ANN (approximate nearest neighbor): HNSW, IVF, LSH, product quantization. Библиотеки: FAISS, ScaNN, Hnswlib. Любая БД, которая хранит векторы, может быть vector database.

В production обычно сочетают оба метода.

  • Последовательно: дешёвый retriever берёт кандидатов, точный и дорогой выбирает лучших. Второй шаг называют reranking.
  • Параллельно: несколько retrievers дают свои рейтинги. Их сливают, например, через RRF (reciprocal rank fusion). Документ получает сумму 1 / (k + rank) по всем рейтингам. Обычно k = 60.

Документ режут на части. Это сильно влияет на качество.

  • Единицы: символы, слова, предложения, абзацы, токены модели.
  • Рекурсивно: разделы, потом абзацы, потом предложения.
  • По типу данных: код, пары «вопрос-ответ».
  • Нужен overlap, иначе фраза порвётся посередине.
  • Chunk не должен быть больше контекста generator и embedding model.
  • Chunking по токенам: при смене tokenizer нужна переиндексация.
Размер chunkПлюсМинус
МеньшеВ контекст влезает больше разных кусковТеряется общий смысл. Больше векторов, больше стоимость, медленнее поиск
БольшеБольше смысла в одном кускеМеньше разнообразия в контексте

Лучшего размера для всех нет. Нужны эксперименты.

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

Запрос в диалоге часто неполный. После вопроса «Какой тариф у Acme?» пользователь пишет «А у Globex?». В поиск это отправлять нельзя. Модель переписывает запрос: «Какой тариф у Globex?» Если данных не хватает («тариф его партнёра»), модель должна сказать, что вопрос не решить, и не выдумывать ответ.

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

  • Метаданные: теги, ключевые слова, сущности. Код ошибки в метаданных помогает найти chunk, даже если он стал embedding.
  • Вопросы, на которые отвечает chunk. Для статьи «Как сбросить пароль» это «не могу войти», «забыл пароль».
  • Контекст документа. Anthropic просит модель написать 50-100 токенов о том, где chunk стоит в документе, и добавляет их в начало chunk.
  • Context precision: какая доля найденных документов релевантна.
  • Context recall: какая доля всех релевантных документов найдена. Для неё нужно знать релевантность всех документов в базе, поэтому её считают реже.
  • Для порядка в выдаче: NDCG, MAP, MRR.
  • Embeddings оценивают бенчмарками MTEB и BEIR. Для vector search смотрят recall, QPS, время построения и размер индекса.

Нужен evaluation set: запросы и документы с метками релевантности (люди или AI judge). Retriever хорош, если помогает получить хороший итоговый ответ. Оценивают и части, и систему целиком.

Цена: основная latency RAG уходит на генерацию, поиск добавляет немного. Но embeddings нужно пересчитывать при смене данных, а расходы на vector database бывают от пятой части до половины расходов на model API.

  • Multimodal RAG. Retriever ищет и картинки: по метаданным (подписи, теги) или по содержимому. Для второго нужна multimodal embedding model, например CLIP.
  • Табличные данные (text-to-SQL). Вопрос: «Сколько единиц товара продано за 7 дней?» Модель по схеме пишет SQL, система выполняет его, модель формулирует ответ. Если схемы не влезают в контекст, нужен шаг выбора таблиц.

Агент (agent) воспринимает среду (environment) и действует в ней. Его определяют среда и набор действий. Действия расширяют tools. RAG с text-to-SQL уже простой агент: «сгенерировать SQL», «выполнить SQL», «ответить».

Агентам нужны более сильные модели. Ошибки накапливаются: при точности 95% на шаг после 10 шагов остаётся около 60%, после 100 шагов около 0,6%. Ставки тоже выше: агент может менять данные.

Цикл агента: задача, план, выбор инструмента, действие, наблюдение, reflection, завершение или повтор; инструменты (поиск, SQL, код, API) и memory

ТипЧто делаетПримеры
Knowledge augmentationДаёт контекстText/image retriever, SQL executor, inventory API, Slack, почта, web browsing
Capability extensionЗакрывает слабости моделиКалькулятор, календарь, конвертер единиц, переводчик, code interpreter, OCR
Write actionsМеняют данныеИзменить таблицу, отправить письмо, сделать платёж
  • Модель плохо считает. Калькулятор дешевле, чем учить модель арифметике.
  • Code interpreter делает агента аналитиком, но несёт риск code injection.
  • Web browsing не даёт модели устареть, но открывает путь для плохого контента.
  • Агент с 13 инструментами (Chameleon) обошёл GPT-4 без инструментов на нескольких бенчмарках.
  • Write actions самые опасные. Не давайте ненадёжной модели права, которых не дали бы стажёру, например удалять production-базу. Нужны защита и подтверждение человеком.

План (plan) это шаги для достижения цели при заданных ограничениях. Этапы: plan generation (task decomposition), reflection на план, execution, reflection на результат. Если цель не достигнута, строят новый план.

  • Отделяйте план от выполнения. Иначе агент может часами выполнять бессмысленный план за ваши деньги. План проверяют эвристиками (нет такого инструмента, слишком много шагов) или AI judge.
  • Intent classifier определяет, чего хочет пользователь. Он помогает выбрать инструменты и отсечь запросы вне задач агента (IRRELEVANT).
  • Человек может проверять или выполнять часть плана. Рискованные действия лучше подтверждать.
  • Умеет ли LLM планировать? Спор открыт. Автор считает, что LLM может быть частью планировщика.

Function calling. Многие API поддерживают вызов инструментов:

  1. Описываете инструменты: имя, параметры, документация.
  2. Для запроса выбираете режим: required, none или auto.
  3. Модель возвращает имя функции и аргументы. Вы вызываете её сами.

Проверяйте значения параметров: модель может угадать их неверно.

Granularity. Детальный план сложно составить, но легко выполнить. Общий план наоборот. Выход: hierarchical planning. План на естественном языке («получить дату») не ломается при переименовании tool, но нужен переводчик в команды.

Control flow. Бывает sequential, parallel, if и for loop. У агента их определяет модель. Параллельность снижает latency. Проверьте, что framework её поддерживает.

Reflection. ReAct чередует Thought, Act, Observation до конца задачи. Reflexion добавляет evaluator и самоанализ: после неудачи агент объясняет причину и строит новый план. Reflection легко внедрить и она помогает, но стоит токенов и времени.

Tool selection. Больше инструментов дают больше возможностей, но агенту сложнее выбирать, а описания занимают контекст. Что делать:

  • делайте ablation: уберите tool. Если качество не упало, tool не нужен;
  • ищите tools, на которых агент часто ошибается, и упрощайте их;
  • смотрите частоту вызовов. Частые пары можно слить в один tool.
Тип сбояПример
Invalid toolПлан вызывает bing_search, которого нет
Valid tool, invalid parameterslbs_to_kg(a, b), а параметр один
Valid tool, wrong valuesВместо 120 передано 100
Goal failureПлан не решает задачу или нарушает бюджет
Reflection errorАгент решил, что закончил, хотя нет (расселил 40 из 50 человек)
Tool failureИнструмент верный, но выдал плохой результат (неверный SQL)
InefficiencyВерный результат, но слишком много шагов и денег

Как оценивать:

  • Соберите planning dataset: пары (task, tool inventory). Для каждой задачи получите K планов.
  • Считайте долю валидных планов и вызовов, число попыток до валидного плана, частоту каждого типа ошибок.
  • Тестируйте каждый tool отдельно. Логируйте все вызовы и их вывод.
  • Меряйте число шагов, цену и время действий. Сравнивайте с человеком: что дёшево ему, может быть дорого для AI.

Memory это механизмы, которыми модель хранит и использует информацию. Они нужны RAG и агентам, потому что информации больше, чем контекст.

ВидЧто этоКогда использовать
Internal knowledgeЗнания в весах модели. Меняются только при обновлении моделиИнформация, нужная почти всем запросам. Закладывают через training или finetuning
Short-term memoryКонтекст модели. Быстрый, но ограниченный. Не живёт между задачамиДанные текущей задачи
Long-term memoryВнешнее хранилище, как в RAG. Живёт между задачами. Данные можно удалить без смены моделиРедкие данные

Memory помогает не терять данные при переполнении контекста, помнить пользователя между сессиями и хранить структуру. Две функции: memory management (что хранить и удалять) и memory retrieval (достать нужное из long-term, как в RAG).

Стратегии для short-term:

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

Книга написана в 2024 году. Вот что важно знать сейчас. Это наше дополнение, его нет в книге.

  • MCP (Model Context Protocol). Открытый протокол от Anthropic (ноябрь 2024). Стал стандартом для подключения tools и данных к моделям. Его поддерживают OpenAI, Google, Microsoft. Есть MCP-серверы для баз данных, BI и облаков.
  • Agentic search вместо классического RAG. Coding agents часто ищут без vector store: grep, чтение файлов, SQL. Агент сам решает, что найти. Vector RAG остаётся для больших коллекций текста.
  • Агенты в продакшене. Есть SDK для агентов у OpenAI, Anthropic, Google. Агенты работают в браузере и на компьютере (computer use).
  • Память агентов стала функцией продукта. Долгая память есть в ChatGPT, Claude, coding agents. Идеи из главы (короткая и долгая память) это и описывают.
ТерминЗначение
RAGДостать данные из внешнего хранилища и дать их модели как контекст
Retriever / generatorЧасть, что ищет данные / часть, что пишет ответ
ChunkingРазбиение документов на куски для индекса
Vector databaseХранилище векторов с быстрым поиском ближайших
BM25Term-based алгоритм ранжирования. Сильная база для сравнения
Hybrid searchTerm-based и embedding-based вместе
RerankingПовторная сортировка кандидатов точным методом
Query rewritingПереписывание запроса, чтобы он был понятен без диалога
Context precision / recallДоля релевантных среди найденных / доля найденных среди релевантных
AgentСистема, что воспринимает среду и действует через tools
Function callingВызов инструментов моделью через API
MemoryInternal knowledge, short-term (контекст) и long-term (внешнее хранилище)
  • Retrieval это data pipeline. Индексация: загрузка, очистка, chunking, embeddings, запись в index. Нужны расписание, версии, алерты и lineage, как в любом пайплайне.
  • Инкрементальные обновления. Пересчёт embeddings стоит денег. Обновляйте только изменённые chunks, как incremental модель в dbt. При смене embedding model или tokenizer нужна полная переиндексация.
  • Свой evaluation set. Запросы, документы и метки релевантности хранят как таблицы в warehouse. Версионируйте их. Считайте precision и recall по расписанию.
  • Не начинайте с vector database. Сначала BM25 или полнотекстовый поиск как база. Потом hybrid. Векторы в PostgreSQL или warehouse могут хватить.
  • Text-to-SQL опирается на ваш слой данных. Чистые имена колонок, описания в dbt docs, понятные grain и метрики делают модель точнее. Давайте ей отдельный read-only доступ к витринам, а не к сырым таблицам.
  • Write actions под контролем. Права только на нужные таблицы, подтверждение человека, лог каждого вызова.
  • Стоимость агента. Считайте шаги, токены и время на задачу. Складывайте их в таблицу логов, как метрики пайплайна.
  1. Почему RAG нужен, даже если у модели очень длинный контекст?
  2. Чем term-based retrieval отличается от embedding-based? Почему в production часто берут hybrid?
  3. Как размер chunk влияет на качество, стоимость и скорость поиска?
  4. Какие виды сбоев бывают у агента и как измерить каждый?

Предыдущая: Prompt engineering. Следующая: Finetuning.