Галоўная / Артыкулы

За межамі касінуснага падабенства: пяць тэхнік пошуку для RAG

Касінус, BM25, гібрыдны RRF, пераранжаванне крос-энкодэрам і MMR з кодам, кампрамісамі і спосабам выбраць тэхніку пошуку для RAG, пачынаючы з запытаў.

Выдавец: REACTAPP.TOP10 хв чытання2236 слоў

Крыніцы: **Beyond Cosine Similarity: The 5 RAG Retrieval Techniques That Actually Move the Needle**

Две фразы — «кіцка сядзела на кілімку» і «коцячая тварына відпочывала на кіліме» — не маюць жодніх спільніх слоў, проце мадэль на основі ембеддынгу оцінюе іх схожысць у 0,85. Саме так формуецца рэпутація косінусовоі схожосты, і саме тут зазвічай закінчуюцца більшысць навчальніх матэрыалів з RAG: показуюць косінус, вставляюць урывок і перэходзяць далі.

collection.query(query_embeddings=embedding, n_results=5)

Гэты падход працюе. Ён таксама ўскладнівае адна з пяці тэхнік выкарыстоўвання дадзеных, кожная з якіх створаная для рашэння разных тыпаў задач. Апошлівасць на косайну самае по сабе значыць, што цэлыя катагорыі запітоў не функцыонуюць, не даючы жадных памылак, а корыстувачы проста атрымляюць некарэктныя адпаведзі. Цікава тое, што на самай працэ ўзвешвае косайна, дзе яя не працюе, а таксама чатыры іншыя тэхнікі, плюс спосаб выбору той, якая трэба выкарыстоўваць.

Што узвешвае косайна

Мадэль эмбедынгу ператварае тэкст у вектор — спіс сотняў або тысяч цяжэй. Тэксты, якія маюць падобны значэнне, становяцца векторамі, якія накіраваны ў адной напрамоўцы. Косайная схожасць параганяе куточак, які роздзеляе два векторы, а не ўжо тое, насколькі яны адстаюць адзін ад другога.

Гэтае і ёсць ключовая мысль. Адна-рэчэнневыя фразы і цэлыя параграфы можу мець адно і тое ж значэнне. Калі ўжо ўсі іх векторы накіраваны ў адной напрамоўцы, косайна паказвае высокі рэйтынг. Дыяметр, які выражаецца ў велічыне вектора, являе сабою шум, а напрамоўка — значэнне.

Тыповыя рэзультаты выглядаюць так:

Пара Рэзультат
"Кацка сядзела на калошку" і "Кацкія тварынкі відпачывалі на калядроце" 0.85
"Як працюе адзінаковасць?" і "Пяшчыце механізм трансфармера" 0.79
"Язык программавання Python" і "Python – відэнасць змеяў" 0.38
"Я люблю ранній кафе" і ">Тэорыя квантовага заплетання" 0.03

Першыя радкі паказваюць, чаму косайны ёсць такім эфектывым. Няма спакульнаваных слоў, рэзультат – 0.85. Мадэль выучыла, што "кацка" і "кацкія тварынкі" знаходзяцца ў блізкіх частках сэмантычнага прастору, і косайны ўловівае гэта без жаднага падабрання ключоўых слоў.

Чаму не евклідава адзінаковасць

Явным альтэрнатыўным варыянтам ёсць евклідава адстань – гэта буквальна адступенне між двума вектарамі. Проблема ў тым, што калі дакумент перапісаць дзесяць разоў, яго вектар стане у дзесяць разоў большым, таму ён будзе вазіцца далёка ад перваснага, хоць за сэнсам нічога не змянілася. Косайны ўсё гэта ігнаруе; значыць, мае значэння толькі напрамак.

Паведамленне пра рэйтынгі

Рэйтынгі на аднойчыну не ёсць універсальнымі. Значэнне 0,7 ад мадэлі all-MiniLM-L6-v2 – гэта іншы сігнал, чым значэнне 0,7 ад мадэлі text-embedding-3-large, таму што кожная мадэль мае свой простор укладання даных з сваёй ўласной ўтрамбованасцю. Налагоджуйце порогі рэйтынга на своем наборэ дадзеных для ацэнкі, і не копіюйце цыфры з інструкцый, дзе вікорыстоўвалася іншая мадэль.

Аналагія з фестывалем для тых, хто не інжынер

Перш чым пераходзіць да коду, створыце у свайму разуме мадэль пяці тэхнік. Вы знаходзіцеся на музычным фестывале і шукаеце друга сярод натовпу, у вас ёсць тры стратэгіі для гэтага.

  • Па направленні (косінус). Вы оба пагадзіліся стаяць спінаймо да сцэны. Аднакова направленні значыць аднаго і таго ж чалавека, незалежна ад таго, на якай адстані вы стоіце. Важлівы кут, кім вы паказуеце, а адстань межа вамі — ні.
  • Па іменнай таблічцы (пошук за ключоўым словам, BM25). Вы крычыце: «Хто-небудзь зваецца Алекс?» Гэта працуе ідэальна, калі іменна таблічка цэлком збігаецца, але не знаходзіць усіх Алексісаў, Алаў чы Сэнды, якія ёсць аднам і тым жа чалавекамі пад іншымі назвамі.
  • Па выглядзе і іменнай таблічцы (гібрыдны метод). Вы пераканаліваеце і адно, і другое. Тыя, хто паспадзялае па обох крытэрыях, выходзяць на першае месца, а тыя, хто паспадзялае толькі па аднам, таксама застаюцца зазначанымі. Гэта дае найшырэе пакрыцце.

Урок, які большасць інструкцый прыховвае: жадны адзін метод не можа знайсці ўсіх. Выбраная вам тэхніка вялічыць, якія адпаведзі і якія людзі вы назаўсёды працінаваеце.

Пяць тэхнік, по адной

1. Падобнасць косінуса, стандартны варыянт

Што яна рабіць. Поручае сэмантычныя напрамленні вектара запіту і дакумента.

Калі яе вжываць. Калі запіты ў фармаце нейтральнай мовы і не трэба точных тэрмінаў: загальныя сістэмы RAG, адпаведзенні на запытанні ў дакументах, будзь-што, дзе ўжываецца многа парафразавання.

Дзе яна не працуе. У разе буквальных страк. Код продукту, номер рахунку або імя чалавека, якія ледзь з’явіліся ў даных для навчання, можу цалкам зламаць работу методу косінуса. Вектары "GPT-4o" і "GPT-4" можу быць настолькі блізкі, што ствараюць шум заместа сігналу.

У кодзе:

collection.query(
    query_embeddings=query_embedding,
    n_results=5
)

Компрасамент. Значэнне мае прыорытэт над точным формулюваннем. Гэта шырока метода, якая ўзятая, досыць точная і не выклікае додатковых налаштаванняў.

2. Пошук за ключоўымі словамі BM25 – інструмент тачнасці

Што ён робіць. Оцінюе дакументы за тым, як часта ў іх з’являюцца слова запіту, з урахоўваннем таго, насколькі часта гэтыя слова зустрэчаюцца ў всім корпусе. Ён не вікорыстоўвае эмбеддынгі, толькі підрахунакі.

Калі яго вжываць. Калі запіт залежыць ад точнага ідэнтыфікатора, які павінен падходзіць сімвол за сімволам, напрыклад, номера рахунку-фактуры, назвы мадэлі з датай выходу або рэферэнса CVE.

Што ён не бачыць. Жаднага значэння. Слова „Feline“ не будуць падходзіць да дакументаў, у якіх напісана „cat“. Сінонімы і парафразы для яго невідомы.

Значны рэзультат. У адзінага невялікага праекту, створанага з нуля, адыякраванне за дапамою BM25 паўз косайн прынясіла яго з 0,25 да 0,75. Прычына была ў тым, што запіты рэальных корыстувачаў мілелі точныя назвы продуктав, а косайн ператвараў іх у майжэ прыдатныя варыянты замест таго, каб знаходзіць іх безпосерэдня. Лепш спрацаваць з гэтым як з аднам пунктом дадзеных, а не як з універсальным показатлем.

Компрэсія. Точнасць адыякравання за цену абсолютнай відсутнасці семантычнай генералізацыі.

3. Гібрыдны пошук, стандарт у практыцы

Што ён робіць. Аднойчы выконвае алгорытмы косайн і BM25, а пасля з’еднае два спісы рангавання за дапамою методу Reciprocal Rank Fusion (RRF). Жадны з эўтах методаў сам по сабе не можа адпаведаць усім тыпам запытанняў.

Як яго выкорыстоўваць. Запыткі спалучаюць нейтаральную мову з конкрэтнымі тэрмінамі, што характэрна для практычна кожной сістэмы адрасавання запыткаў. Калі корыстнік запытаецца "якая політыка вярнення грошаў для замовлення №8821?", гэта часткова стосуецца сэмантычных элементаў (палітыка вярнення грошаў), а часткова — точнага падпадання під певны тэрмін (#8821).

Этап спалучэння. Кожная тэхніка выдае свойі власныя рангаваныя спіскі. Метод RRF прызначае кожнаму дакументу бал на адной засадзе — яго пазіцыі ў кожным з спісакоў, а самэй бал вырахоўваецца як 1/ (k плюс ранг), дзе k — сталяя вялічына, якая зазвычай дорэчвае 60, пасля чаго балы з усіх тэхнік сумуюцца. Дакументы, якія займаюць высокія месцы ў обох спісаках, паднімаюцца на верхню частку рангавання.

# Pseudocode for RRF merge
def rrf_score(rank, k=60):
    return 1 / (k + rank)
def merge_results(cosine_results, bm25_results):
    scores = {}
    for rank, doc in enumerate(cosine_results):
        scores[doc.id] = scores.get(doc.id, 0) + rrf_score(rank)
    for rank, doc in enumerate(bm25_results):
        scores[doc.id] = scores.get(doc.id, 0) + rrf_score(rank)
    return sorted(scores.items(), key=lambda x: x[1], reverse=True)

У AWS OpenSearch падтрымлівае гэта за сваёй прыродай: вы ствараеце гібрыдны запіт з параметрам ваго, і сістэма сама адмаховвае ўзаемную супрацоўку.

Компрэсія. Найлепшы загальны рэкал, але за цену прыблізна удвоўаных віткоў адшукання, што зазвычай ўзрабатваецца.

4. Пераранжаванне за дапамойкай крос-энкодэра

Што гэта робіць. Двухэтапны падход. На першым этапе адшукаюцца 20 лепшых кандыдатаў за дапамойкай косінусовага адшукання чы гібрыднага. На другім этапе кожны кандыдат разам з запітам падаецца ў крос-энкодэр, які ацэнюе ступень рэлевантнасі, разглядаючы іх адразу.

Калі яго вжываць. Калі лепшыя рэзультаты ўсё ж рэлевантныя, але у неправільнай парадзе, і тады важнейшая ёсць точнасць, а не час адпаведзі. Ён падходзіць для другага этапу, а не для першага праходжання.

Чаму два этапы? Крос-кодэр лепшая ацэнюе рэлевантнасць, чым косайн, але яго нельзя выкорыстоўваць для аналізу всей базы дадзеных. Дваццаць вызоў модэлю замест аднаго ёсць прыемлімым. Дзесяткі тысяч вызоў пад час запіту — ні.

from sentence_transformers import CrossEncoder
reranker = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')# Stage 1: retrieve candidates
candidates = collection.query(query_embeddings=embedding, n_results=20)# Stage 2: rerank
pairs = [(query, chunk) for chunk in candidates['documents'][0]]
scores = reranker.predict(pairs)
top_5 = sorted(zip(scores, candidates['documents'][0]), reverse=True)[:5]

Сур’ёзная паведамленне. Не выкорыстоўвайце метод пераранжавання як першы етап. Косцты затрымкі вельмі высокія, адколі вы заменяеце адну працэю з пошукам у эмбедынгу на дваццаць повных вычысленняў модэлю.

Компроміс. Найвышая тачнасць, але і найвышэйшыя вітраты, таму выкорыстоўвайце яго толькі як другі етап.

5. Максімальная маргінальная рэлевантнасць (MMR) для разнаўтныя

Што ён робіць. Компроміс між блізасцю да запіту і схожасцю з ужэ выбранымі фрагментамі. Кожны новы фрагмент павінен быць рэлевантным і не супадаць з тым, што ужо выбрана.

Калі яго выкорыстоўваць. Калі всі верхнія фрагменты гавораюць пра адно і тое ж, напрыклад, у разе шырокага пытання-падсумку, дзе кожны рэзультат павтарае адну факт.

Няжка лямбда.

  • lambda = 1.0 означае чыстую рэлевантнасць, такую ж, як у стандартнам косінусе
  • lambda = 0.0 означае чыстую разнароднасць, калі рэлевантнасць абсалютна ігнаруецца
  • lambda = 0.5 — гэта збалансаваная пачатковая точка для налаштавання
  • def mmr_select(query_embedding, candidates, lambda_param=0.5, k=5):
        selected = []
        remaining = list(candidates)
    
        while len(selected) < k and remaining:
            mmr_scores = []
            for doc in remaining:
                relevance = cosine_similarity(query_embedding, doc.embedding)
                if selected:
                    redundancy = max(cosine_similarity(doc.embedding, s.embedding)
                                    for s in selected)
                else:
                    redundancy = 0
                mmr_scores.append(lambda_param * relevance - (1 - lambda_param) * redundancy)
    
            best = remaining[mmr_scores.index(max(mmr_scores))]
            selected.append(best)
            remaining.remove(best)
    
        return selected
    

    Дзе гэта сяяе. Анотаціі, дослідніцькі запітання і будзь-які віпадкі, колі чытач хоча б побачыць огляд ідэй, а не глыбокі аналіз кожнай з іх.

    Компроміс. Гэта усувае зайвасць, але параметры мадэлі трэба налаштаваць.

    Выбір: нехай вялі вашы запіты

    Перш чым выбраць тэхніку, вывучыце 20 рэальных запітоў ад вашых фактычных корыстувачаў чы рэгіону. Гіпотэтычныя запіты не паслужаюць.

    • 80% чы больш — гэта звычная прыродна мова. Косайн — ваш стандартны выбар. Пачніце з яго, адколькі ён швырак і точны, і не вяршыць додатковых вімаг да інфраструктуры.
    • 30% чы больш — гэта запіты з точнымі тэрмінамі, кодамі, ID чы власнымі іменамі. Дадзіце праблему BM25. Калі вы пазначыце такі шаблон, гібрыдны пошук стане стандартам у працэйнай сіткі, таму рэалізаваць фюзыю RRF. Прырост точнасці зазвычай ўскораецца і будзе значным.
  • Сярод самых лепшых рэзультатаў ёсць рэлевантныя, але першы з іх ўзнікла слаба. Увесьце рэранкер на адной з другіх стадзій, які выбірае 20 кандыдатаў і залішае 5 найлепшых, а таксама пераканайцеся ў дадзенай затрымке пры выкананні задачы перш чым запускаць ў працэс.
  • Усі самыя лепшыя рэзультаты ўзніклі занадта схожыя. Дадаце MMR з значэннем 0,5: калі значэнне будзе бліжэй да 0, рэзультаты стануць разнаобразнейшымі, а калі — да 1, яны стануць рэлевантнейшымі. Гэта неабходна для стварэння апусоў і адпаведзення на запытанні дакладнага характэру.
  • Пользоватары ставяць нечыстае запытанні, якія ледзь опісваюць тое, чаго яны хочуць. Спачатку спробуйце HyDE (Hypothetical Document Embeddings). Створыце вымышленую адпаведзь на запытанне, увесьце яе ў фармат эмбедынга і выкарыстоўваце яе для пошуку заместо самага запытання. Вымышленая адпаведзь знаходзіцца бліжэй да ідэальнага дакумента, чым сама запытанне.
  • Стварэнне сістэмы RAG для працы ў AWS. OpenSearch з аблікованым гібрыдным спосабам запітаў (BM25 плюс ўжоцьплненыя вектары, з’еднанне RRF) і Cohere Rerank як другі этап — гэта комплекс, які выбірае большасць команд.
  • Што не паказваюць навучальныя матэрыялы

    Тэхнікі можа суперсцягвацца, а не проста дапамагаць адна другой. У аднай з эксперыментаў наслаенне расшырэння запітаў, якое генеруе калькі варыянтов запіта і здзейсняе пошук для кожнага з яных, на гібрыдны спосаб пошуку здавалася безальтэрнатыўным рашэнням. Большы захопленне даных апавяралася як прычына лепшых рэзультатаў. Рэйтынгі знізіліся з 0,807 да 0,702. Больша калькі сігналаў пошуку як раз такі ж лёгка паўышаюць шум, як і справжнія сігналы, а дадатковыя варыянты запітаў прыводзілі да выкарыстоўвання суседніх, але некорэктных фрагментаў. Гібрыдны спосаб пошуку вучылася працаваць добра, а расшырэння запітаў толькі стварала перасьцягвання. Неабходна дадаваць кожную тэхніку по чыргу, меркаваць кожную окрэма прытым, перш чым яе наслаяваць, і памятаць, што парадак мае значэнне, адтолькі ўсё, што ў самастойнасці можа быць корыстным, у суме можа нашкодзіць.

    Скалярный добутак — гэта не косынус. Дзеяныя базы вектараў за значчык прызначання часта выбіраюць скалярны добутак. Яны збігаюцца толькі тады, калі вектары ўнітарна нормалізаваны. Калі ваша мадэль эмбедынга не нормалізуе свой выхід, рэйтынгі, апранутыя за скалярным добуткам, нельга пораўняваць між рознымі запытамі, таму значэнне 0.9 для адного запыту і 0.9 для другога маюць разныя значэння. Пераканайцеся, што ваша база дадзеных фактычна вырахоўвае. Напрыклад, ChromaDB зазвычай опісываецца як сістэма, якая выкарыстоўвае іншы стандартны показнік, чым Qdrant, таму пераканайцеся ў гэтым у актуальной документацыі.

    Запіты вялікага значэння наказуюць выбор тэхнікі, а не дасягі. Інжынеры часта выдзейліваюць час на класыфікацыю своіх корпусаў як тэхнічных чыя-то размовных, дзейнасных чыя-то короткіх. Гэта мае значэнне для разбівання на часткі. Для выбору тэхнікі пошуку аналіз запытаў мае ўжо большое значэнне. Тэхнічны корпус, які шукаюць за дапамою запытаў на натуральнай мове, ёсць прыкладам косінусовай задачы, а той жа корпус, які шукаюць па номерах частак, — гібрыдной задачы.

    Полны працэс

    Ось шаровая структура, якая выступае у багатых сістэмах RAG:

    User Query
        ↓
    [Optional: HyDE — if query is vague]
        ↓
    Stage 1 Retrieval: Hybrid (Cosine + BM25 → RRF merge)
        → Top 20 candidates
        ↓
    [Optional: Cross-encoder reranking — if precision matters]
        → Top 5 candidates
        ↓
    [Optional: MMR — if results are redundant]
        → Final k candidates
        ↓
    LLM Context Assembly + Generation
    

    Не кожная сістэма патрэбуе кожны слой. Пачніце з косайна, дадзіце гібрыдны метод, калі з’являюцца працэзледжанні пад час точнага адпаведнення, дадзіце метод пераранжавання, калі парадак некарэктны, і дадзіце MMR, калі рэзультаты павтараюцца. Аналізавайце на кожным кроку, таму што тое, што дапамагае адной сістэме, можа нашкодзіць іншай.

    Найважлівейшая цыфра

    У звятынах эксперыментаў з адзысканнем дакументаў часта пазірае разлік у рэкале межы пошуку толькі на адзысканні косайна і гібрыднага пошуку на сумешаных наборах запыткаў; у аднам маленькім праекце гэты разлік вырас з 0,25 да 0,75. Калі гэта хоць часткова стосуецца вашых дадзенняў, гэта значыць, што прыбліжна у тры разы больш правільных адказоў доходзіць да мовнага модэлю пры напісанні кожнага слова, без якой-лібо працы з формулюванням запыткаў, без апдэйта модэлю і без перабудовы інфраструктуры. Усё зводзіцца да правільнага выбору методу адзыскання.