<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Nomic-Embed-Text — Inferownia</title><link>https://inferownia.pl/tags/nomic-embed-text/</link><description>Inferownia — polski hub wiedzy o lokalnym AI: uruchamianie modeli językowych na własnym sprzęcie, kwantyzacja, inferencja, małe modele, fine-tuning i RAG.</description><language>pl-PL</language><copyright>&#169; 2026 Inferownia</copyright><lastBuildDate>Fri, 10 Jul 2026 00:00:00 +0200</lastBuildDate><atom:link href="https://inferownia.pl/tags/nomic-embed-text/index.xml" rel="self" type="application/rss+xml"/><item><title>RAG lokalnie, bez chmury: jak to się w ogóle spina</title><link>https://inferownia.pl/poradniki/rag-lokalnie/</link><pubDate>Fri, 10 Jul 2026 00:00:00 +0200</pubDate><category>RAG</category><guid>https://inferownia.pl/poradniki/rag-lokalnie/</guid><description>Chcesz, żeby lokalny model gadał o twoich notatkach, a nie o Wikipedii sprzed treningu. Rozbieramy RAG na części: chunking, embeddingi, baza wektorowa, retrieval — i tłumaczymy, czego on NIE załatwia.</description><content:encoded><![CDATA[<p>Pewien człowiek miał na dysku trzysta PDF-ów — faktury, notatki ze spotkań, instrukcje do
sprzętu, o którym już zdążył zapomnieć, że go w ogóle kupił — więc zrobił rzecz z pozoru
oczywistą: zapytał lokalny model „ej, ile płaciłem za tę kartę w zeszłym roku?&quot;. Chciał tylko
odpowiedzi, lokalnie, bez wysyłania własnego życia do cudzej chmury. Model odpowiedział z pełną
powagą — podał kwotę, sklep i datę, wszystkie trzy wyssane z palca. Bo skąd niby miałby to
wiedzieć? Twoich faktur nie było w danych treningowych. Model zna świat do dnia, w którym
zamknięto mu trening, i ani tokena dalej.</p>
<p>I tu pojawia się pytanie, które w dyskusjach o lokalnych modelach wraca co tydzień jak bumerang: „to jak
zrobić, żeby model gadał o MOICH danych?&quot;. Pierwszy odruch połowy internetu to „dotrenuj
go&quot;. Zły odruch — o tym za chwilę. Odruch drugi, ten dobry, to trzy litery: <strong>RAG</strong>.</p>
<h2 id="co-to-właściwie-jest-ten-rag">Co to właściwie jest ten RAG</h2>
<p>RAG — <em>retrieval-augmented generation</em>, czyli generowanie wspomagane wyszukiwaniem — to
pomysł starszy, niż się wydaje. Opisali go Lewis i spółka w pracy z 2020 roku, jeszcze
zanim „chatbot&quot; wszedł pod strzechy.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> Idea jest sprytnie prosta: zamiast upychać całą
wiedzę świata w wagach modelu (to autorzy nazywają <em>pamięcią parametryczną</em> — wszystko, co
model „umie z głowy&quot;), doklejasz mu drugą pamięć — <em>nieparametryczną</em>. U Lewisa był to gęsty
indeks wektorowy całej Wikipedii, przeszukiwany przez osobny model-wyszukiwarkę. Model
najpierw <em>pobiera</em> pasujące fragmenty, a dopiero potem generuje odpowiedź, patrząc na to,
co znalazł.</p>
<p>Przełóż to na twój folder z PDF-ami. Nie douczasz modelu, że kartę kupiłeś za tyle a tyle.
Ty w momencie zadawania pytania podsuwasz mu odpowiedni kawałek faktury i mówisz: „odpowiedz
na podstawie tego&quot;. Model dostaje ściągę tuż przed odpowiedzią. Cała sztuka w tym, żeby
z trzystu PDF-ów wyłuskać akurat ten jeden akapit, który pasuje — i zrobić to w ułamku sekundy.</p>
<h2 id="jak-to-się-spina-krok-po-kroku">Jak to się spina, krok po kroku</h2>
<p>No dobra, „wyłuskać pasujący akapit&quot; brzmi ładnie, ale jak maszyna ma wiedzieć, co pasuje
do „ile płaciłem za kartę&quot;? Rozłóżmy łańcuch na części, bo on ma dokładnie cztery ogniwa
i każde robi jedną robotę.</p>
<p><strong>Raz — chunking.</strong> Dzielisz dokumenty na kawałki (chunki). Nie wrzucasz całego 40-stronicowego
PDF-a jako jednej bryły, tylko tniesz na fragmenty po parę zdań. I tu pierwsza pułapka,
w którą wpada każdy na starcie: cięcie na sztywno co X znaków. Utniesz w połowie zdania,
w połowie tabelki z cenami — i fragment traci sens, a razem z nim traci sens jego reprezentacja.
Podział semantyczny (po akapitach, sekcjach, zdaniach) jest nudniejszy w implementacji, ale
retrieval potem dziękuje.</p>
<p><strong>Dwa — embeddingi.</strong> Każdy chunk przepuszczasz przez <em>model embeddingowy</em> — osobny, mały
model, który zamienia tekst w wektor liczb, czyli <em>osadzenie</em> (embedding). Sęk w tym, że
te wektory układają się w przestrzeni tak, że teksty o podobnym znaczeniu lądują blisko
siebie. „Zapłaciłem 1400 zł za RTX-a&quot; i „koszt karty graficznej wyniósł&quot; wylądują obok,
mimo że nie mają wspólnego słowa. To jest serce całej zabawy.</p>
<p>Dwa modele, które na lokalnej scenie widać najczęściej:</p>
<table>
	<thead>
			<tr>
					<th>Model</th>
					<th>Wymiar wektora</th>
					<th>Kontekst</th>
					<th>Języki</th>
					<th>Licencja</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td><code>nomic-embed-text-v1.5</code></td>
					<td>768 (skalowalny w dół)</td>
					<td>8192 tokenów</td>
					<td>głównie angielski</td>
					<td>Apache 2.0</td>
			</tr>
			<tr>
					<td><code>bge-m3</code></td>
					<td>1024</td>
					<td>8192 tokenów</td>
					<td>100+</td>
					<td>MIT</td>
			</tr>
	</tbody>
</table>
<p><code>nomic-embed-text-v1.5</code> ma jedną fajną sztuczkę — Matryoshka Representation Learning:
natywnie robi wektor 768-wymiarowy, ale możesz go przyciąć w dół, choćby do 64 wymiarów,
tracąc na jakości zaskakująco mało.<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> Mniejszy wektor to mniejsza baza i szybsze
wyszukiwanie. <code>bge-m3</code> gra w inną grę — ogarnia ponad sto języków (czyli i polski),
a przy okazji jeden model daje ci trzy tryby wyszukiwania naraz: gęsty, leksykalny i
wielowektorowy w stylu ColBERT.<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> Do tego drugiego zaraz wrócimy.</p>
<div class="callout">
  <span class="callout__label">Dlaczego to ważne dla lokalnego LLM</span>
<p>Najczęstszy babol na starcie z nomikiem: model wymaga <strong>prefiksów instrukcji</strong>. Dokument,
który indeksujesz do bazy, poprzedzasz <code>search_document: </code>, a zapytanie użytkownika —
<code>search_query: </code>. To nie kosmetyka. Wrzucisz zapytanie z prefiksem dokumentu (albo w ogóle
bez prefiksu) i trafność retrievalu leci na łeb, bo model liczy embedding „nie w tym trybie&quot;,
w którym powinien.<sup id="fnref1:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> Embedding dokumentu i embedding pytania to u nomika DWIE różne
operacje, nie jedna.</p>
</div>
<p><strong>Trzy — baza wektorowa.</strong> Te wszystkie wektory trzeba gdzieś trzymać i umieć szybko
przeszukać. Tu masz dwa światy. Z jednej strony <strong>FAISS</strong> od Meta — biblioteka do
wyszukiwania podobieństwa w gęstych wektorach, z całym menu typów indeksu: <code>IndexFlatL2</code>
(dokładne przeszukanie wszystkiego), IVF (partycjonowanie na kubełki), HNSW (grafy nawigacyjne)
czy Product Quantization (stratna kompresja wektorów).<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup> Szybka i potężna, ale sama
z siebie nie trzyma metadanych ani nie martwi się trwałością — to silnik, nie baza. Z drugiej
strony <strong>Chroma</strong> — pełna baza wektorowa open source, która obok embeddingów przechowuje
metadane, filtruje po nich, wspiera wyszukiwanie gęste, rzadkie i hybrydowe, i którą
odpalisz lokalnie jednym importem.<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup> Mylenie tych dwóch to klasyk: FAISS da ci
surową prędkość, Chroma da ci wygodę i „ten dokument jest z folderu faktury, rok 2025&quot;.</p>
<p><strong>Cztery — retrieval i wstrzyknięcie kontekstu.</strong> Użytkownik pyta. Ty liczysz embedding
pytania (z prefiksem <code>search_query: </code>, pamiętasz?), baza zwraca ci <em>top-k</em> najbliższych
chunków — powiedzmy trzy albo pięć najbardziej pasujących — a ty wklejasz je do promptu tuż
przed pytaniem. To jest to całe <em>context injection</em>: „Oto fragmenty z dokumentów: [&hellip;].
Na ich podstawie odpowiedz: ile płaciłem za kartę?&quot;. Model generuje odpowiedź warunkowaną
na tym, co mu podsunąłeś. Koniec łańcucha.</p>
<p>I tu druga pułapka, na którą łapie się nawet ogarnięty ludek: „skoro więcej kontekstu =
lepiej, to wezmę top-k równe 20&quot;. Nie. Nadmiar fragmentów rozmywa uwagę modelu, zapycha
okno kontekstu i topi ten jeden trafny akapit w morzu luźno pasujących. Mniej, ale celniej.
Stąd zresztą pomysł na re-ranking — najpierw baza wyławia dwadzieścia kandydatów, a osobny
model-sędzia przestawia je i oddaje ci trzy najlepsze. Twórcy <code>bge-m3</code> wprost zalecają
łączyć jego tryby hybrydowo i dokładać re-ranker, jak zależy ci na maksymalnej jakości.<sup id="fnref1:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></p>
<h2 id="czego-rag-nie-robi-i-dlaczego-to-ważne">Czego RAG NIE robi (i dlaczego to ważne)</h2>
<p>Wróćmy do tego „złego odruchu&quot; z początku. RAG <strong>nie douczy</strong> modelu. Nie dotyka jego wag,
nie zaszywa wiedzy na stałe. Podaje kontekst w czasie inferencji — i tyle. Wywal dokument
z bazy wektorowej, a model „zapomina&quot; go w tej samej sekundzie, bo nigdy naprawdę go nie
„zapamiętał&quot;. To zupełnie inna bajka niż fine-tuning, gdzie modyfikujesz parametry i żeby
zaktualizować wiedzę, musisz przepuścić model przez kolejny trening — techniki pokroju QLoRA
rozbieraliśmy <a href="/naukowy/qlora/">tutaj</a>. Prosta zasada na później: <strong>wiedza, która się
zmienia albo jest prywatna → RAG. Zachowanie, styl, format odpowiedzi → fine-tuning.</strong></p>
<p>I jeszcze jedno, żebyś nie wyszedł z fałszywym poczuciem bezpieczeństwa: RAG <strong>nie gwarantuje</strong>
braku halucynacji. Podsuniesz modelowi trafny akapit, a on i tak potrafi go zignorować albo
przekręcić. Redukujesz ryzyko, nie kasujesz go do zera. No i pamiętaj, że te embeddery mają
okno 8192 tokenów — wrzucisz dłuższy dokument bez dzielenia, a końcówka po prostu zostanie
obcięta i nigdy nie trafi do bazy.</p>
<h2 id="zrób-to-sam">Zrób to sam</h2>
<p>Najfajniejsze w lokalnym RAG-u jest to, że embeddingi policzysz tym samym <code>llama.cpp</code>,
którym odpalasz zwykły model — <a href="/poradniki/flagi-llama-cpp/">flagi rozbieraliśmy osobno</a>.
Ściągasz GGUF-a z nomikiem i odpalasz serwer z jedną dodatkową flagą:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">llama-server -m nomic-embed-text-v1.5.Q8_0.gguf <span class="se">\
</span></span></span><span class="line"><span class="cl">  --embeddings <span class="se">\
</span></span></span><span class="line"><span class="cl">  --host 0.0.0.0 --port <span class="m">8080</span>
</span></span></code></pre></div><p><code>--embeddings</code> przełącza <code>llama-server</code> w tryb liczenia wektorów.<sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup> Potem strzelasz
do niego jak do zwykłego API — i tu drobiazg, o który łatwo się potknąć: endpoint
<code>/embeddings</code> obsługuje wszystkie tryby poolingu, łącznie z <code>--pooling none</code> (wektor
per token), natomiast zgodny z OpenAI <code>/v1/embeddings</code> wymaga poolingu innego niż <code>none</code>.<sup id="fnref1:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl http://localhost:8080/v1/embeddings <span class="se">\
</span></span></span><span class="line"><span class="cl">  -H <span class="s2">&#34;Content-Type: application/json&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  -d <span class="s1">&#39;{&#34;input&#34;: &#34;search_document: RTX 4070, faktura, 2799 zł&#34;}&#39;</span>
</span></span></code></pre></div><p>Widzisz ten <code>search_document: </code> wklejony w treść? To nie ozdoba — to ten prefiks, bez
którego nomic liczy nie to, co trzeba. Dostajesz z powrotem wektor 768 liczb, wsadzasz go
do Chromy albo FAISS-a razem z oryginalnym tekstem i metadanymi, i powtarzasz dla każdego
chunka. Zapytanie liczysz identycznie, tylko z prefiksem <code>search_query: </code>. Cały lokalny RAG
to te cztery ogniwa spięte skryptem na sto linijek — reszta to strojenie.</p>
<p>Kończąc, wyobraź to sobie tak: fine-tuning jest jak wysłanie modelu z powrotem do szkoły,
żeby na nowo wykuł materiał. RAG to podanie mu otwartej książki tuż przed egzaminem —
z zakładką na właściwej stronie. Model dalej jest tym samym modelem, wagi ani drgną.
Zmienia się tylko to, że tym razem nie musi zgadywać, ile płaciłeś za tę kartę. Ma to
czarno na białym, w akapicie, który sam mu podsunąłeś.</p>
<h2 id="przypisy--źródła">Przypisy · źródła</h2>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Lewis et al., „Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks&quot;, NeurIPS 2020 — <a href="https://arxiv.org/abs/2005.11401">arxiv.org/abs/2005.11401</a>. Definicja RAG oraz podział na pamięć parametryczną (model seq2seq) i nieparametryczną (gęsty indeks wektorowy Wikipedii przeszukiwany przez neuronowy retriever).&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Karta modelu <code>nomic-ai/nomic-embed-text-v1.5</code>, Hugging Face — <a href="https://huggingface.co/nomic-ai/nomic-embed-text-v1.5">huggingface.co/nomic-ai/nomic-embed-text-v1.5</a>. Wymiar 768 z Matryoshka Representation Learning (skalowanie w dół, np. do 64), kontekst 8192 tokenów, wymagane prefiksy <code>search_document: </code> / <code>search_query: </code>, licencja Apache 2.0.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Karta modelu <code>BAAI/bge-m3</code>, Hugging Face — <a href="https://huggingface.co/BAAI/bge-m3">huggingface.co/BAAI/bge-m3</a>. Wymiar 1024, kontekst 8192, ponad 100 języków (baza XLM-RoBERTa), trzy tryby retrievalu naraz (dense / sparse / multi-vector w stylu ColBERT), zalecenie hybrydowego łączenia z re-rankerem, licencja MIT.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>FAISS (Meta AI Research) — <a href="https://faiss.ai/">faiss.ai</a>. Biblioteka do similarity search i klastrowania gęstych wektorów; typy indeksów <code>IndexFlatL2</code>, IVF, HNSW, Product Quantization, wsparcie GPU.&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>Dokumentacja Chroma, „Introduction&quot; — <a href="https://docs.trychroma.com/docs/overview/introduction">docs.trychroma.com/docs/overview/introduction</a>. Open-source&rsquo;owa baza wektorowa (Apache 2.0): przechowywanie embeddingów z metadanymi, wyszukiwanie dense/sparse/hybrydowe, filtrowanie po metadanych, tryby lokalny / self-hosted / Chroma Cloud.&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>README serwera <code>llama.cpp</code> (ggml-org) — <a href="https://github.com/ggml-org/llama.cpp/blob/master/tools/server/README.md">github.com/ggml-org/llama.cpp/blob/master/tools/server/README.md</a>. Flaga <code>--embeddings</code> do <code>llama-server</code>; endpoint <code>/embeddings</code> wspiera wszystkie tryby poolingu (w tym <code>--pooling none</code>), a zgodny z OpenAI <code>/v1/embeddings</code> wymaga poolingu innego niż <code>none</code>.&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item></channel></rss>