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

Унутры вектарных баз для RAG: захоўванне фрагментаў, HNSW, IVF і пераранжаванне

Як вектарныя базы для RAG захоўваюць фрагменты, шукаюць сярод мільёнаў вектараў праз HNSW і IVF, дадаюць гібрыдны пошук і пераранжаванне і як параўнаць меры падабенства.

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

Крыніцы: Inside Vector Databases for RAG: From Chunk Storage to HNSW & IVF Search

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

Як выглядае зберажаны запіс

У сістэмах, пабудаваных на FAISS, Pinecone чы Weaviate, кожны запіс складаецца з трох элементаў: вектара эмбеддынгу, тэксту фрагмента і дзеякіх метададзэнняў.

{
        "embedding": [0.123, 0.456, ...],
        "text": "Transformer models are powerful...",
        "metadata": {
        "doc_id": "doc1",
        "page": 5
        }
}

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

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

Як пошук застаецца швыткім

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

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

Рэальныя сістэмы выкарыстоўваюць апрыксіматыўны пошук найбліжэйшага суседа (ANN). Ідэя заключаецца у тым, спачатку зменшыць прастор пошуку, а потым пераглядаць толькі невялікі падскуп вектараў, прыймаючы незначную втрату точнасці зарады значнага прышвартавання швальнасці. ANN рэалізуецца за дапамогою спецыялізаваных структура індэксаў. Напрыклад, FAISS апускае індэксы такага роду, і там таксама ёсць HNSW і IVF.

HNSW — шаравая графіка

HNSW — гэта Hierarchical Navigable Small World. Гэта метод, апоўнены графамі, і Pinecone з Weaviate выкарыстоўваюць яго ў сваіх внутрашніх працэсах. Кожны вектар стае вузлом, а кожны вузел паў’язаны з сэроднімі суседамі. Пошук — гэта праход па гэтым графе.

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

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

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

У практыцы важлівыя два параметры:

  • M — гэта колькасць з’яўленняў на вузел. Большая значэнне M павышае рывень вярнага аднаходжэння, але выклікае большы вопыт і час стварэння.
  • efSearch — гэта колькі кандыдатацоў адкрываецца пад час запіту. Большая значэнне павышае рывень вярнага аднаходжэння, але за рахунак большай затрымкі.

Простаючы, M адпрацоўвае якосьць індэкса, тады як efSearch паказвае компрэсію між тачнасцю і шыроцю спрабоў пад час запітаў.

IVF, спачатку кластэруванне

IVF (інвертыраны індэкс файлаў) ўжываецца часта ў FAISS і выкорыстоўвае аблічча, зусім не падобныя да іншых. Ён не стварае графа. Уместа таго ён адбывае кластэруванне, агрупаваючы падобныя вектары і шукаючы толькі ў адпаведных групах. Лібры ў тым падабныя: кнігі сортаваны па катэгорыях, таму ніхто не скануе кожную полку.

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

Этыя два методы разніцяюцца па выкарыстоўванні памяці. IVF зберагае меншае колічэство з’ёднанняў, таму выкарыстоўвае менш памяці. HNSW зберагае граф з многама рэшткамі на кожны вузел, таму выкарыстоўвае больш памяці.

Дзе чысты вектарны пошук не падходзіць

Эмбеддынгі фіксуюць значэнне, кантэкст і канцэптуальную блізкасць. Яны менш эфектывны для точных ключоўых слоў, цяжэй індэксаваныя і выкарыстоўваныя для чыслаў і ідэнтыфікатораў. Прашучы «kafka error code 504», вектарны індэкс можа вернуць «kafka network issues» або «timeouts in distributed systems», працінуўшы дакумент, які насправды містыць код 504.

Сістэмы RAG у прымэтным выкарыстоўванні адпавядаюць на гэта за дапамогою гібрыднага пошуку, які спалюе семантычны пошук (эмбеддынгі плюс методы аналізу сэмантыкі, такія як HNSW або IVF) з пошукам па ключоўых словах для точных знаходак за дапамогою BM25. У тыповай архітэктурэ два віда пошуку адбываюцца на аднарозных сістэмах, а ўсе рэзультаты з’еднаюцца і пераранжуюцца.

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

Чы не значыць «гібрыдны» тое, што усё трэба зберагаць два разы?

За выкарыстоўвання зовнішней наладкі — так: тыя ж фрагменты дадзеных часта знаходзяцца як у вектарной базе дадзеных, так і ў двігуне ключоўых слоў, такім як Elasticsearch. Гэта робіцца намерна. Вектарная база збераглівае індэкс HNSW або IVF для семантычнай супарадненасці, тады як двігун ключоўых слоў збераглівае зворачны індэкс для точнага падбору. Кожны індэкс ствараецца для сваёй меты, таму гэта не ўздвойванне дадзеных.

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

Пераранжаванне топавых рэзультатаў

Багато інжынераў вырашаюць, што работа завершана, калі з базы дадзенаў вектараў атрыманы топ-K рэзультатаў. Аднак гэта не так. Шырокія рэзультаты ёсць толькі апрыксіматыўна рэлевантныя, іх парадак не ўсега правільны, а можа праўіцца прыгледзець дзеякія дробныя аспекты рэлевантнасці.

Возьмемо запіт "kafka error 504 fix". Топ-K можа вернуць "Kafka timeout issues", пасля чаго "Distributed system errors", а потым "Error code 504 gateway timeout". Трэці рэзультат павінен быць першым, але вектарная пашуковая сістэма не завжды можа гэта зробіць.

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

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

Прыклад кампактнага крос-энкодэра з LangChain:

"""Super-simple CrossEncoder reranking example.

Steps:
1. Define a query and a few short documents.
2. Build (query, doc) pairs.
3. Use a CrossEncoder to get a relevance score for each pair.
4. Print raw scores, then print documents sorted by score.
"""

from sentence_transformers import CrossEncoder


def main() -> None:
        # 1. Create model
model_name = "cross-encoder/ms-marco-MiniLM-L-6-v2"
print(f"Loading CrossEncoder model: {model_name}\n")
model = CrossEncoder(model_name)

    # 2. Query and documents
        query = "What is a vector database?"
documents = [
        "A vector database stores embeddings and allows similarity search.",
        "Relational databases store structured data in tables.",
        "FAISS is a library for efficient similarity search of vectors.",
        "Vector databases are used in AI applications like RAG.",
        ]

        # 3. Build (query, doc) pairs
pairs = [(query, doc) for doc in documents]

        # 4. Get scores
scores = model.predict(pairs)

print("Query:\n  " + query + "\n")
print("Raw scores (higher = more relevant):")
    for doc, score in zip(documents, scores):
print(f"  score={score:.4f}  |  doc={doc}")

    # 5. Sort by score (descending)
ranked = sorted(zip(documents, scores), key=lambda x: x[1], reverse=True)

print("\nDocuments sorted by cross-encoder score:\n")
    for rank, (doc, score) in enumerate(ranked, start=1):
print(f"Rank {rank}: score={score:.4f}")
print(f"  {doc}\n")


if __name__ == "__main__":
main()

Output
****************************************************
Query:
  What is a vector database?

Raw scores (higher = more relevant):
  score=8.4591  |  doc=A vector database stores embeddings and allows similarity search.
  score=-7.1590  |  doc=Relational databases store structured data in tables.
  score=1.0106  |  doc=FAISS is a library for efficient similarity search of vectors.
  score=7.0736  |  doc=Vector databases are used in AI applications like RAG.

Documents sorted by cross-encoder score:

Rank 1: score=8.4591
  A vector database stores embeddings and allows similarity search.

Rank 2: score=7.0736
  Vector databases are used in AI applications like RAG.

Rank 3: score=1.0106
  FAISS is a library for efficient similarity search of vectors.

Rank 4: score=-7.1590
  Relational databases store structured data in tables.

Апранак падобнасці

Якасць адзыскання даклэнае ад таго, як вычыляецца аблікавасць вектараў. Тры памеры пакрываюць практычна ўсё.

Падобнасць касіна вырахоўваецца на адной з галоў — куце межы двух вектараў, тыя кабальваюць у адным напрамку ўзяцца за высока падобныя, а працупакальныя — за абсалютна разныя, незалежна ад дужыны. Формула: cos(θ) = A·B / (‖A‖‖B‖). Для запытку „Kafka error 504“ дакумент пра „Раскрыцце памылак Kafka“ атрымае высокі бал (апошней 0,9), а дакумент пра „Індэксаванне базы дадзеных“ — нізкі (апошней 0,2). Гэты памер падходзіць для эмбедынгаў і ўжоўчы выбіраецца ў тэхнологіях RAG, адколькі важна значэнне, а не аблікавасць. Прабуйце: запытка = [1, 1], docA = [2, 2] і docB = [1, 0] — docA кабальвае у тым жа напрамку, чым запытка, таму яго касін коефіцыент будзе ідэальны, нават калі ўжо дужэйшы.

Скалярный дзеянак спалюе напрамленнае і велічыну вектараў, A·B = |A| × |B| × cos(θ). Вектары з большай велічынай сцанованы як болей значныя, а вектары, якія выказваюць аднойчы напрамленнае, сцанованы як болей супадзячыя.

Евклідава адзейнасць мерыя прамую адзейнасць межы двумя тачкамі. Большая адзейнасць значыць большы супад.

Як усе гэта работае

Хорашыя сістэмы RAG — гэта не проста база дадзэння вектараў, прыўязаная да LLM. Напрамленнае вектара ў яго эмбеддынгу несе значэнне, а велічына — сілу сігналу. FAISS, Pinecone і Weaviate выкарыстоўваюць алгорытмы HNSW і IVF для шырокамасштабнага пошуку. Пасля чаго якасць залежыць ад кальколькі дадатковых рашэнняў:

  • атрыбутаваць дакументы адзін за аднім, ўтрымліваючы кантэкст
  • выкарыстоўваць гібрыдны пошук для падтрымкі семантычных і ключавых слов
  • пераранжаваць рэзультаты за дапамогою крос-кодэра або LLM
  • Запісвацьце ўпорныя запросы, каб кераваць модэлем і зменшыць галюцынаціі
  • Настроіць прагрызы top-K і значэнні балавання
  • Усі этапы выглядаюць так: даны, разбіўка на часткі, імбеддынг, індэксаванне, выкарыстоўванне даных, перыяркаванне, стварэнне запросаў, LLM, адпаведзь.