PRODSouveräne europäische BaaS-PlattformÖffnen Sie das Dashboard →

Native KI · 10 Min. Lesezeit

Tutorial: RAG-Pipeline mit Postgres und pgvector

Affane Daylami · Fondateur · 13. April 2026

Zurück zum Blog

Für den Aufbau einer RAG-Pipeline auf Postgres müssen Sie im Allgemeinen mehrere Teile selbst zusammenstellen: einen Text-Slicer, einen Einbettungsaufruf, eine pgvector-Tabelle und eine Ähnlichkeitsabfrage. Dies ist die klassische LangChain + PGVectorchain. Auf Aurabase existiert diese Pipeline bereits auf der Serverseite: Zwei Aufrufe, ragIngest() und rag(), ersetzen sie, während sie sich auf Standard-PostgreSQL und pgvector verlassen, ohne dass eine proprietäre Vektorbasis hinzugefügt werden muss.

Dieser englische Text wurde automatisch aus dem französischen Original generiert und wurde noch nicht überprüft.
Diese Seite wurde automatisch übersetzt. Maßgeblich ist die englische Version.

Das native RAG ist neben NL2SQL Teil der nativen KI, die in das Aurabase-Backendintegriert ist: kein Drittanbieterdienst, der auf einer allgemeinen Basis zusammengestellt werden kann. Voraussetzungen für die Durchführung dieses Tutorials: ein vorhandenes Aurabase-Projekt, ein konfigurierter LLM-Anbieter (OpenAI oder Google Gemini für Einbettungen, einer der drei nativen Anbieter für die Generierung) und ein Projekt-API-Schlüssel.

Das Wesentliche
  • Eine Aurabase RAG-Pipeline besteht aus zwei Aufrufen: ragIngest() zum Indizieren eines Dokuments, rag() zum Abfragen und Generieren einer Antwort. Chunking, Einbettungen und Vektorsuche werden serverseitig verwaltet.
  • Unter der Haube sind es Standard-PostgreSQL und pgvector: eine embeddings-Tabelle mit einer Vektorspalte pro Dimensionsklasse (768, 1536, 3072) und einem partiellen HNSW-Index pro Klasse.
  • Beim Chunking wird ein echter Tokenizer (tiktoken o200k) mit konfigurierbarer Überlappung und einem Explosionsschutz für große Dokumente verwendet.
  • Der abgerufene Inhalt wird neutralisiert, bevor er in die Eingabeaufforderung eingefügt wird: Ein Dokument, das versucht, sein Tag zu umgehen, um Systemanweisungen zu fälschen, wird explizit entschärft.
  • Nur OpenAI und Gemini generieren Einbettungen auf der Aurabase-Seite. Anthropic/Claude verfügt nicht über eine öffentliche Einbettungs-API, sie bleibt für die Generierung der endgültigen Antwort reserviert.
#
Konzept

Wie diese RAG-Pipeline funktioniert

Die Pipeline erfolgt in fünf Stufen. Bei der Aufnahme wird der Text zerschnitten, jeder Block wird stapelweise vektorisiert und dann gespeichert. Bei der Abfrage wird die Frage der Reihe nach vektorisiert, mit den durch Kosinusähnlichkeit gespeicherten Blöcken verglichen und die nächstgelegenen Schnipsel werden in die an das Generierungsmodell gesendete Eingabeaufforderung eingefügt.

Chunking (tiktoken)→Einbettungen (Batch)→pgvector storage (HNSW)→Ähnlichkeitssuche→Erweiterte Generierung

Ein architektonisches Detail, das in der Produktion von Bedeutung ist: Bei Netzwerkanrufen an den Einbettungs- oder Generierungsanbieter wird keine Postgres-Verbindung aufrechterhalten. Die DB-Transaktion wird vor dem externen Aufruf geschlossen und danach erneut geöffnet, um niemals ein gemeinsam genutztes PgBouncer-Backend für Netzwerklatenz von Drittanbietern zu blockieren.

#
Schritt 1

Erstellen Sie das Projekt

Im Gegensatz zu einem typischen selbstgehosteten pgvector müssen Sie für diese Pipeline weder CREATE EXTENSION vector ausführen noch selbst eine Tabelle erstellen. Das embeddings-Schema des Projekts mit seinen Vektorspalten und HNSW-Indizes wird automatisch bereitgestellt, wenn das Projekt erstellt wird.

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

# Erstellen Sie das Projekt und verknüpfen Sie es mit diesem Ordner
aura projects create mon-assistant --engine postgres
aura link --project-id <uuid-du-projet>

# Rufen Sie die API-Schlüssel des verknüpften Projekts ab
aura projects api-keys

Der Einbettungsanbieter wird einmalig auf Projektseite konfiguriert (Studio → IA → Lieferanten). Es ist dieser Anbieter, der die effektive Dimension Ihrer Vektoren bestimmt, also die Spalte, die in der Tabelle embeddingsverwendet wird.

#
Schritt 2

Indizieren Sie Ihre Dokumente mit ragIngest()

Ein Aufruf reicht aus, um ein Dokument zu indizieren: Der Text wird in Blöcke unterteilt, jeder Block wird vektorisiert und dann im angeforderten Namensraum gespeichert. Die Aufteilung verwendet einen echten Tokenizer (tiktoken, Kodierung o200k_base), keine einfache Aufteilung nach Leerzeichen, die bei Text ohne Leerzeichen wie in einigen asiatischen Sprachen korrekt bleibt.

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) // { id, chunks }
}

In rohem HTTP ist die entsprechende Route POST /v1/ai/{project_id}/rag/ingest, authentifiziert durch den API-Schlüssel des Projekts.

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" }
  }'

Die Aufnahme ist standardmäßig idempotent: Eine Dokumentkennung wird automatisch abgeleitet (SHA-256-Hash des Inhalts oder metadata.document_id, wenn Sie ihn angeben). Durch die erneute Einbindung desselben Inhalts werden dessen vorhandene Blöcke ersetzt, anstatt sie zu duplizieren, sodass ein regelmäßiger Synchronisierungsauftrag sicher wiederholt werden kann.

#
Schritt 3

Was tatsächlich in Postgres landet

Hier gibt es keine proprietäre Magie: Die Tabelle, die Ihre Vektoren empfängt, ist eine gewöhnliche Postgres-Tabelle mit einer vector-Spalte pro Dimensionsklasse und einem partiellen HNSW-Index pro Spalte (aktiv nur für die Zeilen, die sie füllen). Hier ist die tatsächliche Definition, vereinfacht:

Plattformdiagramm des Projekts (vereinfacht)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()
);

-- Ein partieller HNSW-Index nach Dimensionsklasse
create index idx_embeddings_vec_1536 on embeddings
  using hnsw (embedding_1536 vector_cosine_ops)
  where embedding_1536 is not null;

-- Über 2000 Dimensionen hinaus unterstützt HNSW den Vektortyp nicht:
-- in Halbvec gegossen für Baureihe 3072
create index idx_embeddings_vec_3072 on embeddings
  using hnsw ((embedding_3072::halfvec(3072)) halfvec_cosine_ops)
  where embedding_3072 is not null;

Bei jeder Suche werden die Vektoren mit dem Kosinus-Abstandsoperator (<=>) verglichen, auf den die Operatorklassen vector_cosine_ops und halfvec_cosine_ops des Index abzielen. Einzelheiten zu den Recall-/Latenz-Kompromissen von HNSW gegenüber IVFFlat finden Sie im Artikel zur HNSW-Indizierung. Für die Wahl der Einbettungsdimension selbst siehe den Vergleich 768 vs 1536 vs 3072.

#
Schritt 4

Fragen Sie ab und generieren Sie eine Antwort mit rag()

Auf der Abfrageseite verkettet rag() die Vektorisierung der Frage, die Suche nach Ähnlichkeit im Namespace, die Konstruktion des erweiterten Prompts und den Aufruf des Generierungsmodells in einem einzigen Netzwerk-Roundtrip auf der Client-Seite.

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)
}

Die Antwort enthält die generierte Antwort und ihre Quellen sowie den tatsächlich verwendeten Anbieter:

Antwort (Auszug)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
  }
}

Der abgerufene Inhalt wird niemals roh in die Systemeingabeaufforderung eingefügt. Hierbei handelt es sich um unzuverlässige Daten (Benutzer-Upload, indizierte Seite): Ein Dokument, das beispielsweise ein Schlussabschnitts-Tag gefolgt von falschen Anweisungen enthält, wird vor dem Zusammensetzen neutralisiert, seine spitzen Klammern werden durch Klammern ersetzt, der Text bleibt erhalten, die Struktur wird jedoch entschärft.

Korpus unter einem anderen Modell indexiert

Wenn rag() nichts findet, obwohl Ihr Namespace nicht leer ist, enthält die Antwort eine explizite Warnung und nicht ein irreführendes Schweigen: Ihr Korpus ist wahrscheinlich unter einem anderen Modell oder einer anderen Einbettungsdimension indiziert. Indizieren Sie es über POST /v1/ai/{project_id}/rag/{namespace}/reindexneu.

#
Vergleich

From LangChain and a handmade pgvector: what changes

Wenn Sie mit LangChain bereits einen RAG-Chatbot auf PostgreSQL erstellt haben, verfügt jeder manuelle Baustein hier über ein serverseitig verwaltetes Äquivalent, ohne die zugrunde liegende Datenbank zu ändern.

Den Text aufbrechenRecursiveCharacterTextSplitter können Sie selbst festlegenragIngest(): integriertes Tiktoken-Chunking, standardmäßig 512 Tokens / 64 Überlappung
EinbettungenManueller Aufruf von OpenAIEmbeddings, Verwaltung von Batch-LimitsAutomatisch gestapelter, integrierter vorübergehender Wiederholungsversuch
Vektorspeicherpgvector-Tabelle + HNSW-Index zum Erstellen und MigrierenSchema und Indizes werden pro Projekt bereitgestellt
Suchen + EingabeaufforderungPGVector.similarity_search() und dann die Eingabeaufforderung manuell zusammenstellenrag(): search and augmented generation in one call
Wiederhergestellter InhaltGespritzt wie es in der Aufforderung stehtAutomatische Neutralisierung von Struktur-Tags vor dem Zusammenbau

Migrieren Sie ein bestehendes, auf Supabase erstelltes Projekt mit dieser Art der manuellen Montage? Die Migrationslogik für den Rest des Backends (Schema, RLS-Richtlinien, SDK) wird in unserem Migrationsleitfaden von Supabase zu Aurabasebehandelt.

#
Produktion

Bevor Sie mit der Produktion beginnen, müssen Sie sich über Einstellungen und Grenzen im Klaren sein

Three settings directly affect cost and latency, all verified in the aura-aiservice code. The number of attempts on a transient embedding call (network failure, provider error 429) is 3 by default, with a base backoff of 100 ms. Große Dokumente werden standardmäßig in Teilstapel eingebettet, die auf 2048 Blöcke begrenzt sind, um die API-Obergrenzen der Lieferanten zu respektieren, ohne dass es bei einem einzigen riesigen Dokument zu Fehlern kommt. Eine Leitplanke (standardmäßig 10.000 Blöcke, konfigurierbar) lehnt explizit die Aufnahme eines Dokuments ab, das eine abweichende Anzahl von Blöcken erzeugen würde.

Auf der Suchseite passt sich die Größe der HNSW-Kandidatenliste automatisch an max(64, top_k × 4)an: Je mehr Ergebnisse Sie anfordern, desto mehr Kandidaten werden vom Index untersucht, um die Erinnerung zu wahren. A fixed value remains possible via an environment variable if your corpus has a particular profile.

Die Vektorräume verschiedener Modelle werden niemals miteinander verglichen: Jede Suche bleibt auf das aktuelle Einbettungsmodell beschränkt, und ein Wechsel der Modelle erfordert eine explizite Neuindizierung und nicht einen stillen Wechsel, der die Konsistenz der Ergebnisse beeinträchtigen würde.

#
Ehrlichkeit

Aktuelle Grenzwerte, die Sie beachten sollten

Die Einbettungsdimension muss in eine der drei unterstützten Klassen fallen: 768, 1536 oder 3072. Ein Anbieter, der eine andere Dimension zurückgibt, wird mit einem expliziten Fehler abgelehnt, niemals abgeschnitten oder stillschweigend umgewandelt.

Die Einbettungsgenerierung ist bei den drei nativen Anbietern nur über OpenAI oder Google Gemini verfügbar: Anthropic/Claude stellt keine öffentliche Einbettungs-API zur Verfügung, daher wird sie nur zum Generieren der endgültigen Antwort in dieser Pipeline verwendet, niemals zur Vektorisierung.

Das JavaScript SDK stellt die Überschreibungen top_k und threshold beim rag()-Aufruf noch nicht zur Verfügung: Sie bleiben im direkten HTTP zugänglich und auf [1, 50] bzw. [0, 1] beschränkt, jedoch nicht wie heute über aura.ai.rag(). The default similarity threshold (0.3) is deliberately permissive; narrow it down to a dense corpus to avoid irrelevant sources in the prompt.

#
Gehen Sie weiter

Um weiter zu gehen

The RAG covers questions on unstructured content (documents, notes, tickets). For questions about your relational data, Aurabase's native NL2SQL directly translates a question into validated SQL. For details of the HNSW parameters and dimension classes mentioned above, see the article on HNSW indexing and the comparison of embedding dimensions. The full API reference remains the RAG & pgvector documentation and the AI Gateway documentation.

#
Häufig gestellte Fragen

FAQs

Müssen Sie die pgvector-Erweiterung und den HNSW-Index selbst verwalten?+
Nein. Das Einbettungsschema, die pgvector-Erweiterung und die partiellen HNSW-Indizes (einer pro Dimensionsklasse: 768, 1536, 3072) werden automatisch bereitgestellt, wenn das Projekt erstellt wird. Sie rufen direkt ragIngest() und dann rag(); auf. Die Feinabstimmung des Index (ef_search, iterative_scan-Modus) bleibt auf der Serverseite zugänglich, wenn Ihr Korpus ein bestimmtes Profil hat.
Welche Einbettungsdimension sollte ich für meinen Anwendungsfall wählen?+
Aurabase validiert die von Ihrem Lieferanten zurückgegebene Dimension anhand von drei unterstützten Klassen: 768, 1536 und 3072. Die Auswahl hängt vom konfigurierten Einbettungsmodell ab (text-embedding-3-small bei OpenAI erzeugt beispielsweise 1536 Dimensionen) und beinhaltet einen Kompromiss zwischen Rückruf, Kosten und Speichergröße, der in unserem Vergleich zu Einbettungsdimensionen detailliert beschrieben wird.

BEREIT ZUM EINSATZ?

Ihr Backend in fünf Minuten.

Keine Kreditkarte erforderlich · 500 MB kostenlos · 50.000 MAU