РозробкаSenior

RAG-архітектура

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

Два конвеєри
Індексація і запит
Більшість збоїв
Пошук, а не генерація
Контроль доступу
Належить індексу

Два конвеєри, а не одна функція

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

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

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

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

Виміряйте пошук, перш ніж судити відповідь

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

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

СимптомЗвичайна причинаДе лагодити
Упевнена відповідь із вигаданою деталлюФрагмент не знайшовся, а промпт не дав способу про це сказати.Пошук — плюс явне «відповідай лише з контексту, інакше скажи, що не знаєш».
Той документ, не те реченняФрагменти завеликі, тож потрібний рядок похований серед абзаців шуму.Менші структурні фрагменти й етап переранжування кандидатів.
Точні ідентифікатори не знаходятьсяВекторна схожість розмиває коди, артикули й імена в їхніх сусідів.Гібридний пошук: паралельно запустити пошук за ключовими словами й обʼєднати два списки.
Цитується застарілий або відкликаний вмістІндекс збудували один раз і ніколи не звіряли з видаленнями.Конвеєр індексації: інкрементні оновлення за ідентифікатором документа, разом із видаленнями.
Добрі відповіді, непридатна затримкаЗнайдено забагато фрагментів, і всі вони надіслані моделі.Шукати широко, переранжувати, а в промпт передавати лише кілька найкращих.

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

RAG, довгий контекст чи fine-tuning

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

Беріть RAG

  • Знання змінюються: щоденні ціни, заявки, документи, які редагують люди, що не розгортають код.
  • Відповіді мають посилатися на джерело, і користувач має мати змогу перевірити твердження.
  • Різні користувачі можуть бачити різні підмножини того самого корпусу.
  • Корпус значно більший за будь-який промпт, і більшість його недоречна для окремого питання.

Беріть fine-tuning

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

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

Як це виявляється в реальній поставці

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

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

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

Де це вироджується

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

Коли це застосовувати

Застосовуйте, коли

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

Уникайте, коли

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

Було корисно?

Поділіться з тим, хто працює над тією ж задачею.