Strona główna / Artykuły / Lokalny RAG bez wektorów: SQLite FTS5 i BM25 do wyszukiwania w kodzie

Lokalny RAG bez wektorów: SQLite FTS5 i BM25 do wyszukiwania w kodzie

Dlaczego gęste indeksy wektorowe obciążają komputer programisty i jak SQLite FTS5 z BM25 daje szybsze, dokładne wyszukiwanie w kodzie przy ułamku pamięci.

758 słów

Przez kilka lat przepis na lokalne wyszukiwanie w kodzie był ten sam: pociąć repozytorium na fragmenty, zamienić każdy fragment na embedding o 1536 wymiarach i trzymać indeks HNSW przy życiu w procesie działającym w tle. Wyglądało to nowocześnie, jakby laptop dostał małą wyszukiwarkę, która rozumie, co znaczy kod. Na mocno obciążonej stacji roboczej ten przepis ma jednak koszt, o którym rzadko pisze się w README.

Nagłówkowe liczby wokół lokalnego wyszukiwania wektorowego robią wrażenie: wysokie wyniki wyszukiwania w MTEB, miliony tokenów kodu zamienione na embeddingi w kilka minut, "natychmiastowa inteligencja semantyczna" na sprzęcie konsumenckim. Gdy jednak zamiast materiałów marketingowych przeczyta się uwagi o pamięci, obraz jest inny. Gęste indeksowanie wektorowe kupuje swoją kompletność wyników za cenę przepustowości pamięci, RAM lub VRAM i przewidywalności.

Gdy wektory wszędzie zderzają się ze ścianą pamięci

Uruchom bazę wektorową obok lokalnego LLM, IDE i kilku kontenerów Docker, a nie będzie bezczynna. Trzyma w RAM lub VRAM duże struktury grafowe, walczy z innymi narzędziami o przepustowość i wnosi dryf semantyczny: szukasz dokładnego ciągu ERR_AUTH_EXPIRED, a dostajesz kod, który tylko w jakiś sposób dotyczy uwierzytelniania.

Dlatego wiele zespołów po cichu wraca do natywnych algorytmów w C, czyli do SQLite FTS5 z BM25. Zamiast matematyki wektorowej przy lokalnych zapytaniach stosują deterministyczny ranking oparty na częstości terminów i znajdują dokładne identyfikatory w mniej niż 5 milisekund.

Dopasowanie pojęć kontra przewidywalna szybkość

To nie jest drobna poprawka. To zmienia sposób budowania narzędzi dla programistów. Zamieniając lokalny narzut wektorowy na FTS5, rezygnujesz z teoretycznego dopasowania pojęć w zamian za oszczędne i szybkie działanie.

  • Wydajność: rezygnacja z gęstego indeksowania zwalnia gigabajty pamięci. Praca, która zajmowała około 200 ms na liczenie embeddingów, kończy się natywnie w mniej niż 5 ms.
  • Precyzja: wyszukiwanie dokładnych słów kluczowych i nazw funkcji, takich jak getUserById(), jest w pełni deterministyczne, więc indeks nie zwróci ciał niezwiązanych funkcji.

Oba przepływy wyglądają w porównaniu tak:

[Dense Vector RAG Flow]
Code Query -> Generate Vector Embeddings -> HNSW Index Search -> Semantic Drift Risk -> LLM Context
[Deterministic BM25 Flow]
Code Query -> Native SQLite C-Index -> Exact Keyword Match (5ms) -> Minimal LLM Context

Objawy, które być może już znasz

Każdy, kto uruchamia lokalnych agentów lub wyszukiwanie w kodzie, pewnie zauważył to tarcie:

  • Rywalizacja o zasoby. Wentylator się rozkręca, bateria wytrzymuje dwie godziny, a lokalna inferencja się wlecze, bo silnik w tle walczy o pamięć.
  • Kara za dokładne dopasowanie. Wyszukanie konkretnego komunikatu błędu lub zmiennej zwraca pięć plików, które znaczeniowo są blisko uwierzytelniania, ale nie ten jeden plik, w którym jest właściwa flaga.

Zestawienie obok siebie, z orientacyjnymi liczbami:

Wymiar Lokalna baza wektorowa (Chroma, Qdrant) SQLite FTS5 (BM25)
Zużycie pamięci Około 1,5 do 4 GB RAM lub VRAM Około 15 do 30 MB RAM
Opóźnienie wyszukiwania 120 do 400 ms, głównie na embeddingi Poniżej 5 ms, natywne C
Dokładne dopasowanie identyfikatorów Słabe, podatne na dryf Mocne, deterministyczne dopasowanie słów kluczowych
Narzut systemowy Demony w tle, powiązania z C++ W bezczynności nic nie działa
Najlepsze do Szerokich, tematycznych wyszukiwań w tekście Precyzyjnych zapytań w kodzie, logach i lokalnym RAG

Traktuj to jako wartości orientacyjne, bo wyniki zależą od wielkości korpusu, wyboru modelu i sprzętu.

Co to oznacza dla liderów zespołów

Odruch dołączania bazy wektorowej do każdego lokalnego problemu słabnie. Bardziej przydatne jest wyczucie proporcji. Umiejętność doświadczonego architekta nie polega na upychaniu coraz cięższej infrastruktury AI w laptopach programistów. Polega na rozpoznaniu, kiedy dziesięć linii natywnego kodu albo plik SQLite o rozmiarze 30 MB wygrywa z neuronowym potokiem liczonym w gigabajtach.

W miarę jak narzędzia przyspieszają, a procesy się odchudzają, wygrywać nie będą stosy z największymi modelami. Wygrają te, które dostarczają czysty kod bez balastu. Nie czyni to embeddingów bezużytecznymi: przy nieostrych pytaniach o pojęcia w zwykłym tekście nadal mają sens. Żeby jednak znaleźć dokładny identyfikator w bazie kodu, zacznij od taniego, deterministycznego narzędzia i dodawaj wektory tylko tam, gdzie ono zawodzi.