Vkládání a vyhledávání vektorů: BERT vs Sentence Transformers
V prvním článku této série jsme prozkoumali architekturu RAG a její roli v vyřešit halucinace LLM. Srdcem každého systému RAG je vyhledávání: schopnost najít v potenciálně znalostní bázi obrovské, nejdůležitější dokumenty k aplikaci. Tato schopnost je založena zcela zapnuto vložení a dál vektorové vyhledávání.
Vložení je číselné vyjádření významu textu: sekvence čísla (vektor), který zachycuje sémantické vztahy mezi slovy, větami a dokumenty. Kvalita vložení přímo určuje kvalitu vyhledávání, a proto kvalitu celého systému RAG. Výběr špatného modelu vkládání znamená postavit základy domu na písku.
V tomto druhém článku seriálu AI Engineering a Advanced RAG, uděláme kompletní cestu: od počátků vkládání s Word2Vec až po revoluce BERT, až po moderní Sentence Transformers. Uvidíme, jak generovat vložení, jak porovnávat texty ve vektorovém prostoru, jak sestavit engine sémantické vyhledávání pomocí FAISS a jak vybrat správný model pro váš případ použití.
Přehled série
| # | Položka | Soustředit |
|---|---|---|
| 1 | RAG Vysvětleno | Základy a kompletní architektura |
| 2 | Jste zde – Vložení a sémantické vyhledávání | Jak se texty stávají vektory |
| 3 | Vektorové databáze v hloubce | Ukládání, indexování, vyhledávání podobností |
| 4 | RAG s LangChainem a Pythonem | Praktická end-to-end implementace |
| 5 | Hybridní vyhledávání a reranking | Hybridní klíčové slovo + sémantické vyhledávání |
| 6 | Kontextové okno a rychlé inženýrství | Optimalizujte kontext pro LLM |
| 7 | RAG ve výrobě | Škálování, monitorování, vyhodnocování |
| 8 | Znalostní grafy a RAG | Znalostní grafy + vyhledávání |
| 9 | Multiagentní systémy | Kolaborativní agenti AI |
| 10 | Budoucnost RAG | Trendy, výzkum a další kroky |
Co se naučíte
- Co je to vložení a jak vyjadřuje význam v číselné podobě
- Evoluce od Word2Vec přes BERT k Sentence Transformers
- proč vanilkový BERT nefunguje pro podobnost a jak SBERT řeší problém
- Jak vybrat ten správný model zapuštění z desítek možností
- Implementujte sémantické vyhledávání pomocí větných transformátorů a FAISS v Pythonu
- Metriky podobnosti vektorů a kdy je použít
- Architektonické srovnání mezi hlavními vektorovými vyhledávači
- Jak doladit vkládání pro konkrétní domény
1. Co je vkládání
Un vkládání je to matematická funkce, která transformuje diskrétní objekt (slovo, věta, dokument, obrázek) do vektoru reálných čísel v jednom souvislý prostor s pevnou rozměrností. V podstatě převádí lidsky čitelný text do strojově srozumitelného seznamu čísel se zachováním sémantických vztahů mezi původními texty.
Základní myšlenkou je, že texty s podobným významem musí mít blízké vektory v prostoru, zatímco texty s různými významy musí mít vzdálené vektory. Tato vlastnost říká se tomu sémantický izomorfismus: struktura sémantických vztahů mezi slovy je zachována v geometrii vektorového prostoru.
1.1 Od One-Hot Encoding k hustým vektorům
Abychom pochopili, proč jsou vložení nezbytná, uvažujme o nejjednodušší alternativě: a jednorázové kódování. Se slovní zásobou 50 000 slov, každé slovo je reprezentován vektorem 50 000 dimenzí pouze s jednou 1 a všechny ostatní nuly.
ONE-HOT ENCODING (vocabolario di 50.000 parole):
"gatto" = [0, 0, ..., 1, ..., 0, 0] (50.000 dimensioni, un solo 1)
"cane" = [0, 0, ..., 0, ..., 1, 0] (50.000 dimensioni, un solo 1)
Distanza tra "gatto" e "cane" = stessa di "gatto" e "frigorifero"
Nessuna informazione semantica!
DENSE EMBEDDING (es. 384 dimensioni):
"gatto" = [0.23, -0.45, 0.89, ..., 0.12] (384 dimensioni, tutti numeri reali)
"cane" = [0.21, -0.42, 0.91, ..., 0.15] (384 dimensioni, tutti numeri reali)
Distanza tra "gatto" e "cane" = PICCOLA (animali domestici)
Distanza tra "gatto" e "frigorifero" = GRANDE (concetti diversi)
Il significato è catturato nella geometria!
Problémy jednorázového kódování jsou zřejmé: vektory jsou obrovské (rozměrnost rovnající se slovní zásobě), rozptýlené (téměř všechny nuly) a především všechny navzájem ortogonální. Jakákoli dvě slova mají stejnou vzdálenost, bez ohledu na význam. Není způsob, jak odlišit „kočka“ od „kočičí“ versus „kočka“ od „ekonomie“.
I husté zabudování vyřešit všechny tři problémy: vektory jsou kompaktní (několik set rozměrů), hustý (všechny hodnoty jsou významné) a zachycují sémantické vztahy ve své geometrii. Podobná slova mají blízké vektory, a směry v prostoru odpovídají lingvistickým konceptům.
1.2 Sémantický prostor
Fascinující vlastností vložek je, že jsou sémantické vztahy ano transformovat do geometrických vztahů. Klasickým příkladem je aritmetika vektor: vektor "král" mínus "muž" plus "žena" vytváří velmi blízký vektor na "královnu". To není magie: znamená to, že prostor zachytil koncept „gender“ jako jeden směr a koncept „království“ jako jiný směr.
Relazioni semantiche come operazioni vettoriali:
vec("re") - vec("uomo") + vec("donna") ~ vec("regina")
vec("Parigi") - vec("Francia") + vec("Italia") ~ vec("Roma")
vec("buono") - vec("migliore") + vec("grande") ~ vec("più grande")
Cluster nello spazio:
[gatto, cane, cavallo, pesce] --> vicini (animali)
[Python, Java, C++, Rust] --> vicini (linguaggi di programmazione)
[felice, contento, gioioso] --> vicinissimi (sinonimi)
Základní intuice
Vložení je v podstatě a znamená kompresor. bere význam textu se všemi jeho nuancemi a rozumí mu v jednom bodě ve vícerozměrném prostoru. Poloha tohoto bodu vzhledem ke všem ostatním body zachycuje všechny sémantické vztahy, které se model naučil. Toto je základ, na kterém je založen celý sémantický výzkum.
2. Klasické vkládání slov: Word2Vec, GloVe, FastText
Novodobá historie embeddingů začíná v roce 2013 Word2Old, publikoval Tomáš Mikolov a kolegové z Google. Revoluční myšlenka byla jednoduchá: můžete se naučit význam slova z kontextu, ve kterém se vyskytuje. Jak řekl lingvista John Firth v roce 1957: "Slovo poznáte podle společnosti, kterou vede."
2.1 Word2Vec: CBOW a Skip-gram
Word2Vec navrhuje dvě neuronové architektury pro učení vložení:
- CBOW (Nepřetržitý pytel slov): Vzhledem k oknu kontextových slov předpovězte ústřední slovo. Příklad: za předpokladu, že „___ hlasitě mňouká“, předpoví „kočka“
- Skipgram: Vzhledem k ústřednímu slovu předpovězte kontextová slova. Příklad: dané „kočka“, předpovídání „the“, „mňau“, „hlasité“
CBOW (Continuous Bag of Words):
Input: parole di contesto ["il", "___", "miagola", "forte"]
Output: parola target "gatto"
Contesto ──> [Embedding Layer] ──> Media vettori ──> [Softmax] ──> "gatto"
Veloce, buono per parole frequenti
SKIP-GRAM:
Input: parola target "gatto"
Output: parole di contesto ["il", "miagola", "forte"]
"gatto" ──> [Embedding Layer] ──> [Softmax] ──> parole contesto
Più lento, migliore per parole rare
Parametri tipici:
- Dimensioni embedding: 100-300
- Finestra di contesto: 5-10 parole
- Vocabolario: 100k-1M parole
- Training: miliardi di parole (Wikipedia, Common Crawl)
2.2 GloVe a FastText
Rukavice (Global Vectors for Word Representation, Stanford 2014) přijímá a odlišný přístup: vytvoří globální matici společného výskytu a faktorizuje ji podle získat vložení. Zachyťte globální vztahy, které Word2Vec, s jeho oknem místní, mohl ztratit.
FastText (Facebook 2016) rozšiřuje Word2Vec o práci na úrovni podslova (n-gramů znaků). Zastoupeno je slovo "vložení". také jeho součástmi: "emb", "mbe", "bed", "edd" atd. To umožňuje generovat vložení také pro slova, která se během tréninku nikdy nezobrazila (slov mimo slovní zásobu), zásadní výhoda pro jazyky s bohatou morfologií, jako je italština.
Porovnání klasických vkládání slov
| Model | Rok | Přístup | Platnost | Omezit |
|---|---|---|---|---|
| Word2Old | 2013 | Predikce místního kontextu | Rychlé, efektivní | Žádné OOV, žádný kontext |
| Rukavice | 2014 | Globální společný výskyt | Globální vztahy | Žádné OOV, žádný kontext |
| FastText | 2016 | N-gramů znaků | Řídí OOV | Jeden vektor na slovo |
2.3 Základní limit: Jeden vektor na slovo
Všechny klasické vkládání slov sdílí strukturální omezení: produkují jeden vektor pro každé slovo, bez ohledu na kontext. Slovo „stůl“ má stejné zakotvení jak v „školní lavici“, tak v „stole“. Itálie“. To je vážný problém, protože význam slova závisí téměř vždy podle kontextu, ve kterém se objevuje.
Dále tyto modely fungují na úrovni jediná slova: ne může vytvořit vložení pro větu nebo odstavec. Zastupovat a věty, musíme se uchýlit k rudimentárním strategiím, jako je průměrování vektorů slova, která jej tvoří, ztrácejí informace o pořadí a syntaktické struktuře.
Proč nepoužít Word2Vec pro RAG
Klasické vkládání slov je pro moderní sémantické vyhledávání nedostatečné, protože: (1) nezachycují kontext, (2) nevytvářejí vložení na úrovni vět, (3) vektorový průměr ztrácí kritické informace. Fráze "pes kousne člověka" a "člověk kousne psa" by mělo stejné vložení. Pro RAG potřebujete modely kteří chápou význam celé věty v jejím kontextu.
3. Kontextové vkládání: revoluce BERT
V roce 2018 Google zveřejňuje BERT (Obousměrná reprezentace kodéru z Transformers) a radikálně mění krajinu. BERT vyrábí kontextová vložení: zastoupení každého slova závisí z celého kontextu věty, ve které se vyskytuje. Slovo "stůl" v "školní lavici" bude mít jiné vložení než „il banca d'Italia“.
3.1 Jak BERT funguje
BERT je založen na architektuře Transformátorový kodér. Přebírá vstup sekvenci tokenů a pro každý token vytvoří kontextový vektor 768 rozměry (BERT-základna) nebo 1024 rozměrů (BERT-large). Síla BERT spočívá v mechanismus sebepozornost: každý žeton "hledí" na všechny ostatní žetony v sekvenci, jak levou, tak pravou (obousměrnou), pro výpočet vlastní zastoupení.
Input: [CLS] il banco di scuola [SEP]
Tokenizzazione:
[CLS] il ban ##co di scuo ##la [SEP]
12 layer di Transformer Encoder:
Layer 1: Self-attention + Feed-forward
Layer 2: Self-attention + Feed-forward
...
Layer 12: Self-attention + Feed-forward
Output: un vettore 768-dim per OGNI token
[CLS] --> [0.23, -0.45, ..., 0.12] (vettore "riassunto")
il --> [0.11, -0.32, ..., 0.08]
ban --> [0.56, 0.12, ..., 0.34] (contestualizzato!)
##co --> [0.45, 0.09, ..., 0.29]
di --> [0.03, -0.21, ..., 0.05]
scuo --> [0.67, 0.33, ..., 0.41]
##la --> [0.59, 0.28, ..., 0.38]
[SEP] --> [0.02, -0.05, ..., 0.01]
3.2 Strategie sdružování: Od tokenu po frázi
BERT vytvoří vektor pro každý token, ale pro sémantické vyhledávání to potřebujeme a jeden vektor pro celou větu. jak to získat? Je jich několik strategie sdružování:
Strategie sdružování pro BERT
| Strategie | Popis | kvalitní |
|---|---|---|
| [CLS] Tokeny | Použít speciální nosič tokenů [CLS] | Průměrný na podobnost |
| Střední sdružování | Průměr všech tokenových vektorů | Obecně dobré |
| Max Pooling | Maximální hodnota pro každý rozměr | Zachyťte výrazné rysy |
| Vážený průměr | Vážený průměr s váhami pozornosti | Dobré, složitější |
3.3 Proč BERT Vanilla nefunguje pro podobnost
Navzdory síle BERT jej použijte přímo k výpočtu podobnosti mezi věty je extrémně neefektivní a přináší špatné výsledky. Důvod je dvojí:
- Výpočetní neefektivita: Chcete-li porovnat N vět mezi sebou, musíte projít každou dvojici vět přes BERT. S 10 000 větami jsou potřeba 10 000 x 10 000 / 2 = 50 milionů přihrávek. S časem přibližně 65 ms za pár, bude to trvat asi 65 hodin
- Degenerovaný prostor pro vkládání: Vložení vytvořená sdružováním na BERT nejsou optimalizovány pro kosinusovou podobnost. Všechny věty mají tendenci skončí v úzké oblasti prostoru, takže je obtížné rozlišit věty podobné z různých vět. Tento jev se nazývá anizotropie
Problém křížového kódování
BERT je navržen jako křížový kodér: jako vstup bere DVĚ věty a vytváří skóre podobnosti. Pro každou dvojici vět je potřeba přepočítat vše od nuly. S korpusem 10 000 dokumentů a dotazem jich potřebujete 10 000 přihrávka vpřed. Chcete-li sestavit index všech možných srovnání, náklady roste kvadraticky. To činí BERT nepraktickým pro vyhledávání v reálném čase.
4. Transformátory vět: Řešení
V roce 2019 publikují Nils Reimers a Iryna Gurevych Věta-BERT (SBERT), který oba problémy elegantně řeší. Klíčovou myšlenkou je transformovat BERT z křížový kodér a bi-kodér: místo předávání dvojic vět, každá věta je nezávisle zakódována do hustého vektoru. Podobnost ano pak počítá s jednoduchou vektorovou operací (kosinová podobnost).
4.1 Siamská architektura a trojité sítě
SBERT je vyškolen s architekturou a siamská síť: dvě kopie identické modely BERT (se sdílenými vahami) zpracovávají dvě věty samostatně. Dopravci výsledné jsou pak porovnány se ztrátovou funkcí, která se "přibližuje" vektorům podobné věty a "odebrat" vektory různých vět.
CROSS-ENCODER (BERT vanilla):
["frase A", "frase B"] ──> [BERT] ──> punteggio similarità
Deve processare OGNI coppia. O(n^2) per n frasi.
BI-ENCODER (SBERT):
"frase A" ──> [BERT + Pooling] ──> vettore_A (384-dim)
"frase B" ──> [BERT + Pooling] ──> vettore_B (384-dim)
similarità = cosine(vettore_A, vettore_B)
Ogni frase viene codificata UNA VOLTA. O(n) per n frasi.
I vettori possono essere pre-calcolati e indicizzati!
TRAINING con Siamese Network:
Frase 1 ──> [BERT] ──> pool ──> u
├──> loss(u, v, label)
Frase 2 ──> [BERT] ──> pool ──> v
Label = 1 se frasi simili, 0 se diverse
Loss: Contrastive Loss o Cosine Similarity Loss
Le tripletové sítě rozšířit přístup o tři vstupy: kotva, pozitivní (podobný) příklad a negativní (jiný) příklad. Ztráta (tripletová ztráta marže) tlačí model tak, aby měl kladnou vzdálenost kotvy menší než vzdálenost kotva-negativní alespoň o předem definovaný okraj.
4.2 Výhody SBERT ve srovnání s BERT
Porovnání výkonu
| Metrický | Křížový kodér BERT | SBERT Bi-Encoder |
|---|---|---|
| Podobnost 10 000 vět | ~65 hodin | ~5 sekund |
| Vektorový předvýpočet | Není možné | Ano, pouze jednou |
| Indexování | Nelze použít | FAISS, HNSW atd. |
| STS Benchmark kvalita | ~87 (spearman) | ~85 (spearman) |
| Výrobní využití | Pouze re-ranking | Vyhledání + pořadí |
SBERT obětuje malé procento přesnosti (asi 2 body na STS Benchmark) ale vydělat si jeden 10 000krát vyšší rychlost. V praxi výběr je povinné: křížový kodér lze použít jako re-ranker na top-k výsledcích SBERT, kombinující to nejlepší z obou přístupů (vzor tzv načíst a přehodnotit).
5. Porovnání modelů vkládání
Ekosystém modelu vkládání je rozsáhlý a rychle se vyvíjí. Výběr z správný model závisí na případu použití: sémantické vyhledávání, shlukování, klasifikace, Vícejazyčný RAG, rozpočet a latence. Zde je podrobné srovnání nejrelevantnějších modelů.
Porovnání modelů vkládání (2024–2025)
| Model | Poskytovatelé | Rozměry | Max Token | MTEB prům | Poznámky |
|---|---|---|---|---|---|
| vše-MiniLM-L6-v2 | SBERT | 384 | 256 | 56,26 | Velmi rychlé, ideální pro prototypování |
| all-mpnet-base-v2 | SBERT | 768 | 384 | 57,78 | Nejlepší poměr kvalita/rychlost open source |
| e5-large-v2 | Microsoft | 1024 | 512 | 62,20 | Vysoká kvalita, vyžaduje předponu "query:" / "passage:" |
| BGE-M3 | BAAI | 1024 | 8192 | 63,55 | Vícejazyčné, husté+řídké+colbert |
| text-embedding-3-small | OpenAI | 1536 | 8191 | 62,26 | Cloud API, levné (0,02 $/1 milion tokenu) |
| text-embedding-3-velký | OpenAI | 3072 | 8191 | 64,59 | Cloud API, špičková kvalita (0,13 $/1 milion tokenu) |
| embed-v3 (anglicky) | Cohere | 1024 | 512 | 64,47 | Cloud API, skvělé pro výzkum |
| nomic-embed-text-v1.5 | Nomic | 768 | 8192 | 62,28 | Open-source, dlouhý kontext, Matrjoška |
Jak číst MTEB Benchmarky
MTEB (Massive Text Embedding Benchmark) je de facto standardem pro vyhodnotit modely vkládání. Zahrnuje 56+ datových sad v 8 kategoriích (klasifikace, shlukování, klasifikace párů, reranking, vyhledávání, STS, sumarizace). Skóre střední je průměr ve všech kategoriích, ale pro RAG dílčí skóre Získávání je to nejrelevantnější. Vždy zkontrolujte konkrétní skóre pro váš případ použití.
5.1 Kritéria výběru
- Rychlé prototypování: all-MiniLM-L6-v2 - rychlý, lehký, zdarma
- Open-source produkce: all-mpnet-base-v2 nebo e5-large-v2
- Nejvyšší kvalita cloudu: text-embedding-3-large (OpenAI) nebo embed-v3 (Cohere)
- Vícejazyčný/italský: BGE-M3 nebo multilingual-e5-large
- Dlouhý kontext (dlouhé dokumenty): BGE-M3 (8192 tokenů) nebo nomic-embed-text-v1.5
- Omezený rozpočet: text-embedding-3-small (OpenAI) nebo samostatně hostované open-source šablony
6. Metriky podobnosti vektorů
Jakmile máte vektory, potřebujete funkci, která změří, kolik jsou dva vektory „podobné“. Výběr metriky ovlivňuje výsledky i výkon.
6.1 Kosinová podobnost
La malá podobnost měří kosinus úhlu mezi dvěma vektory. Rozsahy od -1 (opačné vektory) do +1 (identické vektory), s 0 pro ortogonální vektory. Ignorujte velikost vektorů a zaměřte se pouze na směr: je to metrika nejpoužívanější pro vkládání textu.
COSINE SIMILARITY:
A . B sum(a_i * b_i)
cos(A,B) = ─────── = ──────────────────────────────
|A| |B| sqrt(sum(a_i^2)) * sqrt(sum(b_i^2))
Range: [-1, +1]
+1 = identici, 0 = ortogonali, -1 = opposti
Invariante alla scala (normalizzata)
DOT PRODUCT (Prodotto Scalare):
dot(A,B) = sum(a_i * b_i)
Range: (-inf, +inf)
Sensibile alla magnitudine dei vettori
Più veloce (nessuna normalizzazione)
Equivalente a cosine se i vettori sono già normalizzati (norma L2 = 1)
EUCLIDEAN DISTANCE (L2):
d(A,B) = sqrt(sum((a_i - b_i)^2))
Range: [0, +inf)
0 = identici, valori alti = molto diversi
Sensibile alla magnitudine
Nota: DISTANZA, non similarità (valori bassi = più simili)
Kdy použít kterou metriku
| Metrický | Kdy jej použít | Výkon |
|---|---|---|
| Kosinová podobnost | Výchozí pro vkládání textu, nenormalizované šablony | Průměr (vyžaduje normalizaci) |
| Dot Product | Již normalizované Embeddings (Sentence Transformers), když je potřeba rychlost | Vysoká (snadnější obsluha) |
| euklidovský (L2) | Když je velikost významná, shlukování | Průměrný |
Užitečný tip: pokud používáte Sentence Transformers, lze vektory normalizovat v souladu s jednotným standardem. V tomto případě jsou kosinusová podobnost a bodový součin ekvivalentní a dot product je rychlejší. Většina vektorových databází podporuje všechny tři metriky a umožňuje výběr při vytváření indexu.
7. Praktická implementace s Pythonem
Přejděme ke kódu. Implementujeme kompletní systém sémantického vyhledávání pomocí
sentence-transformers pro vložení e FAISS pro
indexování a vyhledávání vektorů.
7.1 Nastavení a instalace
# Crea ambiente virtuale
python -m venv embedding-env
source embedding-env/bin/activate
# Installa le dipendenze principali
pip install sentence-transformers==3.3.1
pip install faiss-cpu==1.9.0 # Per CPU (usa faiss-gpu per GPU)
pip install numpy==2.1.3
pip install pandas==2.2.3
pip install tqdm==4.67.1
# Opzionale: per visualizzazione
pip install matplotlib==3.9.3
pip install scikit-learn==1.6.0
7.2 Generování vložení pomocí převodníků vět
from sentence_transformers import SentenceTransformer
import numpy as np
# Carica il modello (download automatico al primo utilizzo)
model = SentenceTransformer("all-MiniLM-L6-v2")
# Frasi di esempio
sentences = [
"Il gatto dorme sul divano",
"Il felino riposa sul sofa",
"Python è un linguaggio di programmazione",
"Java è usato per lo sviluppo enterprise",
"La ricerca semantica usa gli embeddings",
]
# Genera embeddings
embeddings = model.encode(sentences, show_progress_bar=True)
# Ogni embedding è un vettore numpy
print(f"Tipo: {type(embeddings)}")
print(f"Shape: {embeddings.shape}") # (5, 384) - 5 frasi, 384 dimensioni
print(f"Norma L2 del primo vettore: {np.linalg.norm(embeddings[0]):.4f}")
# Visualizza i primi 10 valori del primo embedding
print(f"\nPrimi 10 valori: {embeddings[0][:10]}")
7.3 Vypočítat podobnost mezi frázemi
from sentence_transformers import SentenceTransformer, util
import numpy as np
model = SentenceTransformer("all-MiniLM-L6-v2")
# Frasi da confrontare
sentences = [
"Il gatto dorme sul divano",
"Il felino riposa sul sofa",
"Python è un linguaggio di programmazione",
"La pioggia cade sulla citta",
]
embeddings = model.encode(sentences, convert_to_tensor=True)
# Matrice di similarità completa
cosine_scores = util.cos_sim(embeddings, embeddings)
print("Matrice di Similarità Coseno:")
print("-" * 60)
for i in range(len(sentences)):
for j in range(len(sentences)):
score = cosine_scores[i][j].item()
if i != j:
print(f" {sentences[i][:30]:<30} vs {sentences[j][:30]:<30}")
print(f" Similarità: {score:.4f}")
# Calcolo manuale della cosine similarity per verifica
def cosine_similarity_manual(vec_a, vec_b):
"""Calcola cosine similarity manualmente."""
dot_product = np.dot(vec_a, vec_b)
norm_a = np.linalg.norm(vec_a)
norm_b = np.linalg.norm(vec_b)
return dot_product / (norm_a * norm_b)
emb_np = model.encode(sentences)
manual_score = cosine_similarity_manual(emb_np[0], emb_np[1])
print(f"\nVerifica manuale (frase 0 vs 1): {manual_score:.4f}")
Očekávaný výstup
Věty „Kočka spí na pohovce“ a „Kočka odpočívá na pohovce“ budou mít jednu vysoká podobnost (~0,85), protože vyjadřují stejný pojem různými slovy. Podobnost s „Python je programovací jazyk“ bude nízká (~0,10), protože koncepty jsou úplně jiné. To je síla výzkumu sémantika versus vyhledávání klíčových slov.
7.4 Sémantické vyhledávání pomocí FAISS
import faiss
import numpy as np
from sentence_transformers import SentenceTransformer
class SemanticSearchEngine:
"""Motore di ricerca semantica basato su FAISS."""
def __init__(self, model_name: str = "all-MiniLM-L6-v2"):
self.model = SentenceTransformer(model_name)
self.dimension = self.model.get_sentence_embedding_dimension()
self.index = None
self.documents = []
def build_index(self, documents: list[str], use_gpu: bool = False):
"""Costruisce l'indice FAISS dai documenti."""
self.documents = documents
# Genera embeddings per tutti i documenti
embeddings = self.model.encode(
documents,
show_progress_bar=True,
normalize_embeddings=True, # Normalizza per cosine similarity
batch_size=64,
)
embeddings = embeddings.astype("float32")
# Crea indice FAISS (Inner Product = Cosine per vettori normalizzati)
self.index = faiss.IndexFlatIP(self.dimension)
if use_gpu:
# Trasferisci indice su GPU per ricerca più veloce
res = faiss.StandardGpuResources()
self.index = faiss.index_cpu_to_gpu(res, 0, self.index)
self.index.add(embeddings)
print(f"Indice costruito: {self.index.ntotal} documenti indicizzati")
def search(self, query: str, top_k: int = 5) -> list[dict]:
"""Cerca i documenti più simili alla query."""
# Genera embedding della query
query_embedding = self.model.encode(
[query],
normalize_embeddings=True,
).astype("float32")
# Ricerca nell'indice FAISS
scores, indices = self.index.search(query_embedding, top_k)
results = []
for score, idx in zip(scores[0], indices[0]):
if idx != -1: # -1 indica nessun risultato
results.append({
"document": self.documents[idx],
"score": float(score),
"index": int(idx),
})
return results
def save_index(self, path: str):
"""Salva l'indice su disco."""
faiss.write_index(self.index, path)
def load_index(self, path: str):
"""Carica l'indice da disco."""
self.index = faiss.read_index(path)
# Utilizzo
if __name__ == "__main__":
# Corpus di documenti
documents = [
"Python è un linguaggio di programmazione ad alto livello, interpretato e multiparadigma",
"Java è un linguaggio orientato agli oggetti progettato per essere portabile",
"Il machine learning è un sottoinsieme dell'intelligenza artificiale",
"I database relazionali usano SQL per le query sui dati strutturati",
"Docker permette di containerizzare le applicazioni per il deployment",
"Kubernetes orchestra i container in ambienti di produzione distribuiti",
"React è una libreria JavaScript per costruire interfacce utente",
"Angular è un framework TypeScript per applicazioni web enterprise",
"I transformer sono l'architettura alla base dei modelli linguistici moderni",
"FAISS è una libreria per la ricerca efficiente di similarità tra vettori",
"La sicurezza informatica protegge i sistemi da accessi non autorizzati",
"Il cloud computing fornisce risorse computazionali on-demand via internet",
]
engine = SemanticSearchEngine()
engine.build_index(documents)
# Ricerca semantica
queries = [
"Come funziona l'intelligenza artificiale?",
"Framework per sviluppo web frontend",
"Come distribuire applicazioni in modo scalabile?",
]
for query in queries:
print(f"\nQuery: '{query}'")
print("-" * 50)
results = engine.search(query, top_k=3)
for i, result in enumerate(results, 1):
print(f" {i}. [{result['score']:.4f}] {result['document']}")
7.5 Dávkové zpracování velkých datových sad
import faiss
import numpy as np
from sentence_transformers import SentenceTransformer
from tqdm import tqdm
import json
from pathlib import Path
class LargeScaleEmbedder:
"""Gestisce embedding e indicizzazione per grandi dataset."""
def __init__(self, model_name: str = "all-mpnet-base-v2"):
self.model = SentenceTransformer(model_name)
self.dimension = self.model.get_sentence_embedding_dimension()
def encode_in_batches(
self,
texts: list[str],
batch_size: int = 256,
output_path: str | None = None,
) -> np.ndarray:
"""Genera embeddings in batch con salvataggio incrementale."""
all_embeddings = []
for start_idx in tqdm(range(0, len(texts), batch_size)):
batch = texts[start_idx : start_idx + batch_size]
batch_embeddings = self.model.encode(
batch,
normalize_embeddings=True,
batch_size=batch_size,
show_progress_bar=False,
)
all_embeddings.append(batch_embeddings)
# Salvataggio incrementale (checkpoint)
if output_path and (start_idx % (batch_size * 10) == 0):
partial = np.vstack(all_embeddings)
np.save(f"{output_path}_partial.npy", partial)
result = np.vstack(all_embeddings).astype("float32")
if output_path:
np.save(f"{output_path}.npy", result)
print(f"Embeddings salvati: {result.shape}")
return result
def build_ivf_index(
self,
embeddings: np.ndarray,
n_clusters: int = 100,
n_probe: int = 10,
) -> faiss.Index:
"""Costruisce un indice IVF per ricerca approssimata veloce."""
# Quantizzatore per assegnare vettori ai cluster
quantizer = faiss.IndexFlatIP(self.dimension)
# Indice IVF con Inner Product
index = faiss.IndexIVFFlat(
quantizer, self.dimension, n_clusters, faiss.METRIC_INNER_PRODUCT
)
# Training: impara la struttura dei cluster
print(f"Training indice IVF con {n_clusters} cluster...")
index.train(embeddings)
# Aggiungi i vettori
index.add(embeddings)
index.nprobe = n_probe # Numero di cluster da esplorare in ricerca
print(f"Indice IVF costruito: {index.ntotal} vettori, {n_clusters} cluster")
return index
# Esempio di utilizzo con un grande corpus
if __name__ == "__main__":
embedder = LargeScaleEmbedder(model_name="all-MiniLM-L6-v2")
# Simula un grande corpus (in produzione: carica da file/database)
corpus = [f"Documento di esempio numero {i} sul tema tecnologia" for i in range(100_000)]
# Genera embeddings in batch
embeddings = embedder.encode_in_batches(
corpus,
batch_size=512,
output_path="corpus_embeddings",
)
# Costruisci indice IVF (più veloce di Flat per grandi corpus)
index = embedder.build_ivf_index(embeddings, n_clusters=256, n_probe=16)
# Ricerca
query_embedding = embedder.model.encode(
["intelligenza artificiale e machine learning"],
normalize_embeddings=True,
).astype("float32")
scores, indices = index.search(query_embedding, 5)
for score, idx in zip(scores[0], indices[0]):
print(f" [{score:.4f}] {corpus[idx]}")
7.6 Vkládání pomocí šablon E5 (na základě prefixů)
from sentence_transformers import SentenceTransformer
import numpy as np
# I modelli E5 richiedono prefix specifici
model = SentenceTransformer("intfloat/e5-large-v2")
# Per i documenti nel corpus: prefix "passage: "
documents = [
"passage: Python è un linguaggio di programmazione versatile e potente",
"passage: I database NoSQL sono progettati per dati non strutturati",
"passage: Kubernetes gestisce il deployment di applicazioni containerizzate",
"passage: Il deep learning usa reti neurali con molti layer",
]
# Per le query di ricerca: prefix "query: "
queries = [
"query: Come funziona l'apprendimento automatico?",
"query: Strumenti per gestire i container",
]
# Genera embeddings
doc_embeddings = model.encode(documents, normalize_embeddings=True)
query_embeddings = model.encode(queries, normalize_embeddings=True)
# Calcola similarità
for i, query in enumerate(queries):
scores = np.dot(query_embeddings[i], doc_embeddings.T)
best_idx = np.argmax(scores)
print(f"Query: {query}")
print(f" Miglior match: {documents[best_idx]}")
print(f" Score: {scores[best_idx]:.4f}\n")
Dávejte pozor na předpony
Modely E5 a BGE vyžadují specifické předpony pro rozlišení dotazů od dokumentů.
Pro E5: query: e passage: . Pro BGE:
Represent this sentence: pro dotazy. Zapomenutí předpony degraduje
výkon výrazně. Vždy zkontrolujte dokumentaci modelu.
8. Vektorové vyhledávače: architektonické srovnání
FAISS jsou vynikající pro implementaci na nízké úrovni, ale ve výrobě jsou potřeba řešení, která spravují persistenci, filtrování metadat, horizontální škálovatelnost a aktualizace v reálném čase. Zde jsou hlavní vektorové databáze a jejich charakteristiky.
Porovnání vektorové databáze
| Databáze | Typ | Jazyk | Indexy | Ideální případ použití |
|---|---|---|---|---|
| FAISS | Regál | C++/Python | Ploché, IVF, HNSW, PQ | Čistý výzkum, vkládání, prototypování |
| Qdrant | Databáze | Rez | HNSW | Výroba, komplexní filtry, vysoký výkon |
| Borová šiška | Spravováno cloudem | Majitel | Majitel | Zero-ops, spuštění, automatické škálování |
| Milvus | Databáze | Přejít/C++ | Ploché, IVF, HNSW, DiskANN | Podnikové měřítko, miliardy vektorů |
| pgvector | Rozšíření | C | IVFFlat, HNSW | Již používáte PostgreSQL, moderované datové sady |
| ChromaDB | Databáze | Python/Rust | HNSW | Prototypování, integrace LangChain |
| Weaviate | Databáze | Go | HNSW | Multimodální, GraphQL API |
8.1 Příklad s Qdrant
from qdrant_client import QdrantClient
from qdrant_client.models import (
Distance,
VectorParams,
PointStruct,
Filter,
FieldCondition,
MatchValue,
)
from sentence_transformers import SentenceTransformer
# Inizializza client (in-memory per test, o URL per produzione)
client = QdrantClient(":memory:") # oppure QdrantClient("http://localhost:6333")
model = SentenceTransformer("all-MiniLM-L6-v2")
# Crea collection
client.create_collection(
collection_name="articles",
vectors_config=VectorParams(
size=384, # Dimensione vettore all-MiniLM-L6-v2
distance=Distance.COSINE,
),
)
# Documenti con metadati
documents = [
{"text": "Python è ottimo per il data science", "category": "programming", "year": 2024},
{"text": "React è il framework frontend più popolare", "category": "web", "year": 2024},
{"text": "Kubernetes gestisce i container in produzione", "category": "devops", "year": 2023},
{"text": "TensorFlow è usato per il deep learning", "category": "ai", "year": 2024},
{"text": "PostgreSQL è un database relazionale avanzato", "category": "database", "year": 2023},
]
# Indicizzazione
points = []
for i, doc in enumerate(documents):
embedding = model.encode(doc["text"]).tolist()
points.append(
PointStruct(
id=i,
vector=embedding,
payload={"text": doc["text"], "category": doc["category"], "year": doc["year"]},
)
)
client.upsert(collection_name="articles", points=points)
# Ricerca semantica semplice
query = "machine learning e intelligenza artificiale"
query_vector = model.encode(query).tolist()
results = client.search(
collection_name="articles",
query_vector=query_vector,
limit=3,
)
print(f"Query: '{query}'")
for result in results:
print(f" [{result.score:.4f}] {result.payload['text']} ({result.payload['category']})")
# Ricerca con filtro per metadati
filtered_results = client.search(
collection_name="articles",
query_vector=query_vector,
query_filter=Filter(
must=[FieldCondition(key="year", match=MatchValue(value=2024))]
),
limit=3,
)
print(f"\nRicerca filtrata (solo 2024):")
for result in filtered_results:
print(f" [{result.score:.4f}] {result.payload['text']}")
9. Algoritmy indexování: kompromis mezi rychlostí/vyvoláním
Přesné (hrubou silou) vyhledávání v milionech vektorů je příliš pomalé. Algoritmy z Přibližný nejbližší soused (ANN) obětují malé procento přesnosti pro získání řádové rychlosti. Pochopte tyto algoritmy je nezbytné správně nakonfigurovat vektorovou databázi.
9.1 Plochý index (přesné vyhledávání)
Index Byt porovnává dotaz s každým jednotlivým vektorem v databázi. 100% stažení zaručeno, ale cena O(n*d), kde n je počet dopravců ad je rozměrnost. Praktické pouze pro malé datové sady (až do ~100k vektorů).
9.2 IVF (Inverted File Index)
IVF rozděluje vektorový prostor do shluků pomocí k-means. V tuto chvíli
hledání jsou prozkoumány pouze shluky nejblíže dotazu. Parametr
nprobe řídí, kolik shluků se má prozkoumat: vysoké hodnoty zvyšují paměť
ale zpomalují hledání.
9.3 HNSW (Hierarchical Navigable Small World)
HNSW je to nejpopulárnější algoritmus v moderních vektorových databázích. Staví se víceúrovňový splavný graf, kde každý uzel je vektor spojený se svými sousedy nejbližší. Vyhledávání začíná od nejvyšší úrovně (málo uzlů, dlouhá připojení) a klesá na základní úroveň (všechny uzly, krátká spojení), zužuje se oblast výzkumu postupně.
FLAT (Brute Force):
Costruzione: O(n) | Ricerca: O(n*d) | Recall: 100%
Memoria: n*d*4 bytes | Aggiornamento: O(1)
Ideale per: <100k vettori, quando il recall perfetto e necessario
IVF (Inverted File):
Costruzione: O(n*k) | Ricerca: O(nprobe*n/k*d) | Recall: 90-99%
Memoria: n*d*4 bytes | Aggiornamento: richiede re-training
Parametri: nlist (cluster), nprobe (cluster esplorati)
Ideale per: 100k-10M vettori, quando serve controllo fine
HNSW (Hierarchical Navigable Small World):
Costruzione: O(n*log(n)) | Ricerca: O(log(n)*d) | Recall: 95-99.9%
Memoria: n*d*4 + grafo | Aggiornamento: O(log(n))
Parametri: M (connessioni), ef_construction, ef_search
Ideale per: qualsiasi scala, migliore latenza, più memoria
Product Quantization (PQ):
Comprime vettori 768-dim in ~64 bytes (12x compressione)
Recall inferiore ma enorme risparmio memoria
Combinabile con IVF: IVF-PQ per miliardi di vettori
Praktický průvodce výběrem
| Měřítko datové sady | Doporučený algoritmus | Typické vyvolání |
|---|---|---|
| <100 000 dopravců | Ploché (hrubá síla) | 100 % |
| 100 tisíc – 1 milion | HNSW | 98–99 % |
| 1 mil. – 100 mil | HNSW nebo IVF-HNSW | 95–99 % |
| 100 mil. - 1B | IVF-PQ nebo DiskANN | 90–95 % |
| >1B | Distribuované IVF-PQ (Milvus) | 85–95 % |
10. Jemné doladění vložení
Předtrénované modely fungují dobře pro obecné případy použití, ale pro domény specialista (medicína, právo, finance, zákoník). dolaďování může výrazně zlepšit kvalitu vyhledávání. Princip je jednoduchý: přizpůsobte model datům a slovní zásobě vaší domény.
10.1 Kdy doladit
- Odborná slovní zásoba: Vaše doména používá technickou terminologii, která se nenachází v obecných tréninkových datech
- Různé sémantické vztahy: Ve vaší doméně mají slova, která spolu normálně nesouvisí, úzké vztahy
- Nedostatečně zastoupené jazyky: Základní model nenašel dostatek textu ve vašem jazyce
- Špatné načítání: Výsledky sémantického vyhledávání nejsou uspokojivé i přes dobré kusy
10.2 Implementace s kontrastním učením
from sentence_transformers import (
SentenceTransformer,
InputExample,
losses,
evaluation,
)
from torch.utils.data import DataLoader
# Carica modello base
model = SentenceTransformer("all-MiniLM-L6-v2")
# Prepara i dati di training: coppie (frase_a, frase_b, similarità)
# similarità: 1.0 = semanticamente identiche, 0.0 = completamente diverse
train_examples = [
# Coppie positive (dominio medico)
InputExample(texts=["infarto del miocardio", "attacco cardiaco acuto"], label=0.95),
InputExample(texts=["ipertensione arteriosa", "pressione alta cronica"], label=0.90),
InputExample(texts=["cefalea tensiva", "mal di testa da stress"], label=0.85),
InputExample(texts=["diabete mellito tipo 2", "diabete dell'adulto"], label=0.90),
# Coppie negative
InputExample(texts=["infarto del miocardio", "frattura del femore"], label=0.10),
InputExample(texts=["ipertensione arteriosa", "gastrite cronica"], label=0.05),
# Aggiungi migliaia di coppie per risultati ottimali...
]
# DataLoader
train_dataloader = DataLoader(train_examples, shuffle=True, batch_size=16)
# Loss function: Cosine Similarity Loss
train_loss = losses.CosineSimilarityLoss(model)
# Valutazione (opzionale ma consigliata)
eval_examples = [
InputExample(texts=["tachicardia sinusale", "battito cardiaco accelerato"], label=0.85),
InputExample(texts=["polmonite batterica", "infezione polmonare"], label=0.80),
]
evaluator = evaluation.EmbeddingSimilarityEvaluator.from_input_examples(
eval_examples, name="medical-eval"
)
# Fine-tuning
model.fit(
train_objectives=[(train_dataloader, train_loss)],
evaluator=evaluator,
epochs=3,
warmup_steps=100,
evaluation_steps=500,
output_path="models/medical-embedding-model",
)
print("Fine-tuning completato! Modello salvato.")
# Test del modello fine-tuned
finetuned_model = SentenceTransformer("models/medical-embedding-model")
emb1 = finetuned_model.encode("infarto miocardico acuto")
emb2 = finetuned_model.encode("attacco di cuore")
from sentence_transformers import util
score = util.cos_sim([emb1], [emb2])
print(f"Similarità post fine-tuning: {score.item():.4f}")
Kolik dat potřebujete pro jemné doladění?
Zpravidla: minimálně 1000 párů vidět zlepšení, 5 000-10 000 párů pro solidní výsledky, 50 000+ párů pro optimální výsledky. Kvalita dat je důležitější než kvantita: páry hlučné nebo špatně označené degradují model. Pokud nemáte dostatek anotovaných dat, zvážit techniky, jako je tvrdá negativní těžba nebo syntetická generace s LLM.
11. Vložení do italského jazyka
Většina modelů vkládání je trénována převážně na anglickém textu. Pro aplikace v italštině je výběr modelu obzvláště důležitý. Podívejme se dostupné možnosti a jejich výkon.
11.1 Vícejazyčné modely
Vícejazyčné modely se trénují v desítkách jazyků současně. kvalita pro italštinu je to obecně dobré, ale nižší než výkon pro angličtinu. Doporučené modely pro italštinu jsou:
- multilingual-e5-large: Vynikající vícejazyčná kvalita, vyžaduje předponu "query:"/"passage:"
- BGE-M3: Podpora 100+ jazyků s jednotnou kvalitou, podpora hustých + řídkých + Colbert
- parafráze-multilingual-MiniLM-L12-v2: Dobrý kompromis mezi rychlostí a kvalitou pro více než 50 jazyků
- text-embedding-3-small/large (OpenAI): Dobrý vícejazyčný výkon přes API
11.2 Strategie pro zlepšování kvality
- Doladění italských dat: Dokonce i několik tisíc párů anotovaných v italštině může výrazně zlepšit výkon
- Rozšíření dat: Použijte LLM ke generování italských parafrází vašich dokumentů
- Hybridní vyhledávání: Zkombinujte sémantické vyhledávání s BM25 (klíčové slovo), abyste kompenzovali slabé stránky modelu v jazyce
- Překlad dotazu: U vysoce kvalitních anglických modelů přeložte dotaz před vložením do angličtiny (pragmatické řešení)
Cvičný test z italštiny
Před výběrem šablony pro projekt v italštině vždy proveďte test manuál s vašimi dotazy a skutečnými dokumenty. Vytvořte malou hodnotící datovou sadu (50-100 dotazů s očekávanými odpověďmi) a měří precision@k a reminiscen@k. Modelka s vysokým skóre MTEB v angličtině by mohl mít výrazně horší výkon na italštině. Benchmark MTEB zahrnuje vícejazyčné dílčí úkoly – kontrola konkrétně ty.
12. Vložení v kontextu RAG
Vložení jsou nadace každého systému RAG. Kvalita získávání – a tedy celého potrubí – přímo závisí na kvalitě vektorové reprezentace. Takto se vestavby integrují do architektury RAG kompletní.
FASE DI INDICIZZAZIONE (offline):
Documenti ──> Chunking ──> [EMBEDDING MODEL] ──> Vettori ──> Vector DB
|
Stesso modello per query!
FASE DI QUERY (online):
Query utente ──> [EMBEDDING MODEL] ──> Vettore query
|
v
[VECTOR DB: similarity search]
|
v
Top-k chunk rilevanti
|
v
[LLM + Contesto] ──> Risposta con citazioni
REGOLE D'ORO:
1. Usare SEMPRE lo stesso modello per indicizzazione e query
2. La qualità degli embeddings determina la qualità del retrieval
3. Scegliere il modello in base al dominio e alla lingua
4. Normalizzare i vettori per cosine similarity
5. Monitorare retrieval precision e recall in produzione
Nejčastější chybou v systémech RAG je podcenění důležitosti výběru vkládací model. Týmy, které investují týdny do optimalizace výzvy LLM často nikdy netestovali různé modely vkládání. V praxi projděte all-MiniLM-L6-v2 na model jako e5-large-v2 nebo BGE-M3 může zlepšit kvalitu vyhledání 15-25 %, s přímým dopadem na kvalitu konečných odpovědí.
Kontrolní seznam vložení pro RAG
- Testovali jste alespoň 3 různé modely na vaší datové sadě?
- Máte sadu hodnocení s dotazy a očekávanými odpověďmi?
- Podporuje model dostatečně kvalitně váš jazyk?
- Je rozměr kompatibilní s vaším rozpočtem úložiště?
- Je maximální délka kontextu (max. token) adekvátní pro vaše bloky?
- Uvažovali jste o doladění vaší domény?
- Sledujete kvalitu vyhledávání ve výrobě?
13. Náklady a škálování ve výrobě
Volba mezi self-hosted embedding a cloud API má významný dopad na náklady, na latenci a provozní složitosti. Pojďme analyzovat klíčové faktory, které je třeba vzít informované rozhodnutí.
Porovnání nákladů na Embedding API (2024–2025)
| Poskytovatelé | Model | Cena za 1 milion tokenu | Rozměry |
|---|---|---|---|
| OpenAI | text-embedding-3-small | 0,02 USD | 1536 |
| OpenAI | text-embedding-3-velký | 0,13 USD | 3072 |
| Cohere | embed-v3 | 0,10 USD | 1024 |
| Vlastní hostitelství | vše-MiniLM-L6-v2 | Cena GPU | 384 |
| Vlastní hostitelství | BGE-M3 | Cena GPU | 1024 |
13.1 Self-hosted vs Cloud API
- Cloud API (OpenAI, Cohere): Hodnotí se nulová infrastruktura, platba za použití, latence sítě, závislost na externí službě, soukromí dat
- Samoobslužný (vyhrazený GPU): Vysoké počáteční náklady (GPU ~ 1-3 $/hod), žádné náklady na token, minimální latence, plná kontrola dat, provozní složitost
Základní pravidlo: Za méně než 10 milionů tokenů měsíčně, cloudová API jsou levnější. Nad 100 milionů tokenů/měsíc se stává self-hosting pohodlné. Mezi 10M a 100M, závisí na požadované latenci a potřebách soukromí.
13.2 Náklady na vektorové úložiště
Každý dopravce zabírá dimensioni * 4 bytes (plovoucí 32). S modelem 768
velikost a 1 milion dokumentů: 768 * 4 * 1 M = pouze ~3 GB vektorové paměti,
ke kterým je třeba přidat metadata, indexy a režii. Pomocí kvantifikace produktu můžete
komprimovat až 8-16x, ale se ztrátou paměti.
Rychlý odhad nákladů
Pro systém RAG s 1 milionem dokumentů, rozdělených na 500 tokenů na blok, 768-dim model: potřebujete asi 3 GB RAM pro vektory + 2-4 GB pro index HNSW. Stačí cloudová instance s 8 GB RAM (kolem 50-100 $/měsíc). Pro generaci počáteční vložení s OpenAI API (text-embedding-3-small): přibližně 500 milionů tokenů = 10 $. S modelem s vlastním hostitelem a GPU T4: přibližně 2–3 hodiny výpočtu = 3–5 USD.
Závěry a další kroky
V tomto článku jsme se zabývali celým vývojem vkládání textu: no tak statické vkládání slov Word2Vec a GloVe prostřednictvím kontextového vkládání BERT, až po moderní Sentence Transformers optimalizované pro sémantické vyhledávání. máme vidět, proč je vanilkový BERT nevhodný pro vyhledávání a jak SBERT problém řeší s architekturou bi-kodéru.
Implementovali jsme kompletní sémantický vyhledávač s Pythonem, převodníky vět a FAISS, zkoumající strategie pro dávkové zpracování a velké soubory dat. Porovnali jsme hlavní vektorové databáze a indexovací algoritmy, analyzující kompromisy mezi rychlostí, vyvoláním a pamětí.
Klíčové body k zapamatování:
- Výběr modelu zapuštění je nejdůležitější rozhodnutí v systému RAG - důležitější než model LLM
- Sentence Transformers (bi-kodér) jsou standardem pro vyhledávání; Křížový kodér BERT pro přehodnocení
- Testujte další a další modely na vaší skutečné datové sadě před výběrem
- FAISS a HNSW aby bylo vyhledávání v milionech vektorů efektivní a proveditelné
- Jemné doladění může dramaticky zlepšit kvalitu pro specializované domény
- pro italštinu, používejte vícejazyčné modely (BGE-M3, multilingual-e5) a zvažte jemné doladění
V dalším článku
Ve třetím článku série se ponoříme hlouběji do Vektorové databáze: vnitřní architektura, pokročilá konfigurace indexů, strategie shardingu a replikace, filtrování metadat a jak vybrat správnou databázi pro váš případ použití. Uvidíme kompletní implementace s Qdrant, ChromaDB a pgvector.







