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

Як виправити ситуацію, коли система RAG не повертає жодних результатів.

Система RAG, яка не повертає жодних результатів, відлагоджувана етап за етапом: отримання даних, пороги оцінки, фільтри, переписування запитів, гібридний пошук, переранжування та альтернативні рішення.

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

Джерела: **Part II — When RAG Returns Nothing**

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

Пошук може зазнати невдач у багатьох місцях

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

1. Почніть з індексування та ембеддингів

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

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

2. Перегляньте пороги, значення оцінок та фільтри

Агресивні пороги оцінок є поширеною причиною відсутності результатів. Оцінки вбудовування — це не відсотки впевненості, а корисний діапазон змінюється залежно від моделі, метрики відстані, даних та бази даних векторів. Під час дебаггінгу візьміть топ-10 або топ-20 кандидатів без будь-яких порогів та перегляньте їхні первинні оцінки:

results = vector_store.search(query_embedding, top_k=10)
for r in results:
    print(r.score, r.metadata.get('source'))

Потім перевірте, у якому напрямку працюють оцінки. Деякі API повертають косинусову схожість, де чим вище значення, тим краще. Інші повертають косинусову або евклідову відстань, де чим нижче значення, тим краще. Використання неправильного способу порівняння тихо відкидає ваші найкращі кандидати та залишає слабкі. Як правило, не встановлюйте умови порогу, поки не підтвердите конвенцію оцінювання бази даних та не переглянете реальні розподіли оцінок від репрезентативних запитів.

Фільтри можуть видаляти хороші результати

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

3. Перегляд переписування запиту та якості фрагментів

Переписування запиту може допомогти у пошуку, але водночас може призвести до видалення саме того терміна, який зробив запит пошуковим. Уявіть собі, що хтось запитує, як скинути налаштування X500, а пристрій для переписування запитів перетворює це на «відновити стандартні налаштування для серії X». Якщо посібник має називатися «Скидання налаштувань X500», то власні формулювання користувача, ймовірно, краще з ним збігатимуться. Записуйте як оригінальний, так і переписаний запит та тестуйте кожен з них. Для точних ідентифікаторів, кодів помилок, назв продуктів та параметрів API зберігайте буквальні формулювання, навіть якщо решта запиту нормалізована.

Розділення на частини також зазнає невдач подібним чином. Заголовок на кшталт „Скидання налаштувань маршрутизатора X500“ не повинен бути відокремлений від інструкцій під ним. Розділяйте текст відповідно до структури документа, щоб заголовок, його абзаци, пункти списку та навколишній контекст залишалися цілими. Оптимальний розмір частини залежить від обсягу роботи, проте розумний початковий діапазон становить приблизно 500–1 000 токенів із невеликим перекриттям, після чого проводиться оцінка за реальними запитами.

Що вимірювати: візьміть невелику кількість міткованих запитів та зафіксуйте, чи з’являється очікуваний джерело серед результатів типу top-k. Цей тест, орієнтований на відтворення даних, краще за вибір розміру частин або порогів на основі інтуїції.

4. Поєднання лексичного та векторного пошуку

Векторний пошук є ефективним, коли користувач та документ формулюють одну ідею по-різному. Лексичний пошук, такий як BM25, є корисним, коли важливі точні токени. Оскільки складні запити рідко належать до одного типу, у продакшн-системах часто використовуються обидва підходи. BM25 зазвичай краще підходить для таких речей, як коди помилок (наприклад, ERR-XK-1042), SKU, номери рахунків-фактур, назви продуктів, назви класів, ключі конфігурації та назви параметрів API. Векторний пошук знаходить схожі за концепцією результати, тоді як BM25 гарантує, що точні лексичні дані не будуть пропущені. Типова схема спочатку знаходить широкий набір кандидатів, а потім застосовує більш потужний алгоритм для підвищення точності.

5. Знаходьте широкий набір результатів, а потім переорієнтуйте їх

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

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

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

Фузія та усунення дублікатів

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

6. Розширення запиту з запланованим резервним варіантом

Люди та документи рідко мають спільний словниковий запас. Той, хто пише «Я не можу увійти», може потребувати сторінок під назвами «Невдача автентифікації», «Усунення проблем з входом» чи «Доступ до облікового запису». Система розширення генерує кілька альтернативних пошуків, виконує їх усі, а потім усуває дублікати та переурочує результати. Контролюйте цей процес: не чіпайте іменовані ентитети та точні ідентифікатори, уникайте створення великої кількості майже ідентичних запитів та обмежуйте кількість спроб, щоб одне складне питання не спричинило дорогого циклу обробки.

Розслабляйте лише те, що можна безпечно розслабити. Фільтри безпеки, належності користувачів та дозволів ніколи не є необов’язковими та завжди залишаються увімкненими. Щось на кшталт необов’язкової категорії документів, вузького діапазону дат чи додаткових тегів можна послабити, якщо це дозволяють правила вашого додатку. Ось проста послідовність:

docs = retrieve(query)
if not useful(docs): docs = retrieve(expand(query), hybrid=True)
if not useful(docs): return ask_for_clarification_or_no_answer()

Порожній результат проти неправильного пошуку

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

7. Більш стійка архітектура продакшну

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

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

Рівень довіри визначає наступний крок

Якщо довіра достатня, найкраще ранговані докази надсилаються до LLM. Якщо довіра слабка, система може розширити або переформулювати запит, спробувати знову або поставити користувачеві уточнювальне запитання. Це краще, ніж завжди давати відповідь, адже модель чітко отримує інформацію про те, що доказів недостатньо для обґрунтованої відповіді.

Не включайте безпеку у цикл спроб

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

8. Зробити процес отримання даних прозорим

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

log({
  'query': query, 'rewritten': rewritten_query, 'filters': filters,
  'candidate_count': len(raw_results), 'scores': scores,
  'selected_chunk_ids': selected_ids, 'fallback': fallback_stage
})

Розумний порядок відлагодження

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

  1. Спочатку перевірка процесу отримання даних: перевірте кількість документів, оброблений текст, кількість частин, збережені вектори та кілька записів, які, на вашу думку, мають існувати.
  2. Далі — пряме отримання результатів: надішліть початковий запит без усіх додаткових фільтрів та порогів, а потім прочитайте топ-k результатів та їхні оцінки.
  3. Поступово повертайте фільтри, щоб визначити саме той фільтр, який спричиняє порожні результати.
  4. Перевірте семантику оцінок: чи краще вищі чи нижчі значення, та чи застосовується якась нормалізація?
  5. Порівняйте початковий та переписаний запити, зберігаючи точні ідентифікатори, щоб з’ясувати, чи переписування допомагає чи шкодить точності пошуку.
  6. Оцініть гібридний підхід до пошуку та переранжування на основі набору запитів із мітками, перевіряючи, чи з’являються очікувані джерела у списку топ-k та топ-n після переранжування.
  7. Протестуйте механізм резервного варіанту, створюючи порожні та слабкі результати, щоб переконатися, що система надає пояснення або відмовляє, а не створює хибну інформацію.

Що вимірювати

Якість відповіді сама по собі не дає достатньо інформації про процес пошуку. Відстежуйте показник recall@k (чи потрапив очікуваний джерело до списку кандидатів?), точність після переранжування, частку порожніх результатів, частку використання резервного варіанту, час відповіді та частку запитів, які потребували доповнення чи уточнення. Розбивайте ці показники за типом запитів — наприклад, семантичні запити проти точних ідентифікаторів — а також за користувачем, мовою та колекцією документів, оскільки загальні середні значення можуть приховувати проблемні сегменти.

Не звинувачуйте спочатку LLM

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

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

  • RAG під час обробки десяти мільйонів документів: конвеєри отримання даних, маршрутизатори, агенти та метрики оцінки — Конвеєр отримання даних з часом виконання менше 200 мс із використанням фільтрів SQL, гібридного пошуку та переранжування, а також маршрутизації запитів, оркестрації агентів, метрик оцінки та скрипту потоку Qdrant.
  • Практичні поради: покращення продуктивності RAG — Частина 2: HyDE (гіпотетичний документ) — Покрокове пояснення до Практичних порад: покращення продуктивності RAG — Частина 2: HyDE (гіпотетичний документ), включаючи контракти, перевірки та шаблони коду для команд, які використовують цю модель.