Порэшчанне RAG, vectorless RAG і GraphRAG
Класычны RAG на векторах, безвектарныя методы пошуку лексыкі і GraphRAG: разбіўка на часткі, імбеддынгі, BM25 і графы з кальцыямі, а таксама калі кожны з іх ўзгодзіцца для выканання.
Крыніцы: RAG, Vectorless RAG & GraphRAG
Як сучасныя мовы-мадэлі даюць адказы на пытанні, якія ніколі не былі ў матэрыялах для трэніравання.
RAG за адной фразай
Retrieval Augmented Generation — гэта самае тое, што означае гэтая абракатура. Спачатку запошчаецца матэрыял, які стосуецца пытання корыстніка. Потым мадэль пішае адказ, выкорыстоўваючы гэты матэрыял і сам праграматычны запрос. Парадакс: спачатку запошчэнне, потым стварэнне адказу.
За што взагалі гэта робіцца?
Мадэлі ведаюць толькі тое, што было ў матэрыялах, якія вікорыстоўваліся для ўжоў. Усё інша для яных недоступна.
Уявіце сабе рэдкую кнігу з 3 000 стороніц, якая практычна не з’являецца ў Інтэрнэце і ніколі не была часткай жадного корпусу для трэніравання. Калі запытаць мадэль пра яе, вы отрымаеце порожнія адказы. Калі выдаць яе скраперам, таксама не будзе рэзультатаў — няма нічога, што можна было б выкарыстоўваць для збору інфармацыі.
RAG заполняе гэты прыем. Завантажыце PDF у практычную схему обработкі. У момент запіту выберыце найболей рэлевантныя часткі тэксту і прыўяжыце іх як кантэкст. Задача мадэлі скарочваецца да таго, каб яна адпавядала на запіты на базе гэтага тэксту, выкарыстоўваючы свае мовныя навыкі.
Няма патрэбы ў додатковай наладцы. Дастатнька толькі правільны кантэкст у правы момент.
Структура практычной схемы
Спачатку выконуецца індэксаванне, а яно пачынаецца з разбівання тэксту на часткі.
Стратэгіі разбівання
PDF з тыячамі стороніц не падходзіць для зберагання ў векторным сховішчы як адна цэлая частка. Яго трэба разбіць, каб кожная частка магла быць зберажана і запрашвана окрэма.
Пашырэныя способы разбівання:
Па стороніцы. Адна стораніца → адна частка (3,000 стороніц → 3,000 частак). Гэты спосаб падходзіць, калі трэба тачныя і точныя рэзультаты.
Параграф за параграфам. Болей шчыльныя разломы на межах параграфаў. Можа здавацца, што рэзультаты быстрэйшыя, але размеры сільна разніцяюцца (200 токенаў пры 2 000). Неравныя дужыні спрычынаюць неравныя эмбеддынгі і таямна пашкоджаюць працэс выкарыстоўвання інформацыі.
Фіксаваныя вікна. Сталая колькасць токенаў — часта 512 — незалежна ад таго, дзе адбываецца разлом. Аднаковыя размеры даюць болей порównаныя эмбеддынгі. Калі няма вядомасцей, большасць команд выбірае гэты варыянт.
from langchain_text_splitters import CharacterTextSplitter
from langchain_core.documents import Document
def perform_fixed_size_chunking(document, chunk_size=1000, chunk_overlap=200😞
"""
Performs fixed-size chunking on a document with specified overlap.
Args:
document (str): The text document to process
chunk_size (int): The target size of each chunk in characters
chunk_overlap (int): The number of characters of overlap between chunks
Returns:
list: The chunked documents with metadata
"""
# Create the text splitter with optimal parameters
text_splitter = CharacterTextSplitter(
separator="\n\n",
chunk_size=chunk_size,
chunk_overlap=chunk_overlap,
length_function=len
)
# Split the text into chunks
chunks = text_splitter.split_text(document)
print(f"Document split into {len(chunks)} chunks")
# Convert to Document objects with metadata
documents = []
for i, chunk in enumerate(chunks):
doc = Document(
page_content=chunk,
metadata={
"chunk_id": i,
"total_chunks": len(chunks),
"chunk_size": len(chunk),
"chunk_type": "fixed-size"
}
)
documents.append(doc)
return documents
# Example usage
if __name__ == "__main__":
# Create the dummy document
document = create_dummy_document()
# Process with fixed-size chunking
chunked_docs = perform_fixed_size_chunking(
document,
chunk_size=1000,
chunk_overlap=200
)
# Display results
print("\n----- CHUNKING RESULTS -----")
print(f"Total chunks: {len(chunked_docs)}")
# Print an example chunk
print("\n----- EXAMPLE CHUNK -----")
middle_chunk_idx = len(chunked_docs) // 2
example_chunk = chunked_docs[middle_chunk_idx]
print(f"Chunk {middle_chunk_idx} content ({len(example_chunk.page_content)} characters):")
print("-" * 40)
print(example_chunk.page_content)
print("-" * 40)
print(f"Metadata: {example_chunk.metadata}")
# For integration with Databricks Vector Search
print("\nThese documents are ready for embedding and storage in Databricks Vector Search")
print("Example next steps:")
print("1. Create embeddings using the Databricks embedding endpoint")
print("2. Store documents and embeddings in Delta table")
print("3. Create Vector Search index for retrieval")
Эмбеддынгі
Эмбеддынг ператварае тэкст (слова, пазлок, сторанку) у ўпакоўнены вектар высокай размернасці, які кодуе значэнне, так што схожыя ідэі збіраюцца ў адну групу.
Чатыры фазы ў RAG
- Сторона корпусу. Эмбеддаваць кожны фрагмент; зберагчы індэкс + вектар.
- Сторона запіту. Эмбеддаваць запыт корыстніка, каб запыт меў семантычны «відблеск».
- Пошук. Шукаць у базе найбліжэйшыя суседзі — зазвычай за дапамогою косай схожасці.
Дзе знаходзяцца вектары
Гэта спецыялізаваны хранальнік для эмбедынгаў, а не загальны база дадзення з вазносамі чы аб’ектамі. AlloyDB, Pinecone і Qdrant ўжоўцуюцца часта; багатыя команды выкарыстоўваюць pgvector у PostgreSQL.
Дзе мае труднасці стандартны падход RAG з вектарамі
- Разрэзы можаць ігнараваць значэнне. Спадзяючыся фрагменты можаць быць рознымі; большая перакрыценасць іноды дапамагае, але не ўсуне проблему.
- Падабенасць можа не выяўіць парафразы — «продажы зменіліся» і «компанія ў спадзе» можаць не знаходзіцца поблізу ў вектарнай прасторы.
- Факты з кальцэйнарамі ламаюцца, калі прычына і наследкі знаходзяцца ў разных частках і адзін толькі фрагмент адзначаецца.
- Стварэнне, храненне, індэксаванне і паўторна індэксаванне эмбедынгаў ёсць дорогія працэсы.
Таксама: база дадзейнаў вектароў не ёсць сінонімам RAG. Гэта адна з можлівасцей ахавання дадзэнняў. Vectorless RAG застаецца пры методзе «зямліць, а потым стварыць», але відмовляецца ад пошуку за дапамой вектарных інкорпорацыяў.
Чаму адмовіцца ад вектароў? Высокія затраты на стварэнне/перэіндэксаванне інкорпорацыяў, слабкае падтрыманне точнага адпаведнення для ID/чысла/кодаў адзінакоў, а таксама патрэбна дадатковая інфраструктура для ўпрабавання.
Vectorless — гэта група методаў, а не ўніверсальны рэшання:
- Лексычны пошук. BM25, Postgres
tsvector, Elasticsearch — точныя тэрміны лепшая падходзяць для SKU, цытатаў і ліній журналу, чым нечыткія семантычныя аналагіі.
from rank_bm25 import BM25Okapi
def vectorless_retrieve(query, corpus_chunks, top_k=3):
"""
Lexical retrieval over raw text chunks - no embeddings, no vector DB.
"""
tokenized_corpus = [chunk.lower().split() for chunk in corpus_chunks]
bm25 = BM25Okapi(tokenized_corpus)
tokenized_query = query.lower().split()
scores = bm25.get_scores(tokenized_query)
ranked = sorted(zip(corpus_chunks, scores), key=lambda x: x[1], reverse=True)
return [chunk for chunk, score in ranked[:top_k]]
- Ахаванне дадзэнняў за дапамой агентаў/інструментаў. Не існуе прадзейнаўвання; модэль сама шукае, вызывае API пошуку або ачынае неабходныя раздзелы за патрэбай, так як кодавальны агент перашукае рэпазітарый. Пошук здзейснюецца у рэальны час на адной падставе логічных выводаў.
Абмежэнні без вектораў
Ключоўыя словы яшчэ не можаць адобразіць парафразы — інодзе нават гэта гірш, чым з векторамі. Агентныя цыклы адбываюцца з затрымкамі і падвышаннем колькасці токэнаў за запіт. Вялікія корпусы яшчэ продавалююць сабе добра створаны вектарны індэкс. Методы без вектораў часта ўспяваюць у малых/серэдніх масштабах або калі точнасць важлівей, чым нечыткасць.
GraphRAG
Класычны RAG можа памыляцца, спаяваючы прычыну з наследкам у разных частках тэксту. Методы без вектораў заменяюць векторы на ключоўыя словы або большы кантэкст. Жадны з гэтых падходаў не адображае, як ідэі з’яўляюцца ў зв’язку. Graph RAG нацэлёваеся на падрыхтаванне гэтага прыему.
У зяместо “каторы частка ўжо бліжэй?” запытайце “якія зв’язкі межу цымі панямі?” Адказам будзе граф знанняў.
Індэксаванне — пашырэнне графа
Спачатку прыхіліцеся не да частак/вбудованых элементаў. Працавайце з дакументам за дапамогою модэлю, які выдэляе энтытэты і зв’язкі. Расход: вузлы і рэшткі.
У той довгай тэарэтычнай кнізе вы маглі б павінаваць такія вузлы, як Маркс, Энгельс, “Капітал”, “Комуністычны маніфест”, адзыноценнае значэнне, дыялектычны матэрыялізм, а таксама рэшткі на кшталт “апрацаваў”, “спільна напісаў”, “з’явіў-паняму”.
Энтытэты стаюць вузламі; зв’язкі — рэшткамі. Вы картаваеце значэнне, а не раздзеляеце сторанкі.
Агрупавайце ўзаемна зв’язаныя вузлы ў спільнатыя групы (метод Лейдэна ёсць популярны), а потым падсумавайце кожную групу за дапамогою ўтрымнаго працавання модэлю.
Работайце на двух роўнях:
- Вузлы — для конкрэтных фактов і прымітных зв’язкаў
- Спільнатыя групы — для тэмаў і падсумкаў
Спецыфічныя запіты → вузлы. Шырокія запіты на “асалевыя ідэі” → статыстыкі спальні. Адна індэксацыя, два спосабу адказвання.
Запіты — праходжэнне па графе
Запіт: “Хто быў саавтаром з Марксам, і шта яны напісалі разам?”
Класычны RAG стаўкаецца: саавтарство знаходзіцца ў аднай часткі, а працы — за сотні сторанак, і трэба спадзявацца, што эмбеддынгі будуць супагоджаны.
RAG па графе праходзіць так:
- Выявляе Маркса як анкер
- Завантажвае вузел і рэшты Маркса
- Ідзе па лініі “саавтар” → Энгельс
- Ідзе па лініі “апрацаваны Энгельсам” → Маніфест, Станаўленне працавячага класу, адносныя працы
Направленыя рэшты сохраняюць адносіны целымі. Прычына і наследкі, якія класычны RAG раздзеляе, стаюць з’ўязанымі вузламі. Такі мнагахоповы шаблон складна чыста адрабатваць як для базовага, так і для безвектарнага RAG.
Аб’еднвае вузлы, рэшты і статыстыкі спальні ў кантэкст; генеруе як зазвычай.
from graphrag import GraphRAGPipeline
# Indexing — runs once
pipeline = GraphRAGPipeline(llm="claude-3", graph_store="neo4j")
pipeline.index(documents=["book.pdf"])
# Under the hood: entity extraction → graph build → community detection → summaries
# Querying
result = pipeline.query(
"Who co-wrote with Marx and what did they write together?",
mode="global" # uses community summaries for broad questions
# mode="local" # uses node-level traversal for specific facts
)
print(result.answer)
print(result.sources) # returns actual nodes + edges used, fully traceable
mode – гэта не косметычны элемент. Разныя рэалізацыі (вклучаючы апэнтажы з відкрытым кодам Microsoft) прадстаўляюць глобальныя і локальныя варыянты, таму што гэта разныя стратэгіі.
Косты GraphRAG
Экстракцыя ўскладнена і дорога. Патрэбна чытанне всіго дакумента; дужыя кнігі спалююць токены; неявныя апыланні (“як было обгаворваўце”) можаць ніколі не стаць рэшткамі графа.
Якосьць графа вялічы якосьць рэзультата. Некалічная экстракцыя → некалічны граф → некалічнае выкарыстоўванне інфармацыі. Часта для паспакоўкі трэба чытаць усё занова, што ёсць проблемай пад большымі масамі дакументаў.
У практыцы выбіраюць спосаб выкарыстоўвання інфармацыі па тыпу запіту, а не прымушваюць застосаваць однаковы падход да кожнага запіту.
Падсумак: для семантычнага пошуку вжывайце класычны RAG, калі трэба точнасць або меншы рэсурс – без вектараў, а калі ключовым элементам ёсць стосункі межаў – Graph RAG.
Выбір стылю выкарыстоўвання інфармацыі без догм
Корыстныя крокі для прыняцьця рашэння выглядаюць так.
Пачаткавайце з класычнага вектарнага RAG, калі ваш корпус велікі, мовы сільна разніцяюцца, і зазвычай вам патрэбны толькі апрыксіматыўныя семантычныя суседзі. З самага пачатку інвестыруйце ў якасць фрагментавання і працэсы апдэйта вектарных прэдставленняў; гэтыя факторы найбольш вплываюць на якасць.
Выбірайце тэхнікі без вектараў, калі точныя ідэнтыфікаторы важлівей за парафраз, калі корпус дастаткова маленькі для лексычнага пошуку або аналізу дужога кантэксту, або калі вы не хочаце падпісвацца на вітраты, зв’язаныя з інфраструктурой вектарных прэдставленняў. BM25 і падобныя методы не ёсць «старомоднымі» — гэтыя інструменты падходзяць для SKU, цітатаў і стрэнгаў з адзінакамі.
Выбірайце Graph RAG, калі пытанне пра продукт мае рэляцыйны характэр: хто быў на зв’язку з кім, якая ідэя была запропантована якім концэптом, яяе спільнота падсумавала тую тэму. Чакайце вышых вітатаў на індэксаванне і ставіце якасць выкарыстоўвання дадзеных у прыорытэтны ранг.
Багатыя команды выбіраюць гібрыдны падход: спачатку лексычная обработка, потым вектарная, а для часткі домэнаў з кальцамі — граф. Галоўная мета — не выбраць адзін конкрэтны падход, а паспрацаваць знаходзічык так, каб ён падходзіў да рэальных формаў неяксамоце.
Практычныя прыметкі, якія працаваючыя дэманстрацыі прахоўваюць
Часавы план перындэксацыі мае важнае значэнне. Застарэлыя эмбедынгі таямна паслабляюць карыснасць вектарнага RAG, нават калі сама модэль не змянюецца. Настройкі перакрыцча маюць значэнне, калі суседзяючыя фрагменты маюць аднаковы значэнне. Фільтры метаданых неабходны, калі абліканты не павінны бачыць чужыя фрагменты. Наборы для ацэнкі маюць значэнне, калі вы стверджуеце, што метод «лепшы», але няма ярлыкаў.
Для Graph RAG неабходна планаваць практыку перапрыбутків выкарыстоўвання дакументаў, частковых апдэйтаў графа і перыяснення структуры, калі дакументы змінююцца. Для агентскага спосабу знаходжэння інфармацыі трэба планаваць ліміты на выкарыстоўвання інструментаў і правілы тайма-ауту, каб цікавасці модэлі не прывелі да выкарыстоўвання всіх токенаў за адну запытку.
Ніякі з эых заўвешчэнняў не ёсць прыгожымі. Яны являюцься разлікам межы дыяграмы і сістэмы, якая вытрымае месць рэальнага трафіку.