Порэшчанне RAG, vectorless RAG і GraphRAG
Класычны RAG на векторах, лексыкальнае адзысканне без вектораў і GraphRAG: разбіянне на часткі, эмбеддынгі, BM25, графы з кальцамі і супэрвакту, а таксама калі кожны падход ўзьме сябе за прызначэнне.
Як сучасныя мовы-моделі даюць адказы на пытанні, якія ніколі не былі ў матэрыялах для трэніравання.
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 неабходна планаваць практыку перапрыбутків выкарыстоўвання дакументаў, частковых апдэйтаў графа і перыяснення структуры, калі дакументы змінююцца. Для агентскага спосабу знаходжэння інфармацыі трэба планаваць ліміты на выкарыстоўвання інструментаў і правілы тайма-ауту, каб цікавасці модэлі не прывелі да выкарыстоўвання всіх токенаў за адну запытку.
Ніякі з эых заўвешчэнняў не ёсць прыгожымі. Яны являюцься разлікам межы дыяграмы і системы, якая вытрымае месць рэальнага трафіку.