PRODSuwerenna europejska platforma BaaSOtwórz Panel →

Natywna sztuczna inteligencja · 10 min odczytu

Samouczek: Potok RAG z Postgres i pgvector

Affane Daylami · Fondateur · 13 kwietnia 2026

Powrót do bloga

Budowanie potoku RAG w Postgres zazwyczaj wymaga samodzielnego złożenia kilku elementów: fragmentatora tekstu, wywołania osadzania, tabeli pgvector, zapytania o podobieństwo. To jest klasyczny LangChain + PGVectorchain. W Aurabase ten potok już istnieje po stronie serwera: dwa wywołania, ragIngest() i rag(), zastępują go, opierając się na standardowym PostgreSQL i pgvector, bez zastrzeżonej bazy wektorów do dodania.

Ten tekst w języku angielskim został wygenerowany automatycznie na podstawie francuskiego oryginału i nie był jeszcze recenzowany.
Ta strona została przetłumaczona automatycznie. Wersja angielska jest miarodajna.

Natywny RAG jest częścią natywnej sztucznej inteligencjizintegrowanej z backendem Aurabase, wraz z NL2SQL: nie jest to usługa strony trzeciej, którą można montować na bazie ogólnej. Warunki wstępne do wykonania tego samouczka: istniejący projekt Aurabase, skonfigurowany dostawca LLM (OpenAI lub Google Gemini do osadzania, jeden z trzech natywnych dostawców do generowania) oraz klucz API projektu.

Najważniejsze
  • Potok Aurabase RAG składa się z dwóch wywołań: ragIngest() w celu indeksowania dokumentu, rag() w celu zapytania i wygenerowania odpowiedzi. Porcjowanie, osadzanie i wyszukiwanie wektorów są zarządzane po stronie serwera.
  • Pod maską znajduje się standardowy PostgreSQL i pgvector: tabela embeddings z jedną kolumną wektorową na klasę wymiaru (768, 1536, 3072) i częściowym indeksem HNSW na klasę.
  • Dzielenie wykorzystuje prawdziwy tokenizer (tiktoken o200k), z konfigurowalnym nakładaniem się i zabezpieczeniem przeciwwybuchowym w przypadku dużych dokumentów.
  • Pobrana treść jest neutralizowana przed wstrzyknięciem do zachęty: dokument próbujący uciec od swojego znacznika w celu sfałszowania instrukcji systemowych jest jawnie rozbrojony.
  • Tylko OpenAI i Gemini generują osadzanie po stronie Aurabase. Anthropic/Claude nie posiada publicznego interfejsu API do osadzania, pozostaje on zarezerwowany do generowania ostatecznej odpowiedzi.
#
Pojęcie

Jak działa ten rurociąg RAG

Rurociąg przebiega w pięciu etapach. Po spożyciu tekst jest cięty, każdy fragment jest wektoryzowany wsadowo, a następnie przechowywany. Podczas wykonywania zapytania pytanie jest kolejno wektoryzowane w porównaniu z fragmentami przechowywanymi na podstawie podobieństwa cosinus, a najbliższe fragmenty są wstrzykiwane do podpowiedzi wysyłanej do modelu generującego.

Porcjowanie (tiktoken) → Osadzanie (wsadowo) → Magazyn pgvector (HNSW) → Wyszukiwanie podobieństwa → Generowanie rozszerzone

Detal architektoniczny mający znaczenie w produkcji: podczas połączeń sieciowych z dostawcą osadzania lub generowania nie jest utrzymywane żadne połączenie Postgres. Transakcja DB zamyka się przed połączeniem zewnętrznym i otwiera się ponownie po, aby nigdy nie blokować współdzielonego backendu PgBouncer ze względu na opóźnienia w sieci innej firmy.

#
Krok 1

Utwórz projekt

W przeciwieństwie do typowego pgvectora, który jest hostowany samodzielnie, nie musisz uruchamiać CREATE EXTENSION vector ani samodzielnie tworzyć tabeli dla tego potoku. Schemat embeddings projektu z kolumnami wektorowymi i indeksami HNSW jest udostępniany automatycznie podczas tworzenia projektu.

terminalbash
# Konto Aurabase + CLI
npm i -g @aurabase/cli
aura login

# Utwórz projekt i połącz go z tym folderem
aura projects create mon-assistant --engine postgres
aura link --project-id <uuid-du-projet>

# Pobierz klucze API połączonego projektu
aura projects api-keys

Dostawca osadzania konfigurowany jest jednorazowo, po stronie projektu (Studio → IA → Dostawcy). To właśnie ten dostawca określa efektywny wymiar Twoich wektorów, a zatem kolumnę używaną w tabeli embeddings.

#
Krok 2

Indeksuj swoje dokumenty za pomocą ragIngest()

Do zaindeksowania dokumentu wystarczy jedno wywołanie: tekst jest dzielony na fragmenty, każdy fragment jest wektoryzowany, a następnie zapisywany w żądanej przestrzeni nazw. Przy podziale używany jest prawdziwy tokenizer (tiktoken, kodowanie o200k_base), a nie proste dzielenie spacjami, które pozostaje poprawne w przypadku tekstu bez spacji, jak w niektórych językach azjatyckich.

app/api/ingest/route.tstypescript
import { aura } from '@/lib/aurabase'

export async function POST(req: Request) {
  const { content, metadata } = await req.json()

  const { data, error } = await aura.ai.ragIngest({
    namespace: 'docs-produit',
    content,
    metadata,
  })

  if (error) return Response.json({ error }, { status: 400 })
  return Response.json(data) // { identyfikator, kawałki }
}

W surowym protokole HTTP równoważna trasa to POST /v1/ai/{project_id}/rag/ingest, uwierzytelniana za pomocą klucza API projektu.

terminalbash
curl -X POST https://<votre-gateway>/v1/ai/<project_id>/rag/ingest \
  -H "apikey: <votre-cle-api>" \
  -H "Content-Type: application/json" \
  -d '{
    "namespace": "docs-produit",
    "content": "Le texte complet de votre document ici...",
    "metadata": { "source": "guide-utilisateur.pdf" }
  }'

Pozyskiwanie jest domyślnie idempotentne: identyfikator dokumentu jest generowany automatycznie (skrót SHA-256 treści lub metadata.document_id, jeśli go podasz). Ponowne wykorzystanie tej samej treści powoduje zastąpienie jej istniejących fragmentów zamiast ich duplikowania, dzięki czemu okresowe zadanie synchronizacji można bezpiecznie odtwarzać.

#
Krok 3

Co właściwie ląduje w Postgres

Nie ma tu żadnej zastrzeżonej magii: tabela, która odbiera twoje wektory, jest zwykłą tabelą Postgres, z jedną kolumną vector na klasę wymiaru i częściowym indeksem HNSW na kolumnę (aktywnym tylko w wierszach, które ją zapełniają). Oto jego prawdziwa definicja, uproszczona:

schemat platformy projektu (uproszczony)sql
create table embeddings (
  id               uuid primary key default gen_random_uuid(),
  project_id       text not null,
  namespace        text not null,
  content          text not null,
  embedding_768    vector(768),
  embedding_1536   vector(1536),
  embedding_3072   vector(3072),
  embedding_model  text,
  dims             int,
  metadata         jsonb default '{}'::jsonb,
  created_at       timestamptz not null default now()
);

-- Częściowy indeks HNSW według klasy wymiaru
create index idx_embeddings_vec_1536 on embeddings
  using hnsw (embedding_1536 vector_cosine_ops)
  where embedding_1536 is not null;

-- Poza wymiarami 2000 HNSW nie obsługuje typu wektorowego:
-- odlany w halfvec dla klasy 3072
create index idx_embeddings_vec_3072 on embeddings
  using hnsw ((embedding_3072::halfvec(3072)) halfvec_cosine_ops)
  where embedding_3072 is not null;

Każde wyszukiwanie porównuje wektory z cosinusowym operatorem odległości (<=>), będącym celem klas operatorów vector_cosine_ops i halfvec_cosine_ops indeksu. Aby uzyskać szczegółowe informacje na temat kompromisów w zakresie wycofania/opóźnienia HNSW w porównaniu z IVFFlat, zobacz artykuł poświęcony indeksowaniu HNSW. Aby wybrać sam wymiar osadzania, zobacz porównanie 768 vs 1536 vs 3072.

#
Krok 4

Zapytanie i wygenerowanie odpowiedzi za pomocą rag()

Po stronie zapytania rag() łączy wektoryzację pytania, wyszukiwanie według podobieństwa w przestrzeni nazw, konstrukcję rozszerzonego znaku zachęty i wywołanie modelu generacji w ramach jednej operacji sieciowej po stronie klienta.

app/api/ask/route.tstypescript
import { aura } from '@/lib/aurabase'

export async function POST(req: Request) {
  const { question } = await req.json()

  const { data, error } = await aura.ai.rag({
    question,
    namespace: 'docs-produit',
  })

  if (error) return Response.json({ error }, { status: 400 })
  return Response.json(data)
}

Odpowiedź zawiera wygenerowaną odpowiedź i jej źródła, z faktycznie wykorzystanym dostawcą:

odpowiedź (fragment)json
{
  "data": {
    "answer": "D'après la documentation, ...",
    "sources": [
      { "id": "...", "content": "...", "similarity": 0.87 }
    ],
    "model": "claude-3-5-sonnet",
    "tokens": 412,
    "provider": "anthropic",
    "fallback_used": false
  }
}

Pobrana treść nigdy nie jest wstrzykiwana w postaci surowej do zachęty systemowej. Są to dane niewiarygodne (przesłane przez użytkownika, strona zindeksowana): dokument zawierający np. znacznik sekcji zamykającej, po którym następują fałszywe instrukcje, jest przed montażem neutralizowany, nawiasy ostrokątne zastąpione nawiasami ostrokątnymi, tekst zachowany, ale pozbawiona struktury.

Korpus indeksowany w ramach innego modelu

Jeśli rag() nic nie znajdzie, mimo że Twoja przestrzeń nazw nie jest pusta, odpowiedź zawiera wyraźne ostrzeżenie, a nie wprowadzającą w błąd ciszę: Twój korpus jest prawdopodobnie indeksowany w ramach innego modelu lub innego wymiaru osadzania. Zindeksuj go ponownie za pomocą POST /v1/ai/{project_id}/rag/{namespace}/reindex.

#
Porównanie

Z LangChain i ręcznie robionego pgvectora: co się zmienia

Jeśli zbudowałeś już chatbota RAG na PostgreSQL z LangChain, każdy ręczny klocek ma tutaj odpowiednik zarządzany po stronie serwera, bez zmiany podstawowej bazy danych.

Rozbijanie tekstuRecursiveCharacterTextSplitter, aby ustawić siebieragIngest(): zintegrowane dzielenie tiktokenów, domyślnie 512 tokenów / 64 nakładanie się
OsadzeniaRęczne wywołanie OpenAIEmbeddings, zarządzanie limitami wsadowymiAutomatycznie grupowana, wbudowana ponowna próba przejściowa
Przechowywanie wektorówtabela pgvector + indeks HNSW do samodzielnego tworzenia i migracjiSchemat i indeksy udostępniane dla każdego projektu
Wyszukaj + podpowiedźPGVector.similarity_search(), a następnie ręczne złożenie podpowiedzirag(): wyszukiwanie i generowanie rozszerzone w jednym wywołaniu
Odzyskana zawartośćWstrzyknięto zgodnie z poleceniemAutomatyczna neutralizacja oznaczeń konstrukcji przed montażem

Czy migrujesz istniejący projekt zbudowany na Supabase z tego rodzaju ręcznym montażem? Logikę migracji pozostałej części backendu (schemat, zasady RLS, SDK) omówiono w naszym przewodniku migracji Supabase do Aurabase.

#
Produkcja

Ustawienia i ograniczenia, o których należy pamiętać przed rozpoczęciem produkcji

Trzy ustawienia bezpośrednio wpływają na koszt i opóźnienia, wszystkie weryfikowane w kodzie usługi aura-ai. Liczba prób tymczasowego połączenia osadzającego (awaria sieci, błąd dostawcy 429) wynosi domyślnie 3, z podstawowym opóźnieniem wynoszącym 100 ms. Duże dokumenty są domyślnie umieszczane w podpartiach ograniczonych do 2048 fragmentów, aby przestrzegać pułapów API dostawców bez utraty pojedynczego, ogromnego dokumentu. Poręcz (domyślnie 10 000 fragmentów, konfigurowalna) wyraźnie odrzuca przyjęcie dokumentu, który wygenerowałby nieprawidłową liczbę fragmentów.

Po stronie wyszukiwania rozmiar listy kandydatów HNSW automatycznie dostosowuje się do max(64, top_k × 4): im więcej żądanych wyników, tym więcej kandydatów bada indeks, aby zachować ich zapamiętanie. Stała wartość pozostaje możliwa poprzez zmienną środowiskową, jeśli korpus ma określony profil.

Przestrzenie wektorowe różnych modeli nigdy nie są ze sobą porównywane: każde wyszukiwanie ogranicza się do bieżącego modelu osadzania, a zmiana modeli wymaga jawnego ponownego indeksowania, a nie cichego przełącznika, który zakłóciłby spójność wyników.

#
Uczciwość

Aktualne ograniczenia, o których należy pamiętać

Wymiar osadzania musi należeć do jednej z trzech obsługiwanych klas: 768, 1536 lub 3072. Dostawca, który zwraca inny wymiar, jest odrzucany z jawnym błędem, nigdy nie jest obcinany ani dyskretnie rzutowany.

Generowanie osadzania jest dostępne tylko za pośrednictwem OpenAI lub Google Gemini wśród trzech natywnych dostawców: Anthropic/Claude nie udostępnia publicznego interfejsu API osadzania, więc jest używany tylko do generowania ostatecznej odpowiedzi w tym potoku, nigdy do wektoryzacji.

JavaScript SDK nie udostępnia jeszcze przesłonięć top_k i threshold w wywołaniu rag(): pozostają one dostępne w bezpośrednim HTTP, z ograniczeniem odpowiednio do [1, 50] i [0, 1], ale nie z aura.ai.rag(), jak ma to miejsce obecnie. Domyślny próg podobieństwa (0,3) jest celowo liberalny; zawęź go do gęstego korpusu, aby uniknąć nieistotnych źródeł w podpowiedzi.

#
Idź dalej

Aby pójść dalej

Wytyczne obejmują pytania dotyczące treści nieustrukturyzowanych (dokumenty, notatki, bilety). W przypadku pytań dotyczących danych relacyjnych natywna wersja Aurabase NL2SQL bezpośrednio tłumaczy pytanie na zatwierdzony kod SQL. Szczegóły dotyczące parametrów HNSW i klas wymiarów wymienionych powyżej można znaleźć w artykule na temat indeksowania HNSW i porównaniu wymiarów osadzania. Pełną dokumentacją API pozostaje dokumentacja RAG i pgvector i dokumentacja AI Gateway.

#
Często zadawane pytania

Często zadawane pytania

Czy musisz samodzielnie zarządzać rozszerzeniem pgvector i indeksem HNSW?+
Nie. Schemat osadzania, rozszerzenie pgvector i częściowe indeksy HNSW (po jednym na klasę wymiaru: 768, 1536, 3072) są udostępniane automatycznie podczas tworzenia projektu. Bezpośrednio wywołujesz ragIngest(), a następnie rag(); dostrajanie indeksu (tryb ef_search, iterative_scan) pozostaje dostępne po stronie serwera, jeśli Twój korpus ma określony profil.
Który wymiar osadzania powinienem wybrać dla mojego przypadku użycia?+
Aurabase sprawdza wymiar zwrócony przez dostawcę w oparciu o trzy obsługiwane klasy: 768, 1536 i 3072. Wybór zależy od skonfigurowanego modelu osadzania (np. Text-embedding-3-small w OpenAI tworzy 1536 wymiarów) i obejmuje kompromis pomiędzy wycofaniem, kosztem i wielkością pamięci wyszczególnioną w naszym porównaniu poświęconym wymiarom osadzania.

GOTOWY DO WDROŻENIA?

Twój backend w pięć minut.

Karta kredytowa nie jest wymagana · 500 MB za darmo · 50 000 MAU