Postgres può gestire la tua pipeline RAG?

Abbiamo testato l’approccio database-first di pgai per capire dove semplifica le operazioni RAG e dove i carichi di lavoro complessi richiedono ancora maggiore flessibilità.

Sintesi

  • Gli LLM possono «vedere» solo una quantità limitata di testo alla volta (la finestra di contesto). Questo approccio funziona per attività circoscritte, ma entra in crisi quando una base di conoscenza si estende per migliaia di pagine. Anche quando la finestra di contesto è sufficiente, le prestazioni possono comunque peggiorare a causa del problema dell’«ago nel pagliaio».

  • Il RAG («generazione aumentata tramite recupero») si è affermato come modello molto diffuso: si mantiene una base di conoscenza (documenti, wiki, policy, trascrizioni e così via), si esegue una ricerca semantica sulla richiesta dell’utente per recuperare tramite embedding i frammenti più pertinenti, quindi si forniscono tali frammenti all’LLM insieme alla domanda. Questo limita il contesto del modello e, se eseguito correttamente, può migliorare la qualità delle risposte e ridurre le allucinazioni.

  • pgai è un’estensione open source per Postgres, corredata da appositi strumenti, che aiuta a creare flussi di lavoro di «recupero tramite IA» basati su PostgreSQL, l’affidabile database open source.

  • L’idea principale è trasferire più fasi della pipeline RAG standard al livello del database (acquisizione → suddivisione → embedding → sincronizzazione degli embedding), anziché considerare il DB un «semplice spazio di archiviazione» per gli embedding.

  • Le prime impressioni sono promettenti, ma pgai non sembra adatto quando la pipeline RAG diventa anche solo moderatamente complessa, soprattutto per quanto riguarda le strategie di suddivisione. Continueremo comunque a seguire attentamente il progetto.

Il modello RAG

Esistono molti modi per creare un sistema RAG. Per un’analisi più approfondita dei diversi approcci, leggi Esempi pratici di soluzioni RAG personalizzate. Quando la qualità diventa importante, le possibilità di progettazione si rivelano sorprendentemente ampie. Il comune approccio «predefinito» è in genere questo:

  1. Raccogliere una serie di documenti.

  2. Suddividerli in frammenti. Esistono molti metodi per farlo, ad esempio per paragrafi o raggruppamenti semantici.

  3. Trasformare ogni frammento in un embedding.

  4. Archiviare gli embedding in un database vettoriale (Pinecone, Milvus e così via) oppure in Postgres tramite pgvector.

  5. Al momento della richiesta, cercare i frammenti più vicini `e passarli all’LLM (anche in questo caso esistono molti modi per farlo).

In molte architetture, i passaggi (1)–(3) avvengono fuori dal database, nel codice dell’applicazione o in una pipeline di dati, mentre il database viene usato principalmente per:

  • archiviare gli embedding

  • cercare gli embedding

Lo scopo di pgai

pgai è un’estensione open source per Postgres, sviluppata da Timescale), che cerca di rendere meno netta questa distinzione.

Invece di trattare gli embedding come elementi da gestire manualmente nell’applicazione, pgai li rende una funzionalità del database:

  • Si definiscono la tabella o i documenti da trasformare in embedding.

  • Si specificano il modello di embedding e una strategia di suddivisione.

  • pgai gestisce tutto il resto, mantenendo aggiornati gli embedding anche quando cambiano i dati di origine.

I vantaggi promessi sono interessanti:

  • Meno codice di integrazione personalizzato da mantenere.

  • Dovrebbe essere più facile mantenere «aggiornati» gli embedding quando cambiano i documenti di origine.

  • Postgres/pgai gestisce nuovi tentativi, limiti di frequenza, processi non riusciti e così via.

Nota per chi legge: pgai include pgvector, un’altra estensione per Postgres molto diffusa nel campo del RAG. pgvector aggiunge a Postgres l’archiviazione vettoriale e la ricerca per similarità; pgai sfrutta queste funzioni per automatizzare fasi della pipeline RAG come la suddivisione, la creazione degli embedding e il loro aggiornamento.

Prime impressioni su pgai

Cosa ci è piaciuto

1) È facile da avviare.

La procedura ideale è piuttosto semplice:

  • Scaricare le immagini Docker di Timescale (database + worker).

  • Fornire la chiave API del provider di embedding.

  • Eseguire poche istruzioni SQL per dichiarare il vettorizzatore, indicando in sostanza cosa trasformare in embedding, come suddividerlo e quale modello usare.

A quel punto, pgai configura un worker di vettorizzazione che viene eseguito come processo separato e genera gli embedding in modo asincrono, ad esempio ogni 5 minuti o con qualsiasi altra frequenza desiderata.

2) È comodo eseguire l’intera pipeline «vicino» al database.

pgai può acquisire contenuti dalle tabelle e caricare documenti da servizi come S3, quindi analizzarli, suddividerli e trasformarli in embedding. Può inoltre gestire diversi formati di documenti testuali, come PDF, Markdown e altri.

Gli aspetti che ci sono sembrati limitanti

1) Si perde molto controllo, che talvolta è essenziale nel RAG.

I sistemi RAG ad alte prestazioni, in termini di qualità delle risposte, richiedono spesso pipeline personalizzate, ad esempio:

  • regole di suddivisione personalizzate (per titoli, pagine, turni di parola e così via)

  • suddivisione basata sui metadati (conservando titoli delle sezioni, timestamp, autori e tipo di documento)

  • strategie di embedding diverse per ciascun tipo di documento

pgai offre meno flessibilità negli ambiti appena descritti.

Al momento esistono due strategie di suddivisione principali: il separatore di testo per caratteri e quello ricorsivo per caratteri, oltre a un’opzione che non prevede alcuna suddivisione. Potrebbe bastare per alcuni casi d’uso, ma molti sistemi RAG in produzione richiedono una maggiore personalizzazione.

Sarebbe molto interessante se Timescale integrasse alcune delle strategie di suddivisione più sofisticate presenti in librerie come Chonkie e supportasse allo stesso modo soluzioni avanzate come il recupero contestuale di Anthropic.

2) Incentrato sul testo, non multimodale.

Molti problemi interessanti nell’ambito del RAG non riguardano più soltanto il testo:

  • PDF con diagrammi

  • screenshot/immagini

  • registrazioni audio

  • clip video

Anche se è possibile «estrarre il testo» da queste fonti, non equivale a una vera pipeline di embedding multimodale.

Se in futuro pgai supportasse modelli multimodali end-to-end (caricamento → suddivisione → embedding di immagini, audio e video di grandi dimensioni archiviati in S3, con una sincronizzazione affidabile), sarebbe molto interessante. Oggi, però, offre un flusso di lavoro per embedding testuali.

3) Se servono soltanto gli embedding, pgai potrebbe non essere necessario.

Se la pipeline di acquisizione è già personalizzata, o deve esserlo, «creare embedding da frammenti di testo» non è la parte più difficile del RAG. In questo scenario, pgai risolve la parte più semplice del problema.

Inoltre, se la base di conoscenza viene aggiornata di rado, la sincronizzazione automatica degli embedding offre un vantaggio più limitato.

Livello text-to-SQL

Un modo particolarmente efficace di usare pgai consiste nell’implementare un’interfaccia text-to-SQL per i propri database. È piuttosto facile farlo con il modulo semantic_catalog offerto da pgai. È sufficiente configurarlo così:

Bash

OPENAI_API_KEY="your-OpenAPI-key-goes-here"TARGET_DB="postgres://user:password@host:port/database"CATALOG_DB="postgres://user:password@host:port/database"

quindi fare in modo che il catalogo semantico analizzi i dizionari dei dati con pgai semantic-catalog create. In questo modo viene generato dal datastore un contesto simile al seguente:

Plain Text

---schema: postgres_airname: aircrafttype: tabledescription: Lists aircraft models with performance characteristics and unique codes.columns:- name: model  description: Commercial name of the aircraft model.- name: range  description: Maximum flight range in kilometers.- name: class  description: Airframe class category or configuration indicator.- name: velocity  description: Cruising speed of the aircraft.- name: code  description: Three-character aircraft code serving as the primary key....

Questo contesto è ora disponibile per pgai in diversi modi:

Tramite ricerca semantica:

Questa query restituisce le tabelle, le funzioni e gli altri oggetti potenzialmente pertinenti alla richiesta in linguaggio naturale:

Bash

pgai semantic-catalog search -p "Your natural language question goes here!"

Ottenere il contesto grezzo:

In questo modo viene visualizzato il contesto YAML grezzo relativo alla richiesta in linguaggio naturale:

Bash

pgai semantic-catalog search -p "Your natural language question goes here!" --render

Generare SQL:

In alternativa, è possibile generare direttamente il codice SQL grezzo necessario per rispondere alla richiesta. Il contesto del passaggio precedente viene inviato a un LLM, che genera la risposta:

Bash

pgai semantic-catalog generate-sql -p "Your natural language question goes here!"

Come usare pgai già da ora

Se stai creando un sistema RAG relativamente semplice, vale la pena provare pgai se desideri:

  • usare Postgres come sistema di riferimento,

  • ridurre al minimo il codice di integrazione,

  • mantenere gli embedding sincronizzati automaticamente,

  • applicare rapidamente un sistema text-to-SQL ai tuoi database,

  • sperimentare nuovi strumenti RAG ed estensioni per Postgres.

Dove consigliamo cautela

Probabilmente conviene aspettare prima di adottare pgai se la pipeline RAG richiede una delle seguenti funzionalità:

  • logica di acquisizione o suddivisione fortemente personalizzata

  • molti tipi di documenti con requisiti di analisi differenti

  • embedding multimodali

Infine, sebbene pgvector sia stato chiaramente adottato su vasta scala, non è ancora chiaro se pgai susciterà lo stesso interesse e riceverà quindi lo stesso supporto, considerando anche che esiste solo da circa 18 mesi.

Grafico della cronologia delle stelle su GitHub che mostra nel tempo l’adozione di pgai di Timescale.

pgai propone un approccio interessante al RAG: affidare ai database una parte maggiore delle operazioni di routine per semplificare il codice dell’applicazione.

Al momento è:

  • utilizzabile e davvero piacevole per configurazioni RAG semplici

  • non abbastanza flessibile per pipeline più personalizzate, soprattutto multimodali

È promettente e vale sicuramente la pena seguirne l’evoluzione.

Autore

Andrew Liubinas