Powrót do strony głównej

Wyszukiwanie hybrydowe bez chmury: PostgreSQL i VectorChord

Przewodnik techniczny po tworzeniu lokalnego hybrydowego systemu wyszukiwania na bazie PostgreSQL i VectorChord. Szczegółowa konfiguracja Jina v4 przez llama.cpp, implementacja natywnego rerankera i semantycznego chunkera chonkie. Porównanie metryk jakości i rekomendacje optymalizacji.

Pełny przewodnik po lokalnym wyszukiwaniu hybrydowym w systemach RAG
Advertisement 728x90

# Lokalny hybrydowy system wyszukiwania: PostgreSQL i VectorChord bez chmury

Po wdrożeniu podstawowej infrastruktury hybrydowego wyszukiwania w pierwszej części cyklu nadszedł czas na zastąpienie tymczasowych komponentów rozwiązaniami produkcyjnymi. Prawdziwa implementacja wymaga rezygnacji z chmurowych API i przejścia na w pełni lokalne modele SOTA. W tym poradniku szczegółowo omówimy wdrożenie wielojęzycznego embeddera Jina v4 za pomocą llama.cpp, natywnego rerankera na PyTorch oraz semantycznego chunkera chonkie — wszystkie elementy działają w trybie offline bez utraty jakości wyszukiwania.

Kluczowym wyzwaniem jest zachowanie równowagi między wydajnością a precyzją przy przetwarzaniu złożonych dokumentów z tabelami i ilustracjami. Skupiamy się na systemach RAG, gdzie kluczowe jest wsparcie dla Matryoshka-embeddings oraz poprawna obsługa kontekstowych prefiksów dla passage/query.

Konfiguracja lokalnego embeddera na Jina v4

Wybór modelu wynika z trzech czynników: wsparcie dla wektorów Matryoshka, specjalizacja w text-retrieval oraz otwartość architektury. Jina-embeddings-v4-text-retrieval jest zoptymalizowana pod wyszukiwanie dokumentów i wymaga 2,4 GB pamięci wideo przy pracy z pełnowymiarowymi embeddingami o wymiarowości 2048. Aby oszczędzać zasoby, używamy kompresji GGUF i konfigurujemy dynamiczne zmniejszanie wymiarowości.

Google AdInline article slot

Przygotowanie środowiska

  • Pobieramy model jina-embeddings-v4-text-retrieval-Q8_0.gguf z HuggingFace
  • Umieszczamy w katalogu nlp_models/jina_embeddings_v4
  • Konfigurujemy obraz Docker z akceleracją GPU:
services:
  jina-embeddings:
    image: ghcr.io/ggml-org/llama.cpp:server-cuda
    volumes:
      - ./nlp_models/jina_embeddings_v4:/models
    ports:
      - "8080:8080"
    command: >
      -m /models/jina-embeddings-v4-text-retrieval-Q8_0.gguf
      --embedding
      --pooling mean
      --host 0.0.0.0
      --port 8080
      -ngl 99
      -c 8192
      --flash-attn on
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]

Krytyczne parametry:

  • -ngl 99 — załadowanie wszystkich warstw na GPU
  • -c 8192 — maksymalny rozmiar kontekstu
  • --flash-attn on — aktywacja optymalizacji obliczeń

Integracja z VectorChord

Tworzymy klasę LocalJinaEmbedding, dziedziczącą po BaseEmbedding. Szczególną uwagę poświęcamy prefiksom:

class LocalJinaEmbedding(BaseEmbedding):
    async def vectorize_chunk(self, text: str) -> np.ndarray:
        prefixed_text = f'Passage: {text}'
        return (await self._get_embeddings(prefixed_text))[0]

    async def vectorize_query(self, text: str) -> np.ndarray:
        prefixed_text = f'Query: {text}'
        return (await self._get_embeddings(prefixed_text))[0]

Dokumentacja Jina v4 wymaga ścisłego rozdzielania prefiksów:

Google AdInline article slot
  • Dla dokumentów: Passage: {original_text}
  • Dla zapytań: Query: {original_text}

To kluczowe dla osiągnięcia deklarowanej precyzji 89,7% na zbiorze danych BEIR.

Implementacja natywnego rerankera

Algorytm RRF z pierwszej części zastępujemy modelem jina-reranker-v3 — modelem z 140M parametrami, zdolnym do przetwarzania par (zapytanie, dokument) z prędkością 230 zapytań/sek przy użyciu NVIDIA A100.

Optymalizacja pod produkcję

  • Batchowanie zapytań: Grupowanie do 32 par w jednym batchu w celu maksymalizacji wykorzystania GPU
  • Kwantyzacja: Zastosowanie 8-bitowej kwantyzacji za pomocą bitsandbytes
  • Buforowanie: Zapis wyników dla często powtarzających się zapytań
from transformers import AutoModelForSequenceClassification

model = AutoModelForSequenceClassification.from_pretrained(
    "jinaai/jina-reranker-v3",
    trust_remote_code=True,
    device_map="auto",
    load_in_8bit=True
)

Ważne: Model wymaga wstępnego przetwarzania tekstu za pomocą tokenizera Jina, który automatycznie dodaje specjalne tokeny [CLS] i [SEP].

Google AdInline article slot

Semantyczny chunking z chonkie

Standardowy splitter oparty na spaCy zastępujemy biblioteką chonkie — zorientowaną na zachowanie semantycznej spójności chunków. Kluczowe parametry konfiguracji:

  • max_tokens=512 — ograniczenie długości chunku
  • semantic_threshold=0.75 — minimalna kosinusowa podobieństwo dla łączenia zdań
  • overlap=0.2 — nakładanie między sąsiednimi chunkami

Zaleta chonkie nad prostymi splitterami:

  • Zachowanie tabel i list w jednym chunke
  • Automatyczne wykrywanie sekcji za pomocą nagłówków
  • Wsparcie dla tekstów wielojęzycznych bez przekwalifikowania

Co jest ważne

  • Matryoshka-embeddings pozwalają na dynamiczną regulację wymiarowości od 128 do 2048 bez ponownego przetwarzania danych
  • Przetwarzanie prefiksowe Query/Passage jest kluczowe dla osiągnięcia maksymalnej precyzji
  • Flash Attention przyspiesza przetwarzanie o 40% przy pracy z długimi dokumentami
  • Kwantyzacja modeli zachowuje 98% precyzji przy redukcji zużycia pamięci o 75%
  • Semantyczny chunking zwiększa relewantność wyników o 22% w porównaniu z wyrażeniami regularnymi

Testy integracyjne

Przeprowadzono serię testów na zbiorze danych MS MARCO z pomiarem metryk:

| Metryka | spaCy (część 1) | Jina v4 + chonkie |

|------------|-----------------|-------------------|

| MRR@10 | 0.312 | 0.487 |

| Recall@100 | 0.674 | 0.891 |

| Latency | 120ms | 210ms |

Obserwowany kompromis: wzrost opóźnienia jest rekompensowany znaczącym wzrostem precyzji. Do optymalizacji opóźnienia zalecamy:

  • Użyć wymiarowości 1024 zamiast 2048
  • Włączyć buforowanie embeddingów
  • Skonfigurować pulę połączeń HTTPX z max_connections=50

Kluczowa rekomendacja: Przy wdrażaniu w produkcji zawsze przeprowadzajcie testy A/B z waszym specyficznym zbiorem danych — uniwersalne metryki mogą nie odzwierciedlać rzeczywistych potrzeb waszego systemu RAG.

— Editorial Team

Advertisement 728x90

Czytaj dalej