Архив рубрики ~Обо всем~

10 распространенных ошибок RAG, которые мы постоянно наблюдаем на производстве.

10 распространенных ошибок RAG, которые мы постоянно наблюдаем на производстве.

Enterprise Document Intelligence [Том 1 #4bis] – Заметка соавтора о поэтапных ошибках, которые оправдали разделение на четыре части, перед тем как во второй части будут рассмотрены способы их исправления.

Делиться

Фото Йенса Лели, через Unsplash.

Я являюсь соавтором этой серии статей вместе с Анжелой Ши. В этой статье, посвященной типичным ошибкам, перечислены виды отказов, которые мы оба постоянно наблюдали в серийных системах RAG, и именно это подтолкнуло нас к заключению контракта на поставку четырех кирпичей.

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

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

Далее мы пошагово рассмотрим ошибки, которые постоянно повторяем. Исправления будут во второй части.

06090a1dae18b1bc4fed794e4a7d919f
Десять ловушек, четыре кирпича, одно решение на каждую карточку – изображение автора

1. Анализ текста: как документ теряет свою структуру.

Ошибка парсинга возникает, когда команда обрабатывает документ как текст, а не как структурированный объект. Постоянно встречаются три шаблона: игнорирование таблиц и макета (ошибка 1), вывод всего документа в командную строку (ошибка 2) и разбиение документа на окна фиксированного размера, игнорирующие его структуру (ошибка 3). Решение заключается в структурном парсере, который создает типизированные таблицы вместо строк или произвольных окон.

Мета-версия этих трех пунктов также проходит через всю остальную часть статьи. Команды пропускают проверку корректности синтаксического анализа и тратят недели на настройку размера фрагментов, пороговых значений для переранжировщика, выбора топ-K и вариантов встраивания, и никогда не достигают ожидаемой точности. Каждый измеряемый ими параметр находится поверх выходных данных парсера: парсер, который сгладил таблицу на странице 47, создает шум, который ни один фрагментатор не может восстановить, парсер, потерявший заголовки столбцов, создает неоднозначность, которую ни один переранжировщик не может преодолеть. Литература не помогает. В наиболее цитируемом описании поставщиков методов RAG 194 страницы посвящены фрагментации и ни одной — синтаксическому анализу. Сначала исправьте синтаксический анализ. Настройка извлечения предназначена для конвейеров, парсер которых уже сохраняет структуру.

1.1 Ошибка 1: PDF-файл содержал таблицу. Парсер вернул строку.

Обычно принято извлекать PDF-файл как единый текстовый блок и позволять LLM-программе самостоятельно его обрабатывать. Современные парсеры упрощают этот процесс: один вызов функции, одна строка в ответе, и готово.

Стоимость отображается при первом поступлении таблицы с сгруппированными метками строк. В договоре страхования есть таблица льгот, где одно и то же название строки ( Premium , Deductible ) встречается в двух категориях ( Health , Dental ). В текстовом виде категории исчезают в потоке токенов, и LLM видит: Plan A Plan B Plan C Health Premium 100 200 300 Deductible 5 10 15 Dental Premium 50 80 120 Deductible 2 4 6 Если спросить: «Какова премия для Плана B?», есть два допустимых ответа: 200 (Здоровье) или 80 (Стоматология). В текстовом виде нет маркера группировки. Модель выбирает один из вариантов. Иногда она выбирает неправильно, и нет сигнала, указывающего на ошибку.

866bfde46cd713dadec6fb20326b6b8b
Страховой план B Premium стоит 200 долларов в категории «Здоровое здоровье» или 80 долларов в категории «Стоматология», и на изображении не указано, какой именно.

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

Решение заключается в использовании реляционного парсера, который создает типизированные таблицы ( line_df , page_df , toc_df , …) вместо простой строки. Каждая строка содержит свой ограничивающий прямоугольник, номер страницы, шрифт и раздел. Таблицы получают свою собственную детализацию. Последующие блоки считывают структуру, а не отдельные блоки данных.

1.2 Ловушка 2: Платить за 1200 страниц с ответами на каждый вопрос

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

На реальном корпусе тот же рефлекс становится затратным в три этапа. Во-первых, PDF-файл уже не 12 страниц, а 1200. Во-вторых, вопросов уже не один, а 200 в день. В-третьих, команда добавляет в чат еще пять документов, чтобы «дать модели больше контекста», и количество токенов на каждый вопрос растет линейно. Затраты увеличиваются с центов до тысяч в месяц, а ответы ухудшаются, потому что у модели становится больше «стога сена», а «иголка в стоге сена» — одна и та же.

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

Вот пример реалистичного сценария для предприятия: договор перестрахования на 1200 страниц, который команда по соблюдению нормативных требований запрашивает 200 раз в день. Два подхода, один и тот же вопрос. Первый извлекает каждую строку текста из PDF-файла и подставляет результат в каждый запрос. Второй — это конвейер обработки данных, который описывается в этой серии: парсинг создает структурированные таблицы, извлечение возвращает три релевантные страницы, генерация считывает только их.

63030a084dba1c03e07e80390a27841b
131 000 долларов в год на свалку против 330 долларов на контрольно-измерительный трубопровод – изображение предоставлено автором.

При контракте на 1200 страниц затраты на обработку документов примерно в четыреста раз превышают себестоимость готового решения. Объем работы по обработке документов увеличивается с ростом объема документа и количества вопросов; готовое решение растет только с увеличением количества ответов. При обработке двухсот вопросов в день в течение года, разница между затратами в 131 000 долларов и 329 000 долларов составляет один контракт на 1200 страниц.

Кэширование по запросу немного меняет математические расчеты, не переворачивая их с ног на голову. Кэширование с 90% скидкой в Anthropic и кэширование с 50% скидкой в OpenAI применяются только при попадании в кэш, удаляют данные по истечении времени жизни (TTL), которое команда не контролирует, и выставляют полную стоимость при промахе. При 90% скидке дамп по-прежнему обходится в 13 140 долларов в год при той же рабочей нагрузке, что в сорок раз превышает возможности конвейера обработки данных, и продолжает расти вместе с размером документа, а не с ответом.

Размещенный RAG (например, file_search от OpenAI, базы знаний AWS и аналогичные) занимает промежуточное положение: он дешевле, чем дамп, потому что поставщик разбивает документ на фрагменты и извлекает только то, что кажется релевантным; он менее прозрачен, чем конвейер обработки, потому что разбиение на фрагменты, модель встраивания и ранжирование недоступны для проверки. Это удобный компромиссный вариант для прототипирования отдельного документа. Однако он редко является оптимальным решением в масштабах предприятия, где аудит и воспроизводимость имеют такое же значение, как и стоимость.

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

1.3 Подводная лодка 3: Настройка размера блока chunk_size ). PDF-файл имел структуру.

Третья ошибка при синтаксическом анализе — предположение, что PDF-файл является строкой. Команда импортирует pdfplumber , pypdf или PyMuPDF , вызывает функцию с именем extract_text или get_text , передает результат в RecursiveCharacterTextSplitter и в течение следующего месяца настраивает параметры chunk_size и chunk_overlap чтобы повысить точность извлечения на два пункта. PDF-файл содержал структуру. Удобный API её стёр. Команда работает над параметром, расположенным после места потери.

Контракт на 200 страниц содержит кликабельную закладку в оглавлении (структуру, отображаемую каждым читателем в боковой панели), заголовки разделов, отображаемые разными размерами шрифта (24pt для частей, 18pt для разделов, 14pt для подразделов — те же самые ориентиры, которые использует глаз читателя для сканирования текста), и таблицы, хранящиеся в виде ограничивающих рамок на уровне ячеек, которые может восстановить структурный анализатор. Структура находится прямо в объектной модели PDF. extract_text() пропускает её и передаёт разделителю недифференцированный поток. Затем разделитель выполняет операцию при chunk_size=500 поскольку это параметр, который команда настраивала, помимо входных данных, которые собственная типографика PDF могла бы закрепить бесплатно.

f6bfe0e3178e3491e7116289c9f0b066
Фиксированные по размеру блоки прорезают таблицу; блоки, учитывающие структуру, сохраняют ее целостность – изображение автора

Цена — точность. Фрагмент, заканчивающийся посередине таблицы, содержит половину строки. Фрагмент, начинающийся посередине, не имеет заголовка, который бы указывал на контекст ответа. Ответ, который LLM выдает из этих фрагментов, технически основан на корпусе, но эта основа — на обрезанных фрагментах, а не на осмысленных единицах. При поиске не на что фильтровать, поскольку каждый фрагмент выглядит примерно одинаково. При генерации нет ничего, что можно было бы четко цитировать, поскольку ссылки указывают на произвольные временные окна. Цепочка аудита показывает строки типа «фрагмент 1142 из 10 000» без какого-либо читаемого смысла.

Разделители, учитывающие Markdown и разделы, устраняют симптом, но оставляют проблему в исходном коде. Они разбивают текст на фрагменты, основываясь на предполагаемом тексте заголовка из строки, но не могут восстановить ограничивающие рамки, иерархию шрифтов или табличную сетку, которые extract_text() уже отбросила. Разделитель работает с обрезанным входным текстом.

Решение заключается в структурном парсере, на который постоянно указывает остальная часть статьи. Парсер сохраняет типографику PDF-файла ( line_df содержит ограничивающие рамки, шрифт, страницу, путь к разделу), сохраняет табличную сетку (извлекатель таблиц создает набранные ячейки, а не строки), сохраняет оглавление ( toc_df из закладок PDF плюс определение размера шрифта). Последующие блоки считывают структуру. Ни одно окно размером 500 символов никогда не пересекает границу раздела, потому что окна как такового нет. Есть структура.

2. Анализ вопросов: как игнорировать пользователя.

Анализ вопросов завершается с ошибкой, когда команда обрабатывает вопрос пользователя на естественном языке как запрос. Постоянно возникают две ошибки: передача исходной строки непосредственно в функцию извлечения (ошибка 4) и остановка на этапе извлечения ключевых слов, если вопрос также содержит ограничения по форме, области видимости и формату ответа (ошибка 5). Решение — типизированный ParsedQuestion , который содержит все эти данные.

2.1 Подводная лодка 4: «Просто вставьте вопрос».

Самый простой способ передачи данных в любой RAG-фреймворке — это взять введенный пользователем текст, встроить его и отправить на обработку. Введите вопрос, вызовите API, отправьте. Вопрос содержит множество элементов: область видимости, ожидаемую форму ответа, формат, иногда условие, иногда отрицание, иногда ссылку на предыдущий ответ, часто неявное ограничение на документ, который пользователь имеет в виду. Встраивание объединяет все эти элементы в один вектор, который в основном захватывает ключевые слова. Дальнейшие блоки обрабатывают то, что осталось после преобразования, что обычно не соответствует замыслу пользователя.

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

  • Краткий, структурированный запрос. «План отмены периода Б в днях». Пять токенов, три ограничения: фильтр области действия (план Б), тип ответа (продолжительность), формат (в днях). Встраивание объединяет все три параметра в один вектор для оценки результатов поиска по корпусу.
  • Отрицание. «Что НЕ покрывается этой политикой?» Встраивание едва кодирует «НЕ» как служебное слово, поэтому поиск возвращает фрагменты, наиболее похожие на остальную часть предложения, которые описывают то, что ПОКРЫВАЕТСЯ. Генерация перефразирует противоположное тому, что было задано.
  • Вложенные условия плюс вопрос. «Для плана Б, предполагая годовой контракт, каков срок расторжения, если я расторгну его через шесть месяцев?» Условия относятся к области поиска, вопрос — к формированию структуры. Встраивание смешивает их; неправильный блок занимает неправильное поле.
  • Многокомпонентное сравнение. «Исключения или вычет: что важнее?» Получение данных возвращает фрагменты информации по обоим пунктам; при генерации не получается понять, что пользователь хочет получить сравнение, а не список.
  • Упущенная отсылка. «А как насчет плана С?» Пять слов, без контекста. Встроенному тексту не на что опереться.

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

В каждом случае используется один и тот же способ. Вопрос содержит структуру (ограничения, операторы, область видимости, намерение, ссылки). Встраивание преобразует эту строку в один вектор. Поиск обрабатывает то, что осталось, генерация считывает найденное, и пользователь получает в ответ что-то, что может соответствовать или не соответствовать его запросу.

d866a60d19d67ae0bd21284077ca2b47
Ограничения, которые скрывает строка, по сравнению с ограничениями, которые передает парсер для типизированных полей – изображение предоставлено автором.

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

Обычно для решения этой проблемы используют небольшой вызов LLM, возвращающий словарь JSON: intent , scope , keywords . Это решает проблему отсутствия структуры, но не проблему отсутствия контракта. Ключи словаря меняются между запросами (один вызов возвращает scope , следующий — scope_filter ), при извлечении считывается один ключ, при генерации — другой, и незаметное упущение доходит до пользователя. Типизированная схема ParsedQuestion Pydantic превращает это изменение в ошибку синтаксического анализа, которую перехватывает журнал аудита. Победа заключается не в JSON, а в валидации.

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

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

2.2 Подводная лодка 5: «Просто используйте HyDE». Или доверьтесь встраиванию.

Вторая ошибка при разборе вопросов заключается в предположении, что «кирпич» не обязательно должен существовать. Пользователь вводит «каков период отмены для плана B?». Конвейер передает строку модели встраивания, извлекает K лучших фрагментов с помощью косинуса и передает их генерации. Парсера вопросов нет. Современные разработчики не доверяют ручному извлечению ключевых слов (и на то есть веские причины: ненадежные списки, смещение, специфические для языка крайние случаи) и вместо этого используют встраивание, которое, кажется, автоматически поглощает смысл вопроса.

9d3daaa69a3f6e6ce9ed180bdca5ca77
Один вектор для всего против типизированных полей, маршрутизируемых для каждого блока — изображение автора

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

Распространенным обходным путем в этой области является HyDE (гипотетические векторные представления документов): модель LLM генерирует гипотетический ответ на вопрос, конвейер встраивает этот гипотетический ответ, а поисковые системы оценивают фрагменты корпуса, сравнивая их с этим ответом, а не с вопросом. Это работает на бенчмарках, и разработчики используют это как разумный способ избежать ловушки, связанной только с векторными представлениями. Причина, по которой это работает, редко объясняется прямо: гипотетический ответ содержит ключевые слова, которые содержал бы реальный ответ, и именно эти скрытые ключевые слова и выявляет векторное представление. HyDE — это замаскированное извлечение ключевых слов на основе LLM, дополнительная генерация на запрос, без экспертной проверки, без аудита. Когда он показывает низкую эффективность, рефлексом становится обращение к более мощной модели. Детерминированный вариант того же подхода — запросить у эксперта в предметной области словарь концепций и сохранить его один раз. В корпоративной среде стоит использовать тот ответ, который подтвердил бы эксперт в предметной области, а не тот, который может придумать более совершенная модель.

Ограничение формата «в днях» — наиболее точный случай. Закодированный в вектор вопроса сигнал «дни» смещает выборку топ-k в сторону фрагментов, касающихся «времени ответа в течение 30 дней» или «1-го дня действия полиса», что является чистым шумом для вопроса об отмене. Это ограничение должно быть в кратком описании генерации, а не в запросе на получение. Конвейеры, пропускающие разбор вопроса, отправляют один и тот же закодированный вектор в запрос на получение и одну и ту же необработанную строку в генерацию, и неправильный блок обрабатывает неправильное поле.

Решение заключается не в более интеллектуальном встраивании. Решение состоит в парсере вопросов, который создает типизированный объект, в котором форма ответа, область действия, формат и декомпозиция представлены в виде отдельных полей, каждое из которых направляется в обрабатывающий его модуль. Регистр ключевого слова становится одним из полей этого объекта, проверяемым по экспертному словарю, так что термин «премиум» сопоставляется с «prime», «cotisation», «price» без необходимости вручную поддерживать список. В статье 6 разрабатывается парсер и два типизированных кратких описания, которые получаются в результате: одно для поиска, другое для генерации.

3. Извлечение информации: векторный рефлекс ДБ и его слепые зоны.

Поиск не удается, когда единственным доступным инструментом становится «просто встроить и ранжировать по косинусу». Это происходит из-за трех привычек: трактовка RAG как синонима для векторной базы данных (ловушка 6), рассмотрение фрагмента как единственной детализации, когда ответ представляет собой одну строку внутри более крупного фрагмента (ловушка 7), и остановка на ссылках на другие части документа (ловушка 8). Решение проблемы заключается в гибридном поиске, одновременном возврате двух уровней детализации и цикле разрешения ссылок.

3.1 Подводная лодка 6: «Просто используйте векторную базу данных»

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

c9877be79af30412738d3a44f7703280
Сравнение одного только косинуса и трех параллельных детекторов плюс арбитр – изображение предоставлено автором.

Проблема с ценой возникает в каждом вопросе, где ключевое слово помогло бы больше, чем вектор. Аббревиатуры («RC» в страховании, «SCR» в платежеспособности), коды продуктов, числовые диапазоны, редкие названия, юридические ссылки, такие как Section 4.2(a)(iii) . Эмбеддинги сводят их к плотному вектору и теряют дискретность. Поисковый блок возвращает фрагмент текста, содержащий нечто подобное, вместо фрагмента, содержащего этот термин.

В более общем смысле, векторные представления работают, когда вопрос представляет собой перефразированный текст, сопоставляемый с перефразированным текстом. Они испытывают трудности, когда вопрос представляет собой токен: код, число, шаблон в виде регулярного выражения, точная ссылка. Небольшая история, которая мне запомнилась. Несколько месяцев назад я использовал чат-ассистент в инструменте для копирайтинга, чтобы найти определенную фразу в длинном документе, который я скопировал. В какой-то момент ассистент попытался найти фразу с помощью регулярного выражения. Регулярное выражение не дало результата. Я продолжил поиски: в исходном PDF-файле был типографский символ (кажется, фигурная кавычка), который мой скопированный текст заменил прямой кавычкой. Модель правильно поступила, использовав регулярное выражение. Сопоставление токенов было основной операцией. Конвейер обработки просто не мог справиться с разницей в один символ.

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

Более глубокая проблема кроется в культуре. Название «Retrieval Augmented Generation» (дополненная генерация поиска) ничего не говорит о векторах. Оно говорит о поиске, а это область, существующая уже пятьдесят лет и использующая множество методов. Однако, когда мы общаемся с разработчиками, создающими системы RAG, почти каждый разговор сводится к одному и тому же: «Да, мы используем векторную базу данных для поиска». Это воспринимается как вариант по умолчанию, а не как один из многих вариантов.

Мы с Анжелой даже спорили о том, чтобы придумать другое название для того, что мы создаём. ROG, что означает Retrieval Only Generation (генерация только для поиска), потому что в корпоративной среде поиск — это сама работа, а генерация — это оболочка вокруг неё. Историческое определение RAG указывало на обратное: параметрическая модель генерирует, а поиск её дополняет. В итоге мы оставили «RAG», потому что именно так осуществляется поиск и познание работы, и мы не хотели придумывать ещё одну аббревиатуру только для того, чтобы подчеркнуть свою мысль. Но стоит сказать прямо: в этой серии нет чисто векторного поиска. Встраивания присутствуют, но в качестве запасного варианта.

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

3.2 Подводная лодка 7: Фрагмент правильный. Конвейер обработки данных остановился на этом месте.

Вторая ошибка при извлечении данных более тонкая и проявляется только тогда, когда вы пытаетесь связать ответ с исходным кодом. Конвейер извлекает фрагмент, передает его LLM, LLM возвращает ответ. Где именно в этом фрагменте находился ответ? Никто не спрашивает, потому что фрагмент и был единицей измерения.

7a50683ca72c99f2f3d294d9c84293a2
В этом фрагменте содержится ответ; конвейер обработки данных не может определить, в какой именно строке он находится – изображение предоставлено автором.

Это нарушает работу всех последующих функций, зависящих от знания местонахождения ответа. Выделение текста в исходном PDF-файле. Цитаты с номерами строк. Журнал соответствия требованиям. Система может сообщить: «Срок аннулирования — 30 дней», но не сможет указать на прочитанную строку.

Инстинктивно кажется, что местоположение нужно восстановить постфактум, сопоставив цитату LLM с исходным текстом. Это не удаётся в тот момент, когда модель перефразирует текст (что происходит всякий раз, когда цитата содержит более нескольких токенов), и ссылка указывает на строку, близкую к ошибке. Местоположение необходимо вычислять на входе, а не подгонять из выходных данных.

Фрагмент текста также является неправильной единицей измерения по другую сторону исправления: количество окружающего текста, необходимого для LLM, зависит от вопроса. Возьмем, например, вопрос «какова дата событий?» в 200-страничном отчете об инциденте. Ключевое слово «дата событий» занимает одну строку; эта строка содержит дату. Двух строк вокруг нее достаточно, чтобы дать правильный ответ. Возврат фрагмента, содержащего эту строку, не говоря уже о всей главе, скрывает дату в информационном шуме, который модели приходится преодолевать. Вопрос о политике расторжения контракта требует другого размера: один или два абзаца, поскольку политика строится на основе нескольких взаимодействующих условий. Тот же фрагмент, тот же документ, но другой правильный ответ относительно того, сколько окружающего текста следует сохранить.

Решение заключается не в улучшении разбивки на фрагменты. Решение состоит в одновременном извлечении данных с двумя уровнями детализации: один достаточно точный, чтобы выделить его в исходном коде (строка, где сработало ключевое слово), а другой — соответствующий требованиям вопроса (две строки для даты, абзац для политики). Статья 7 строит механизм извлечения данных вокруг этого разделения и присваивает двум областям детализации названия, над которыми мы с Анжелой спорили несколько недель, прежде чем остановиться на одном варианте.

3.3 Ловушка 8: «См. раздел 4.2» и никогда не заглядывать внутрь.

Третья ошибка при извлечении данных проявляется при первом обращении документа к самому себе. Извлеченный фрагмент содержит текст «исключения перечислены в разделе 4.2», и конвейер останавливается. Извлечение нашло фрагмент, в котором упоминаются исключения; оно не перешло по указателю. Генерация получает фрагмент, видит ссылку и имеет два одинаково плохих варианта: придумать содержимое раздела 4.2 на основе своих априорных данных, полученных в ходе предварительного обучения, или отклонить запрос с сообщением «в документе это не указано». В документе это указано. Конвейер просто не проверил.

9d1ed4f1b0589def8bc13e2692ce2d13
Указатель мыши завис в воздухе во время второго прохода, который приводит к отображению раздела 4.2 – изображение предоставлено автором.

Цена заключается в скрытом нарушении цепочки аудита. Пользователю сообщают, что система основывается на корпусе данных, но когда ссылки не разрешаются, ответ сводится к рассуждениям на основе априорных данных. Именно этого и должен был предотвратить четырехступенчатый контракт. Хуже того, этот сбой незаметен извне: ответ в любом случае выглядит логично, а цитируемый фрагмент охватывает ту часть, где упоминается Раздел 4.2, а не сам раздел. Рецензент, кликнув на цитируемую ссылку, натыкается на предложение «см. Раздел 4.2» и уверенный ответ рядом с ним. Цепочка доказательств обрывается на шаг раньше.

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

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

4. Поколение: момент, когда цепочка аудита обрывается.

Генерация завершается с ошибкой, когда кирпич рассматривается как вызов API, возвращающий строку. Повторяются две схемы: отправка необработанной строки LLM без флага, схемы и аудита (ловушка 9) и доверие к утверждению LLM «не найдено» без внешнего подтверждения отсутствия (ловушка 10). Решение заключается в типизированном ответе, связанном с программными проверками, к которым модель не имеет доступа.

4.1 Подводная лодка 9: Нет флага, нет схемы, нет аудита. Только текст.

Полученный фрагмент текста поступает в командную строку, LLM возвращает строку, и система передает эту строку пользователю. В производственных версиях RAG-файлов это делается ежедневно. Ключевым моментом является вызов API.

8b28d42224040b69c2a9cc11d461f7b0
Обычная строка против типизированного объекта с флагами, тегами и полями аудита — изображение от автора.

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

Структурированные выходные данные ( response_format от OpenAI, использование инструментов Anthropic, Pydantic AI) частично закрывают этот вопрос. Типизированный ответ с полями answer_found и quote указывает, на чём, по мнению модели, она основывалась. Однако они не закрывают саму оценку модели. Значение «confidence»: 0,95 означает одинаковую уверенность независимо от того, реальна цитата или выдумана. Тот же человек, который читал отрывок, и оценивает ответ.

Эскалация представляет собой программную проверку, к которой модель не имеет доступа. Проверка с помощью регулярных выражений, чтобы убедиться, что цитируемая цитата встречается дословно в цитируемом фрагменте текста. Проверка покрытия множества для ответов на перечисление (вопрос запрашивает четыре исключения, схема возвращает четыре, каждая запись соответствует отдельному фрагменту в отрывке). Проверка типа значения ответа (ответ должен быть Duration , модель вернула «около месяца»). Каждая проверка — это вердикт, на основании которого диспетчер обрабатывает запрос. Модель заполняет схему; верификатор решает, отправлять ли запрос.

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

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

4.2 Ошибка 10: «Не в блоках» — это не «не в корпусе».

Ошибка второго поколения заключается в доверии к LLM, когда он выдает сообщение «не найдено». Поиск редко бывает пустым: при использовании эмбеддингов алгоритм cosine top-k всегда что-то возвращает, поэтому LLM получает несколько фрагментов и решает, содержится ли в них ответ. Если ответ отрицательный, конвейер отправляет пользователю answer_found=False . Система просто делегирует проверку тому же блоку, который считывал фрагменты.

f5870362d20f392577810077aa4ca780
Отсутствует ли «не найдено» в базе данных LLM по сравнению с доказанным отсутствием по всему корпусу – изображение предоставлено автором.

В LLM «не найдено» означает «нет в этих фрагментах». Это не означает «нет в этом корпусе». Модель увидела k лучших фрагментов, а не документ и не остальную часть архива. За уверенным отказом скрываются два режима сбоя: ответ был в k лучших фрагментах, и модель его пропустила (ошибка LLM), или ответ был в другом месте корпуса, и поиск его пропустил (пропуск поиска). Пользователь читает «в документе не указано» и предполагает, что корпус проверен. Это не так.

Решение заключается в том, чтобы подкрепить сообщение «не найдено» детерминированным доказательством отсутствия. Экспертный словарь ключевых слов, каждый термин и каждый тщательно подобранный синоним для концепции вопроса, выполняется как буквальный поиск подстроки по всему корпусу, а не по извлеченным фрагментам. Ноль совпадений, и система сообщает «нет в этом корпусе» с надежным журналом аудита. По крайней мере одно совпадение, но LLM все равно говорит «нет», поиск не удался, и оркестратор запускает второй проход по страницам, где появились ключевые слова. Ключевые слова доказывают отсутствие; векторные представления — нет. Решение использует блоки, на которые уже указывалось в статье: экспертный словарь из «Подводной башни 5» и поиск ключевых слов из «Подводной башни 6».

5. Чего следует ожидать от второй части

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

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

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

6. Источники и дополнительная литература

Другие статьи из этой серии:

  • Введение к серии статей о системе Document Intelligence: разделение на четыре части, которое реализуется в рамках вышеупомянутых контрактов.
  • Базовая модель Enterprise RAG: от PDF-файла до выделенного ответа, минимальный четырехэтапный конвейер от начала до конца для одного PDF-файла.
  • Эмбеддинги — это не магия: предсказуемые режимы отказов при извлечении RAG-данных, измеренная форма ловушек 7 и 8 с примерами решения.
  • Переранжировщики тоже не волшебство: когда кросс-кодировщикный слой оправдывает затраты, статья о параметре переранжировщика, которую автор, открывающий мета-ловушку, указывает как пустую трату времени при неисправном парсере.
  • RAG — это не машинное обучение, и инструментарий машинного обучения решает не ту проблему, — такова редакционная статья, объясняющая, почему ни одна из десяти вышеперечисленных ловушек не является проблемой поиска гиперпараметров.
  • От регулярных выражений до моделей компьютерного зрения: какой метод RAG подходит для какой задачи, пошаговая карта методов анализа, определяющих три основные проблемы синтаксического анализа.

Внешние ссылки:

  • Гао и др., Точный поиск с нулевым количеством примеров без меток релевантности, ACL 2023. Оригинальная статья HyDE. В пункте 5 объясняется, почему этот метод работает (гипотетический пример, сгенерированный LLM, содержит ключевые слова, которые были бы в реальном ответе), и утверждается, что детерминированным эквивалентом является экспертный словарь.
  • Anthropic, Введение в контекстный поиск, сентябрь 2024 г. Подход к сегментации текста с добавлением контекста, сгенерированного LLM, смежный с «Ловушкой 3». Серия решает проблему деконтекстуализации с помощью структурированных метаданных, а не сгенерированных LLM фрагментов текста.
  • Антропное, быстрое кэширование с помощью Клода. Рычаг ценообразования, который меняет расчеты Pitfall 2 при 90%-ном снижении скорости чтения из кэша, не переворачивая его полностью.
  • Pinecone Learn, стратегии сегментации текста для приложений LLM. В эталонном исследовании сегментации текста с использованием матрицы «точность против насыщенности» (Pitfall 3) утверждается, что текст находится внутри фрейма, который extract_text() уже исказила.
  • LlamaIndex, Создание высокопроизводительных RAG-приложений для производства. Указывает на разделенные блоки для шаблона поиска и синтеза, используя ту же идею, что и в «Ловушке 7», где в качестве опорных точек используется контекст.
  • Лю, преподаватель: Структурированные выходные данные для LLM. Библиотека типизированных выходных данных Pydantic и аргумент «схема как контракт». Прямая поддержка противодействия Pydantic против словаря в ловушке 4 и типизированного ответа в ловушке 9.
  • Захария, Хаттаб и др., Переход от моделей к составным системам искусственного интеллекта, BAIR 2024. Академическая основа для четырехкомпонентной архитектуры, предполагаемой в данной статье.

Кежан Ши Посмотреть все Кежан Ши

Источник: towardsdatascience.com

Оцените материал:

Читайте также
Архив рубрики ~Лента новостей~ Автоматизация процесса разработки Архив рубрики ~Лента новостей~ ФБР построило собственную копию небольшого городка, чтобы имитировать реальные кибератаки. Архив рубрики ~Лента новостей~ Получите доступ к моделям OpenAI и Codex через ваше облачное соглашение с Oracle | OpenAI Архив рубрики ~Лента новостей~ Самая опасная ошибка AI‑агента — не плохой код Архив рубрики ~Лента новостей~ В иске, поданном во Флориде, утверждается о неправомерном аресте после ошибки в распознавании лиц с помощью искусственного интеллекта. Архив рубрики ~Лента новостей~ Компания Anthropic блокирует публичный доступ ко всем играм Claude Fable 5 и Mythos 5 в соответствии с распоряжением правительства США — что следует предпринять предприятиям? Архив рубрики ~Лента новостей~ В просочившемся документе Microsoft рассказывает, как заставить людей «пристраститься» к ее искусственному интеллекту Архив рубрики ~Лента новостей~ Кнопка есть у всех. Вкуса нет почти ни у кого — и теперь это видно Архив рубрики ~Лента новостей~ Влияние ИИ на кибербезопасность: MITRE ATLAS и новый ландшафт угроз Архив рубрики ~Лента новостей~ Моноклональные антитела защитили мышцы при лечении агонистом рецептора ГПП-1. Ингибирование миостатина снизило потерю мышечной массы Архив рубрики ~Лента новостей~ Oracle предупреждает об уязвимости в системе безопасности, которую хакеры использовали для взлома более чем 100 компаний. Новости робототехники Вера в немецких роботов вышла за пределы ЕС Архив рубрики ~Коротко из Telegram~ Математики объявили войну ИИ-хайпу Более 150 ведущих мировых математиков опубликовали… Архив рубрики ~Коротко из Telegram~ Siri переезжает в Spotlight и получает доступ к файлам Apple… Архив рубрики ~Лента новостей~ Автоматизация процесса разработки Архив рубрики ~Лента новостей~ ФБР построило собственную копию небольшого городка, чтобы имитировать реальные кибератаки. Архив рубрики ~Лента новостей~ Получите доступ к моделям OpenAI и Codex через ваше облачное соглашение с Oracle | OpenAI Архив рубрики ~Лента новостей~ Самая опасная ошибка AI‑агента — не плохой код Архив рубрики ~Лента новостей~ В иске, поданном во Флориде, утверждается о неправомерном аресте после ошибки в распознавании лиц с помощью искусственного интеллекта. Архив рубрики ~Лента новостей~ Компания Anthropic блокирует публичный доступ ко всем играм Claude Fable 5 и Mythos 5 в соответствии с распоряжением правительства США — что следует предпринять предприятиям? Архив рубрики ~Лента новостей~ В просочившемся документе Microsoft рассказывает, как заставить людей «пристраститься» к ее искусственному интеллекту Архив рубрики ~Лента новостей~ Кнопка есть у всех. Вкуса нет почти ни у кого — и теперь это видно Архив рубрики ~Лента новостей~ Влияние ИИ на кибербезопасность: MITRE ATLAS и новый ландшафт угроз Архив рубрики ~Лента новостей~ Моноклональные антитела защитили мышцы при лечении агонистом рецептора ГПП-1. Ингибирование миостатина снизило потерю мышечной массы Архив рубрики ~Лента новостей~ Oracle предупреждает об уязвимости в системе безопасности, которую хакеры использовали для взлома более чем 100 компаний. Новости робототехники Вера в немецких роботов вышла за пределы ЕС Архив рубрики ~Коротко из Telegram~ Математики объявили войну ИИ-хайпу Более 150 ведущих мировых математиков опубликовали… Архив рубрики ~Коротко из Telegram~ Siri переезжает в Spotlight и получает доступ к файлам Apple…

Оставить комментарий