Zpět na domů

RAG systémy v Pythonu: principy a implementace

RAG systémy rozšiřují schopnosti jazykových modelů externími daty a snižují halucinace. Článek vysvětluje principy chunkingu, retrievalu a generování. Ukazuje minimální implementaci v Pythonu s langchain, Chroma a Wikipedia.

RAG systémy: Jak implementovat v Pythonu krok za krokem
Advertisement 728x90

RAG systémy: principy fungování a minimální implementace v Pythonu

Jazykové modely jsou omezené daty, na kterých byly trénovány: jejich znalosti jsou statické, neodrážejí aktuální události a trpí halucinacemi – generováním vymyšlených faktů. Kontextové okno tento problém ještě zhoršuje, protože při překročení limitu odstraňuje část vstupních dat. Retrieval-Augmented Generation (RAG) tento problém řeší tím, že během generování získává relevantní kontext z externích zdrojů, snižuje chyby a poskytuje odkazy na zdroje.

RAG propojuje dokumenty, databáze nebo repozitáře kódu, díky čemuž jsou odpovědi ověřitelné a aktuální. To je klíčové pro specializované domény, kde model nebyl trénován.

Rozdělování dokumentů na chunk

Rozdělování na chunk (chunking) znamená rozdělení textů na fragmenty (chunky) pro indexování. LLM pracuje s omezeným množstvím chunků, takže kvalita rozdělení určuje dostupnost faktů.

Google AdInline article slot

Velké chunky přidávají šum, zvyšují náklady a snižují přesnost vyhledávání. Malé chunky ztrácí kontext a oddělují související prvky. Strategie:

  • Pevná délka znaků nebo tokenů.
  • Sémantické hranice (odstavce, nadpisy).
  • Překrytí (overlap) pro zachování spojitosti.

Parametry se ladí empiricky podle korpusu a dotazů.

Fáze fungování RAG

RAG zahrnuje předzpracování, retrieval a generování:

Google AdInline article slot
  • Indexování: chunky se převádějí na vektory a ukládají do vektorové databáze.
  • Retrieval: dotaz se vektorizuje, získávají se top-relevantní chunky.
  • Augmentace: výsledky se řadí, čistí od duplicit a šumu.
  • Generování: kontext se přidá k dotazu pro LLM.

V základním Naive RAG je zpracování minimální. Advanced RAG přidává přeformulování dotazu a reranking. Modular RAG používá moduly: směrování, fúzi výsledků.

Srovnání s doladěním

RAG rozšiřuje přístup k znalostem bez změny modelu, na rozdíl od doladění (fine-tuning), které vyžaduje data a zdroje. Prompt engineering optimalizuje dotazy, ale nepřidává externí data.

| Přístup | Výhody | Nevýhody |

Google AdInline article slot

|--------|-------------|------------|

| RAG | Aktuálnost, nízké náklady, citace | Závisí na kvalitě retrievalu |

| Doladění | Hluboká adaptace | Náročnost na zdroje, zastaralost |

RAG je ideální pro dynamická data, doladění pro statické domény.

Minimální RAG pipeline: praxe

Implementujeme Naive RAG v Pythonu s Wikipedií (500 článků) a Qwen2.5-3B-Instruct. Používáme langchain, Chroma, sentence-transformers.

Krok 1: Načtení a chunking

import torch
from datasets import load_dataset
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_core.documents import Document

device = "cuda" if torch.cuda.is_available() else "cpu"

dataset = load_dataset(
    "wikimedia/wikipedia",
    "20231101.ru",
    split="train[:500]"
)

documents = [
    Document(
        page_content=row["text"],
        metadata={"title": row["title"]}
    )
    for row in dataset
]

splitter = RecursiveCharacterTextSplitter(
    chunk_size=800,
    chunk_overlap=100
)

chunks = splitter.split_documents(documents)

print("Chunků:", len(chunks))

Získáme ~17892 chunků po 800 znacích s overlapem 100.

Krok 2: Vektorový index

from langchain_community.vectorstores import Chroma
from langchain_community.embeddings import HuggingFaceEmbeddings

embedding_model = HuggingFaceEmbeddings(
    model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
    model_kwargs={"device": device}
)

vectorstore = Chroma.from_documents(
    documents=chunks,
    embedding=embedding_model
)

Model multilingual MiniLM pro embeddingy, Chroma pro úložiště.

Krok 3: Retrieval

import textwrap

def search(query, k=3, width=80):
    results = vectorstore.similarity_search(query, k=k)

    for i, doc in enumerate(results, 1):
        print(f"\n--- Výsledek {i} ---")
        print("Nadpis:", doc.metadata["title"])
        print(textwrap.fill(doc.page_content[:1000], width))

search("Kdo je Puškin?")

Vrátí relevantní fragmenty z článků o Puškinovi.

Krok 4: Generování

Přidejte LLM pro generování na základě retrieved chunků (kód vynechán pro stručnost, kompletní ve zdroji).

Co je důležité

  • RAG snižuje halucinace díky externímu kontextu, přičemž model zůstává nezměněn.
  • Kvalita závisí na chunkingu a embeddingech: laděte podle domény.
  • Naive RAG pro start, Advanced/Modular pro produkci.
  • Integrace s langchain usnadňuje prototypování.
  • Testujte na reálných korpusech pro optimalizaci.

— Editorial Team

Advertisement 728x90

Číst dál