Uwagi praktyczne: Przeprowadziłem testy porównawcze 5 baz danych wektorowych pod kątem lokalnego RAG. Tylko jedna
Praktyczne wskazówki: Przeprowadziłem porównanie 5 baz danych wektorowych pod kątem zastosowania w lokalnym systemie RAG. Tylko jedna z nich: umowy, sprawdzenia oraz gotowe miejsca na kod dla zespołów wdrażających ten model.
Poniższe notatki przedstawiają praktyczne podejście do tematu „Przeprowadziłem testy 5 baz danych wektorowych pod kątem lokalnego RAG. Tylko jedna naprawdę mnie zaskoczyła”. Nacisk kładziony jest na umowy, sprawdzenia oraz miejsca zastępcze dla kodu, a nie na motywacyjne aspekty. Podczas przechodzenia przez etap przeglądu najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Wolno preferować małe, testowalne jednostki zamiast rozbudowanych skryptów. Gdy jakiś krok się nie powiedzie, błąd powinien wskazywać na konkretną odpowiedzialność, a nie na skomplikowany proces.
TL;DR. Tabela, po której przyszłeś.
Krótko mówiąc: etap tabel działa najlepiej, gdy traktuje się go jako powierzchnię poddającą się pomiarom. Zapisz jeden idealny przykład działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres pracy. Traktuj ten etap jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nadaj nazwy poszczególnym elementom, zdefiniuj kryteria sukcesu i odrzucaj ciche, częściowe ukończenie zadań. Rozdziel politykę dzielenia na fragmenty od polityki pobierania danych. Zmiana jednej z nich nie powinna zmuszać do przepisywania drugiej, gdy zmieniają się metryki jakości.
„Ktara baza wektorowa jest najszybsza?” to błędne pytanie
Baza danych wektorowych typu Which działa najlepiej, gdy traktuje się ją jako mierzalną powierzchnię. Zanim rozszerzysz zakres, zapisz jeden idealny przykład działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian. Zapisz czasy wykonywania operacji oraz koszt tokenów lub zapytań obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega niespodziewanym rachunkom, gdy przechodzi się z środowiska demonstracyjnego do współdzielonych środowisk. Rozdziel politykę dzielenia na fragmenty od polityki wyszukiwania. Zmiana jednej z nich nie powinna zmuszać do przepisywania drugiej, gdy zmieniają się metryki jakości.
To, co stworzyłeś (oraz to, co celowo pominąłeś)
To, co zbudowaliśmy oraz etapy realizacji działają najlepiej, gdy traktuje się je jako mierzalną powierzchnię. Zapisz jeden idealny przepis działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres projektu. Trzymaj konfigurację poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Oddziel zasadę dzielenia na fragmenty od zasady pobierania danych. Zmiana jednej z nich nie powinna zmuszać do przepisywania drugiej, gdy zmieniają się metryki jakości. To, co zbudowaliśmy oraz etapy realizacji działają najlepiej, gdy traktuje się je jako mierzalną powierzchnię. Zapisz jeden idealny przepis działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres projektu. Wolimy małe, testowalne jednostki niż rozbudowane skrypty. Gdy jakiś krok się nie powiedzie, awaria powinna wskazywać na konkretną odpowiedzialność, a nie na skomplikowaną sekwencję operacji.
Metodologia w 30 sekund
W ramach metodologii składającej się z 30 etapów należy przed zmianą kodu określić dane wejściowe, osobę odpowiedzialną za dany etap oraz kryteria zakończenia. Operatorzy powinni móc ponownie uruchomić dany etap na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Traktuj ten etap jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nazwij poszczególne elementy, zdefiniuj kryteria sukcesu i odrzuć ciche, częściowe ukończenie zadania. Podaj fragmenty tekstu, które faktycznie stanowią podstawę odpowiedzi. Bez tych odniesień operatorzy nie będą w stanie odróżnić halucynacji od luki w indeksowaniu.
vectlite : 0.10.0
vectors : 5,000 (synthetic, normalized)
dimensions : 384
queries : 50
top_k : 10
metric : cosine
filter : tenant_id (exact-match)
warmup : 5 queries discarded
hardware : macOS x86_64, Python 3.12.8
PYTHONPATH=src python -m vectlite_benchmark_lab run \
--stores vectlite,faiss,chroma,lancedb,numpy_exact \
--vectors 5000 --dimensions 384 --queries 50 \
--top-k 10 --batch-size 500 \
--output-dir results/vectlite-0.10.0 \
--data-dir data/vectlite-0.10.0
Co faktycznie mówią liczby
Zanim zmieni się kod, należy określić, co faktycznie pokazują liczby – dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia. Operatorzy powinni móc ponownie uruchomić ten krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Obok wyników funkcjonalnych należy zapisywać czas trwania oraz koszt tokenów lub zapytań. Wczesna widoczność kosztów zapobiega niespodziewanym rachunkom, gdy ścieżka przechodzi z środowiska demonstracyjnego do współdzielonych środowisk. Należy podawać fragmenty tekstu, które faktycznie stanowiły podstawę odpowiedzi. Bez tych odniesień operatorzy nie mogą odróżnić halucynacji od luki w indeksowaniu.
FAISS – górna granica szybkości
Dla etapu ograniczenia prędkości w FAISS należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić ten krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Konfigurację należy przechowywać poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Należy podawać konkretne fragmenty tekstu, na których opiera się odpowiedź. Bez tych odniesień operatorzy nie będą w stanie odróżnić halucynacji od braku indeksowania. Dla etapu ograniczenia prędkości w FAISS należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić ten krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy preferować małe, łatwe do przetestowania jednostki nad rozbudowanymi skryptami. Gdy jakiś krok zawiedzie, powinien wskazywać na konkretną odpowiedzialność, a nie na skomplikowaną strukturę.
eline.Chroma – łatwy start, zwracaj uwagę na powtarzalność
Gdy przechodzisz przez etap łatwego startu w Chromie, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Traktuj ten etap jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nadaj nazwy poszczególnym elementom, zdefiniuj kryteria sukcesu i odrzuć ciche, częściowe ukończenie zadania. Zmierz powtarzalność na ustalonej serii pytań przed dostosowywaniem promptów. Częste zmiany promptów rzadko naprawiają słabe możliwości wyszukiwania.
VectLite – niespodzianka
Gdy przechodzisz przez etap testowania VectLite, najpierw zapisz specyfikację: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Zapisz czas wykonywania oraz koszt tokenów lub zapytań obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega nieoczekiwanym rachunkom, gdy ścieżka przechodzi z środowiska demonstracyjnego do współdzielonych środowisk. Zmierz stopień odzyskiwania informacji na ustalonej grupie pytań przed dostosowywaniem promptów. Częste zmiany promptów rzadko poprawiają słabe możliwości wyszukiwania.
LanceDB – doskonały stopień odzyskiwania informacji, ale kosztem opóźnienia
Gdy pracujesz nad osiągnięciem perfekcyjnego poziomu odzyskiwania danych w LanceDB, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Przechowuj konfigurację poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Mierz poziom odzyskiwania danych na ustalonej grupie pytań przed dostosowywaniem promptów. Częste zmiany promptów rzadko naprawiają słabe mechanizmy wyszukiwania. Gdy pracujesz nad osiągnięciem perfekcyjnego poziomu odzyskiwania danych w LanceDB, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Wolij małe, testowalne jednostki nad rozbudowane skrypty. Gdy jakiś krok się nie powiedzie, błąd powinien wskazywać na konkretną odpowiedzialność, a nie na skomplikowaną sekwencję operacji.
NumPy – sędzia
Numericalna faza arbitrażu w NumPy działa najlepiej, gdy traktuje się ją jako mierzalną powierzchnię. Zapisz jeden udany przypadek, jeden przypadek niepowodzenia oraz notatkę o cofnięciu zmian przed rozszerzaniem zakresu. Traktuj tę fazę jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nadaj nazwy poszczególnym elementom, zdefiniuj kryteria sukcesu i odrzuć ciche, częściowe ukończenie zadania. Oddziel zasadę dzielenia na fragmenty od zasady pobierania danych. Zmiana jednej nie powinna zmuszać do przepisywania drugiej, gdy zmieniają się metryki jakości.
Który silnik więc powinieneś wybrać?
Więc który silnik będzie działał najlepiej, jeśli potraktujemy go jako mierzalną powierzchnię? Zapisz jeden idealny przypadek, jeden przypadek awarii oraz notatkę o cofnięciu zmian, zanim rozszerzysz zakres pracy. Zarejestruj czasy wykonywania oraz koszt tokenów lub zapytań obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega niespodziewanym rachunkom, gdy proces przechodzi z środowiska demonstracyjnego do współdzielonych środowisk. Oddziel zasadę dzielenia na fragmenty od zasady wyszukiwania. Zmiana jednej z nich nie powinna zmuszać do przepisywania drugiej, gdy zmieniają się metryki jakości.
Początek pracy od zera i przenośność – test, którego nikt nie przeprowadza
Faza rozruchu z zimnego startu i przenoszności działa najlepiej, gdy traktuje się ją jako mierzalną powierzchnię do analizy. Zapisz jeden idealny przykład działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres pracy. Trzymaj konfigurację poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Oddziel zasadę dzielenia na fragmenty od zasady pobierania danych. Zmiana jednej z nich nie powinna zmuszać do przepisywania drugiej, gdy zmieniają się metryki jakości. Faza rozruchu z zimnego startu i przenoszności działa najlepiej, gdy traktuje się ją jako mierzalną powierzchnię do analizy. Zapisz jeden idealny przykład działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres pracy. Wolij małe, testowalne jednostki nad rozbudowane skrypty. Gdy jakiś krok zawiedzie, awaria powinna wskazywać na konkretną odpowiedzialność, a nie na skomplikowaną sekwencję operacji.
Czego ten benchmark NIE dowodzi
W etapie „Co robi ten benchmark” należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić ten krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Traktuj ten etap jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nazwij poszczególne elementy, zdefiniuj kryteria sukcesu i odrzuć ciche, częściowe ukończenie zadania. Podaj fragmenty tekstu, które faktycznie stanowią podstawę odpowiedzi. Bez tych odniesień operatorzy nie będą w stanie odróżnić halucynacji od luki w indeksowaniu.
Kolejne kroki
W fazie „Co dalej?” należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy odnotować czasy wykonywania oraz koszt tokenów lub zapytań obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega nieoczekiwanym rachunkom, gdy ścieżka przechodzi z środowiska demonstracyjnego do współdzielonych środowisk. Należy podać fragmenty tekstu, które faktycznie stanowiły podstawę odpowiedzi. Bez tych odniesień operatorzy nie mogą odróżnić halucynacji od luki w indeksowaniu.
To, czego naprawdę się nauczyłeś
W etapie „Co faktycznie się nauczyłeś” należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Konfigurację należy przechowywać poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Należy podawać konkretne fragmenty tekstu, na których opiera się odpowiedź. Bez tych odniesień operatorzy nie będą w stanie odróżnić halucynacji od braku danych w indeksie. W etapie „Co faktycznie się nauczyłeś” należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy preferować małe, testowalne jednostki nad rozbudowanymi skryptami. Gdy dany krok zawiedzie, powinien wskazywać na konkretną odpowiedzialność, a nie na skomplikowaną strukturę.
pipeline.Odnośniki
Podczas prace na etapie Odnośników najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Traktuj ten etap jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nadaj nazwy artefaktom, zdefiniuj kryteria sukcesu i odrzuć ciche, częściowe ukończenie zadania. Zmierz stopień przywoływalności na ustalonej serii pytań przed dostosowywaniem promptów. Częste zmiany promptów rzadko naprawiają słabe możliwości wyszukiwania.
Lista kontrolna operacyjna
Na etapie Listy kontrolnej operacyjnej zdefiniuj dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed wprowadzaniem zmian w kodzie. Operatorzy powinni móc ponownie uruchomić dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu.
Zdokumentuj zarówno ścieżkę prawidłowego działania, jak i ścieżkę przywracania. Próby ponowne, kontrola przez ludzi oraz obsługa wiadomości błędnych stanowią część produktu, a nie elementy dodawane później.
Cytuj fragmenty, które faktycznie stanowią podstawę odpowiedzi. Bez cytatów operatorzy nie mogą odróżnić halucynacji od luki w indeksowaniu.
Ewentualnie gorsza odpowiedź, która kosztuje 10 razy mniej, może być właściwym kompromisem w produkcji – należy uwzględniać przy tym zarówno jakość, jak i koszt oraz opóźnienia.
Zaznacz wersje zależności i zapisz digest obrazu użytego do przeprowadzenia demo. Reprodukowalność jest ważniejsza od lokalnej wiedzy zespołu.
Zapisz czasy wykonywania oraz koszt tokenów lub zapytań obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega niespodziewanym rachunkom, gdy ścieżka przechodzi z demo do wspólnych środowisk.
Zanim zaczniesz promować tę architekturę, zamroź wersje, utwórz dokładny zapis dla kluczowych ścieżek oraz potwierdź kroki odwracania zmian. Środowiska współdzielone wymagają ograniczeń szybkości, weryfikacji użytkowników oraz wyraźnego właściciela odpowiedzialnego za rotację haseł. Wolimy nudną niezawodność od pomysłowych, jednorazowych demonstracji.
Uwaga dotycząca 67d5abfd67f4: trzymaj klucze dostawcy poza repozytorium, ustaw ograniczenie liczby tokenów na sesję oraz przechowuj zapisy obok narzędzi do oceny, aby późniejsze zmiany modeli pozostały porównywalne.