Головна / Статті

Вісім найкращих практик RAG, протестованих на 746 сторінках посібників.

Які популярні оптимізації RAG витримали тестування на трьох посібниках з продуктом: очищення тексту за допомогою м’яких розділових знаків, розміркування блоків інформації, маршрутизація, пороги ескалації та переранжування.

Видавець: REACTAPP.TOP9 хв читання2005 слів

Джерела: I Measured Every RAG “Best Practice” on 746 Pages of Product Manuals. Only Four Survived.

Бот підтримки, створений на основі трьох справжніх PDF-файлів — 408-сторінкового посібника власника електромобіля, 329-сторінкового телепрограмного календаря та 9-сторінкової інформаційної брошури з бездротовою мишею, — став полігоном для тестування восьми популярних оптимізацій типу RAG. Правило було суворим: ніщо не приймалося до використання, якщо показники цього корпусу даних, оцінені за допомогою маркованого ключа відповідей, не свідчили про їх ефективність. Література та звички не враховувалися.

Результатом стало підвищення точності з 72% до 89%, водночас кількість токенів запиту на один запит зменшилася з 14 до 57%. Це було досягнуто завдяки чотирьом змінам, а не восьми. Дві з відхиленої ідей навіть завдали шкоди, а одна з реалізованих оптимізацій взагалі так і не була виконана. Усе дослідження коштувало приблизно 0,015 долара у вигляді викликів API.

Ось як справи склалися з кожною ідеєю. Найціннішим елементом у цьому списку взагалі не є жодна техніка типу RAG.

Баг, більший за будь-який гіперпараметр

Перш ніж налаштовувати процес пошуку, перевірте, що насправді потрапило до індексу. Усі підтверджують, що PDF було розпарсовано. Краще запитання — у якому стані знаходиться текст.

Вільний цикл дає відповідь на це:

SOFT = "­"    # U+00AD, the soft hyphen
for manual in manuals:
    print(manual.name, extract(manual).count(SOFT))

У посібнику з автомобілем було знайдено 2,272 слова.

„М’який дефіс“ — це вказівка верстальника для програми форматування: розділити слово тут, якщо рядок закінчується. Читач PDF дотримується цієї вказівки та приховує його, тож очі його не бачать, але засіб з вилучення тексту передає його у первинному вигляді. На сторінці відображається ціле слово, тоді як у індексі з’являються такі рядки, як ve, м’який дефіс, новий рядок, hicle.

У тому посібнику 999 різних слів було розділено навпіл, серед них неодноразово найважливіше іменник у будь-якому посібнику з автомобілем. Слово „Vehicle“ з’являлося 1,486 разів як ціле слово, тоді як мало з’явитися 1,580 разів. 94 випадки залишилися недоступними для пошуку.

Це одночасно пошкоджує кожен шлях пошуку. Пошук за ключовими словами знаходить буквальні рядки, і „hicle“ не є „vehicle“, тож не нараховується жодних балів. Пошук за векторами працює гірше, ніж очікувалося, оскільки моделі ембеддингу розбивають текст на частини, і фрагмент на кшталт „hicle“ розпадається на беззмістовні частини. Навіть у випадку удачного знаходження у запиті потрапляє спотворений контекст.

Виправлення полягає у одному рядку, але поруч з ним є підступ. Вирівняний текст також розривається на справжніх дефісах. Слово „cus-tomer“, яке розірване, слід знову об’єднати у „customer“, але „toll-free“ має залишатися з дефісом, і щоб їх розрізнити, потрібен словник. Таких слів було 95, і всі вони залишилися розірваними, причому кількість була записана. Відома прогалина у 95 слів — це зовсім інший артефакт, ніж тихий припущення, яке тихо пошкоджує корпус даних. Жодний розмір частин не може відновити слово, якого індекс ніколи не вважав словом.

Найкращий розмір частин — це підступ

Більші фрагменти містять більше контексту, тому відповідають більшій кількості запитань, але водночас вони постійно включають зайвий нерелевантний текст до кожного запиту. Існує перекриття, щоб відповідь, розташована на межі, не розрізалася навпіл.

Було протестовано дев’ять конфігурацій проти ключа відповідей. Точність можна виміряти без жодних витрат, тоді як саме витрати є наслідком її використання.

Перекриття ніколи не заслуговувало на своє місце, хоча не так, як може здатися при першому читанні. При 700 символах відсутність перекриття дала збільшення на 11 балів, що здається критичним, але при перевірці іншої групи даних: при 1800 символах рівень перекриття 0, 100 та 200 усі дали точно 89%. Одне порівняння свідчить про те, що перекриття є дорогим, а інше — що воно нічого не впливає.

Причиною обох результатів є статистика, яка майже не з’являлась на сторінці. У кожній конфігурації, навіть у найменшій, кожна відповідь повністю поміщалась в один блок, і жодна з них не була обрізана біля межі. Накладання дозволяло уникнути проблеми, якої бракує в цьому корпусі, тому його виміряне значення коливалося від нуля до від’ємних значень. Перевірка того, наскільки часто відповіді дійсно перетинають межу, має передувати сплаті цього платежу.

Потім з’являється пастка. Найкращий результат — 89% — було досягнуто при 1400 символах та 200 одиницях накладання. Щоб отримати його, потрібно надсилати 1 283 токени за запит замість 750, що на 71% більше за кожен запит протягом усього терміну служби продукту. При 18 запитаннях у тесті 89% означає 16 правильних відповідей, а 83% — 15. Найкраща конфігурація перевершує найдешевшу рівно на одне запитання.

Отже, переможця не слід визначати автоматично. Варто обрати найдешевшу конфігурацію, чий рейтинг не можна відрізнити від рейтингу переможця, що тут означало будь-яку різницю до 8 балів. За цим правилом шість із дев’яти конфігурацій зрівнялися, і перемогла найдешевша з них. Точність підвищилась з 72% до 83%, крім того, витрати на обробку даних зменшилися — це був перший випадок, коли проект отримав „безкоштовну їжу“, досягнутий завдяки відмові від оптимізації вимірюваної метрики.

Фільтр, який коштував 22 бали

Корпус даних охоплює три продукти. Питання щодо миші не має підстав шукати інформацію у 408-сторінковому посібнику з автомобіля, адже два інші документи лише підвищують ймовірність помилки. План полягав у тому, щоб виявити відповідний продукт та обмежити пошук лише цим посібником.

Це зробив класифікатор. Він правильно вибирав рішення у 78% випадків протягом менше ніж 4 мс без жодних витрат, що є значно кращим показником порівняно з пошуком у три рази більшого обсягу тексту. Проте точність знизилась на 22 бали.

Механізм проявився з неприємною повільністю. Неправильний фільтр не просто знижує ранг правильної відповіді — він її видаляє. Без фільтравання заплутаний пошук у всіх трьох посібниках все одно знаходить правильний уривок, можливо, на позиції 4 замість 1, і алгоритм переранжування може його врятувати. З фільтрацією неправильно сформульоване запитання шукає у неправильному документі, і правильний уривок не потрапляє у низький ранг, оскільки його немає у наборі кандидатів.

Класифікатор, який правильно робить висновки у 78% випадків, тому не призводить до незначного погіршення якості. Він встановлює жорсткий ліміт у 78% для всіх наступних етапів, незалежно від того, наскільки хорошим є решта процесу обробки даних.

Рішенням є не більш точний класифікатор, а можливість утриматися від рішення: застосовувати фільтр лише тоді, коли є впевненість, а шукати всі варіанти — коли оцінки двох провідних продуктів близькі. У запитанні на кшталт «Як під’єднати його через Bluetooth?» слово «його» має велике значення, і класифікатор такий самий невпевнений, як і будь-хто інший.

Або взагалі пропустити процес інференції

Найдешевший роутер — це простий дроп-даун. Для такого інструменту задати питання про те, який саме продукт мається на увазі, коштує лише одного натискання, яке користувач і так часто робить, відкриваючи чат зі сторінки допомоги продукту. Це миттєво усуває неоднозначність, яку класифікатор може лише здогадуватися, а фільтр завжди працює правильно.

Цифри є точними. Класифікатор неправильно спрямував 4 з 18 запитань. Пошук без фільтра знайшов 15 відповідей, а з фільтром — 11, причому кожна неправильна спрямованість перетворювала успішний пошук на невдалий. Якщо усунути ці неправильні спрямування, точність залишиться незмінною, а також буде досягнута точність, про яку обіцяв фільтр.

Оптимізація, яка так і не була виконана

Цю частину можна було б спокуситися видалити заради зовнішнього вигляду.

План полягав у тому, щоб відповідати за допомогою дешевої моделі об’ємом 20 мільярдів параметрів, коли результати пошуку здавалися надійними, а переходити до моделі об’ємом 120 мільярдів параметрів, коли це не було так. Неправильні відповіді зазвичай збираються там, де результати пошуку є нестабільними, а алгоритм переупорядкування вже генерує оцінку надійності, тож додаткові витрати немає.

Поріг було встановлено на 0.0, що здавалося принциповим рішенням: крос-енкодер генерує логіт, sigmoid(0) дорівнює 0.5, а зниження значень нижче нуля означає посилення ефекту, коли верхній фрагмент є менш імовірним, ніж релевантним. Однак реальний розподіл показував іншу картину – спостережувані максимальні значення становили мінімум 3.24, медіану 8.29 та максимум 10.00.

Поріг знаходився нижче найнижчого коли-небудь зафіксованого значення, тому він ніколи не спрацьовував, жодного разу. Політика посилення була ідентична використанню дешевої моделі завжди, плюс додаткові витрати у вигляді рядка в таблиці результатів, який нічого не вимірював, але виглядав як результат дослідження. Нульовий поріг – це не нейтральний стандарт; це твердження щодо розподілу, який ніхто не перевіряв. Кожен абсолютний поріг логіту має цю слабкість, адже розподіл змінюється, коли змінюється алгоритм ранжування чи корпус даних.

Рішенням було отримання цього числа шляхом обчислень. Необхідно запустити лише два кінцеві пункти — для ситуації «справжня», яка завжди є дешевою, та для ситуації «дорога», яка завжди є дорогою, записуючи оцінку, правильність та витрати кожного запиту. Кожен проміжний поріг тоді є повторним обробленням даних, вже збережених у пам’яті, без жодних додаткових викликів API та з повним переглядом усіх даних замість вибіркового.

Результат тестування приніс сюрприз: кожен поріг змінює лише вартість, а точність залишається незмінною. Діагностика показує причину. Із дванадцяти запитань вдалося відновити лише одне, що означає, що дешева модель зазнала невдачі, тоді як дорога — успіху. Це запитання отримало оцінку 10,00, що є максимумом у діапазоні, тоді як запитання, які дешева модель вже відповіла правильно, мали середнє значення 8,29. Єдиною невдачею, яку варто було б підвищити у пріоритеті, була та, щодо якої система була найбільш впевнена у відновленні, тому жодне правило, засноване на підвищенні пріоритету при невизначеності, не може виявити її на жодному порозі. Сигнал маршрутизації не може передбачити те, що мав передбачати.

З’явився ще й побічний ефект. Під час прямого виконання було зафіксовано 92%, проте повторний аналіз вже оплачених рядків дав прогноз 83%. Різниця не пов’язана з пороговими значеннями. Вона виникає через те, що алгоритм оцінювання LLM оцінює ідентичні відповіді по-різному під час другого проходження та уникає оголошення про приріст у 9 балів, який є лише шумом.

Зміна, яка принесла подвійну вигоду

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

Векторний пошук вставляє запитання та кожен фрагмент окремо, за допомогою моделі, яка ніколи не розглядає їх як пару. Крос-кодер сприймає пару як єдиний вхід та оцінює її безпосередньо, що робить процес набагато точнішим, але занадто повільним для обробки всього корпусу. Тому цей механізм дешево отримує 25 кандидатів, пересортує їх та залишає найкращі 4.

Рівень пригадування підвищився з 83% до 89%. Ще більш значущим є те, де опинилася відповідь. До переранжування правий фрагмент зазвичай займав друге чи третє місце, тому для безпеки відправляли п’ять фрагментів. Після цього він зазвичай опинявся на першому місці, і чотирьох фрагментів вже було достатньо. Якщо задовольнитися базовою точністю, можна скоротити кількість фрагментів до двох, що дозволяє зменшити кількість токенів на 57%.

Оскільки порядок покращується, менша кількість фрагментів досягає однакової точності, а саме токени запиту є об’єктом оплати. Ця зміна забезпечує вищу точність та водночас дає знижку. Її вартість становить 73 мс роботи локального процесора, на відміну від 1 252 мс для виклику LLM — різницю ніхто не помічає.

Що залишається незмінним

  • Перевірте вхідні дані перед тим, як використовувати механізм пошуку. Один простий цикл може або виявити проблеми, наприклад із дефісами, або підтвердити, що немає перешкод, що робить подальші дії безпечнішими.
  • Стандартні налаштування — це часто показники когось іншого або взагалі жодних показників. Коефіцієнт перекриття 100 ніколи не допомагав, а поріг 0,0 ніколи не спрацьовував, і в реальних умовах жоден з них не буде проявлятися. Єдиним симптомом може бути більша рахунок без пояснень.
  • Варто розглянути, як поводиться оптимізація у випадках помилок, а не лише частоту цих помилок. Фільтр, який пропускає 22% випадків, але лише переупорядковує результати, ще можна терпіти. Той же фільтр, який пропускає 22% випадків та робить відповідь недоступною, — ні.
  • Відхилена ідея — це також результат. Чотири ідеї, які не були впроваджені, — це ще чотири елементи без обслуговування, моніторингу, версіонування чи попереджень уночі.

Існує одне застереження. Ключ відповідей містить 18 перевірених пар запитання та відповіді, тож кожне запитання коштує 5,6 балів. Колапс маршрутизації на рівні 22 балів стосується чотирьох запитань, що достатньо для подальших дій. Результат перетину на рівні 11 балів стосується двох запитань, тож це у кращому разі лише напрямковий показник. Ключ відповідей, створений на основі власних даних команди, має мати пріоритет перед довірою до чужих цифр. Повний процес виконання займає приблизно п’ять секунд на процесорі ноутбука, причому існує жорсткий ліміт бюджету, який створює виняток замість того, щоб відображати цю цифру у рахунку-фактурі.

Пов’язана література

  • Практичні нотатки: Чому вашій RAG-пайплайн потрібен ре-ранкер (і як це зробити) — Детальний посібник з практичних нотаток: Чому вашій RAG-пайплайн потрібен ре-ранкер (і як це зробити): контракти, перевірки та готові фрагменти коду для команд, які використовують цю схему.