Krátké uvození #

V první části jsem RAG vysvětlil přes knihovníka který umí najít relevantní knihy a pasáže místo aby pokaždé pročítal celou knihovnu. Teď se podíváme co se za tím „rozumí významu" a „najde podobné" technicky skrývá. Bez programátorského žargonu zase nešlo, ale držím se principů, ne implementačních detailů.

Tři fáze RAG detailněji #

V první části jsem rozdělil RAG do tří fází: indexace, vyhledávání, generování odpovědi. Pojďme je rozebrat pořádně.

Fáze 1: indexace (jednorázová příprava dat)

Probíhá jednou, dlouho předtím než kdokoli položí první otázku. Obvykle v noci na pozadí. Skládá se z těchto kroků:

  1. Z dokumentů (PDF, Word, HTML, emaily, cokoli) se vytáhne čistý text
  2. Tenhle text se rozseká na menší kousky, takzvané chunky
  3. Každý chunk projde embedding modelem, který z něj udělá číselnou reprezentaci významu (vektor)
  4. Chunk samotný plus jeho vektor plus metadata se uloží do vektorové databáze

Když přibude nový dokument, prochází stejnou pipeline. Když se starý dokument změní, jeho chunky se musí přegenerovat. Indexace je z hlediska výpočetní náročnosti drahá, protože pro každý chunk se musí spustit embedding model, ale děje se jednorázově.

Fáze 2: retrieval (vyhledávání při každém dotazu)

Probíhá v reálném čase pokaždé když uživatel položí otázku.

  1. Otázka uživatele projde stejným embedding modelem jako dokumenty. To je klíčové, musí to být stejný model, jinak se vektory nedají porovnávat.
  2. Vznikne vektor otázky
  3. Vektorová databáze najde top-K chunků jejichž vektory jsou nejpodobnější vektoru otázky (typicky K = 5 až 20)
  4. Vrátí texty těchto chunků plus jejich metadata

Tahle fáze je rychlá, protože vektorová databáze je optimalizovaná na rychlé hledání nejbližších vektorů. Při milionu chunků trvá obvykle pod 100 milisekund.

Fáze 3: generation (sestavení odpovědi)

LLM dostane prompt který zhruba vypadá takhle:

Jsi asistent zákaznické podpory. Odpověz na otázku 
pouze na základě následujících úryvků z dokumentace.

Úryvky:
[chunk 1]
[chunk 2]
[chunk 3]
...

Otázka uživatele: Jak resetovat heslo?

Pokud odpověď v úryvcích není, řekni že nevíš. 
Cituj odkud informace bereš.

LLM zpracuje prompt a vygeneruje odpověď. Často s odkazy („podle dokumentu X, sekce Y..."). Klíčová instrukce je omezit LLM na to co mu dáte v úryvcích. Bez ní si LLM dolepí odpověď z toho co se naučil při tréninku, a tam je vysoké riziko nepřesnosti.

Embedding model, srdce celé operace #

Embedding model je samostatná neuronová síť specializovaná na jeden úkol: vzít text a vyrobit z něj vektor čísel který reprezentuje jeho význam.

Konkrétně: pošlete embedding modelu větu „Naše dodací lhůta je 5 pracovních dní." Vrátí vám něco co vypadá takhle (zkráceně):

[0.0234, -0.1521, 0.0876, 0.4521, -0.2103, ..., 0.0455]

Typicky 384 až 3072 čísel (podle modelu). Každý kus textu má svůj jedinečný vektor.

Klíčová vlastnost těchto vektorů: dva texty se podobným významem mají vektory které jsou v matematickém prostoru blízko sebe. Konkrétně:

  • „Naše dodací lhůta je 5 pracovních dní"
  • „Zboží doručujeme do týdne"

Tyhle dvě věty používají úplně jiná slova, ale jejich vektory budou matematicky velmi blízko, protože význam je podobný. Tohle je magie sémantického vyhledávání.

Naopak:

  • „Naše dodací lhůta je 5 pracovních dní"
  • „Modré auto stojí na parkovišti"

Tyhle dva vektory budou daleko od sebe.

Známé embedding modely:

  • text-embedding-3-small a text-embedding-3-large od OpenAI (placené přes API)
  • voyage-large-2 od Voyage AI
  • bge-large-en a bge-large-zh od BAAI (open source, dobré pro angličtinu a čínštinu)
  • multilingual-e5-large (open source, podporuje češtinu)
  • Cohere Embed v3

Pro češtinu pozor, ne všechny modely česky umí dobře. Multilingvální modely (E5, BGE-M3) jsou lepší volba než modely trénované primárně na angličtině.

Vektorová databáze a podobnost #

Vektorová databáze je databáze postavená na jediný úkol: rychle najít vektory které jsou podobné jinému vektoru.

Princip se jmenuje cosine similarity (kosinová podobnost). Lidsky řečeno: představte si vektor jako šipku ze středu souřadnicového systému. Dva vektory které směřují stejným směrem mají vysokou podobnost. Dva vektory které směřují opačnými směry mají nízkou. Délka šipek se přitom neřeší, záleží jen na úhlu mezi nimi.

V praxi se to projeví takhle. Vektorová databáze dostane vektor otázky a projede své uložené vektory. Pro každý spočítá kosinovou podobnost. Vrátí top-K s nejvyšší hodnotou.

Klíčový pojem je top-K: kolik výsledků chcete? Typické hodnoty:

  • K=5 pro úzké faktické dotazy
  • K=10 jako výchozí pro většinu RAG aplikací
  • K=20 když chcete víc kontextu, ale dražší pro LLM

Vyšší K znamená víc kontextu pro LLM, ale taky víc šumu a vyšší cenu (LLM platí za vstupní tokeny).

Známé vektorové databáze:

  • Pinecone, managed cloud, jednoduchý setup, drahý
  • Weaviate, open source plus cloud, bohaté možnosti
  • pgvector, rozšíření PostgreSQL, dobré pro firmy které už PostgreSQL používají
  • Chroma, lightweight, dobré pro prototypování
  • Qdrant, open source, výkonný, populární v ČR
  • Milvus, pro velká nasazení
  • Vectorize, Cloudflare, integrace s jejich Worker ekosystémem

Volba závisí na tom kolik máte vektorů, jakou cenu jste ochotni platit, a jestli chcete cloud nebo self-hosted.

Chunkovací strategie, jak sekat dokumenty #

Tady je první místo kde se rozhoduje o kvalitě celého systému. Špatné chunkování zničí i jinak dobrý RAG.

Chunk může být cokoli od jedné věty po několik stránek. Jak velký chunk je optimální? Záleží na typu dokumentu a typu otázek. Existuje pět hlavních strategií:

1. Fixed-size chunking

Nejjednodušší. Rozsekáš text na kusy o pevné velikosti, třeba 500 tokenů, s malým překryvem (overlap) mezi sousedy. Překryv je důležitý, protože myšlenka by se mohla lámat přesně na hraně chunků.

Chunk 1: tokeny 1-500
Chunk 2: tokeny 450-950
Chunk 3: tokeny 900-1400

Výhoda: triviální implementace, předvídatelné. Nevýhoda: seká napříč strukturou textu, uprostřed věty, uprostřed odstavce, uprostřed myšlenky. Pro produkční použití nedoporučuju.

2. Sentence / paragraph chunking

Sekáš po větách nebo odstavcích. Respektuje to strukturu textu. Chunky pak nejsou stejně velké, některý odstavec má dvě věty, jiný deset.

Výhoda: respektuje přirozené hranice textu. Nevýhoda: stále může lámat související myšlenky pokud jsou rozkresleny přes dva odstavce.

3. Semantic chunking

Sofistikovaný přístup. Pomocí embedding modelu se hledají místa kde se významově láme text, kde končí jedna myšlenka a začíná jiná. Tam se seká.

V praxi: spočítáš embedding pro každou větu. Tam kde sousední věty mají největší rozdíl ve významu, je hranice nového chunku.

Výhoda: významové celky zůstávají pohromadě. Nevýhoda: drahé (každá věta musí přes embedding model už při indexaci), pomalé.

4. Structural chunking

Sekáš podle struktury dokumentu. U HTML stránky podle nadpisů <h1>, <h2>, <h3>. U Markdownu podle headerů. U smlouvy podle článků a odstavců. U API dokumentace podle endpointů.

Výhoda: respektuje logickou strukturu dokumentu, kterou tam někdo vědomě dal. Nevýhoda: vyžaduje dobrý parser pro každý typ dokumentu a funguje jen u dokumentů které mají jasnou strukturu.

5. Recursive chunking

Kombinace strukturálního a fixed-size. Nejdřív se zkusí seknout podle struktury (kapitola, sekce, odstavec). Pokud výsledný kus je moc velký, seká se rekurzivně dál na menší. Pokud je moc malý, sloučí se se sousedem.

Výhoda: flexibilní, dobré výsledky na různých typech dokumentů. Nevýhoda: složitější implementace, vyžaduje tuning parametrů.

Praktická poznámka: v knihovnách jako LangChain a LlamaIndex jsou tyhle strategie už hotové. Většina RAG implementací používá recursive nebo structural přístup. Fixed-size se používá pro rychlé prototypy.

Tři typy vyhledávání #

Sémantické vyhledávání přes vektory není jediný nástroj v nástrojovém kufříku. V praxi se kombinují tři přístupy, každý dobrý na něco jiného.

Sémantické vyhledávání (vektorové)

To co jsme probrali. Hledá podle významu. Skvělé na:

  • Synonyma a parafráze („rychlost" najde „tempo", „frekvence")
  • Volně formulované dotazy v přirozeném jazyce
  • Konceptuální podobnost

Špatné na:

  • Přesné hodnoty (datum, číslo dokumentu, název produktu)
  • Negace („dokumenty které NEMAJÍ X")
  • Přesnou shodu slov (paragraf zákona, kód chyby)

Fulltextové vyhledávání (BM25 a podobné)

Klasické vyhledávání podle slov. Indexuje tokeny (slova) a hledá dokumenty které je obsahují. Algoritmus BM25 počítá relevanci podle toho jak vzácná jsou hledaná slova a jak často se vyskytují v daném dokumentu.

Skvělé na:

  • Přesná slova (jméno, kód, identifikátor)
  • Boolean dotazy („X AND Y NOT Z")
  • Frázovou shodu („vyšší moc")
  • Rychlost, deterministické výsledky

Špatné na:

  • Synonyma (hledáte „auto", neuvidíte texty kde je jen „vůz")
  • Sémantickou podobnost
  • Volně formulované dotazy

Známé fulltextové enginy: Elasticsearch, OpenSearch, Meilisearch, Typesense.

Strukturované vyhledávání (SQL nad metadaty)

Hledání podle strukturovaných atributů. Když máte u každého dokumentu uložené datum, autora, typ, klienta, kategorii, to jsou metadata. Můžete je filtrovat SQL dotazem.

Skvělé na:

  • „Všechny dokumenty z roku 2024"
  • „Faktury nad 100 000 Kč"
  • „Smlouvy s klientem ABC"
  • Filtry, agregace, řazení

Špatné na:

  • Cokoliv co se týká obsahu dokumentu, strukturované vyhledávání nečte text

Hybrid retrieval, proč se to kombinuje #

V produkčním RAG se málokdy používá jen jeden typ vyhledávání. Místo toho se kombinují všechny tři. Důvody jsou prosté: každý typ má slepá místa která druhý zalátá.

Konkrétní příklad z e-commerce:

Otázka: „Najdi mi recenze na boty Adidas Samba z roku 2024 které kritizují kvalitu materiálu."

Co tady potřebujeme?

  • „Adidas Samba" je název produktu, přesná slova → fulltextové vyhledávání
  • „z roku 2024" je datum, strukturované metadata → SQL filtr
  • „kritizují kvalitu materiálu" je sémantický význam, recenze nemusí obsahovat slovo „kritizuje", ale třeba „rozpadl se po měsíci" nebo „látka se trhá" → sémantické vyhledávání

Žádný z těch tří typů by sám o sobě úlohu nesplnil. Sémantické vyhledávání nezná konkrétní produkt. Fulltextové neumí „kvalita materiálu". SQL nečte text recenzí.

Jak se výsledky slučují

Když se hledá ve dvou nebo třech systémech paralelně, vrátí každý seznam dokumentů s nějakými skóre. Sjednotit je se dá několika způsoby:

  • Reciprocal Rank Fusion (RRF), populární a jednoduchý. Místo toho aby porovnával skóre (která mají různé škály) porovnává pořadí. Dokument který byl ve dvou seznamech vysoko, je vysoko i v sloučeném výsledku.
  • Vážený průměr, pokud víte že fulltextové vyhledávání má pro váš případ vyšší kvalitu než sémantické, dáte mu větší váhu.
  • Reranking, vezme se top 50 z hybrid hledání a projde se přes specializovaný reranking model (Cohere Rerank, BGE Reranker), který je seřadí znovu s ohledem na konkrétní otázku.

V produkčním RAG se obvykle používá kombinace: hybrid retrieval pro získání kandidátů, pak reranking pro finální výběr top 5 až 10 pro LLM.

Metadata jako kontext #

Až sem jsme mluvili o chuncích jako o textu. Ale v praxi je každý chunk obohacený o metadata, tedy strukturované informace o tom co to za chunk je.

Paralela s webem: když se podíváte do zdrojového kódu moderní webové stránky, najdete tam často víc metadat než vlastního obsahu. Open Graph tagy, JSON-LD, schema.org. Stránka má autora, datum publikace, kategorii, vztahy k jiným stránkám, hodnocení, geolokaci. Cílem je aby vyhledávač (a dnes AI) rozuměl kontextu stránky, ne jen jejímu textu.

V RAG je to úplně stejné. Každý chunk by měl mít metadata která říkají:

Identifikace zdroje:

  • ID dokumentu odkud chunk pochází
  • Typ dokumentu (smlouva, manuál, recenze, ticket)
  • Název nebo titulek dokumentu

Strukturální umístění:

  • Která stránka, sekce, kapitola
  • Pozice v dokumentu (úvod / hlavní text / appendix)
  • Pořadí mezi sourozeneckými chunky

Časové údaje:

  • Datum vzniku dokumentu
  • Datum poslední úpravy
  • Účinnost (u smluv)

Klasifikace:

  • Kategorie (technická dokumentace, marketing, podpora)
  • Tagy (auth, billing, onboarding, ...)
  • Jazyk

Vztahy:

  • Odkazy na související dokumenty
  • Autor / vlastník
  • Klient nebo projekt

Proč to záleží? Protože text chunku sám o sobě často nestačí. Věta „Lhůta je 30 dnů." je pro vektorovou databázi sémanticky zajímavá, ale bez kontextu je k ničemu. Lhůta čeho? Které smlouvy? K čemu se vztahuje?

Když má chunk metadata, sémantický retrieval najde kandidáty, strukturované metadata pomohou filtrovat (jen smlouvy s klientem X), a LLM dostane chunky s plným kontextem.

Klíčové pozorování: čím menší chunk, tím důležitější jsou metadata. U fixed-size chunku 200 tokenů můžou metadata být obsahově rozsáhlejší než samotný text chunku. To je v pořádku. Metadata jsou strukturovaná, zabírají méně místa v kontextovém okně LLM, a dávají hledání směr.

Závěrečné shrnutí druhé části #

Pojďme si shrnout co jsme prošli:

  • RAG má tři fáze: indexace (jednorázová příprava), retrieval (hledání při dotazu), generation (LLM tvořící odpověď)
  • Embedding model vyrábí číselné reprezentace významu textu, tedy vektory
  • Vektorová databáze najde podobné vektory pomocí kosinové podobnosti
  • Chunkovací strategie rozhoduje o kvalitě, od jednoduchého fixed-size po sofistikované semantic a structural
  • V produkci se kombinují tři typy vyhledávání: sémantické, fulltextové, strukturované. Tomu se říká hybrid retrieval.
  • Metadata u chunků jsou často důležitější než samotný text, protože dávají hledání kontext

Teď máte technickou kostru. V další části si projdeme kde to selhává, protože RAG má zajímavé limity a slabá místa o kterých se v marketingových materiálech moc nemluví.